all: support ipv6 for upstream bootstrap ip

This commit is contained in:
Cuong Manh Le
2022-12-18 00:51:34 +07:00
committed by Cuong Manh Le
parent ebcc545547
commit a7ae6c9853
3 changed files with 58 additions and 17 deletions

23
cmd/ctrld/net.go Normal file
View File

@@ -0,0 +1,23 @@
package main
import (
"net"
"sync"
)
var (
stackOnce sync.Once
ipv6Enabled bool
)
func probeStack() {
if ln, err := net.Listen("tcp6", "[::]:0"); err == nil {
ln.Close()
ipv6Enabled = true
}
}
func supportsIPv6() bool {
stackOnce.Do(probeStack)
return ipv6Enabled
}

View File

@@ -51,23 +51,40 @@ func (p *prog) run() {
if uc.BootstrapIP == "" {
// resolve it manually and set the bootstrap ip
c := new(dns.Client)
m := new(dns.Msg)
m.SetQuestion(uc.Domain+".", dns.TypeA)
m.RecursionDesired = true
r, _, err := c.Exchange(m, net.JoinHostPort(bootstrapDNS, "53"))
if err != nil {
proxyLog.Error().Err(err).Msgf("could not resolve domain %s for upstream.%s", uc.Domain, n)
} else {
for _, dnsType := range []uint16{dns.TypeAAAA, dns.TypeA} {
if !supportsIPv6() && dnsType == dns.TypeAAAA {
continue
}
m := new(dns.Msg)
m.SetQuestion(uc.Domain+".", dnsType)
m.RecursionDesired = true
r, _, err := c.Exchange(m, net.JoinHostPort(bootstrapDNS, "53"))
if err != nil {
proxyLog.Error().Err(err).Msgf("could not resolve domain %s for upstream.%s", uc.Domain, n)
continue
}
if r.Rcode != dns.RcodeSuccess {
proxyLog.Error().Msgf("could not resolve domain return code: %d, upstream.%s", r.Rcode, n)
} else {
for _, a := range r.Answer {
if ar, ok := a.(*dns.A); ok {
uc.BootstrapIP = ar.A.String()
proxyLog.Info().Str("bootstrap_ip", uc.BootstrapIP).Msgf("Setting bootstrap IP for upstream.%s", n)
}
}
continue
}
if len(r.Answer) == 0 {
continue
}
for _, a := range r.Answer {
switch ar := a.(type) {
case *dns.A:
uc.BootstrapIP = ar.A.String()
case *dns.AAAA:
uc.BootstrapIP = ar.AAAA.String()
default:
continue
}
proxyLog.Info().Str("bootstrap_ip", uc.BootstrapIP).Msgf("Setting bootstrap IP for upstream.%s", n)
// Stop if we reached here, because we got the bootstrap IP from r.Answer.
break
}
// If we reached here, uc.BootstrapIP was set, nothing to do anymore.
break
}
}
uc.SetupTransport()

View File

@@ -2,7 +2,6 @@ package ctrld
import (
"context"
"fmt"
"net"
"net/http"
"net/url"
@@ -145,8 +144,10 @@ func (uc *UpstreamConfig) SetupTransport() {
}
Log(ctx, ProxyLog.Debug(), "debug dial context %s - %s - %s", addr, network, bootstrapDNS)
// if we have a bootstrap ip set, use it to avoid DNS lookup
if uc.BootstrapIP != "" && addr == fmt.Sprintf("%s:443", uc.Domain) {
addr = fmt.Sprintf("%s:443", uc.BootstrapIP)
if uc.BootstrapIP != "" {
if _, port, _ := net.SplitHostPort(addr); port != "" {
addr = net.JoinHostPort(uc.BootstrapIP, port)
}
Log(ctx, ProxyLog.Debug(), "sending doh request to: %s", addr)
}
return dialer.DialContext(ctx, network, addr)