Skip to content

Commit

Permalink
Merge pull request #2747 from eugercek/wildcard-host
Browse files Browse the repository at this point in the history
Add Wildcard to `Hosts`
  • Loading branch information
Ivan Mirić committed Dec 6, 2022
2 parents 1b9c5fa + 4494b47 commit a403c90
Show file tree
Hide file tree
Showing 18 changed files with 656 additions and 172 deletions.
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.NullHosts{Trie: tb.Dialer.Hosts, Valid: true},
InsecureSkipTLSVerify: null.BoolFrom(true),
NoVUConnectionReuse: null.BoolFrom(noConnReuse),
Batch: null.IntFrom(20),
Expand Down Expand Up @@ -797,7 +797,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.NullHosts{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.NullHosts{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.NullHosts{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.NullHosts{Trie: tb.Dialer.Hosts}}))
arc := r1.MakeArchive()
registry := metrics.NewRegistry()
builtinMetrics := metrics.RegisterBuiltinMetrics(registry)
Expand Down
16 changes: 10 additions & 6 deletions js/modules/k6/execution/execution_test.go
Expand Up @@ -292,12 +292,16 @@ func TestOptionsTestFull(t *testing.T) {
require.NoError(t, err)
return bh
}(),
Hosts: map[string]*lib.HostAddress{
"test.k6.io": {
IP: []byte{0x01, 0x02, 0x03, 0x04},
Port: 8443,
},
},
Hosts: func() types.NullHosts {
hs, err := types.NewNullHosts(map[string]types.Host{
"test.k6.io": {
IP: []byte{0x01, 0x02, 0x03, 0x04},
Port: 8443,
},
})
require.NoError(t, err)
return hs
}(),
External: map[string]json.RawMessage{
"ext-one": json.RawMessage(`{"rawkey":"rawvalue"}`),
},
Expand Down
32 changes: 22 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,17 @@ 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.NewHost(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: func() *types.Hosts {
hosts, er := types.NewHosts(map[string]types.Host{"expired.localhost": *mybadsslHostname})
require.NoError(t, er)
return hosts
}(),
}
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 +2410,13 @@ 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.NewHost(ip, port)
require.NoError(t, err)
hosts, err := types.NewHosts(map[string]types.Host{
versionTest.URL: *mybadsslHostname,
})
require.NoError(t, err)
state.Dialer = &netext.Dialer{Hosts: map[string]*lib.HostAddress{
versionTest.URL: mybadsslHostname,
}}
state.Dialer = &netext.Dialer{Hosts: hosts}
state.Transport = client.Transport
state.TLSConfig = s.TLS
client.Transport.(*http.Transport).DialContext = state.Dialer.DialContext //nolint:forcetypeassert
Expand Down Expand Up @@ -2442,11 +2452,13 @@ 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.NewHost(ip, port)
require.NoError(t, err)
hosts, err := types.NewHosts(map[string]types.Host{
cipherSuiteTest.URL: *mybadsslHostname,
})
require.NoError(t, err)
state.Dialer = &netext.Dialer{Hosts: map[string]*lib.HostAddress{
cipherSuiteTest.URL: mybadsslHostname,
}}
state.Dialer = &netext.Dialer{Hosts: hosts}
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.NullHosts{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
35 changes: 21 additions & 14 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.NewHost(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,10 @@ 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, err = types.NewNullHosts(map[string]types.Host{
"mybadssl.localhost": *mybadsslHostname,
})
require.NoError(t, err)
registry := metrics.NewRegistry()
builtinMetrics := metrics.RegisterBuiltinMetrics(registry)
r2, err := NewFromArchive(
Expand Down Expand Up @@ -1261,9 +1262,14 @@ func TestVUIntegrationHosts(t *testing.T) {

r1.SetOptions(lib.Options{
Throw: null.BoolFrom(true),
Hosts: map[string]*lib.HostAddress{
"test.loadimpact.com": {IP: net.ParseIP("127.0.0.1")},
},
Hosts: func() types.NullHosts {
hosts, er := types.NewNullHosts(map[string]types.Host{
"test.loadimpact.com": {IP: net.ParseIP("127.0.0.1")},
})
require.NoError(t, er)

return hosts
}(),
})

registry := metrics.NewRegistry()
Expand Down Expand Up @@ -1306,7 +1312,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.NewHost(ip, port)
require.NoError(t, err)
unsupportedVersionErrorMsg := "remote error: tls: handshake failure"
for _, tag := range build.Default.ReleaseTags {
Expand Down Expand Up @@ -1364,9 +1370,10 @@ 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, err = types.NewNullHosts(map[string]types.Host{
"sha256-badssl.localhost": *mybadsslHostname,
})
require.NoError(t, err)
r2, err := NewFromArchive(
&lib.TestPreInitState{
Logger: testutils.NewLogger(t),
Expand Down Expand Up @@ -1534,7 +1541,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.NullHosts{Trie: tb.Dialer.Hosts}

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

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

err = r1.SetOptions(lib.Options{
Hosts: tb.Dialer.Hosts,
Hosts: types.NullHosts{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.Hosts

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.Host, 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.NewHost(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.NewHost(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.Host, 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
54 changes: 42 additions & 12 deletions lib/netext/dialer_test.go
Expand Up @@ -14,16 +14,18 @@ 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")},
}

hosts, err := types.NewHosts(
map[string]types.Host{
"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")},
})
require.NoError(t, err)
dialer.Hosts = hosts
ipNet, err := lib.ParseCIDR("8.9.10.0/24")
require.NoError(t, err)

Expand Down Expand Up @@ -75,9 +77,11 @@ func TestDialerAddr(t *testing.T) {
func TestDialerAddrBlockHostnamesStar(t *testing.T) {
t.Parallel()
dialer := NewDialer(net.Dialer{}, newResolver())
dialer.Hosts = map[string]*lib.HostAddress{
hosts, err := types.NewHosts(map[string]types.Host{
"example.com": {IP: net.ParseIP("3.4.5.6")},
}
})
require.NoError(t, err)
dialer.Hosts = hosts

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

// Benchmarks /etc/hosts like hostname mapping
func BenchmarkDialerHosts(b *testing.B) {
hosts, err := types.NewHosts(map[string]types.Host{
"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},
})
require.NoError(b, err)

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:gosec,errcheck
dialer.getDialAddr(tc)
}
}
}

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

0 comments on commit a403c90

Please sign in to comment.