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  }