Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Wildcard to Hosts #2747

Merged
merged 5 commits into from Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/engine_test.go
Expand Up @@ -656,7 +656,7 @@ func TestSentReceivedMetrics(t *testing.T) {
test := newTestEngine(t, nil, r, []output.Output{mockOutput}, lib.Options{
Iterations: null.IntFrom(tc.Iterations),
VUs: null.IntFrom(tc.VUs),
Hosts: tb.Dialer.Hosts,
Hosts: types.NullAddressTrie{Trie: tb.Dialer.Hosts, Valid: true},
InsecureSkipTLSVerify: null.BoolFrom(true),
NoVUConnectionReuse: null.BoolFrom(noConnReuse),
Batch: null.IntFrom(20),
Expand Down Expand Up @@ -795,7 +795,7 @@ func TestRunTags(t *testing.T) {
test := newTestEngine(t, nil, r, []output.Output{mockOutput}, lib.Options{
Iterations: null.IntFrom(3),
VUs: null.IntFrom(2),
Hosts: tb.Dialer.Hosts,
Hosts: types.NullAddressTrie{Trie: tb.Dialer.Hosts, Valid: true},
RunTags: runTags,
SystemTags: &metrics.DefaultSystemTagSet,
InsecureSkipTLSVerify: null.BoolFrom(true),
Expand Down
6 changes: 4 additions & 2 deletions js/http_bench_test.go
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"testing"

"go.k6.io/k6/lib/types"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/guregu/null.v3"
Expand All @@ -30,7 +32,7 @@ func BenchmarkHTTPRequests(b *testing.B) {
err = r.SetOptions(lib.Options{
Throw: null.BoolFrom(true),
MaxRedirects: null.IntFrom(10),
Hosts: tb.Dialer.Hosts,
Hosts: types.NullAddressTrie{Trie: tb.Dialer.Hosts},
NoCookiesReset: null.BoolFrom(true),
SystemTags: &metrics.DefaultSystemTagSet,
RunTags: map[string]string{"myapp": "myhttpbench"},
Expand Down Expand Up @@ -70,7 +72,7 @@ func BenchmarkHTTPRequestsBase(b *testing.B) {
err = r.SetOptions(lib.Options{
Throw: null.BoolFrom(true),
MaxRedirects: null.IntFrom(10),
Hosts: tb.Dialer.Hosts,
Hosts: types.NullAddressTrie{Trie: tb.Dialer.Hosts},
NoCookiesReset: null.BoolFrom(true),
})
require.NoError(b, err)
Expand Down
4 changes: 3 additions & 1 deletion js/module_loading_test.go
Expand Up @@ -7,6 +7,8 @@ import (
"testing"
"time"

"go.k6.io/k6/lib/types"

"github.com/spf13/afero"
"github.com/stretchr/testify/require"
"gopkg.in/guregu/null.v3"
Expand Down Expand Up @@ -197,7 +199,7 @@ func TestLoadDoesntBreakHTTPGet(t *testing.T) {
`, fs, lib.RuntimeOptions{CompatibilityMode: null.StringFrom("extended")})
require.NoError(t, err)

require.NoError(t, r1.SetOptions(lib.Options{Hosts: tb.Dialer.Hosts}))
require.NoError(t, r1.SetOptions(lib.Options{Hosts: types.NullAddressTrie{Trie: tb.Dialer.Hosts}}))
arc := r1.MakeArchive()
registry := metrics.NewRegistry()
builtinMetrics := metrics.RegisterBuiltinMetrics(registry)
Expand Down
4 changes: 2 additions & 2 deletions js/modules/k6/execution/execution_test.go
Expand Up @@ -292,12 +292,12 @@ func TestOptionsTestFull(t *testing.T) {
require.NoError(t, err)
return bh
}(),
Hosts: map[string]*lib.HostAddress{
Hosts: types.NewNullAddressTrie(map[string]types.HostAddress{
"test.k6.io": {
IP: []byte{0x01, 0x02, 0x03, 0x04},
Port: 8443,
},
},
}),
External: map[string]json.RawMessage{
"ext-one": json.RawMessage(`{"rawkey":"rawvalue"}`),
},
Expand Down
22 changes: 12 additions & 10 deletions js/modules/k6/http/request_test.go
Expand Up @@ -27,6 +27,8 @@ import (
"testing"
"time"

"go.k6.io/k6/lib/types"

"github.com/andybalholm/brotli"
"github.com/dop251/goja"
"github.com/klauspost/compress/zstd"
Expand Down Expand Up @@ -2358,11 +2360,11 @@ func TestRequestAndBatchTLS(t *testing.T) {
host, port, err := net.SplitHostPort(s.Listener.Addr().String())
require.NoError(t, err)
ip := net.ParseIP(host)
mybadsslHostname, err := lib.NewHostAddress(ip, port)
mybadsslHostname, err := types.NewHostAddress(ip, port)
require.NoError(t, err)
state.Transport = client.Transport
state.TLSConfig = s.TLS
state.Dialer = &netext.Dialer{Hosts: map[string]*lib.HostAddress{"expired.localhost": mybadsslHostname}}
state.Dialer = &netext.Dialer{Hosts: types.NewAddressTrie(map[string]types.HostAddress{"expired.localhost": *mybadsslHostname})}
client.Transport.(*http.Transport).DialContext = state.Dialer.DialContext //nolint:forcetypeassert
_, err = rt.RunString(`throw JSON.stringify(http.get("https://expired.localhost/"));`)
require.Error(t, err)
Expand Down Expand Up @@ -2402,11 +2404,11 @@ func TestRequestAndBatchTLS(t *testing.T) {
host, port, err := net.SplitHostPort(s.Listener.Addr().String())
require.NoError(t, err)
ip := net.ParseIP(host)
mybadsslHostname, err := lib.NewHostAddress(ip, port)
mybadsslHostname, err := types.NewHostAddress(ip, port)
require.NoError(t, err)
state.Dialer = &netext.Dialer{Hosts: map[string]*lib.HostAddress{
versionTest.URL: mybadsslHostname,
}}
state.Dialer = &netext.Dialer{Hosts: types.NewAddressTrie(map[string]types.HostAddress{
versionTest.URL: *mybadsslHostname,
})}
state.Transport = client.Transport
state.TLSConfig = s.TLS
client.Transport.(*http.Transport).DialContext = state.Dialer.DialContext //nolint:forcetypeassert
Expand Down Expand Up @@ -2442,11 +2444,11 @@ func TestRequestAndBatchTLS(t *testing.T) {
host, port, err := net.SplitHostPort(s.Listener.Addr().String())
require.NoError(t, err)
ip := net.ParseIP(host)
mybadsslHostname, err := lib.NewHostAddress(ip, port)
mybadsslHostname, err := types.NewHostAddress(ip, port)
require.NoError(t, err)
state.Dialer = &netext.Dialer{Hosts: map[string]*lib.HostAddress{
cipherSuiteTest.URL: mybadsslHostname,
}}
state.Dialer = &netext.Dialer{Hosts: types.NewAddressTrie(map[string]types.HostAddress{
cipherSuiteTest.URL: *mybadsslHostname,
})}
state.Transport = client.Transport
state.TLSConfig = s.TLS
client.Transport.(*http.Transport).DialContext = state.Dialer.DialContext //nolint:forcetypeassert
Expand Down
2 changes: 1 addition & 1 deletion js/modules/k6/marshalling_test.go
Expand Up @@ -113,7 +113,7 @@ func TestSetupDataMarshalling(t *testing.T) {

err = runner.SetOptions(lib.Options{
SetupTimeout: types.NullDurationFrom(5 * time.Second),
Hosts: tb.Dialer.Hosts,
Hosts: types.NullAddressTrie{Trie: tb.Dialer.Hosts},
})
require.NoError(t, err)

Expand Down
2 changes: 1 addition & 1 deletion js/runner.go
Expand Up @@ -157,7 +157,7 @@ func (r *Runner) newVU(idLocal, idGlobal uint64, samplesOut chan<- metrics.Sampl
Resolver: r.Resolver,
Blacklist: r.Bundle.Options.BlacklistIPs,
BlockedHostnames: r.Bundle.Options.BlockedHostnames.Trie,
Hosts: r.Bundle.Options.Hosts,
Hosts: r.Bundle.Options.Hosts.Trie,
}
if r.Bundle.Options.LocalIPs.Valid {
var ipIndex uint64
Expand Down
26 changes: 13 additions & 13 deletions js/runner_test.go
Expand Up @@ -1000,7 +1000,7 @@ func TestVUIntegrationInsecureRequests(t *testing.T) {
host, port, err := net.SplitHostPort(s.Listener.Addr().String())
require.NoError(t, err)
ip := net.ParseIP(host)
mybadsslHostname, err := lib.NewHostAddress(ip, port)
mybadsslHostname, err := types.NewHostAddress(ip, port)
require.NoError(t, err)
cert, err := x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0])
require.NoError(t, err)
Expand Down Expand Up @@ -1033,9 +1033,9 @@ func TestVUIntegrationInsecureRequests(t *testing.T) {
require.NoError(t, err)
require.NoError(t, r1.SetOptions(lib.Options{Throw: null.BoolFrom(true)}.Apply(data.opts)))

r1.Bundle.Options.Hosts = map[string]*lib.HostAddress{
"mybadssl.localhost": mybadsslHostname,
}
r1.Bundle.Options.Hosts = types.NewNullAddressTrie(map[string]types.HostAddress{
"mybadssl.localhost": *mybadsslHostname,
})
registry := metrics.NewRegistry()
builtinMetrics := metrics.RegisterBuiltinMetrics(registry)
r2, err := NewFromArchive(
Expand Down Expand Up @@ -1261,9 +1261,9 @@ func TestVUIntegrationHosts(t *testing.T) {

r1.SetOptions(lib.Options{
Throw: null.BoolFrom(true),
Hosts: map[string]*lib.HostAddress{
Hosts: types.NewNullAddressTrie(map[string]types.HostAddress{
"test.loadimpact.com": {IP: net.ParseIP("127.0.0.1")},
},
}),
})

registry := metrics.NewRegistry()
Expand Down Expand Up @@ -1306,7 +1306,7 @@ func TestVUIntegrationTLSConfig(t *testing.T) {
host, port, err := net.SplitHostPort(s.Listener.Addr().String())
require.NoError(t, err)
ip := net.ParseIP(host)
mybadsslHostname, err := lib.NewHostAddress(ip, port)
mybadsslHostname, err := types.NewHostAddress(ip, port)
require.NoError(t, err)
unsupportedVersionErrorMsg := "remote error: tls: handshake failure"
for _, tag := range build.Default.ReleaseTags {
Expand Down Expand Up @@ -1364,9 +1364,9 @@ func TestVUIntegrationTLSConfig(t *testing.T) {
opts := lib.Options{Throw: null.BoolFrom(true)}
require.NoError(t, r1.SetOptions(opts.Apply(data.opts)))

r1.Bundle.Options.Hosts = map[string]*lib.HostAddress{
"sha256-badssl.localhost": mybadsslHostname,
}
r1.Bundle.Options.Hosts = types.NewNullAddressTrie(map[string]types.HostAddress{
"sha256-badssl.localhost": *mybadsslHostname,
})
r2, err := NewFromArchive(
&lib.TestPreInitState{
Logger: testutils.NewLogger(t),
Expand Down Expand Up @@ -1534,7 +1534,7 @@ func TestVUIntegrationCookiesReset(t *testing.T) {
require.NoError(t, err)
r1.Bundle.Options.Throw = null.BoolFrom(true)
r1.Bundle.Options.MaxRedirects = null.IntFrom(10)
r1.Bundle.Options.Hosts = tb.Dialer.Hosts
r1.Bundle.Options.Hosts = types.NullAddressTrie{Trie: tb.Dialer.Hosts}

registry := metrics.NewRegistry()
builtinMetrics := metrics.RegisterBuiltinMetrics(registry)
Expand Down Expand Up @@ -1592,7 +1592,7 @@ func TestVUIntegrationCookiesNoReset(t *testing.T) {
r1.SetOptions(lib.Options{
Throw: null.BoolFrom(true),
MaxRedirects: null.IntFrom(10),
Hosts: tb.Dialer.Hosts,
Hosts: types.NullAddressTrie{Trie: tb.Dialer.Hosts},
NoCookiesReset: null.BoolFrom(true),
})

Expand Down Expand Up @@ -2531,7 +2531,7 @@ func TestForceHTTP1Feature(t *testing.T) {
require.NoError(t, err)

err = r1.SetOptions(lib.Options{
Hosts: tb.Dialer.Hosts,
Hosts: types.NullAddressTrie{Trie: tb.Dialer.Hosts},
// We disable TLS verify so that we don't get a TLS handshake error since
// the certificates on the endpoint are not certified by a certificate authority
InsecureSkipTLSVerify: null.BoolFrom(true),
Expand Down
22 changes: 12 additions & 10 deletions lib/netext/dialer.go
Expand Up @@ -21,7 +21,7 @@ type Dialer struct {
Resolver Resolver
Blacklist []*lib.IPNet
BlockedHostnames *types.HostnameTrie
Hosts map[string]*lib.HostAddress
Hosts *types.AddressTrie

BytesRead int64
BytesWritten int64
Expand Down Expand Up @@ -148,7 +148,7 @@ func (d *Dialer) getDialAddr(addr string) (string, error) {
return remote.String(), nil
}

func (d *Dialer) findRemote(addr string) (*lib.HostAddress, error) {
func (d *Dialer) findRemote(addr string) (*types.HostAddress, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
Expand All @@ -161,13 +161,15 @@ func (d *Dialer) findRemote(addr string) (*lib.HostAddress, error) {
}
}

remote, err := d.getConfiguredHost(addr, host, port)
if err != nil || remote != nil {
return remote, err
if d.Hosts != nil {
remote, e := d.getConfiguredHost(addr, host, port)
if e != nil || remote != nil {
return remote, e
}
}

if ip != nil {
return lib.NewHostAddress(ip, port)
return types.NewHostAddress(ip, port)
}

ip, err = d.Resolver.LookupIP(host)
Expand All @@ -179,15 +181,15 @@ func (d *Dialer) findRemote(addr string) (*lib.HostAddress, error) {
return nil, fmt.Errorf("lookup %s: no such host", host)
}

return lib.NewHostAddress(ip, port)
return types.NewHostAddress(ip, port)
}

func (d *Dialer) getConfiguredHost(addr, host, port string) (*lib.HostAddress, error) {
if remote, ok := d.Hosts[addr]; ok {
func (d *Dialer) getConfiguredHost(addr, host, port string) (*types.HostAddress, error) {
if remote := d.Hosts.Match(addr); remote != nil {
return remote, nil
}

if remote, ok := d.Hosts[host]; ok {
if remote := d.Hosts.Match(host); remote != nil {
if remote.Port != 0 || port == "" {
return remote, nil
}
Expand Down
48 changes: 37 additions & 11 deletions lib/netext/dialer_test.go
Expand Up @@ -14,15 +14,16 @@ import (
func TestDialerAddr(t *testing.T) {
t.Parallel()
dialer := NewDialer(net.Dialer{}, newResolver())
dialer.Hosts = map[string]*lib.HostAddress{
"example.com": {IP: net.ParseIP("3.4.5.6")},
"example.com:443": {IP: net.ParseIP("3.4.5.6"), Port: 8443},
"example.com:8080": {IP: net.ParseIP("3.4.5.6"), Port: 9090},
"example-deny-host.com": {IP: net.ParseIP("8.9.10.11")},
"example-ipv6.com": {IP: net.ParseIP("2001:db8::68")},
"example-ipv6.com:443": {IP: net.ParseIP("2001:db8::68"), Port: 8443},
"example-ipv6-deny-host.com": {IP: net.ParseIP("::1")},
}
dialer.Hosts = types.NewAddressTrie(
map[string]types.HostAddress{
"example.com": {IP: net.ParseIP("3.4.5.6")},
"example.com:443": {IP: net.ParseIP("3.4.5.6"), Port: 8443},
"example.com:8080": {IP: net.ParseIP("3.4.5.6"), Port: 9090},
"example-deny-host.com": {IP: net.ParseIP("8.9.10.11")},
"example-ipv6.com": {IP: net.ParseIP("2001:db8::68")},
"example-ipv6.com:443": {IP: net.ParseIP("2001:db8::68"), Port: 8443},
"example-ipv6-deny-host.com": {IP: net.ParseIP("::1")},
})

ipNet, err := lib.ParseCIDR("8.9.10.0/24")
require.NoError(t, err)
Expand Down Expand Up @@ -75,9 +76,9 @@ func TestDialerAddr(t *testing.T) {
func TestDialerAddrBlockHostnamesStar(t *testing.T) {
t.Parallel()
dialer := NewDialer(net.Dialer{}, newResolver())
dialer.Hosts = map[string]*lib.HostAddress{
dialer.Hosts = types.NewAddressTrie(map[string]types.HostAddress{
"example.com": {IP: net.ParseIP("3.4.5.6")},
}
})

blocked, err := types.NewHostnameTrie([]string{"*"})
require.NoError(t, err)
Expand Down Expand Up @@ -109,6 +110,31 @@ func TestDialerAddrBlockHostnamesStar(t *testing.T) {
}
}

// Benchmarks /etc/hosts like hostname mapping
func BenchmarkDialerHosts(b *testing.B) {
hosts := types.NewAddressTrie(map[string]types.HostAddress{
"k6.io": {IP: []byte("192.168.1.1"), Port: 80},
"specific.k6.io": {IP: []byte("192.168.1.2"), Port: 80},
"grafana.com": {IP: []byte("aa::ff"), Port: 80},
"specific.grafana.com": {IP: []byte("aa:bb:::ff"), Port: 80},
})

dialer := Dialer{
Dialer: net.Dialer{},
Hosts: hosts,
}

tcs := []string{"k6.io", "specific.k6.io", "grafana.com", "specific.grafana.com", "not.exists.com"}

b.ResetTimer()
for i := 0; i < b.N; i++ {
for _, tc := range tcs {
//nolint:errcheck
dialer.getDialAddr(tc)
}
}
}

func newResolver() *mockresolver.MockResolver {
return mockresolver.New(
map[string][]net.IP{
Expand Down