-
-
Save Integralist/8a9cb8924f75ae42487fd877b03360e2 to your computer and use it in GitHub Desktop.
| package main | |
| import ( | |
| "crypto/tls" | |
| "errors" | |
| "fmt" | |
| "io" | |
| "log" | |
| "net" | |
| "net/http" | |
| "syscall" | |
| "time" | |
| ) | |
| func main() { | |
| client := &http.Client{ | |
| Timeout: time.Second * time.Duration(5*time.Second), | |
| Transport: &http.Transport{ | |
| // Avoid: "x509: certificate signed by unknown authority" | |
| TLSClientConfig: &tls.Config{ | |
| InsecureSkipVerify: true, | |
| }, | |
| // Inspect the network connection type | |
| DialContext: (&net.Dialer{ | |
| Control: func(network, address string, c syscall.RawConn) error { | |
| // Reference: https://golang.org/pkg/net/#Dial | |
| if network == "tcp4" { | |
| return errors.New("we don't want you to use IPv4") | |
| } | |
| return nil | |
| }, | |
| }).DialContext, | |
| }, | |
| } | |
| req, err := http.NewRequest("GET", "https://ipv4.lookup.test-ipv6.com/", nil) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| res, err := client.Do(req) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| b, err := io.ReadAll(res.Body) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| fmt.Printf("%+v\n", string(b)) | |
| } |
@thepabloaguilar I think you might want to append errors to your var err error rather than reset it on each loop iteration...
if innerErr != nil {
err = fmt.Errorf("%w: %w", err, innerErr)
continue
}Otherwise, multiple servers might fail to resolve and you'd only know about the last one.
Also, one thing I discovered recently was the issue of truncation. See https://pkg.go.dev/github.com/miekg/dns#Client.Exchange
Exchange does not retry a failed query, nor will it fall back to TCP in case of truncation. It is up to the caller to create a message that allows for larger responses to be returned. Specifically this means adding an EDNS0 OPT RR that will advertise a larger buffer, see SetEdns0.
Check the implementation in this PR for an example:
domainr/dnsr#118
Yeah, appending makes sense but probably I'm gonna put some OTel spans inside it so the last error will be enough!
Talking about the truncation issue, I could just create another "dns.Client" setting the "Net" attribute to "tcp", right?
I'm thinking on leave the control of all the DNS calls to Golang by providing that "Resolver.Dial" function, everytime the function is called the code get the next DNS address. This approach has two great things (at least for my use case):
- If an error occurs, Go will retry and the next retry will be a different DNS address
- Round-Robin the DNS servers

Hey @Integralist, great gist! In some cases we can have more than one DNS server, I'd like to know if in that case the code below is right (multiples DNS servers forcing IPV4 resolution):