func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) { if len(laddrs) < 1 { return nil } // make sure that we ONLY use local addrs that match the remote addr. laddrs = manet.AddrMatch(raddr, laddrs) if len(laddrs) < 1 { return nil } // make sure that we ONLY use local addrs that CAN dial the remote addr. // filter out all the local addrs that aren't capable raddrIPLayer := ma.Split(raddr)[0] raddrIsLoopback := manet.IsIPLoopback(raddrIPLayer) raddrIsLinkLocal := manet.IsIP6LinkLocal(raddrIPLayer) laddrs = addrutil.FilterAddrs(laddrs, func(a ma.Multiaddr) bool { laddrIPLayer := ma.Split(a)[0] laddrIsLoopback := manet.IsIPLoopback(laddrIPLayer) laddrIsLinkLocal := manet.IsIP6LinkLocal(laddrIPLayer) if laddrIsLoopback { // our loopback addrs can only dial loopbacks. return raddrIsLoopback } if laddrIsLinkLocal { return raddrIsLinkLocal // out linklocal addrs can only dial link locals. } return true }) // TODO pick with a good heuristic // we use a random one for now to prevent bad addresses from making nodes unreachable // with a random selection, multiple tries may work. return laddrs[rand.Intn(len(laddrs))] }
// ResolveUnspecifiedAddress expands an unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to // use the known local interfaces. If ifaceAddr is nil, we request interface addresses // from the network stack. (this is so you can provide a cached value if resolving many addrs) func ResolveUnspecifiedAddress(resolve ma.Multiaddr, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) { // split address into its components split := ma.Split(resolve) // if first component (ip) is not unspecified, use it as is. if !manet.IsIPUnspecified(split[0]) { return []ma.Multiaddr{resolve}, nil } out := make([]ma.Multiaddr, 0, len(ifaceAddrs)) for _, ia := range ifaceAddrs { // must match the first protocol to be resolve. if ia.Protocols()[0].Code != resolve.Protocols()[0].Code { continue } split[0] = ia joined := ma.Join(split...) out = append(out, joined) log.Debug("adding resolved addr:", resolve, joined, out) } if len(out) < 1 { return nil, fmt.Errorf("failed to resolve: %s", resolve) } return out, nil }
// ParseMultiaddr parses a multiaddr into an IPFSAddr func ParseMultiaddr(m ma.Multiaddr) (a IPFSAddr, err error) { // never panic. defer func() { if r := recover(); r != nil { log.Debug("recovered from panic: ", r) a = nil err = ErrInvalidAddr } }() if m == nil { return nil, ErrInvalidAddr } // make sure it's an ipfs addr parts := ma.Split(m) if len(parts) < 1 { return nil, ErrInvalidAddr } ipfspart := parts[len(parts)-1] // last part if ipfspart.Protocols()[0].Code != ma.P_IPFS { return nil, ErrInvalidAddr } // make sure ipfs id parses as a peer.ID peerIdParts := strings.Split(ipfspart.String(), "/") peerIdStr := peerIdParts[len(peerIdParts)-1] id, err := peer.IDB58Decode(peerIdStr) if err != nil { return nil, err } return ipfsAddr{ma: m, id: id}, nil }
// AddrOverNonLocalIP returns whether the addr uses a non-local ip link func AddrOverNonLocalIP(a ma.Multiaddr) bool { split := ma.Split(a) if len(split) < 1 { return false } if manet.IsIP6LinkLocal(split[0]) { return false } return true }
// AddrIsShareableOnWAN returns whether the given address should be shareable on the // wide area network (wide internet). func AddrIsShareableOnWAN(addr ma.Multiaddr) bool { s := ma.Split(addr) if len(s) < 1 { return false } a := s[0] if manet.IsIPLoopback(a) || manet.IsIP6LinkLocal(a) || manet.IsIPUnspecified(a) { return false } return manet.IsThinWaist(a) }
func toPeerInfo(bp config.BootstrapPeer) peer.PeerInfo { // for now, we drop the "ipfs addr" part of the multiaddr. the rest // of the codebase currently uses addresses without the peerid part. m := bp.Multiaddr() s := ma.Split(m) m = ma.Join(s[:len(s)-1]...) return peer.PeerInfo{ ID: bp.ID(), Addrs: []ma.Multiaddr{m}, } }
func TestTransport(t *testing.T) { for _, g := range good { a, err := ParseString(g) if err != nil { t.Error("failed to parse", g, err) continue } m := newMultiaddr(t, g) split := ma.Split(m) m = ma.Join(split[:len(split)-1]...) if a.Multiaddr().Equal(m) { t.Error("should not be equal", a.Multiaddr(), m) } if !Transport(a).Equal(m) { t.Error("should be equal", Transport(a), m) } } }
// observerGroup is a function that determines what part of // a multiaddr counts as a different observer. for example, // two ipfs nodes at the same IP/TCP transport would get // the exact same NAT mapping; they would count as the // same observer. This may protect against NATs who assign // different ports to addresses at different IP hosts, but // not TCP ports. // // Here, we use the root multiaddr address. This is mostly // IP addresses. In practice, this is what we want. func observerGroup(m ma.Multiaddr) string { return ma.Split(m)[0].String() }
func Transport(iaddr IPFSAddr) (maddr ma.Multiaddr) { maddr = iaddr.Multiaddr() split := ma.Split(maddr) maddr = ma.Join(split[:len(split)-1]...) return }