// DialArgs is a convenience function returning arguments for use in net.Dial func DialArgs(m ma.Multiaddr) (string, string, error) { if !IsThinWaist(m) { return "", "", fmt.Errorf("%s is not a 'thin waist' address", m) } str := m.String() parts := strings.Split(str, "/")[1:] if len(parts) == 2 { // only IP return parts[0], parts[1], nil } network := parts[2] if parts[2] == "udp" && len(parts) > 4 && parts[4] == "utp" { network = parts[4] } var host string switch parts[0] { case "ip4": host = strings.Join([]string{parts[1], parts[3]}, ":") case "ip6": host = fmt.Sprintf("[%s]:%s", parts[1], parts[3]) } return network, host, nil }
// addrInList returns whether or not an address is part of a list. // this is useful to check if NAT is happening (or other bugs?) func addrInList(addr ma.Multiaddr, list []ma.Multiaddr) bool { for _, addr2 := range list { if addr.Equal(addr2) { return true } } return false }
// DialAddr connects to a peer over a particular address // Ensures raddr is part of peer.Addresses() // Example: d.DialAddr(ctx, peer.Addresses()[0], peer) func (d *Dialer) DialAddr(ctx context.Context, raddr ma.Multiaddr, remote peer.Peer) (Conn, error) { found := false for _, addr := range remote.Addresses() { if addr.Equal(raddr) { found = true } } if !found { return nil, debugerror.Errorf("address %s is not in peer %s", raddr, remote) } network, _, err := manet.DialArgs(raddr) if err != nil { return nil, err } laddr := d.LocalPeer.NetAddress(network) if laddr == nil { return nil, debugerror.Errorf("No local address for network %s", network) } if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") { return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr) } remote.SetType(peer.Remote) remote, err = d.Peerstore.Add(remote) if err != nil { log.Errorf("Error putting peer into peerstore: %s", remote) } // TODO: try to get reusing addr/ports to work. // madialer := manet.Dialer{LocalAddr: laddr} madialer := manet.Dialer{} log.Infof("%s dialing %s %s", d.LocalPeer, remote, raddr) maconn, err := madialer.Dial(raddr) if err != nil { return nil, err } c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn) if err != nil { return nil, err } return newSecureConn(ctx, c, d.Peerstore) }
// IsIPLoopback returns whether a Multiaddr is a "Loopback" IP address // This means either /ip4/127.0.0.1 or /ip6/::1 func IsIPLoopback(m ma.Multiaddr) bool { b := m.Bytes() // /ip4/127 prefix (_entire_ /8 is loopback...) if bytes.HasPrefix(b, []byte{4, 127}) { return true } // /ip6/::1 if IP6Loopback.Equal(m) || IP6LinkLocalLoopback.Equal(m) { return true } return false }
func outfmt(m ma.Multiaddr) string { switch format { case "string": return m.String() case "slice": return fmt.Sprintf("%v", m.Bytes()) case "bytes": return string(m.Bytes()) case "hex": return "0x" + hex.EncodeToString(m.Bytes()) } die("error: invalid format", format) return "" }
// Handshake3Msg constructs a Handshake3 msg. func Handshake3Msg(localPeer peer.Peer, remoteAddr ma.Multiaddr) *pb.Handshake3 { var msg pb.Handshake3 // don't need publicKey after secure channel. // msg.PublicKey = localPeer.PubKey().Bytes() // local listen addresses addrs := localPeer.Addresses() msg.ListenAddrs = make([][]byte, len(addrs)) for i, a := range addrs { msg.ListenAddrs[i] = a.Bytes() } // observed remote address msg.ObservedAddr = remoteAddr.Bytes() // services // srv := localPeer.Services() // msg.Services = make([]mux.ProtocolID, len(srv)) // for i, pid := range srv { // msg.Services[i] = pid // } return &msg }
// IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols. // This means: /{IP4, IP6}[/{TCP, UDP}] func IsThinWaist(m ma.Multiaddr) bool { p := m.Protocols() // nothing? not even a waist. if len(p) == 0 { return false } if p[0].Code != ma.P_IP4 && p[0].Code != ma.P_IP6 { return false } // only IP? still counts. if len(p) == 1 { return true } switch p[1].Code { case ma.P_TCP, ma.P_UDP, ma.P_IP4, ma.P_IP6: return true default: return false } }