cmd/ctrld: add --iface for setting DNS on specific interface

This commit is contained in:
Cuong Manh Le
2023-01-06 00:55:21 +07:00
committed by Cuong Manh Le
parent d5344aea52
commit b00a7c34ee
13 changed files with 473 additions and 45 deletions

View File

@@ -1,7 +1,18 @@
package main
import (
"bufio"
"bytes"
"fmt"
"net"
"net/netip"
"os/exec"
"strings"
"tailscale.com/net/dns"
"tailscale.com/util/dnsname"
"github.com/Control-D-Inc/ctrld/internal/resolvconffile"
)
// allocate loopback ip
@@ -23,3 +34,84 @@ func deAllocateIP(ip string) error {
}
return nil
}
// set the dns server for the provided network interface
func setDNS(iface *net.Interface, nameservers []string) error {
logf := func(format string, args ...any) {
mainLog.Debug().Msgf(format, args...)
}
r, err := dns.NewOSConfigurator(logf, iface.Name)
if err != nil {
mainLog.Error().Err(err).Msg("failed to create DNS OS configurator")
return err
}
ns := make([]netip.Addr, 0, len(nameservers))
for _, nameserver := range nameservers {
ns = append(ns, netip.MustParseAddr(nameserver))
}
return r.SetDNS(dns.OSConfig{
Nameservers: ns,
SearchDomains: []dnsname.FQDN{},
})
}
func resetDNS(iface *net.Interface, nameservers []string) error {
if err := setDNS(iface, nameservers); err != nil {
mainLog.Error().Err(err).Msg("resetDNS failed.")
return err
}
return nil
}
func currentDNS(iface *net.Interface) []string {
for _, fn := range []getDNS{getDNSByResolvectl, getDNSByNmcli, resolvconffile.NameServers} {
if ns := fn(iface.Name); len(ns) > 0 {
return ns
}
}
return nil
}
func getDNSByResolvectl(iface string) []string {
b, err := exec.Command("resolvectl", "dns", "-i", iface).Output()
if err != nil {
return nil
}
parts := strings.SplitN(string(b), "%", 2)
if len(parts) != 2 {
return nil
}
parts = strings.Fields(parts[0])
if len(parts) > 2 {
fmt.Println(parts)
return parts[3:]
}
return nil
}
func getDNSByNmcli(iface string) []string {
b, err := exec.Command("nmcli", "dev", "show", iface).Output()
if err != nil {
return nil
}
s := bufio.NewScanner(bytes.NewReader(b))
var dns []string
do := func(line string) {
parts := strings.SplitN(line, ":", 2)
if len(parts) > 1 {
dns = append(dns, strings.TrimSpace(parts[1]))
}
}
for s.Scan() {
line := s.Text()
switch {
case strings.HasPrefix(line, "IP4.DNS"):
fallthrough
case strings.HasPrefix(line, "IP6.DNS"):
do(line)
}
}
return dns
}