Skip to content

Commit

Permalink
Merge pull request #417 from nats-io/randomize_lookup_host_result
Browse files Browse the repository at this point in the history
[FIXED] Randomize IPs result from LookupHost before creating connection
  • Loading branch information
derekcollison authored Dec 15, 2018
2 parents aa1eeb0 + 8534270 commit 27716ff
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
8 changes: 4 additions & 4 deletions nats.go
Original file line number Diff line number Diff line change
Expand Up @@ -1178,18 +1178,18 @@ func (nc *Conn) createConn() (err error) {
}

// We will auto-expand host names if they resolve to multiple IPs
var hosts []string
hosts := map[string]struct{}{}
u := nc.current.url

if net.ParseIP(u.Hostname()) == nil {
addrs, _ := net.LookupHost(u.Hostname())
for _, addr := range addrs {
hosts = append(hosts, fmt.Sprintf("%s:%s", addr, u.Port()))
hosts[net.JoinHostPort(addr, u.Port())] = struct{}{}
}
}
// Fall back to what we were given.
if len(hosts) == 0 {
hosts = append(hosts, u.Host)
hosts[u.Host] = struct{}{}
}

// CustomDialer takes precedence. If not set, use Opts.Dialer which
Expand All @@ -1203,7 +1203,7 @@ func (nc *Conn) createConn() (err error) {
dialer = &copyDialer
}

for _, host := range hosts {
for host := range hosts {
nc.conn, err = dialer.Dial("tcp", host)
if err == nil {
break
Expand Down
37 changes: 37 additions & 0 deletions nats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1555,3 +1555,40 @@ func TestNKeyOptionFromSeed(t *testing.T) {
close(ch)
wg.Wait()
}

func TestLookupHostResultIsRandomized(t *testing.T) {
orgAddrs, err := net.LookupHost("localhost")
if err != nil {
t.Fatalf("Error looking up host: %v", err)
}
if len(orgAddrs) < 2 {
t.Skip("localhost resolves to less than 2 addresses, so test not relevant")
}

opts := gnatsd.DefaultTestOptions
// For this test, important to be able to listen on both IPv4/v6
// because it is likely than in local test, localhost will resolve
// to ::1 and 127.0.0.1
opts.Host = "0.0.0.0"
opts.Port = TEST_PORT
s := RunServerWithOptions(opts)
defer s.Shutdown()

for i := 0; i < 10; i++ {
nc, err := Connect(fmt.Sprintf("localhost:%d", TEST_PORT))
if err != nil {
t.Fatalf("Error on connect: %v", err)
}
nc.mu.Lock()
host, _, _ := net.SplitHostPort(nc.conn.LocalAddr().String())
nc.mu.Unlock()
isFirst := host == orgAddrs[0]
nc.Close()
if !isFirst {
// We used one that is not the first of the resolved addresses,
// so we consider the test good in that IPs were randomized.
return
}
}
t.Fatalf("Always used first address returned by LookupHost")
}

0 comments on commit 27716ff

Please sign in to comment.