From 1f421f981bb455a759f92a10cbd8f6ecfae2c6df Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Wed, 6 Dec 2023 18:59:46 +0900 Subject: [PATCH] feat: support ipv6 link-local address --- p2p/host/basic/basic_host.go | 13 ++++--- p2p/net/reuseport/dialer.go | 2 +- p2p/net/swarm/swarm_dial.go | 2 -- p2p/transport/tcp/tcp.go | 5 ++- p2p/transport/tcp/tcp_test.go | 64 +++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 8 deletions(-) diff --git a/p2p/host/basic/basic_host.go b/p2p/host/basic/basic_host.go index 8e6e8efe7c..354ea0af52 100644 --- a/p2p/host/basic/basic_host.go +++ b/p2p/host/basic/basic_host.go @@ -782,22 +782,27 @@ func (h *BasicHost) Addrs() []ma.Multiaddr { // Copy addrs slice since we'll be modifying it. addrsOld := addrs - addrs = make([]ma.Multiaddr, len(addrsOld)) - copy(addrs, addrsOld) + addrs = make([]ma.Multiaddr, 0, len(addrsOld)) - for i, addr := range addrs { + for _, addr := range addrsOld { if ok, n := libp2pwebtransport.IsWebtransportMultiaddr(addr); ok && n == 0 { t := s.TransportForListening(addr) tpt, ok := t.(addCertHasher) if !ok { + addrs = append(addrs, addr) continue } addrWithCerthash, added := tpt.AddCertHashes(addr) if !added { + addrs = append(addrs, addr) log.Debug("Couldn't add certhashes to webtransport multiaddr because we aren't listening on webtransport") continue } - addrs[i] = addrWithCerthash + addrs = append(addrs, addrWithCerthash) + } else if manet.IsIP6LinkLocal(addr) { + continue + } else { + addrs = append(addrs, addr) } } return addrs diff --git a/p2p/net/reuseport/dialer.go b/p2p/net/reuseport/dialer.go index 2efc02d393..102f3e75cc 100644 --- a/p2p/net/reuseport/dialer.go +++ b/p2p/net/reuseport/dialer.go @@ -50,7 +50,7 @@ func (d *dialer) DialContext(ctx context.Context, network, addr string) (net.Con return nil, err } ip := tcpAddr.IP - if !ip.IsLoopback() && !ip.IsGlobalUnicast() { + if !ip.IsLoopback() && !ip.IsGlobalUnicast() && !ip.IsLinkLocalUnicast() { return nil, fmt.Errorf("undialable IP: %s", ip) } diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go index 3fb15383a2..b0497650b3 100644 --- a/p2p/net/swarm/swarm_dial.go +++ b/p2p/net/swarm/swarm_dial.go @@ -489,8 +489,6 @@ func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) (goodAdd } return true }, - // TODO: Consider allowing link-local addresses - func(addr ma.Multiaddr) bool { return !manet.IsIP6LinkLocal(addr) }, func(addr ma.Multiaddr) bool { if s.gater != nil && !s.gater.InterceptAddrDial(p, addr) { addrErrs = append(addrErrs, TransportError{Address: addr, Cause: ErrGaterDisallowedConnection}) diff --git a/p2p/transport/tcp/tcp.go b/p2p/transport/tcp/tcp.go index d52bb96019..45b0274a6f 100644 --- a/p2p/transport/tcp/tcp.go +++ b/p2p/transport/tcp/tcp.go @@ -152,7 +152,10 @@ func NewTCPTransport(upgrader transport.Upgrader, rcmgr network.ResourceManager, return tr, nil } -var dialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_TCP)) +var dialMatcher = mafmt.Or( + mafmt.And(mafmt.IP, mafmt.Base(ma.P_TCP)), + mafmt.And(mafmt.Base(ma.P_IP6ZONE), mafmt.IP, mafmt.Base(ma.P_TCP)), +) // CanDial returns true if this transport believes it can dial the given // multiaddr. diff --git a/p2p/transport/tcp/tcp_test.go b/p2p/transport/tcp/tcp_test.go index d96c34317b..00e27c6e13 100644 --- a/p2p/transport/tcp/tcp_test.go +++ b/p2p/transport/tcp/tcp_test.go @@ -3,6 +3,7 @@ package tcp import ( "context" "errors" + "net" "testing" "github.com/libp2p/go-libp2p/core/crypto" @@ -46,6 +47,69 @@ func TestTcpTransport(t *testing.T) { envReuseportVal = true } +func TestTcpTransportCanDialToLinkLocalAddress(t *testing.T) { + addr := ma.StringCast("/ip6zone/eth0/ip6/fe80::fc54:ff:fe43:e553/tcp/1234") + + var u transport.Upgrader + tpt, err := NewTCPTransport(u, nil) + require.NoError(t, err) + + if !tpt.CanDial(addr) { + t.Fatal("should be able to dial ip6zone") + } +} + +func TestTcpTransportWithLinkLocalAddress(t *testing.T) { + ifaces, err := net.Interfaces() + if err != nil { + t.Error(err) + return + } + + var targetAddr ma.Multiaddr + +findInterface: + for _, iface := range ifaces { + addrs, err := iface.Addrs() + if err == nil { + for _, a := range addrs { + addr, err := manet.FromNetAddr(a) + if err == nil { + if manet.IsIP6LinkLocal(addr) { + targetAddr = ma.StringCast("/ip6zone/" + iface.Name + addr.String()) + break findInterface + } + } + } + } + } + + if targetAddr == nil { + t.Fail() + return + } + + for i := 0; i < 2; i++ { + peerA, ia := makeInsecureMuxer(t) + _, ib := makeInsecureMuxer(t) + + ua, err := tptu.New(ia, muxers, nil, nil, nil) + require.NoError(t, err) + ta, err := NewTCPTransport(ua, nil) + require.NoError(t, err) + ub, err := tptu.New(ib, muxers, nil, nil, nil) + require.NoError(t, err) + tb, err := NewTCPTransport(ub, nil) + require.NoError(t, err) + + zero := targetAddr.String() + "/tcp/0" + ttransport.SubtestTransport(t, ta, tb, zero, peerA) + + envReuseportVal = false + } + envReuseportVal = true +} + func TestTcpTransportWithMetrics(t *testing.T) { peerA, ia := makeInsecureMuxer(t) _, ib := makeInsecureMuxer(t)