diff --git a/cmd/cli/dns_proxy.go b/cmd/cli/dns_proxy.go index be0b731..9c486ed 100644 --- a/cmd/cli/dns_proxy.go +++ b/cmd/cli/dns_proxy.go @@ -573,9 +573,23 @@ func (p *prog) getClientInfo(remoteIP string, msg *dns.Msg) *ctrld.ClientInfo { ci.Hostname = p.ciTable.LookupHostname(ci.IP, ci.Mac) } ci.Self = queryFromSelf(ci.IP) + p.spoofLoopbackIpInClientInfo(ci) return ci } +// spoofLoopbackIpInClientInfo replaces loopback IPs in client info. +// +// - Preference IPv4. +// - Preference RFC1918. +func (p *prog) spoofLoopbackIpInClientInfo(ci *ctrld.ClientInfo) { + if ip := net.ParseIP(ci.IP); ip == nil || !ip.IsLoopback() { + return + } + if ip := p.ciTable.LookupRFC1918IPv4(ci.Mac); ip != "" { + ci.IP = ip + } +} + // queryFromSelf reports whether the input IP is from device running ctrld. func queryFromSelf(ip string) bool { netIP := netip.MustParseAddr(ip) diff --git a/internal/clientinfo/client_info.go b/internal/clientinfo/client_info.go index 6d6cbf9..f591174 100644 --- a/internal/clientinfo/client_info.go +++ b/internal/clientinfo/client_info.go @@ -241,6 +241,21 @@ func (t *Table) LookupHostname(ip, mac string) string { return "" } +// LookupRFC1918IPv4 returns the RFC1918 IPv4 address for the given MAC address, if any. +func (t *Table) LookupRFC1918IPv4(mac string) string { + t.initOnce.Do(t.init) + for _, r := range t.ipResolvers { + ip, err := netip.ParseAddr(r.LookupIP(mac)) + if err != nil || ip.Is6() { + continue + } + if ip.IsPrivate() { + return ip.String() + } + } + return "" +} + type macEntry struct { mac string src string diff --git a/internal/clientinfo/client_info_test.go b/internal/clientinfo/client_info_test.go index 79e5912..e6575f2 100644 --- a/internal/clientinfo/client_info_test.go +++ b/internal/clientinfo/client_info_test.go @@ -25,3 +25,22 @@ func Test_normalizeIP(t *testing.T) { }) } } + +func TestTable_LookupRFC1918IPv4(t *testing.T) { + table := &Table{ + dhcp: &dhcp{}, + arp: &arpDiscover{}, + } + + table.ipResolvers = append(table.ipResolvers, table.dhcp) + table.ipResolvers = append(table.ipResolvers, table.arp) + + macAddress := "cc:19:f9:8a:49:e6" + rfc1918IPv4 := "10.0.10.245" + table.dhcp.ip.Store(macAddress, "127.0.0.1") + table.arp.ip.Store(macAddress, rfc1918IPv4) + + if got := table.LookupRFC1918IPv4(macAddress); got != rfc1918IPv4 { + t.Fatalf("unexpected result, want: %s, got: %s", rfc1918IPv4, got) + } +}