From f3a3227f2140eeb0f0bc86df1bb43edaf76fc8dd Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 27 Jun 2023 01:22:32 +0700 Subject: [PATCH] all: dealing with VLAN config on Firewalla Firewalla ignores 127.0.0.1 in all VLAN config, so making 127.0.0.1 as dnsmasq upstream would break thing when multiple VLAN presents. To deal with this, we need to gather all interfaces available, and making them as upstream of dnsmasq. Then changing ctrld to listen on all interfaces, too. It also leads to better improvement for dnsmasq configuration template, as the upstream server can now be generated dynamically instead of hard coding to 127.0.0.1:5354. --- cmd/ctrld/prog.go | 8 ++++++-- internal/router/dnsmasq.go | 19 +++++++++++++++++-- internal/router/firewalla.go | 26 ++++++++++++++++++++++++++ internal/router/router.go | 7 +++++++ 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/cmd/ctrld/prog.go b/cmd/ctrld/prog.go index e917f88..e09289a 100644 --- a/cmd/ctrld/prog.go +++ b/cmd/ctrld/prog.go @@ -236,10 +236,14 @@ func (p *prog) setDNS() { } logger.Debug().Msg("setting DNS for interface") ns := cfg.Listener["0"].IP - if router.Name() == router.Firewalla && ns == "127.0.0.1" { + if router.Name() == router.Firewalla && (ns == "127.0.0.1" || ns == "0.0.0.0" || ns == "") { // On Firewalla, the lo interface is excluded in all dnsmasq settings of all interfaces. // Thus, we use "br0" as the nameserver in /etc/resolv.conf file. - logger.Warn().Msg("127.0.0.1 won't work on Firewalla") + if ns == "127.0.0.1" { + logger.Warn().Msg("127.0.0.1 as DNS server won't work on Firewalla") + } else { + logger.Warn().Msgf("%q could not be used as DNS server", ns) + } if netIface, err := net.InterfaceByName("br0"); err == nil { addrs, _ := netIface.Addrs() for _, addr := range addrs { diff --git a/internal/router/dnsmasq.go b/internal/router/dnsmasq.go index 9df4132..68fc78a 100644 --- a/internal/router/dnsmasq.go +++ b/internal/router/dnsmasq.go @@ -7,7 +7,9 @@ import ( const dnsMasqConfigContentTmpl = `# GENERATED BY ctrld - DO NOT MODIFY no-resolv -server=127.0.0.1#5354 +{{- range .Upstreams}} +server={{ .Ip }}#{{ .Port }} +{{- end}} {{- if .SendClientInfo}} add-mac {{- end}} @@ -45,6 +47,11 @@ if [ -n "$pid" ] && [ -f "/proc/${pid}/cmdline" ]; then fi ` +type dnsmasqUpstream struct { + Ip string + Port int +} + func dnsMasqConf() (string, error) { var sb strings.Builder var tmplText string @@ -55,10 +62,18 @@ func dnsMasqConf() (string, error) { tmplText = merlinDNSMasqPostConfTmpl } tmpl := template.Must(template.New("").Parse(tmplText)) + upstreams := []dnsmasqUpstream{{ListenIP(), ListenPort()}} + if Name() == Firewalla { + if fu := firewallaDnsmasqUpstreams(); len(fu) > 0 { + upstreams = fu + } + } var to = &struct { SendClientInfo bool + Upstreams []dnsmasqUpstream }{ - routerPlatform.Load().sendClientInfo, + SendClientInfo: routerPlatform.Load().sendClientInfo, + Upstreams: upstreams, } if err := tmpl.Execute(&sb, to); err != nil { return "", err diff --git a/internal/router/firewalla.go b/internal/router/firewalla.go index 6d57409..7e81b24 100644 --- a/internal/router/firewalla.go +++ b/internal/router/firewalla.go @@ -2,8 +2,10 @@ package router import ( "fmt" + "net" "os" "os/exec" + "path/filepath" "strings" ) @@ -78,3 +80,27 @@ func writeFirewallStartupScript() error { script := fmt.Sprintf("#!/bin/bash\n\nsudo %q %s\n", exe, argStr) return os.WriteFile(firewallaCtrldInitScriptPath, []byte(script), 0755) } + +func firewallaDnsmasqUpstreams() []dnsmasqUpstream { + matches, err := filepath.Glob("/home/pi/firerouter/etc/dnsmasq.dns.*.conf") + if err != nil { + return nil + } + upstreams := make([]dnsmasqUpstream, 0, len(matches)) + for _, match := range matches { + // Trim prefix and suffix to get the iface name only. + ifaceName := strings.TrimSuffix(strings.TrimPrefix(match, "/home/pi/firerouter/etc/dnsmasq.dns."), ".conf") + if netIface, _ := net.InterfaceByName(ifaceName); netIface != nil { + addrs, _ := netIface.Addrs() + for _, addr := range addrs { + if netIP, ok := addr.(*net.IPNet); ok && netIP.IP.To4() != nil { + upstreams = append(upstreams, dnsmasqUpstream{ + Ip: netIP.IP.To4().String(), + Port: ListenPort(), + }) + } + } + } + } + return upstreams +} diff --git a/internal/router/router.go b/internal/router/router.go index c53178f..0c18f50 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -220,6 +220,13 @@ func Cleanup(svc *service.Config) error { // ListenIP returns the listener IP of ctrld on router. func ListenIP() string { + name := Name() + switch name { + case Firewalla: + // Firewalla excepts 127.0.0.1 in all interfaces config. So we need to listen on all interfaces, + // making dnsmasq to be able to forward DNS query to specific interface based on VLAN config. + return "0.0.0.0" + } return "127.0.0.1" }