Skip to content

Instantly share code, notes, and snippets.

@simonswine
Last active September 1, 2020 13:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simonswine/f1826127e499673df1dbf539df5923b0 to your computer and use it in GitHub Desktop.
Save simonswine/f1826127e499673df1dbf539df5923b0 to your computer and use it in GitHub Desktop.
Golang DNS test
$ GODEBUG=netdns=cgo+1 go run main.go
go package net: using cgo DNS resolver
2020/08/26 11:15:12 #01 212.58.233.253:443
2020/08/26 11:15:12 #02 212.58.237.251:443
2020/08/26 11:15:13 #03 212.58.233.251:443
2020/08/26 11:15:13 #04 212.58.233.251:443
2020/08/26 11:15:13 #05 212.58.237.253:443
2020/08/26 11:15:13 #06 212.58.237.254:443
2020/08/26 11:15:14 #07 212.58.237.254:443
2020/08/26 11:15:14 #08 212.58.233.254:443
2020/08/26 11:15:14 #09 212.58.233.254:443
$ GODEBUG=netdns=go+1 go run main.go
go package net: GODEBUG setting forcing use of Go's resolver
2020/08/26 11:15:17 #01 212.58.233.254:443
2020/08/26 11:15:17 #02 212.58.233.253:443
2020/08/26 11:15:18 #03 212.58.233.251:443
2020/08/26 11:15:18 #04 212.58.233.254:443
2020/08/26 11:15:18 #05 212.58.233.253:443
2020/08/26 11:15:19 #06 212.58.233.254:443
2020/08/26 11:15:19 #07 212.58.233.253:443
2020/08/26 11:15:19 #08 212.58.233.253:443
2020/08/26 11:15:19 #09 212.58.233.253:443
package main
import (
"context"
"log"
"net"
"net/http"
)
func main() {
var remoteAddr string
client := &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
conn, err := net.Dial(network, addr)
remoteAddr = conn.RemoteAddr().String()
return conn, err
},
},
}
for i := 1; i < 10; i++ {
resp, err := client.Get("https://www.bbc.co.uk/")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
log.Printf("#%02d %v %s", i, remoteAddr, resp.Request.RemoteAddr)
}
}
@jdbaldry
Copy link

jdbaldry commented Sep 1, 2020

Interestingly I get very different behavior on my system running a slightly modified version of the above Gist:

package main

import (
	"context"
	"log"
	"net"
	"net/http"
)

func main() {
	var remoteAddr string
	remoteAddrs := make(map[string]int)
	client := &http.Client{
		Transport: &http.Transport{
			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
				conn, err := net.Dial(network, addr)
				remoteAddr = conn.RemoteAddr().String()
				_, ok := remoteAddrs[remoteAddr]
				if !ok {
					remoteAddrs[remoteAddr] = 0
				}
				remoteAddrs[remoteAddr]++

				return conn, err
			},
		},
	}

	for i := 1; i < 100; i++ {
		resp, err := client.Get("https://www.bbc.co.uk/")
		if err != nil {
			log.Fatal(err)
		}
		defer resp.Body.Close()
		log.Printf("#%02d %v %s", i, remoteAddr, resp.Request.RemoteAddr)
	}

	log.Printf("%20s | %s", "Address", "Count")
	for addr, count := range remoteAddrs {
		log.Printf("%20s | %03d", addr, count)
	}
}
$ GODEBUG=netdns=cgo+1 go run main.go
...
2020/09/01 11:35:22              Address | Count
2020/09/01 11:35:22   212.58.237.253:443 | 099
$ GODEBUG=netdns=go+1 go run main.go
...
2020/09/01 11:36:05              Address | Count
2020/09/01 11:36:05   212.58.237.251:443 | 044
2020/09/01 11:36:05   212.58.237.253:443 | 027
2020/09/01 11:36:05   212.58.237.254:443 | 028

@simonswine
Copy link
Author

Running your code I get a fairly equal distribution with both DNS methods. I think you might have something caching locally (like a nscd daemon)

@jdbaldry
Copy link

jdbaldry commented Sep 1, 2020

Gosh darn it, I looked for systemd-resolved because I thought that NixOS was pretty systemd heavy but it turns out that indeed I have nscd running. I thought most distributions moved away from nscd...

Good catch. It was indeed good evidence for local DNS caching (although weirdly the Go resolver seemed to bypass it anyway).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment