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 }
// 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 }
// 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 (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") }
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 (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 }
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 }
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 }
// 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 (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") }
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 }
// 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 } }
func IsUtpMultiaddr(a ma.Multiaddr) bool { p := a.Protocols() return len(p) == 3 && p[2].Name == "utp" }
func IsTcpMultiaddr(a ma.Multiaddr) bool { p := a.Protocols() return len(p) == 2 && (p[0].Name == "ip4" || p[0].Name == "ip6") && p[1].Name == "tcp" }