internal/controld: check if ipv4 is available before connect to API

Updates #53
This commit is contained in:
Cuong Manh Le
2023-02-10 01:19:53 +07:00
committed by Cuong Manh Le
parent 45f827a2c5
commit 83b551fb2d
8 changed files with 108 additions and 87 deletions

View File

@@ -24,6 +24,7 @@ import (
"github.com/Control-D-Inc/ctrld"
"github.com/Control-D-Inc/ctrld/internal/controld"
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
)
var (
@@ -105,7 +106,7 @@ func initCLI() {
log.Fatalf("failed to unmarshal config: %v", err)
}
// Wait for network up.
if !netUp() {
if !ctrldnet.Up() {
log.Fatal("network is not up yet")
}
processLogAndCacheFlags()

View File

@@ -15,6 +15,7 @@ import (
"github.com/Control-D-Inc/ctrld"
"github.com/Control-D-Inc/ctrld/internal/dnscache"
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
)
const staleTTL = 60 * time.Second
@@ -55,7 +56,7 @@ func (p *prog) serveUDP(listenerNum string) error {
// On Windows, there's no easy way for disabling/removing IPv6 DNS resolver, so we check whether we can
// listen on ::1, then spawn a listener for receiving DNS requests.
if runtime.GOOS == "windows" && supportsIPv6ListenLocal() {
if runtime.GOOS == "windows" && ctrldnet.SupportsIPv6() {
go func() {
s := &dns.Server{
Addr: net.JoinHostPort("::1", strconv.Itoa(listenerConfig.Port)),

View File

@@ -1,65 +0,0 @@
package main
import (
"context"
"net"
"sync"
"time"
"tailscale.com/logtail/backoff"
"github.com/Control-D-Inc/ctrld/internal/controld"
)
const (
controldIPv6Test = "ipv6.controld.io"
)
var (
stackOnce sync.Once
ipv6Enabled bool
canListenIPv6Local bool
hasNetworkUp bool
)
func probeStack() {
b := backoff.NewBackoff("probeStack", func(format string, args ...any) {}, time.Minute)
for {
if _, err := controld.Dialer.Dial("udp", net.JoinHostPort(bootstrapDNS, "53")); err == nil {
hasNetworkUp = true
break
} else {
b.BackOff(context.Background(), err)
}
}
if _, err := controld.Dialer.Dial("tcp6", net.JoinHostPort(controldIPv6Test, "80")); err == nil {
ipv6Enabled = true
}
if ln, err := net.Listen("tcp6", "[::1]:53"); err == nil {
ln.Close()
canListenIPv6Local = true
}
}
func netUp() bool {
stackOnce.Do(probeStack)
return hasNetworkUp
}
func supportsIPv6() bool {
stackOnce.Do(probeStack)
return ipv6Enabled
}
func supportsIPv6ListenLocal() bool {
stackOnce.Do(probeStack)
return canListenIPv6Local
}
// isIPv6 checks if the provided IP is v6.
//
//lint:ignore U1000 use in os_windows.go
func isIPv6(ip string) bool {
parsedIP := net.ParseIP(ip)
return parsedIP != nil && parsedIP.To4() == nil && parsedIP.To16() != nil
}

View File

@@ -19,6 +19,7 @@ import (
"tailscale.com/util/dnsname"
"github.com/Control-D-Inc/ctrld/internal/dns"
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
"github.com/Control-D-Inc/ctrld/internal/resolvconffile"
)
@@ -111,7 +112,7 @@ func resetDNS(iface *net.Interface) error {
}
// TODO(cuonglm): handle DHCPv6 properly.
if supportsIPv6() {
if ctrldnet.SupportsIPv6() {
c := client6.NewClient()
conversation, err := c.Exchange(iface.Name)
if err != nil {

View File

@@ -10,6 +10,8 @@ import (
"strconv"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
)
// TODO(cuonglm): implement.
@@ -39,7 +41,7 @@ func setDNS(iface *net.Interface, nameservers []string) error {
// TODO(cuonglm): should we use system API?
func resetDNS(iface *net.Interface) error {
if supportsIPv6ListenLocal() {
if ctrldnet.SupportsIPv6ListenLocal() {
if output, err := netsh("interface", "ipv6", "set", "dnsserver", strconv.Itoa(iface.Index), "dhcp"); err != nil {
mainLog.Warn().Err(err).Msgf("failed to reset ipv6 DNS: %s", string(output))
}
@@ -54,7 +56,7 @@ func resetDNS(iface *net.Interface) error {
func setPrimaryDNS(iface *net.Interface, dns string) error {
ipVer := "ipv4"
if isIPv6(dns) {
if ctrldnet.IsIPv6(dns) {
ipVer = "ipv6"
}
idx := strconv.Itoa(iface.Index)
@@ -73,7 +75,7 @@ func setPrimaryDNS(iface *net.Interface, dns string) error {
func addSecondaryDNS(iface *net.Interface, dns string) error {
ipVer := "ipv4"
if isIPv6(dns) {
if ctrldnet.IsIPv6(dns) {
ipVer = "ipv6"
}
output, err := netsh("interface", ipVer, "add", "dns", strconv.Itoa(iface.Index), dns, "index=2")

View File

@@ -13,6 +13,7 @@ import (
"github.com/Control-D-Inc/ctrld"
"github.com/Control-D-Inc/ctrld/internal/dnscache"
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
)
var errWindowsAddrInUse = syscall.Errno(0x2740)
@@ -64,7 +65,7 @@ func (p *prog) run() {
// resolve it manually and set the bootstrap ip
c := new(dns.Client)
for _, dnsType := range []uint16{dns.TypeAAAA, dns.TypeA} {
if !supportsIPv6() && dnsType == dns.TypeAAAA {
if !ctrldnet.SupportsIPv6() && dnsType == dns.TypeAAAA {
continue
}
m := new(dns.Msg)