diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index ae9934e3d..96c593128 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -135,7 +135,7 @@ }, { "ImportPath": "github.com/jbenet/go-multiaddr-net", - "Rev": "2b8f35303d2855c79f9f3f9b3584338a1ff7edbd" + "Rev": "04044c2289504304472715d827a8f564fa3759a8" }, { "ImportPath": "github.com/jbenet/go-multihash", diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/.travis.yml b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/.travis.yml new file mode 100644 index 000000000..7725b3095 --- /dev/null +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/.travis.yml @@ -0,0 +1,11 @@ +language: go + +go: + - 1.3 + - release + - tip + +script: + - make test + +env: TEST_VERBOSE=1 diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Makefile b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Makefile index 0ab6e6813..56311c449 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Makefile +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/Makefile @@ -12,5 +12,8 @@ vendor: godep install: dep cd multiaddr && go install +test: + go test ./... + dep: cd multiaddr && go get ./... diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert.go index 05f00a66c..fa1476c94 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert.go @@ -112,13 +112,13 @@ func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) { } switch network { - case "tcp": + case "tcp", "tcp4", "tcp6": return net.ResolveTCPAddr(network, host) - case "udp": + case "udp", "udp4", "udp6": return net.ResolveUDPAddr(network, host) - case "utp": + case "utp", "utp4", "utp6": return utp.ResolveUTPAddr(network, host) - case "ip": + case "ip", "ip4", "ip6": return net.ResolveIPAddr(network, host) } @@ -158,8 +158,10 @@ func DialArgs(m ma.Multiaddr) (string, string, error) { 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 diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert_test.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert_test.go index de4b338b1..8e3f1b95e 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert_test.go @@ -152,7 +152,10 @@ func TestDialArgs(t *testing.T) { } } - test("/ip4/127.0.0.1/udp/1234", "udp", "127.0.0.1:1234") - test("/ip4/127.0.0.1/tcp/4321", "tcp", "127.0.0.1:4321") - test("/ip4/127.0.0.1/udp/1234/utp", "utp", "127.0.0.1:1234") + test("/ip4/127.0.0.1/udp/1234", "udp4", "127.0.0.1:1234") + test("/ip4/127.0.0.1/tcp/4321", "tcp4", "127.0.0.1:4321") + test("/ip4/127.0.0.1/udp/1234/utp", "utp4", "127.0.0.1:1234") + test("/ip6/::1/udp/1234", "udp6", "[::1]:1234") + test("/ip6/::1/tcp/4321", "tcp6", "[::1]:4321") + test("/ip6/::1/udp/1234/utp", "utp6", "[::1]:1234") } diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/ip.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/ip.go index 57d2e38d6..be4707cfb 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/ip.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/ip.go @@ -57,7 +57,7 @@ func IsIPLoopback(m ma.Multiaddr) bool { b := m.Bytes() // /ip4/127 prefix (_entire_ /8 is loopback...) - if bytes.HasPrefix(b, []byte{4, 127}) { + if bytes.HasPrefix(b, []byte{ma.P_IP4, 127}) { return true } @@ -69,6 +69,14 @@ func IsIPLoopback(m ma.Multiaddr) bool { return false } +// IP6 Link Local addresses are non routable. The prefix is technically +// fe80::/10, but we test fe80::/16 for simplicity (no need to mask). +// So far, no hardware interfaces exist long enough to use those 2 bits. +// Send a PR if there is. +func IsIP6LinkLocal(m ma.Multiaddr) bool { + return bytes.HasPrefix(m.Bytes(), []byte{ma.P_IP6, 0xfe, 0x80}) +} + // IsIPUnspecified returns whether a Multiaddr is am Unspecified IP address // This means either /ip4/0.0.0.0 or /ip6/:: func IsIPUnspecified(m ma.Multiaddr) bool { diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net.go index 59842a91f..2fec9663f 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net.go @@ -106,12 +106,12 @@ func (d *Dialer) Dial(remote ma.Multiaddr) (Conn, error) { // ok, Dial! var nconn net.Conn switch rnet { - case "tcp": + case "tcp", "tcp4", "tcp6": nconn, err = d.Dialer.Dial(rnet, rnaddr) if err != nil { return nil, err } - case "utp": + case "udp", "udp4", "udp6": return nil, fmt.Errorf("utp is currently broken") // // construct utp dialer, with options on our net.Dialer @@ -236,6 +236,14 @@ func Listen(laddr ma.Multiaddr) (Listener, error) { return nil, err } + // we need to fetch the new multiaddr from the listener, as it + // may have resolved to some other value. + nladdr, err := FromNetAddr(nl.Addr()) + if err != nil { + return nil, err + } + laddr = nladdr + return &maListener{ Listener: nl, laddr: laddr, @@ -258,3 +266,30 @@ func InterfaceMultiaddrs() ([]ma.Multiaddr, error) { } return maddrs, 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 +} diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net_test.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net_test.go index fd0167caf..acc8c6937 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net_test.go @@ -2,6 +2,7 @@ package manet import ( "bytes" + "fmt" "net" "sync" "testing" @@ -140,7 +141,10 @@ func TestListen(t *testing.T) { func TestListenAddrs(t *testing.T) { - test := func(addr string, succeed bool) { + test := func(addr, resaddr string, succeed bool) { + if resaddr == "" { + resaddr = addr + } maddr := newMultiaddr(t, addr) l, err := Listen(maddr) @@ -151,10 +155,13 @@ func TestListenAddrs(t *testing.T) { return } if succeed && err != nil { - t.Fatal("failed to listen", addr, err) + t.Error("failed to listen", addr, err) } if l == nil { - t.Fatal("failed to listen", addr, succeed, err) + t.Error("failed to listen", addr, succeed, err) + } + if l.Multiaddr().String() != resaddr { + t.Error("listen addr did not resolve properly", l.Multiaddr().String(), resaddr, succeed, err) } if err = l.Close(); err != nil { @@ -162,9 +169,18 @@ func TestListenAddrs(t *testing.T) { } } - test("/ip4/127.0.0.1/tcp/4324", true) - test("/ip4/127.0.0.1/udp/4325", false) - test("/ip4/127.0.0.1/udp/4326/udt", false) + test("/ip4/127.0.0.1/tcp/4324", "", true) + test("/ip4/127.0.0.1/udp/4325", "", false) + test("/ip4/127.0.0.1/udp/4326/udt", "", false) + test("/ip4/0.0.0.0/tcp/4324", "", true) + test("/ip4/0.0.0.0/udp/4325", "", false) + test("/ip4/0.0.0.0/udp/4326/udt", "", false) + test("/ip6/::1/tcp/4324", "", true) + test("/ip6/::1/udp/4325", "", false) + test("/ip6/::1/udp/4326/udt", "", false) + test("/ip6/::/tcp/4324", "", true) + test("/ip6/::/udp/4325", "", false) + test("/ip6/::/udp/4326/udt", "", false) // test("/ip4/127.0.0.1/udp/4326/utp", true) } @@ -334,3 +350,89 @@ func TestIPUnspecified(t *testing.T) { t.Error("IsIPUnspecified failed (IP6Unspecified)") } } + +func TestIP6LinkLocal(t *testing.T) { + if !IsIP6LinkLocal(IP6LinkLocalLoopback) { + t.Error("IsIP6LinkLocal failed (IP6LinkLocalLoopback)") + } + + for a := 0; a < 65536; a++ { + isLinkLocal := (a == 0xfe80) + m := newMultiaddr(t, fmt.Sprintf("/ip6/%x::1", a)) + if IsIP6LinkLocal(m) != isLinkLocal { + t.Error("IsIP6LinkLocal failed (%s != %v)", m, isLinkLocal) + } + } +} + +func TestAddrMatch(t *testing.T) { + + test := func(m ma.Multiaddr, input, expect []ma.Multiaddr) { + actual := AddrMatch(m, input) + testSliceEqual(t, expect, actual) + } + + a := []ma.Multiaddr{ + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/2345"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"), + newMultiaddr(t, "/ip6/::1/tcp/1234"), + newMultiaddr(t, "/ip6/::1/tcp/2345"), + newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"), + newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"), + newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"), + newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"), + newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"), + newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"), + } + + test(a[0], a, []ma.Multiaddr{ + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/2345"), + }) + test(a[2], a, []ma.Multiaddr{ + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/tcp/2345"), + }) + test(a[4], a, []ma.Multiaddr{ + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/udp/1234"), + }) + test(a[6], a, []ma.Multiaddr{ + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234/ip6/::1"), + }) + test(a[8], a, []ma.Multiaddr{ + newMultiaddr(t, "/ip6/::1/tcp/1234"), + newMultiaddr(t, "/ip6/::1/tcp/2345"), + }) + test(a[10], a, []ma.Multiaddr{ + newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"), + newMultiaddr(t, "/ip6/::1/tcp/1234/tcp/2345"), + }) + test(a[12], a, []ma.Multiaddr{ + newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"), + newMultiaddr(t, "/ip6/::1/tcp/1234/udp/1234"), + }) + test(a[14], a, []ma.Multiaddr{ + newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"), + newMultiaddr(t, "/ip6/::1/tcp/1234/ip6/::1"), + }) + +} + +func testSliceEqual(t *testing.T, a, b []ma.Multiaddr) { + if len(a) != len(b) { + t.Error("differ", a, b) + } + for i, addrA := range a { + if !addrA.Equal(b[i]) { + t.Error("differ", a, b) + } + } +} diff --git a/core/bootstrap.go b/core/bootstrap.go index b2f8a59a2..a6cbfbbb4 100644 --- a/core/bootstrap.go +++ b/core/bootstrap.go @@ -117,7 +117,7 @@ func connect(ctx context.Context, ps peer.Peerstore, r *dht.IpfsDHT, peers []pee err := r.Connect(ctx, p.ID) if err != nil { log.Event(ctx, "bootstrapFailed", p.ID) - log.Criticalf("failed to bootstrap with %v", p.ID) + log.Criticalf("failed to bootstrap with %v: %s", p.ID, err) return } log.Event(ctx, "bootstrapSuccess", p.ID) diff --git a/core/core.go b/core/core.go index 9408d76ff..be8f8e643 100644 --- a/core/core.go +++ b/core/core.go @@ -24,6 +24,7 @@ import ( p2phost "github.com/jbenet/go-ipfs/p2p/host" p2pbhost "github.com/jbenet/go-ipfs/p2p/host/basic" swarm "github.com/jbenet/go-ipfs/p2p/net/swarm" + addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr" peer "github.com/jbenet/go-ipfs/p2p/peer" path "github.com/jbenet/go-ipfs/path" pin "github.com/jbenet/go-ipfs/pin" @@ -352,11 +353,18 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) { // isolates the complex initialization steps func constructPeerHost(ctx context.Context, ctxg ctxgroup.ContextGroup, cfg *config.Config, id peer.ID, ps peer.Peerstore) (p2phost.Host, error) { listenAddrs, err := listenAddresses(cfg) - // make sure we dont error out if our config includes some addresses we cant use. - filteredAddrs := swarm.FilterAddrs(listenAddrs) if err != nil { return nil, debugerror.Wrap(err) } + + // make sure we error out if our config does not have addresses we can use + log.Debugf("Config.Addresses.Swarm:%s", listenAddrs) + filteredAddrs := addrutil.FilterAddrs(listenAddrs) + log.Debugf("Config.Addresses.Swarm:%s (filtered)", listenAddrs) + if len(filteredAddrs) < 1 { + return nil, debugerror.Errorf("addresses in config not usable: %s", listenAddrs) + } + network, err := swarm.NewNetwork(ctx, filteredAddrs, id, ps) if err != nil { return nil, debugerror.Wrap(err) @@ -371,6 +379,7 @@ func constructPeerHost(ctx context.Context, ctxg ctxgroup.ContextGroup, cfg *con if err != nil { return nil, debugerror.Wrap(err) } + log.Info("Swarm listening at: %s", addrs) ps.AddAddresses(id, addrs) return peerhost, nil } diff --git a/p2p/net/conn/dial.go b/p2p/net/conn/dial.go index a56d3d545..a9df7d3c4 100644 --- a/p2p/net/conn/dial.go +++ b/p2p/net/conn/dial.go @@ -22,7 +22,7 @@ func (d *Dialer) String() string { // Example: d.DialAddr(ctx, peer.Addresses()[0], peer) func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) { - network, _, err := manet.DialArgs(raddr) + _, _, err := manet.DialArgs(raddr) if err != nil { return nil, err } @@ -31,17 +31,20 @@ func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) ( return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr) } - var laddr ma.Multiaddr if len(d.LocalAddrs) > 0 { - // laddr := MultiaddrNetMatch(raddr, d.LocalAddrs) - laddr = NetAddress(network, d.LocalAddrs) - if laddr == nil { - return nil, debugerror.Errorf("No local address for network %s", network) + laddrs := manet.AddrMatch(raddr, d.LocalAddrs) + if len(laddrs) < 1 { + return nil, debugerror.Errorf("No local address matches %s %s", raddr, d.LocalAddrs) } - } - // TODO: try to get reusing addr/ports to work. - // d.Dialer.LocalAddr = laddr + // 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. + // laddr := laddrs[rand.Intn(len(laddrs))] + + // TODO: try to get reusing addr/ports to work. + // d.Dialer.LocalAddr = laddr + } log.Debugf("%s dialing %s %s", d.LocalPeer, remote, raddr) maconn, err := d.Dialer.Dial(raddr) @@ -116,15 +119,3 @@ func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr { } return nil } - -// NetAddress returns the first Multiaddr found for a given network. -func NetAddress(n string, addrs []ma.Multiaddr) ma.Multiaddr { - for _, a := range addrs { - for _, p := range a.Protocols() { - if p.Name == n { - return a - } - } - } - return nil -} diff --git a/p2p/net/conn/listen.go b/p2p/net/conn/listen.go index bec01d71e..32011651e 100644 --- a/p2p/net/conn/listen.go +++ b/p2p/net/conn/listen.go @@ -102,11 +102,7 @@ func (l *listener) Addr() net.Addr { // If there is an error converting from net.Addr to ma.Multiaddr, // the return value will be nil. func (l *listener) Multiaddr() ma.Multiaddr { - maddr, err := manet.FromNetAddr(l.Addr()) - if err != nil { - return nil // error - } - return maddr + return l.Listener.Multiaddr() } // LocalPeer is the identity of the local Peer. @@ -140,7 +136,7 @@ func Listen(ctx context.Context, addr ma.Multiaddr, local peer.ID, sk ic.PrivKey } l.cg.SetTeardown(l.teardown) - log.Infof("swarm listening on %s", l.Multiaddr()) + log.Debugf("Conn Listener on %s", l.Multiaddr()) log.Event(ctx, "swarmListen", l) return l, nil } diff --git a/p2p/net/swarm/addr.go b/p2p/net/swarm/addr.go deleted file mode 100644 index 497466c57..000000000 --- a/p2p/net/swarm/addr.go +++ /dev/null @@ -1,193 +0,0 @@ -package swarm - -import ( - conn "github.com/jbenet/go-ipfs/p2p/net/conn" - eventlog "github.com/jbenet/go-ipfs/util/eventlog" - - context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" - ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" -) - -// SupportedTransportStrings is the list of supported transports for the swarm. -// These are strings of encapsulated multiaddr protocols. E.g.: -// /ip4/tcp -var SupportedTransportStrings = []string{ - "/ip4/tcp", - "/ip6/tcp", - // "/ip4/udp/utp", disabled because the lib is broken - // "/ip6/udp/utp", disabled because the lib is broken - // "/ip4/udp/udt", disabled because the lib doesnt work on arm - // "/ip6/udp/udt", disabled because the lib doesnt work on arm -} - -// SupportedTransportProtocols is the list of supported transports for the swarm. -// These are []ma.Protocol lists. Populated at runtime from SupportedTransportStrings -var SupportedTransportProtocols = [][]ma.Protocol{} - -func init() { - // initialize SupportedTransportProtocols - transports := make([][]ma.Protocol, len(SupportedTransportStrings)) - for _, s := range SupportedTransportStrings { - t, err := ma.ProtocolsWithString(s) - if err != nil { - panic(err) // important to fix this in the codebase - } - transports = append(transports, t) - } - SupportedTransportProtocols = transports -} - -// FilterAddrs is a filter that removes certain addresses -// from a list. the addresses removed are those known NOT -// to work with swarm. Namely, addresses with UTP. -func FilterAddrs(a []ma.Multiaddr) []ma.Multiaddr { - b := make([]ma.Multiaddr, 0, len(a)) - for _, addr := range a { - if AddrUsable(addr) { - b = append(b, addr) - } - } - return b -} - -// AddrUsable returns whether the swarm can use this addr. -func AddrUsable(a ma.Multiaddr) bool { - // test the address protocol list is in SupportedTransportProtocols - - matches := func(a, b []ma.Protocol) bool { - if len(a) != len(b) { - return false - } - - for i := range a { - if a[i].Code != b[i].Code { - return false - } - } - return true - } - - transport := a.Protocols() - for _, supported := range SupportedTransportProtocols { - if matches(supported, transport) { - return true - } - } - - return false -} - -// ListenAddresses returns a list of addresses at which this swarm listens. -func (s *Swarm) ListenAddresses() []ma.Multiaddr { - listeners := s.swarm.Listeners() - addrs := make([]ma.Multiaddr, 0, len(listeners)) - for _, l := range listeners { - if l2, ok := l.NetListener().(conn.Listener); ok { - addrs = append(addrs, l2.Multiaddr()) - } - } - return addrs -} - -// InterfaceListenAddresses returns a list of addresses at which this swarm -// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to -// use the known local interfaces. -func InterfaceListenAddresses(s *Swarm) ([]ma.Multiaddr, error) { - return resolveUnspecifiedAddresses(s.ListenAddresses()) -} - -// resolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to -// use the known local interfaces. -func resolveUnspecifiedAddresses(unspecifiedAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) { - var outputAddrs []ma.Multiaddr - - // todo optimize: only fetch these if we have a "any" addr. - ifaceAddrs, err := interfaceAddresses() - if err != nil { - return nil, err - } - - for _, a := range unspecifiedAddrs { - - // split address into its components - split := ma.Split(a) - - // if first component (ip) is not unspecified, use it as is. - if !manet.IsIPUnspecified(split[0]) { - outputAddrs = append(outputAddrs, a) - continue - } - - // unspecified? add one address per interface. - for _, ia := range ifaceAddrs { - split[0] = ia - joined := ma.Join(split...) - outputAddrs = append(outputAddrs, joined) - } - } - - log.Event(context.TODO(), "interfaceListenAddresses", func() eventlog.Loggable { - var addrs []string - for _, addr := range outputAddrs { - addrs = append(addrs, addr.String()) - } - return eventlog.Metadata{"addresses": addrs} - }()) - log.Debug("InterfaceListenAddresses:", outputAddrs) - return outputAddrs, nil -} - -// interfaceAddresses returns a list of addresses associated with local machine -func interfaceAddresses() ([]ma.Multiaddr, error) { - maddrs, err := manet.InterfaceMultiaddrs() - if err != nil { - return nil, err - } - - var nonLoopback []ma.Multiaddr - for _, a := range maddrs { - if !manet.IsIPLoopback(a) { - nonLoopback = append(nonLoopback, a) - } - } - - return nonLoopback, 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 -} - -// checkNATWarning checks if our observed addresses differ. if so, -// informs the user that certain things might not work yet -func checkNATWarning(s *Swarm, observed ma.Multiaddr, expected ma.Multiaddr) { - if observed.Equal(expected) { - return - } - - listen, err := InterfaceListenAddresses(s) - if err != nil { - log.Errorf("Error retrieving swarm.InterfaceListenAddresses: %s", err) - return - } - - if !addrInList(observed, listen) { // probably a nat - log.Warningf(natWarning, observed, listen) - } -} - -const natWarning = `Remote peer observed our address to be: %s -The local addresses are: %s -Thus, connection is going through NAT, and other connections may fail. - -IPFS NAT traversal is still under development. Please bug us on github or irc to fix this. -Baby steps: http://jbenet.static.s3.amazonaws.com/271dfcf/baby-steps.gif -` diff --git a/p2p/net/swarm/addr/addr.go b/p2p/net/swarm/addr/addr.go new file mode 100644 index 000000000..91e8febf4 --- /dev/null +++ b/p2p/net/swarm/addr/addr.go @@ -0,0 +1,258 @@ +package addrutil + +import ( + "fmt" + + eventlog "github.com/jbenet/go-ipfs/util/eventlog" + + context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" +) + +var log = eventlog.Logger("p2p/net/swarm/addr") + +// SupportedTransportStrings is the list of supported transports for the swarm. +// These are strings of encapsulated multiaddr protocols. E.g.: +// /ip4/tcp +var SupportedTransportStrings = []string{ + "/ip4/tcp", + "/ip6/tcp", + // "/ip4/udp/utp", disabled because the lib is broken + // "/ip6/udp/utp", disabled because the lib is broken + // "/ip4/udp/udt", disabled because the lib doesnt work on arm + // "/ip6/udp/udt", disabled because the lib doesnt work on arm +} + +// SupportedTransportProtocols is the list of supported transports for the swarm. +// These are []ma.Protocol lists. Populated at runtime from SupportedTransportStrings +var SupportedTransportProtocols = [][]ma.Protocol{} + +func init() { + // initialize SupportedTransportProtocols + transports := make([][]ma.Protocol, len(SupportedTransportStrings)) + for _, s := range SupportedTransportStrings { + t, err := ma.ProtocolsWithString(s) + if err != nil { + panic(err) // important to fix this in the codebase + } + transports = append(transports, t) + } + SupportedTransportProtocols = transports +} + +// FilterAddrs is a filter that removes certain addresses +// from a list. the addresses removed are those known NOT +// to work with our network. Namely, addresses with UTP. +func FilterAddrs(a []ma.Multiaddr) []ma.Multiaddr { + b := make([]ma.Multiaddr, 0, len(a)) + for _, addr := range a { + if AddrUsable(addr, false) { + b = append(b, addr) + } + } + return b +} + +// 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 +} + +// 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 !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 +} + +// 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 +} + +// ResolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to +// use the known local interfaces. +func ResolveUnspecifiedAddresses(unspecAddrs, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) { + + // todo optimize: only fetch these if we have a "any" addr. + if len(ifaceAddrs) < 1 { + var err error + ifaceAddrs, err = InterfaceAddresses() + if err != nil { + return nil, err + } + // log.Debug("InterfaceAddresses:", ifaceAddrs) + } + + var outputAddrs []ma.Multiaddr + for _, a := range unspecAddrs { + // unspecified? + resolved, err := ResolveUnspecifiedAddress(a, ifaceAddrs) + if err != nil { + continue // optimistic. if we cant resolve anything, we'll know at the bottom. + } + // log.Debug("resolved:", a, resolved) + outputAddrs = append(outputAddrs, resolved...) + } + + if len(outputAddrs) < 1 { + return nil, fmt.Errorf("failed to specify addrs: %s", unspecAddrs) + } + + log.Event(context.TODO(), "interfaceListenAddresses", func() eventlog.Loggable { + var addrs []string + for _, addr := range outputAddrs { + addrs = append(addrs, addr.String()) + } + return eventlog.Metadata{"addresses": addrs} + }()) + + log.Debug("ResolveUnspecifiedAddresses:", unspecAddrs, ifaceAddrs, outputAddrs) + return outputAddrs, nil +} + +// InterfaceAddresses returns a list of addresses associated with local machine +// Note: we do not return link local addresses. IP loopback is ok, because we +// may be connecting to other nodes in the same machine. +func InterfaceAddresses() ([]ma.Multiaddr, error) { + maddrs, err := manet.InterfaceMultiaddrs() + if err != nil { + return nil, err + } + log.Debug("InterfaceAddresses: from manet:", maddrs) + + var out []ma.Multiaddr + for _, a := range maddrs { + if !AddrUsable(a, true) { // partial + // log.Debug("InterfaceAddresses: skipping unusable:", a) + continue + } + + out = append(out, a) + } + + log.Debug("InterfaceAddresses: usable:", out) + return out, 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 +} + +// 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) +} + +// WANShareableAddrs filters addresses based on whether they're shareable on WAN +func WANShareableAddrs(inp []ma.Multiaddr) []ma.Multiaddr { + out := make([]ma.Multiaddr, 0, len(inp)) + for _, a := range inp { + if AddrIsShareableOnWAN(a) { + out = append(out, a) + } + } + return out +} + +// 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) + } +} + +const natWarning = `Remote peer observed our address to be: %s +The local addresses are: %s +Thus, connection is going through NAT, and other connections may fail. + +IPFS NAT traversal is still under development. Please bug us on github or irc to fix this. +Baby steps: http://jbenet.static.s3.amazonaws.com/271dfcf/baby-steps.gif +` diff --git a/p2p/net/swarm/addr/addr_test.go b/p2p/net/swarm/addr/addr_test.go new file mode 100644 index 000000000..7f355ef5e --- /dev/null +++ b/p2p/net/swarm/addr/addr_test.go @@ -0,0 +1,198 @@ +package addrutil + +import ( + "testing" + + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" +) + +func newMultiaddr(t *testing.T, s string) ma.Multiaddr { + maddr, err := ma.NewMultiaddr(s) + if err != nil { + t.Fatal(err) + } + return maddr +} + +func TestFilterAddrs(t *testing.T) { + + bad := []ma.Multiaddr{ + newMultiaddr(t, "/ip4/1.2.3.4/udp/1234"), // unreliable + newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/sctp/1234"), // not in manet + newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/utp"), // utp is broken + newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/udt"), // udt is broken on arm + newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), // link local + newMultiaddr(t, "/ip6/fe80::100/tcp/1234"), // link local + } + + good := []ma.Multiaddr{ + newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), + newMultiaddr(t, "/ip6/::1/tcp/1234"), + } + + goodAndBad := append(good, bad...) + + // test filters + + for _, a := range bad { + if AddrUsable(a, false) { + t.Errorf("addr %s should be unusable", a) + } + if AddrUsable(a, true) { + t.Errorf("addr %s should be unusable", a) + } + } + + for _, a := range good { + if !AddrUsable(a, false) { + t.Errorf("addr %s should be usable", a) + } + if !AddrUsable(a, true) { + t.Errorf("addr %s should be usable", a) + } + } + + subtestAddrsEqual(t, FilterAddrs(bad), []ma.Multiaddr{}) + subtestAddrsEqual(t, FilterAddrs(good), good) + subtestAddrsEqual(t, FilterAddrs(goodAndBad), good) +} + +func subtestAddrsEqual(t *testing.T, a, b []ma.Multiaddr) { + if len(a) != len(b) { + t.Error(t) + } + + in := func(addr ma.Multiaddr, l []ma.Multiaddr) bool { + for _, addr2 := range l { + if addr.Equal(addr2) { + return true + } + } + return false + } + + for _, aa := range a { + if !in(aa, b) { + t.Errorf("%s not in %s", aa, b) + } + } +} + +func TestInterfaceAddrs(t *testing.T) { + addrs, err := InterfaceAddresses() + if err != nil { + t.Fatal(err) + } + + if len(addrs) < 1 { + t.Error("no addresses") + } + + for _, a := range addrs { + if manet.IsIP6LinkLocal(a) { + t.Error("should not return ip link local addresses", a) + } + } + + if len(addrs) < 1 { + t.Error("no good interface addrs") + } +} + +func TestResolvingAddrs(t *testing.T) { + + unspec := []ma.Multiaddr{ + newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), + newMultiaddr(t, "/ip6/::/tcp/1234"), + newMultiaddr(t, "/ip6/::100/tcp/1234"), + } + + iface := []ma.Multiaddr{ + newMultiaddr(t, "/ip4/127.0.0.1"), + newMultiaddr(t, "/ip4/10.20.30.40"), + newMultiaddr(t, "/ip6/::1"), + newMultiaddr(t, "/ip6/::f"), + } + + spec := []ma.Multiaddr{ + newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), + newMultiaddr(t, "/ip4/10.20.30.40/tcp/1234"), + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), + newMultiaddr(t, "/ip6/::1/tcp/1234"), + newMultiaddr(t, "/ip6/::f/tcp/1234"), + newMultiaddr(t, "/ip6/::100/tcp/1234"), + } + + actual, err := ResolveUnspecifiedAddresses(unspec, iface) + if err != nil { + t.Fatal(err) + } + + for i, a := range actual { + if !a.Equal(spec[i]) { + t.Error(a, " != ", spec[i]) + } + } + + ip4u := []ma.Multiaddr{newMultiaddr(t, "/ip4/0.0.0.0")} + ip4i := []ma.Multiaddr{newMultiaddr(t, "/ip4/1.2.3.4")} + + ip6u := []ma.Multiaddr{newMultiaddr(t, "/ip6/::")} + ip6i := []ma.Multiaddr{newMultiaddr(t, "/ip6/::1")} + + if _, err := ResolveUnspecifiedAddress(ip4u[0], ip6i); err == nil { + t.Fatal("should have failed") + } + if _, err := ResolveUnspecifiedAddress(ip6u[0], ip4i); err == nil { + t.Fatal("should have failed") + } + + if _, err := ResolveUnspecifiedAddresses(ip6u, ip4i); err == nil { + t.Fatal("should have failed") + } + if _, err := ResolveUnspecifiedAddresses(ip4u, ip6i); err == nil { + t.Fatal("should have failed") + } + +} + +func TestWANShareable(t *testing.T) { + + wanok := []ma.Multiaddr{ + newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), + newMultiaddr(t, "/ip6/abcd::1/tcp/1234"), + } + + wanbad := []ma.Multiaddr{ + newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), + newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"), + newMultiaddr(t, "/ip6/::1/tcp/1234"), + newMultiaddr(t, "/ip6/::/tcp/1234"), + newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), + newMultiaddr(t, "/ip6/fe80::/tcp/1234"), + } + + for _, a := range wanok { + if !AddrIsShareableOnWAN(a) { + t.Error("should be true", a) + } + } + + for _, a := range wanbad { + if AddrIsShareableOnWAN(a) { + t.Error("should be false", a) + } + } + + wanok2 := WANShareableAddrs(wanok) + if len(wanok) != len(wanok2) { + t.Error("should be the same") + } + + wanbad2 := WANShareableAddrs(wanbad) + if len(wanbad2) != 0 { + t.Error("should be zero") + } +} diff --git a/p2p/net/swarm/swarm.go b/p2p/net/swarm/swarm.go index 1f42bdddd..54d53f8d9 100644 --- a/p2p/net/swarm/swarm.go +++ b/p2p/net/swarm/swarm.go @@ -3,7 +3,10 @@ package swarm import ( + "fmt" + inet "github.com/jbenet/go-ipfs/p2p/net" + addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr" peer "github.com/jbenet/go-ipfs/p2p/peer" eventlog "github.com/jbenet/go-ipfs/util/eventlog" @@ -37,6 +40,14 @@ type Swarm struct { func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr, local peer.ID, peers peer.Peerstore) (*Swarm, error) { + if len(listenAddrs) > 0 { + filtered := addrutil.FilterAddrs(listenAddrs) + if len(filtered) < 1 { + return nil, fmt.Errorf("swarm cannot use any addr in: %s", listenAddrs) + } + listenAddrs = filtered + } + s := &Swarm{ swarm: ps.NewSwarm(PSTransport), local: local, diff --git a/p2p/net/swarm/swarm_addr.go b/p2p/net/swarm/swarm_addr.go new file mode 100644 index 000000000..336523152 --- /dev/null +++ b/p2p/net/swarm/swarm_addr.go @@ -0,0 +1,39 @@ +package swarm + +import ( + conn "github.com/jbenet/go-ipfs/p2p/net/conn" + addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr" + + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" +) + +// ListenAddresses returns a list of addresses at which this swarm listens. +func (s *Swarm) ListenAddresses() []ma.Multiaddr { + listeners := s.swarm.Listeners() + addrs := make([]ma.Multiaddr, 0, len(listeners)) + for _, l := range listeners { + if l2, ok := l.NetListener().(conn.Listener); ok { + addrs = append(addrs, l2.Multiaddr()) + } + } + return addrs +} + +// InterfaceListenAddresses returns a list of addresses at which this swarm +// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to +// use the known local interfaces. +func InterfaceListenAddresses(s *Swarm) ([]ma.Multiaddr, error) { + return addrutil.ResolveUnspecifiedAddresses(s.ListenAddresses(), nil) +} + +// checkNATWarning checks if our observed addresses differ. if so, +// informs the user that certain things might not work yet +func checkNATWarning(s *Swarm, observed ma.Multiaddr, expected ma.Multiaddr) { + listen, err := InterfaceListenAddresses(s) + if err != nil { + log.Errorf("Error retrieving swarm.InterfaceListenAddresses: %s", err) + return + } + + addrutil.CheckNATWarning(observed, expected, listen) +} diff --git a/p2p/net/swarm/addr_test.go b/p2p/net/swarm/swarm_addr_test.go similarity index 65% rename from p2p/net/swarm/addr_test.go rename to p2p/net/swarm/swarm_addr_test.go index 4703cdaf8..65e196efa 100644 --- a/p2p/net/swarm/addr_test.go +++ b/p2p/net/swarm/swarm_addr_test.go @@ -3,6 +3,7 @@ package swarm import ( "testing" + addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr" peer "github.com/jbenet/go-ipfs/p2p/peer" testutil "github.com/jbenet/go-ipfs/util/testutil" @@ -25,6 +26,8 @@ func TestFilterAddrs(t *testing.T) { m("/ip4/1.2.3.4/udp/1234/sctp/1234"), // not in manet m("/ip4/1.2.3.4/udp/1234/utp"), // utp is broken m("/ip4/1.2.3.4/udp/1234/udt"), // udt is broken on arm + m("/ip6/fe80::1/tcp/1234"), // link local + m("/ip6/fe80::100/tcp/1234"), // link local } good := []ma.Multiaddr{ @@ -37,20 +40,20 @@ func TestFilterAddrs(t *testing.T) { // test filters for _, a := range bad { - if AddrUsable(a) { + if addrutil.AddrUsable(a, true) { t.Errorf("addr %s should be unusable", a) } } for _, a := range good { - if !AddrUsable(a) { + if !addrutil.AddrUsable(a, true) { t.Errorf("addr %s should be usable", a) } } - subtestAddrsEqual(t, FilterAddrs(bad), []ma.Multiaddr{}) - subtestAddrsEqual(t, FilterAddrs(good), good) - subtestAddrsEqual(t, FilterAddrs(goodAndBad), good) + subtestAddrsEqual(t, addrutil.FilterAddrs(bad), []ma.Multiaddr{}) + subtestAddrsEqual(t, addrutil.FilterAddrs(good), good) + subtestAddrsEqual(t, addrutil.FilterAddrs(goodAndBad), good) // now test it with swarm @@ -95,3 +98,29 @@ func subtestAddrsEqual(t *testing.T, a, b []ma.Multiaddr) { } } } + +func TestDialBadAddrs(t *testing.T) { + + m := func(s string) ma.Multiaddr { + maddr, err := ma.NewMultiaddr(s) + if err != nil { + t.Fatal(err) + } + return maddr + } + + ctx := context.Background() + s := makeSwarms(ctx, t, 1)[0] + + test := func(a ma.Multiaddr) { + p := testutil.RandPeerIDFatal(t) + s.peers.AddAddress(p, a) + if _, err := s.Dial(ctx, p); err == nil { + t.Error("swarm should not dial: %s", m) + } + } + + test(m("/ip6/fe80::1")) // link local + test(m("/ip6/fe80::100")) // link local + test(m("/ip4/127.0.0.1/udp/1234/utp")) // utp +} diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go index dde967fbc..d17d31c8d 100644 --- a/p2p/net/swarm/swarm_dial.go +++ b/p2p/net/swarm/swarm_dial.go @@ -5,6 +5,7 @@ import ( "fmt" conn "github.com/jbenet/go-ipfs/p2p/net/conn" + addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr" peer "github.com/jbenet/go-ipfs/p2p/peer" lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables" @@ -38,6 +39,8 @@ func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) { } remoteAddrs := s.peers.Addresses(p) + // make sure we can use the addresses. + remoteAddrs = addrutil.FilterAddrs(remoteAddrs) if len(remoteAddrs) == 0 { return nil, errors.New("peer has no addresses") } @@ -67,6 +70,9 @@ func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) { if err != nil { return nil, err } + if connC == nil { + err = fmt.Errorf("failed to dial %s", p) + } // ok try to setup the new connection. swarmC, err := dialConnSetup(ctx, s, connC) diff --git a/p2p/net/swarm/swarm_listen.go b/p2p/net/swarm/swarm_listen.go index d6380b9b5..56c889a92 100644 --- a/p2p/net/swarm/swarm_listen.go +++ b/p2p/net/swarm/swarm_listen.go @@ -4,6 +4,7 @@ import ( "fmt" conn "github.com/jbenet/go-ipfs/p2p/net/conn" + addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr" lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables" context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" @@ -16,7 +17,7 @@ import ( func (s *Swarm) listen(addrs []ma.Multiaddr) error { for _, addr := range addrs { - if !AddrUsable(addr) { + if !addrutil.AddrUsable(addr, true) { return fmt.Errorf("cannot use addr: %s", addr) } } @@ -59,10 +60,12 @@ func (s *Swarm) setupListener(maddr ma.Multiaddr) error { // may be fine for sk to be nil, just log a warning. log.Warning("Listener not given PrivateKey, so WILL NOT SECURE conns.") } + log.Infof("Swarm Listening at %s", maddr) list, err := conn.Listen(s.cg.Context(), maddr, s.local, sk) if err != nil { return err } + log.Infof("Swarm Listening at %s", s.ListenAddresses()) // AddListener to the peerstream Listener. this will begin accepting connections // and streams! diff --git a/routing/dht/dht.go b/routing/dht/dht.go index 78fef653b..9b1279f10 100644 --- a/routing/dht/dht.go +++ b/routing/dht/dht.go @@ -66,8 +66,13 @@ func NewDHT(ctx context.Context, h host.Host, dstore ds.ThreadSafeDatastore) *Ip dht.peerstore = h.Peerstore() dht.ContextGroup = ctxgroup.WithContext(ctx) dht.host = h - h.SetStreamHandler(ProtocolDHT, dht.handleNewStream) + // sanity check. this should **never** happen + if len(dht.peerstore.Addresses(dht.self)) < 1 { + panic("attempt to initialize dht without addresses for self") + } + + h.SetStreamHandler(ProtocolDHT, dht.handleNewStream) dht.providers = NewProviderManager(dht.Context(), dht.self) dht.AddChildGroup(dht.providers) @@ -132,19 +137,23 @@ func (dht *IpfsDHT) putValueToPeer(ctx context.Context, p peer.ID, // can provide the value of 'key' func (dht *IpfsDHT) putProvider(ctx context.Context, p peer.ID, key string) error { - pmes := pb.NewMessage(pb.Message_ADD_PROVIDER, string(key), 0) - // add self as the provider pi := dht.peerstore.PeerInfo(dht.self) - pmes.ProviderPeers = pb.PeerInfosToPBPeers(dht.host.Network(), []peer.PeerInfo{pi}) + // // only share WAN-friendly addresses ?? + // pi.Addrs = addrutil.WANShareableAddrs(pi.Addrs) + if len(pi.Addrs) < 1 { + log.Errorf("%s putProvider: %s for %s error: no wan-friendly addresses", dht.self, p, u.Key(key), pi.Addrs) + return fmt.Errorf("no known addresses for self. cannot put provider.") + } + pmes := pb.NewMessage(pb.Message_ADD_PROVIDER, string(key), 0) + pmes.ProviderPeers = pb.PeerInfosToPBPeers(dht.host.Network(), []peer.PeerInfo{pi}) err := dht.sendMessage(ctx, p, pmes) if err != nil { return err } log.Debugf("%s putProvider: %s for %s (%s)", dht.self, p, u.Key(key), pi.Addrs) - return nil }