Пример #1
0
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()
}
Пример #2
0
// 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
}
Пример #3
0
// 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
}
Пример #4
0
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
}
Пример #5
0
// 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
}
Пример #6
0
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
}
Пример #7
0
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())
	}
}
Пример #8
0
// 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
}
Пример #9
0
func addrInAddrs(a ma.Multiaddr, as []ma.Multiaddr) bool {
	for _, b := range as {
		if a.Equal(b) {
			return true
		}
	}
	return false
}
Пример #10
0
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")
}
Пример #11
0
// 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)
	}
}
Пример #12
0
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
}
Пример #13
0
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
}
Пример #14
0
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
}
Пример #15
0
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
}
Пример #16
0
// 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)
}
Пример #17
0
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
}
Пример #18
0
// 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
}
Пример #19
0
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)
}
Пример #20
0
// 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
}
Пример #21
0
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
}
Пример #22
0
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")
}
Пример #23
0
// 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
}
Пример #24
0
// 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
}
Пример #25
0
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
}
Пример #26
0
// 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
}
Пример #27
0
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
}
Пример #28
0
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 ""
}
Пример #29
0
// 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
}
Пример #30
0
// 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
	}
}