|
package main |
|
|
|
import ( |
|
"context" |
|
"crypto/tls" |
|
"fmt" |
|
"io" |
|
"log" |
|
"net" |
|
"net/http" |
|
"strings" |
|
"time" |
|
|
|
"github.com/miekg/dns" |
|
) |
|
|
|
func main() { |
|
client := &http.Client{ |
|
Timeout: time.Second * 5, |
|
Transport: &http.Transport{ |
|
// Avoid: "x509: certificate signed by unknown authority" |
|
TLSClientConfig: &tls.Config{ |
|
InsecureSkipVerify: true, |
|
}, |
|
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) { |
|
ipv4, err := resolveIPv4(addr) |
|
if err != nil { |
|
return nil, err |
|
} |
|
timeout, err := time.ParseDuration("10s") |
|
if err != nil { |
|
return nil, err |
|
} |
|
return (&net.Dialer{ |
|
Timeout: timeout, |
|
}).DialContext(ctx, network, ipv4) |
|
}, |
|
}, |
|
} |
|
|
|
// Also try: https://v4.testmyipv6.com/ |
|
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)) |
|
} |
|
|
|
// resolveIPv4 resolves an address to IPv4 address. |
|
func resolveIPv4(addr string) (string, error) { |
|
url := strings.Split(addr, ":") |
|
|
|
m := new(dns.Msg) |
|
m.SetQuestion(dns.Fqdn(url[0]), dns.TypeA) |
|
m.RecursionDesired = true |
|
|
|
// NOTE: you shouldn't consult or rely on /etc/resolv.conf as it has proven historically to contain nameservers that don't respond. |
|
config, _ := dns.ClientConfigFromFile("/etc/resolv.conf") |
|
c := new(dns.Client) |
|
r, _, err := c.Exchange(m, net.JoinHostPort(config.Servers[0], config.Port)) |
|
if err != nil { |
|
return "", err |
|
} |
|
for _, ans := range r.Answer { |
|
if a, ok := ans.(*dns.A); ok { |
|
url[0] = a.A.String() |
|
} |
|
} |
|
|
|
return strings.Join(url, ":"), nil |
|
} |
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?