github.com/ethersphere/bee/v2@v2.2.0/pkg/p2p/libp2p/static_resolver.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 "fmt" 10 "net" 11 "strings" 12 13 libp2ppeer "github.com/libp2p/go-libp2p/core/peer" 14 ma "github.com/multiformats/go-multiaddr" 15 ) 16 17 type staticAddressResolver struct { 18 multiProto string 19 port string 20 } 21 22 func newStaticAddressResolver(addr string, lookupIP func(host string) ([]net.IP, error)) (*staticAddressResolver, error) { 23 host, port, err := net.SplitHostPort(addr) 24 if err != nil { 25 return nil, err 26 } 27 28 var multiProto string 29 if host != "" { 30 multiProto, err = getMultiProto(host, lookupIP) 31 if err != nil { 32 return nil, err 33 } 34 } 35 36 return &staticAddressResolver{ 37 multiProto: multiProto, 38 port: port, 39 }, nil 40 } 41 42 func (r *staticAddressResolver) Resolve(observedAddress ma.Multiaddr) (ma.Multiaddr, error) { 43 observableAddrInfo, err := libp2ppeer.AddrInfoFromP2pAddr(observedAddress) 44 if err != nil { 45 return nil, err 46 } 47 48 if len(observableAddrInfo.Addrs) < 1 { 49 return nil, errors.New("invalid observed address") 50 } 51 52 observedAddrSplit := strings.Split(observableAddrInfo.Addrs[0].String(), "/") 53 54 // if address is not in a form of '/ipversion/ip/protocol/port/...` don't compare to addresses and return it 55 if len(observedAddrSplit) < 5 { 56 return observedAddress, nil 57 } 58 59 var multiProto string 60 if r.multiProto != "" { 61 multiProto = r.multiProto 62 } else { 63 multiProto = strings.Join(observedAddrSplit[:3], "/") 64 } 65 66 var port string 67 if r.port != "" { 68 port = r.port 69 } else { 70 port = observedAddrSplit[4] 71 } 72 a, err := ma.NewMultiaddr(multiProto + "/" + observedAddrSplit[3] + "/" + port) 73 if err != nil { 74 return nil, err 75 } 76 77 return buildUnderlayAddress(a, observableAddrInfo.ID) 78 } 79 80 func getMultiProto(host string, lookupIP func(host string) ([]net.IP, error)) (string, error) { 81 if host == "" { 82 return "", nil 83 } 84 ip := net.ParseIP(host) 85 if ip != nil { 86 if ip.To4() == nil { 87 return "/ip6/" + ip.String(), nil 88 } 89 return "/ip4/" + ip.String(), nil 90 } 91 ips, err := lookupIP(host) 92 if err != nil { 93 return "", fmt.Errorf("invalid IP or Domain Name %q", host) 94 } 95 ipv4, ipv6 := ipsClassifier(ips) 96 if ipv4 { 97 if ipv6 { 98 return "/dns/" + host, nil 99 } 100 return "/dns4/" + host, nil 101 } 102 return "/dns6/" + host, nil 103 } 104 105 func ipsClassifier(ips []net.IP) (ipv4, ipv6 bool) { 106 for _, ip := range ips { 107 if ip.To4() != nil { 108 ipv4 = true 109 } else { 110 ipv6 = true 111 } 112 if ipv4 && ipv6 { 113 return 114 } 115 } 116 return 117 }