github.com/ethersphere/bee/v2@v2.2.0/pkg/p2p/libp2p/upnp.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package libp2p 6 7 import ( 8 "errors" 9 "strings" 10 11 "github.com/libp2p/go-libp2p/core/host" 12 libp2ppeer "github.com/libp2p/go-libp2p/core/peer" 13 ma "github.com/multiformats/go-multiaddr" 14 ) 15 16 type UpnpAddressResolver struct { 17 host host.Host 18 } 19 20 // Resolve checks if there is a possible better advertisable underlay then the provided observed address. 21 // In some NAT situations, for example in the case when nodes are behind upnp, observer might send the observed address with a wrong port. 22 // In this case, observed address is compared to addresses provided by host, and if there is a same address but with different port, that one is used as advertisable address instead of provided observed one. 23 // TODO: this is a quickfix and it will be improved in the future 24 func (r *UpnpAddressResolver) Resolve(observedAddress ma.Multiaddr) (ma.Multiaddr, error) { 25 observableAddrInfo, err := libp2ppeer.AddrInfoFromP2pAddr(observedAddress) 26 if err != nil { 27 return nil, err 28 } 29 30 if len(observableAddrInfo.Addrs) < 1 { 31 return nil, errors.New("invalid observed address") 32 } 33 34 observedAddrSplit := strings.Split(observableAddrInfo.Addrs[0].String(), "/") 35 36 // if address is not in a form of '/ipversion/ip/protocol/port/...` don't compare to addresses and return it 37 if len(observedAddrSplit) < 5 { 38 return observedAddress, nil 39 } 40 41 observedAddressPort := observedAddrSplit[4] 42 43 // observervedAddressShort is an obaserved address without port 44 observervedAddressShort := strings.Join(append(observedAddrSplit[:4], observedAddrSplit[5:]...), "/") 45 46 for _, a := range r.host.Addrs() { 47 asplit := strings.Split(a.String(), "/") 48 if len(asplit) != len(observedAddrSplit) { 49 continue 50 } 51 52 aport := asplit[4] 53 if strings.Join(append(asplit[:4], asplit[5:]...), "/") != observervedAddressShort { 54 continue 55 } 56 57 if aport != observedAddressPort { 58 aaddress, err := buildUnderlayAddress(a, observableAddrInfo.ID) 59 if err != nil { 60 continue 61 } 62 63 return aaddress, nil 64 } 65 } 66 67 return observedAddress, nil 68 }