From 2d950eecdfd3652a33bfe239d7ab6b1aba797ba7 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 30 May 2023 00:52:04 +0700 Subject: [PATCH] cmd/ctrld: spoofing client IP on routers --- cmd/ctrld/dns_proxy.go | 17 +++++++++++++++-- cmd/ctrld/dns_proxy_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/cmd/ctrld/dns_proxy.go b/cmd/ctrld/dns_proxy.go index ac9af50..a7602f0 100644 --- a/cmd/ctrld/dns_proxy.go +++ b/cmd/ctrld/dns_proxy.go @@ -50,11 +50,12 @@ func (p *prog) serveDNS(listenerNum string) error { q := m.Question[0] domain := canonicalName(q.Name) reqId := requestID() - fmtSrcToDest := fmtRemoteToLocal(listenerNum, w.RemoteAddr().String(), w.LocalAddr().String()) + remoteAddr := spoofRemoteAddr(w.RemoteAddr(), router.GetClientInfoByMac(macFromMsg(m))) + fmtSrcToDest := fmtRemoteToLocal(listenerNum, remoteAddr.String(), w.LocalAddr().String()) t := time.Now() ctx := context.WithValue(context.Background(), ctrld.ReqIdCtxKey{}, reqId) ctrld.Log(ctx, mainLog.Debug(), "%s received query: %s %s", fmtSrcToDest, dns.TypeToString[q.Qtype], domain) - upstreams, matched := p.upstreamFor(ctx, listenerNum, listenerConfig, w.RemoteAddr(), domain) + upstreams, matched := p.upstreamFor(ctx, listenerNum, listenerConfig, remoteAddr, domain) var answer *dns.Msg if !matched && listenerConfig.Restricted { answer = new(dns.Msg) @@ -418,6 +419,18 @@ func macFromMsg(msg *dns.Msg) string { return "" } +func spoofRemoteAddr(addr net.Addr, ci *ctrld.ClientInfo) net.Addr { + if ci != nil && ci.IP != "" { + switch addr := addr.(type) { + case *net.UDPAddr: + addr.IP = net.ParseIP(ci.IP) + case *net.TCPAddr: + addr.IP = net.ParseIP(ci.IP) + } + } + return addr +} + // runDNSServer starts a DNS server for given address and network, // with the given handler. It ensures the server has started listening. // Any error will be reported to the caller via returned channel. diff --git a/cmd/ctrld/dns_proxy_test.go b/cmd/ctrld/dns_proxy_test.go index c0e8443..2d29bc3 100644 --- a/cmd/ctrld/dns_proxy_test.go +++ b/cmd/ctrld/dns_proxy_test.go @@ -191,3 +191,28 @@ func Test_macFromMsg(t *testing.T) { }) } } + +func Test_remoteAddrFromMsg(t *testing.T) { + loopbackIP := net.ParseIP("127.0.0.1") + tests := []struct { + name string + addr net.Addr + ci *ctrld.ClientInfo + want string + }{ + {"tcp", &net.TCPAddr{IP: loopbackIP, Port: 12345}, &ctrld.ClientInfo{IP: "192.168.1.10"}, "192.168.1.10:12345"}, + {"udp", &net.UDPAddr{IP: loopbackIP, Port: 12345}, &ctrld.ClientInfo{IP: "192.168.1.11"}, "192.168.1.11:12345"}, + {"nil client info", &net.UDPAddr{IP: loopbackIP, Port: 12345}, nil, "127.0.0.1:12345"}, + {"empty ip", &net.UDPAddr{IP: loopbackIP, Port: 12345}, &ctrld.ClientInfo{}, "127.0.0.1:12345"}, + } + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + addr := spoofRemoteAddr(tc.addr, tc.ci) + if addr.String() != tc.want { + t.Errorf("unexpected result, want: %q, got: %q", tc.want, addr.String()) + } + }) + } +}