func (oas *ObservedAddrSet) Add(addr ma.Multiaddr, observer ma.Multiaddr) { oas.Lock() defer oas.Unlock() // for zero-value. if oas.addrs == nil { oas.addrs = make(map[string]*ObservedAddr) oas.ttl = peer.OwnObservedAddrTTL } s := addr.String() oa, found := oas.addrs[s] // first time seeing address. if !found { oa = &ObservedAddr{ Addr: addr, SeenBy: make(map[string]struct{}), } oas.addrs[s] = oa } // mark the observer oa.SeenBy[observerGroup(observer)] = struct{}{} oa.LastSeen = time.Now() }
// AddrMatch returns the Multiaddrs that match the protocol stack on addr func AddrMatch(match ma.Multiaddr, addrs []ma.Multiaddr) []ma.Multiaddr { // we should match transports entirely. p1s := match.Protocols() out := make([]ma.Multiaddr, 0, len(addrs)) for _, a := range addrs { p2s := a.Protocols() if len(p1s) != len(p2s) { continue } match := true for i, p2 := range p2s { if p1s[i].Code != p2.Code { match = false break } } if match { out = append(out, a) } } return out }
// 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": network = network + "4" host = strings.Join([]string{parts[1], parts[3]}, ":") case "ip6": network = network + "6" host = fmt.Sprintf("[%s]:%s", parts[1], parts[3]) } return network, host, nil }
func (t *TcpTransport) Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error) { t.dlock.Lock() defer t.dlock.Unlock() s := laddr.String() d, found := t.dialers[s] if found { return d, nil } var base manet.Dialer var doReuse bool for _, o := range opts { switch o := o.(type) { case TimeoutOpt: base.Timeout = time.Duration(o) case ReuseportOpt: doReuse = bool(o) default: return nil, fmt.Errorf("unrecognized option: %#v", o) } } tcpd, err := t.newTcpDialer(base, laddr, doReuse) if err != nil { return nil, err } t.dialers[s] = tcpd return tcpd, nil }
// 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 }
func (_ IP) Apply(m ma.Multiaddr, side int, ctx match.Context) error { p := m.Protocols()[0] name := p.Name s, _ := m.ValueForProtocol(p.Code) mctx := ctx.Misc() ip := net.ParseIP(s) if ip == nil { return fmt.Errorf("incorrect ip %s", m) } switch name { case "ip4": if ip = ip.To4(); ip == nil { return fmt.Errorf("incorrect ip4 %s", m) } case "ip6": if ip = ip.To16(); ip == nil { return fmt.Errorf("incorrent ip6 %s", m) } } mctx.IPs = append(mctx.IPs, ip) return nil }
func assertEcho(t *testing.T, rwc io.ReadWriteCloser, m ma.Multiaddr) { str := "test string" done := make(chan struct{}) defer rwc.Close() go func() { defer close(done) _, err := fmt.Fprint(rwc, str) if err != nil { t.Error(err) return } buf := make([]byte, 256) n, err := rwc.Read(buf) if err != nil { t.Error(err) return } got := string(buf[:n]) if got != str { t.Errorf("expected \"%s\", got \"%s\"", str, got) } }() select { case <-done: case <-time.After(time.Second): t.Errorf("assertEcho: %s timed out", m.String()) } }
// 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 }
func addrInAddrs(a ma.Multiaddr, as []ma.Multiaddr) bool { for _, b := range as { if a.Equal(b) { return true } } return false }
func (w WS) Apply(m ma.Multiaddr, side int, ctx Context) error { var path string // ws client matches /http/ws too, so /ws might not be the first protocol for _, p := range m.Protocols() { if p.Name == "ws" { pth, err := m.ValueForProtocol(p.Code) if err != nil { return err } path = pth break } } sctx := ctx.Special() mctx := ctx.Misc() switch side { case S_Client: // resolve url var url string if mctx.Host != "" { // this will make mctx.Host appear in http request headers, // cloud servers often require that url = fmt.Sprintf("ws://%s/%s", mctx.Host, path) } else { switch t := sctx.NetConn.(type) { case *net.TCPConn: url = fmt.Sprintf("ws://%s/%s", t.RemoteAddr().String(), path) default: url = fmt.Sprintf("ws://foo.bar/%s", path) } } wcon, err := w.Select(sctx.NetConn, url) if err != nil { return err } sctx.NetConn = wcon return nil case S_Server: if mctx.HTTPMux == nil { // help the user out if /http is missing before /ws HTTP{}.Apply(m, S_Server, ctx) } ln, err := w.Handle(mctx.HTTPMux, "/"+path) if err != nil { return err } sctx.NetListener = ln sctx.CloseFn = ConcatClose(ln.Close, sctx.CloseFn) return nil } return fmt.Errorf("incorrect side constant") }
// CheckNATWarning checks if our observed addresses differ. if so, // informs the user that certain things might not work yet func CheckNATWarning(observed, expected ma.Multiaddr, listen []ma.Multiaddr) { if observed.Equal(expected) { return } if !AddrInList(observed, listen) { // probably a nat log.Warningf(natWarning, observed, listen) } }
func (_ DNS) Match(m ma.Multiaddr, side int) (int, bool) { ps := m.Protocols() if len(ps) > 0 && ps[0].Name == "dns" { return 1, true } return 0, false }
func trimPrefix(m, prem ma.Multiaddr) (ma.Multiaddr, bool) { s := m.String() pres := prem.String() if !strings.HasPrefix(s, pres) { return nil, false } return ma.StringCast(strings.TrimPrefix(s, pres)), true }
func (p HTTP) Match(m ma.Multiaddr, side int) (int, bool) { if side != S_Server { return 0, false } ms := m.Protocols() if len(ms) >= 1 && ms[0].Name == "http" { return 1, true } return 0, false }
func (t TCP) Match(m ma.Multiaddr, side int) (int, bool) { ps := m.Protocols() if len(ps) < 1 { return 0, false } if ps[0].Name == "tcp" { return 1, true } return 0, false }
// rawConnDial dials the underlying net.Conn + manet.Conns func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (transport.Conn, error) { if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") { log.Event(ctx, "connDialZeroAddr", lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr)) return nil, fmt.Errorf("Attempted to connect to zero address: %s", raddr) } sd := d.subDialerForAddr(raddr) if sd == nil { return nil, fmt.Errorf("no dialer for %s", raddr) } return sd.Dial(raddr) }
func (_ IP) Match(m ma.Multiaddr, side int) (int, bool) { ps := m.Protocols() if len(ps) < 1 { return 0, false } name := ps[0].Name if name == "ip" || name == "ip4" || name == "ip6" { return 1, true } return 0, false }
// IsIPLoopback returns whether a Multiaddr is a "Loopback" IP address // This means either /ip4/127.0.0.1 or /ip6/::1 // TODO: differentiate IsIPLoopback and OverIPLoopback func IsIPLoopback(m ma.Multiaddr) bool { b := m.Bytes() // /ip4/127 prefix (_entire_ /8 is loopback...) if bytes.HasPrefix(b, []byte{ma.P_IP4, 127}) { return true } // /ip6/::1 if IP6Loopback.Equal(m) || IP6LinkLocalLoopback.Equal(m) { return true } return false }
func addPortMapping(nmgr *natManager, intaddr ma.Multiaddr) { nat := nmgr.NAT() if nat == nil { panic("natManager addPortMapping called without a nat.") } // first, check if the port mapping already exists. for _, mapping := range nat.Mappings() { if mapping.InternalAddr().Equal(intaddr) { return // it exists! return. } } ctx := context.TODO() lm := make(lgbl.DeferredMap) lm["internalAddr"] = func() interface{} { return intaddr.String() } defer log.EventBegin(ctx, "natMgrAddPortMappingWait", lm).Done() select { case <-nmgr.proc.Closing(): lm["outcome"] = "cancelled" return // no use. case <-nmgr.ready: // wait until it's ready. } // actually start the port map (sub-event because waiting may take a while) defer log.EventBegin(ctx, "natMgrAddPortMapping", lm).Done() // get the nat m, err := nat.NewMapping(intaddr) if err != nil { lm["outcome"] = "failure" lm["error"] = err return } extaddr, err := m.ExternalAddr() if err != nil { lm["outcome"] = "failure" lm["error"] = err return } lm["outcome"] = "success" lm["externalAddr"] = func() interface{} { return extaddr.String() } log.Infof("established nat port mapping: %s <--> %s", intaddr, extaddr) }
// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks. func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool { ap := a.Protocols() bp := b.Protocols() if len(ap) != len(bp) { return false } for i, api := range ap { if api.Code != bp[i].Code { return false } } return true }
func (w WS) Match(m ma.Multiaddr, side int) (int, bool) { ps := m.Protocols() if len(ps) >= 1 && ps[0].Name == "ws" { return 1, true } // If we're a client, also match "/http/ws". if side == S_Client && len(ps) >= 2 && ps[0].Name == "http" && ps[1].Name == "ws" { return 2, true } return 0, false }
func (t TCP) Apply(m ma.Multiaddr, side int, ctx match.Context) error { p := m.Protocols()[0] portstr, _ := m.ValueForProtocol(p.Code) port, err := strconv.Atoi(portstr) if err != nil { return err } mctx := ctx.Misc() sctx := ctx.Special() if len(mctx.IPs) == 0 { return fmt.Errorf("no ips in context") } switch side { case match.S_Client: var con net.Conn var err error if len(mctx.IPs) == 1 { con, err = t.Dial(mctx.IPs[0], port) } else { con, err = t.DialMany(mctx.IPs, port) } if err != nil { return err } sctx.NetConn = con sctx.CloseFn = con.Close return nil case match.S_Server: netln, err := t.Listen(mctx.IPs[0], port) if err != nil { return err } sctx.NetListener = netln sctx.CloseFn = netln.Close return nil } return fmt.Errorf("incorrect side constant") }
// Dial metadata is metadata for dial events func Dial(sys string, lid, rid peer.ID, laddr, raddr ma.Multiaddr) DeferredMap { m := DeferredMap{} m["subsystem"] = sys if lid != "" { m["localPeer"] = func() interface{} { return lid.Pretty() } } if laddr != nil { m["localAddr"] = func() interface{} { return laddr.String() } } if rid != "" { m["remotePeer"] = func() interface{} { return rid.Pretty() } } if raddr != nil { m["remoteAddr"] = func() interface{} { return raddr.String() } } return m }
// NewMapping attemps to construct a mapping on protocol and internal port // It will also periodically renew the mapping until the returned Mapping // -- or its parent NAT -- is Closed. // // May not succeed, and mappings may change over time; // NAT devices may not respect our port requests, and even lie. // Clients should not store the mapped results, but rather always // poll our object for the latest mappings. func (nat *NAT) NewMapping(maddr ma.Multiaddr) (Mapping, error) { if nat == nil { return nil, fmt.Errorf("no nat available") } network, addr, err := manet.DialArgs(maddr) if err != nil { return nil, fmt.Errorf("DialArgs failed on addr:", maddr.String()) } switch network { case "tcp", "tcp4", "tcp6": network = "tcp" case "udp", "udp4", "udp6": network = "udp" default: return nil, fmt.Errorf("transport not supported by NAT: %s", network) } intports := strings.Split(addr, ":")[1] intport, err := strconv.Atoi(intports) if err != nil { return nil, err } m := &mapping{ nat: nat, proto: network, intport: intport, intaddr: maddr, } m.proc = goprocess.WithTeardown(func() error { nat.rmMapping(m) return nil }) nat.addMapping(m) m.proc.AddChild(periodic.Every(MappingDuration/3, func(worker goprocess.Process) { nat.establishMapping(m) })) // do it once synchronously, so first mapping is done right away, and before exiting, // allowing users -- in the optimistic case -- to use results right after. nat.establishMapping(m) return m, nil }
func (_ DNS) Apply(m ma.Multiaddr, side int, ctx match.Context) error { p := m.Protocols()[0] host, _ := m.ValueForProtocol(p.Code) ips, err := net.LookupIP(host) if err != nil { return err } if len(ips) == 0 { return fmt.Errorf("failed to resolve domain") } mctx := ctx.Misc() mctx.Host = host mctx.IPs = ips return nil }
// matchPrefix finds a MatchApplier (in mr.protocols or mr.reusable) for one or // more first m.Protocols() and also returns an int of how many protocols it can // consume. // // matchPrefix returns an error if it can't find any or finds more than one // MatchApplier func (mr matchreg) matchPrefix(m ma.Multiaddr, side int) (match.MatchApplier, int, error) { ret := []match.MatchApplier{} for _, mch := range mr.reusable { if _, ok := mch.Match(m, side); ok { ret = append(ret, mch) } } if len(ret) == 1 { n, _ := ret[0].Match(m, side) return ret[0], n, nil } else if len(ret) > 1 { return nil, 0, fmt.Errorf("found more than one reusable for %s", m.String()) } for _, mch := range mr.protocols { if _, ok := mch.Match(m, side); ok { ret = append(ret, mch) } } if len(ret) == 0 { return nil, 0, fmt.Errorf("no matchers found for %s", m.String()) } else if len(ret) > 1 { return nil, 0, fmt.Errorf("found more than one matcher for %s", m.String()) } n, _ := ret[0].Match(m, side) return ret[0], n, nil }
func (t *TcpTransport) Listen(laddr ma.Multiaddr) (Listener, error) { t.llock.Lock() defer t.llock.Unlock() s := laddr.String() l, found := t.listeners[s] if found { return l, nil } list, err := manetListen(laddr) if err != nil { return nil, err } tlist := &tcpListener{ list: list, transport: t, } t.listeners[s] = tlist return tlist, nil }
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 "" }
// AddrUsable returns whether our network can use this addr. // We only use the transports in SupportedTransportStrings, // and we do not link local addresses. Loopback is ok // as we need to be able to connect to multiple ipfs nodes // in the same machine. func AddrUsable(a ma.Multiaddr, partial bool) bool { if a == nil { return false } if !AddrOverNonLocalIP(a) { return false } // test the address protocol list is in SupportedTransportProtocols matches := func(supported, test []ma.Protocol) bool { if len(test) > len(supported) { return false } // when partial, it's ok if test < supported. if !partial && len(supported) != len(test) { return false } for i := range test { if supported[i].Code != test[i].Code { return false } } return true } transport := a.Protocols() for _, supported := range SupportedTransportProtocols { if matches(supported, transport) { return true } } return false }
// 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 } }