From 34f3c9539b49396b17524ee72ea20498f96600b9 Mon Sep 17 00:00:00 2001 From: Nishant Das Date: Sat, 24 Apr 2021 00:18:10 +0800 Subject: [PATCH] p2p/discover: improve discv5 handling of IPv4-in-IPv6 addresses (#22703) When receiving PING from an IPv4 address over IPv6, the implementation sent back a IPv4-in-IPv6 address. This change makes it reflect the IPv4 address. --- p2p/discover/v5_udp.go | 9 ++++++++- p2p/discover/v5_udp_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index eb01d95e9..71a39ea5a 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -763,9 +763,16 @@ func (t *UDPv5) matchWithCall(fromID enode.ID, nonce v5wire.Nonce) (*callV5, err // handlePing sends a PONG response. func (t *UDPv5) handlePing(p *v5wire.Ping, fromID enode.ID, fromAddr *net.UDPAddr) { + remoteIP := fromAddr.IP + // Handle IPv4 mapped IPv6 addresses in the + // event the local node is binded to an + // ipv6 interface. + if remoteIP.To4() != nil { + remoteIP = remoteIP.To4() + } t.sendResponse(fromID, fromAddr, &v5wire.Pong{ ReqID: p.ReqID, - ToIP: fromAddr.IP, + ToIP: remoteIP, ToPort: uint16(fromAddr.Port), ENRSeq: t.localNode.Node().Seq(), }) diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 292785bd5..f061f5ab4 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -597,6 +597,38 @@ func TestUDPv5_LocalNode(t *testing.T) { } } +func TestUDPv5_PingWithIPV4MappedAddress(t *testing.T) { + t.Parallel() + test := newUDPV5Test(t) + defer test.close() + + rawIP := net.IPv4(0xFF, 0x12, 0x33, 0xE5) + test.remoteaddr = &net.UDPAddr{ + IP: rawIP.To16(), + Port: 0, + } + remote := test.getNode(test.remotekey, test.remoteaddr).Node() + done := make(chan struct{}, 1) + + // This handler will truncate the ipv4-mapped in ipv6 address. + go func() { + test.udp.handlePing(&v5wire.Ping{ENRSeq: 1}, remote.ID(), test.remoteaddr) + done <- struct{}{} + }() + test.waitPacketOut(func(p *v5wire.Pong, addr *net.UDPAddr, _ v5wire.Nonce) { + if len(p.ToIP) == net.IPv6len { + t.Error("Received untruncated ip address") + } + if len(p.ToIP) != net.IPv4len { + t.Errorf("Received ip address with incorrect length: %d", len(p.ToIP)) + } + if !p.ToIP.Equal(rawIP) { + t.Errorf("Received incorrect ip address: wanted %s but received %s", rawIP.String(), p.ToIP.String()) + } + }) + <-done +} + // udpV5Test is the framework for all tests above. // It runs the UDPv5 transport on a virtual socket and allows testing outgoing packets. type udpV5Test struct {