cmd/ctrld: ensure cleaning up done when self-uninstall

While at it, also making DNS reset always use DHCP.
This commit is contained in:
Cuong Manh Le
2023-01-21 13:43:07 +07:00
committed by Cuong Manh Le
parent 340016ab70
commit cd37d93b06
5 changed files with 74 additions and 46 deletions
+16 -5
View File
@@ -111,11 +111,7 @@ func initCLI() {
initCache() initCache()
if iface == "auto" { if iface == "auto" {
dri, err := interfaces.DefaultRouteInterface() iface = defaultIfaceName()
if err != nil {
mainLog.Error().Err(err).Msg("failed to get default route interface")
}
iface = dri
} }
if daemon { if daemon {
@@ -450,6 +446,7 @@ func readConfigFile(writeDefaultConfig bool) bool {
err := v.ReadInConfig() err := v.ReadInConfig()
if err == nil { if err == nil {
fmt.Println("loading config file from:", v.ConfigFileUsed()) fmt.Println("loading config file from:", v.ConfigFileUsed())
defaultConfigFile = v.ConfigFileUsed()
return true return true
} }
@@ -529,6 +526,12 @@ func processCDFlags() {
stderrMsg(err.Error()) stderrMsg(err.Error())
return return
} }
if iface == "auto" {
iface = defaultIfaceName()
}
if netIface, _ := netIfaceFromName(iface); netIface != nil {
_ = resetDNS(netIface)
}
tasks := []task{{s.Uninstall, true}} tasks := []task{{s.Uninstall, true}}
if doTasks(tasks) { if doTasks(tasks) {
log.Println("uninstalled service") log.Println("uninstalled service")
@@ -623,3 +626,11 @@ func netIfaceFromName(ifaceName string) (*net.Interface, error) {
} }
return iface, err return iface, err
} }
func defaultIfaceName() string {
dri, err := interfaces.DefaultRouteInterface()
if err != nil {
mainLog.Error().Err(err).Msg("failed to get default route interface")
}
return dri
}
+41 -4
View File
@@ -8,6 +8,10 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv4/client4"
"github.com/insomniacslk/dhcp/dhcpv6"
"github.com/insomniacslk/dhcp/dhcpv6/client6"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
@@ -45,7 +49,7 @@ func setDNS(iface *net.Interface, nameservers []string) error {
mainLog.Error().Err(err).Msg("failed to create DNS OS configurator") mainLog.Error().Err(err).Msg("failed to create DNS OS configurator")
return err return err
} }
defer r.Close()
ns := make([]netip.Addr, 0, len(nameservers)) ns := make([]netip.Addr, 0, len(nameservers))
for _, nameserver := range nameservers { for _, nameserver := range nameservers {
ns = append(ns, netip.MustParseAddr(nameserver)) ns = append(ns, netip.MustParseAddr(nameserver))
@@ -56,11 +60,44 @@ func setDNS(iface *net.Interface, nameservers []string) error {
}) })
} }
func resetDNS(iface *net.Interface, nameservers []string) error { func resetDNS(iface *net.Interface) error {
if err := setDNS(iface, nameservers); err != nil { c := client4.NewClient()
mainLog.Error().Err(err).Msg("resetDNS failed.") conversation, err := c.Exchange(iface.Name)
if err != nil {
return err return err
} }
for _, packet := range conversation {
if packet.MessageType() == dhcpv4.MessageTypeAck {
nameservers := packet.DNS()
ns := make([]string, 0, len(nameservers))
for _, nameserver := range nameservers {
ns = append(ns, nameserver.String())
}
_ = setDNS(iface, ns)
}
}
if supportsIPv6() {
c := client6.NewClient()
conversation, err := c.Exchange(iface.Name)
if err != nil {
return err
}
for _, packet := range conversation {
if packet.Type() == dhcpv6.MessageTypeReply {
msg, err := packet.GetInnerMessage()
if err != nil {
return err
}
nameservers := msg.Options.DNS()
ns := make([]string, 0, len(nameservers))
for _, nameserver := range nameservers {
ns = append(ns, nameserver.String())
}
_ = setDNS(iface, ns)
}
}
}
return nil return nil
} }
+4 -2
View File
@@ -6,6 +6,8 @@ package main
import ( import (
"net" "net"
"os/exec" "os/exec"
"github.com/Control-D-Inc/ctrld/internal/resolvconffile"
) )
// allocate loopback ip // allocate loopback ip
@@ -44,7 +46,7 @@ func setDNS(iface *net.Interface, nameservers []string) error {
} }
// TODO(cuonglm): use system API // TODO(cuonglm): use system API
func resetDNS(iface *net.Interface, _ []string) error { func resetDNS(iface *net.Interface) error {
cmd := "networksetup" cmd := "networksetup"
args := []string{"-setdnsservers", iface.Name, "empty"} args := []string{"-setdnsservers", iface.Name, "empty"}
@@ -56,5 +58,5 @@ func resetDNS(iface *net.Interface, _ []string) error {
} }
func currentDNS(_ *net.Interface) []string { func currentDNS(_ *net.Interface) []string {
return nil return resolvconffile.NameServers("")
} }
+10 -30
View File
@@ -4,7 +4,6 @@
package main package main
import ( import (
"bytes"
"errors" "errors"
"net" "net"
"os/exec" "os/exec"
@@ -39,14 +38,18 @@ func setDNS(iface *net.Interface, nameservers []string) error {
} }
// TODO(cuonglm): should we use system API? // TODO(cuonglm): should we use system API?
func resetDNS(iface *net.Interface, nameservers []string) error { func resetDNS(iface *net.Interface) error {
if err := resetDNSUseDHCP(iface); err != nil { if supportsIPv6ListenLocal() {
mainLog.Debug().Err(err).Msg("could not reset DNS using DHCP") 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))
}
} }
if len(nameservers) == 0 { output, err := netsh("interface", "ipv4", "set", "dnsserver", strconv.Itoa(iface.Index), "dhcp")
return nil if err != nil {
mainLog.Error().Err(err).Msgf("failed to reset ipv4 DNS: %s", string(output))
return err
} }
return setDNS(iface, nameservers) return nil
} }
func setPrimaryDNS(iface *net.Interface, dns string) error { func setPrimaryDNS(iface *net.Interface, dns string) error {
@@ -80,28 +83,11 @@ func addSecondaryDNS(iface *net.Interface, dns string) error {
return nil return nil
} }
func resetDNSUseDHCP(iface *net.Interface) error {
if 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))
}
}
output, err := netsh("interface", "ipv4", "set", "dnsserver", strconv.Itoa(iface.Index), "dhcp")
if err != nil {
mainLog.Error().Err(err).Msgf("failed to reset ipv4 DNS: %s", string(output))
return err
}
return nil
}
func netsh(args ...string) ([]byte, error) { func netsh(args ...string) ([]byte, error) {
return exec.Command("netsh", args...).Output() return exec.Command("netsh", args...).Output()
} }
func currentDNS(iface *net.Interface) []string { func currentDNS(iface *net.Interface) []string {
if hasDNSFromDHCP(iface, "ipv4") || hasDNSFromDHCP(iface, "ipv6") {
return nil
}
luid, err := winipcfg.LUIDFromIndex(uint32(iface.Index)) luid, err := winipcfg.LUIDFromIndex(uint32(iface.Index))
if err != nil { if err != nil {
mainLog.Error().Err(err).Msg("failed to get interface LUID") mainLog.Error().Err(err).Msg("failed to get interface LUID")
@@ -118,9 +104,3 @@ func currentDNS(iface *net.Interface) []string {
} }
return ns return ns
} }
func hasDNSFromDHCP(iface *net.Interface, ipVer string) bool {
idx := strconv.Itoa(iface.Index)
output, _ := netsh("interface", ipVer, "show", "dnsservers", idx)
return bytes.Contains(output, []byte(" through DHCP:"))
}
+3 -5
View File
@@ -23,9 +23,8 @@ var svcConfig = &service.Config{
} }
type prog struct { type prog struct {
cfg *ctrld.Config cfg *ctrld.Config
cache dnscache.Cacher cache dnscache.Cacher
origDNS []string
} }
func (p *prog) Start(s service.Service) error { func (p *prog) Start(s service.Service) error {
@@ -40,7 +39,6 @@ func (p *prog) run() {
if err != nil { if err != nil {
mainLog.Error().Err(err).Msg("could not get interface") mainLog.Error().Err(err).Msg("could not get interface")
} else { } else {
p.origDNS = currentDNS(netIface)
if err := setDNS(netIface, []string{cfg.Listener["0"].IP}); err != nil { if err := setDNS(netIface, []string{cfg.Listener["0"].IP}); err != nil {
mainLog.Error().Err(err).Str("iface", iface).Msgf("could not set DNS for interface") mainLog.Error().Err(err).Str("iface", iface).Msgf("could not set DNS for interface")
} }
@@ -179,7 +177,7 @@ func (p *prog) Stop(s service.Service) error {
} }
if iface != "" { if iface != "" {
if netIface, err := netIfaceFromName(iface); err == nil { if netIface, err := netIfaceFromName(iface); err == nil {
if err := resetDNS(netIface, p.origDNS); err != nil { if err := resetDNS(netIface); err != nil {
mainLog.Error().Err(err).Str("iface", iface).Msgf("could not reset DNS") mainLog.Error().Err(err).Str("iface", iface).Msgf("could not reset DNS")
} }
} else { } else {