p2p/net/swarm: do not usre link local addrs
Juan Batiz-Benet committed
Jan 12, 2015 at 12:21 UTC
7ec1a674e34c5d30868c2d936d689ffe7b011ecb
12 files changed
+586
-233
core/core.go
+8
-2
@@ -24,6 +24,7 @@ import (
24
p2phost "github.com/jbenet/go-ipfs/p2p/host"
25
p2pbhost "github.com/jbenet/go-ipfs/p2p/host/basic"
26
swarm "github.com/jbenet/go-ipfs/p2p/net/swarm"
27
+ addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
28
peer "github.com/jbenet/go-ipfs/p2p/peer"
29
path "github.com/jbenet/go-ipfs/path"
30
pin "github.com/jbenet/go-ipfs/pin"
@@ -352,11 +353,16 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
353
// isolates the complex initialization steps
354
func constructPeerHost(ctx context.Context, ctxg ctxgroup.ContextGroup, cfg *config.Config, id peer.ID, ps peer.Peerstore) (p2phost.Host, error) {
355
listenAddrs, err := listenAddresses(cfg)
355
- // make sure we dont error out if our config includes some addresses we cant use.
356
- filteredAddrs := swarm.FilterAddrs(listenAddrs)
356
if err != nil {
357
return nil, debugerror.Wrap(err)
358
}
359
+
360
+ // make sure we error out if our config does not have addresses we can use
361
+ filteredAddrs := addrutil.FilterAddrs(listenAddrs)
362
+ if len(filteredAddrs) < 1 {
363
+ return nil, debugerror.Errorf("addresses in config not usable: %s", listenAddrs)
364
+ }
365
+
366
network, err := swarm.NewNetwork(ctx, filteredAddrs, id, ps)
367
if err != nil {
368
return nil, debugerror.Wrap(err)
p2p/net/conn/dial.go
+12
-21
@@ -22,7 +22,7 @@ func (d *Dialer) String() string {
22
// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
23
func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {
24
25
- network, _, err := manet.DialArgs(raddr)
25
+ _, _, err := manet.DialArgs(raddr)
26
if err != nil {
27
return nil, err
28
}
@@ -31,17 +31,20 @@ func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (
31
return nil, debugerror.Errorf("Attempted to connect to zero address: %s", raddr)
32
}
33
34
- var laddr ma.Multiaddr
34
if len(d.LocalAddrs) > 0 {
36
- // laddr := MultiaddrNetMatch(raddr, d.LocalAddrs)
37
- laddr = NetAddress(network, d.LocalAddrs)
38
- if laddr == nil {
39
- return nil, debugerror.Errorf("No local address for network %s", network)
35
+ laddrs := manet.AddrMatch(raddr, d.LocalAddrs)
36
+ if len(laddrs) < 1 {
37
+ return nil, debugerror.Errorf("No local address matches %s %s", raddr, d.LocalAddrs)
38
}
41
- }
39
43
- // TODO: try to get reusing addr/ports to work.
44
- // d.Dialer.LocalAddr = laddr
40
+ // TODO pick with a good heuristic
41
+ // we use a random one for now to prevent bad addresses from making nodes unreachable
42
+ // with a random selection, multiple tries may work.
43
+ // laddr := laddrs[rand.Intn(len(laddrs))]
44
+
45
+ // TODO: try to get reusing addr/ports to work.
46
+ // d.Dialer.LocalAddr = laddr
47
+ }
48
49
log.Debugf("%s dialing %s %s", d.LocalPeer, remote, raddr)
50
maconn, err := d.Dialer.Dial(raddr)
@@ -116,15 +119,3 @@ func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
119
}
120
return nil
121
}
119
-
120
-// NetAddress returns the first Multiaddr found for a given network.
121
-func NetAddress(n string, addrs []ma.Multiaddr) ma.Multiaddr {
122
- for _, a := range addrs {
123
- for _, p := range a.Protocols() {
124
- if p.Name == n {
125
- return a
126
- }
127
- }
128
- }
129
- return nil
130
-}
p2p/net/conn/listen.go
+2
-6
@@ -102,11 +102,7 @@ func (l *listener) Addr() net.Addr {
102
// If there is an error converting from net.Addr to ma.Multiaddr,
103
// the return value will be nil.
104
func (l *listener) Multiaddr() ma.Multiaddr {
105
- maddr, err := manet.FromNetAddr(l.Addr())
106
- if err != nil {
107
- return nil // error
108
- }
109
- return maddr
105
+ return l.Listener.Multiaddr()
106
}
107
108
// 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
136
}
137
l.cg.SetTeardown(l.teardown)
138
143
- log.Infof("swarm listening on %s", l.Multiaddr())
139
+ log.Debugf("Conn Listener on %s", l.Multiaddr())
140
log.Event(ctx, "swarmListen", l)
141
return l, nil
142
}
p2p/net/swarm/addr.go
deleted
-193
@@ -1,193 +0,0 @@
1
-package swarm
2
-
3
-import (
4
- conn "github.com/jbenet/go-ipfs/p2p/net/conn"
5
- eventlog "github.com/jbenet/go-ipfs/util/eventlog"
6
-
7
- context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8
- ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9
- manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
10
-)
11
-
12
-// SupportedTransportStrings is the list of supported transports for the swarm.
13
-// These are strings of encapsulated multiaddr protocols. E.g.:
14
-// /ip4/tcp
15
-var SupportedTransportStrings = []string{
16
- "/ip4/tcp",
17
- "/ip6/tcp",
18
- // "/ip4/udp/utp", disabled because the lib is broken
19
- // "/ip6/udp/utp", disabled because the lib is broken
20
- // "/ip4/udp/udt", disabled because the lib doesnt work on arm
21
- // "/ip6/udp/udt", disabled because the lib doesnt work on arm
22
-}
23
-
24
-// SupportedTransportProtocols is the list of supported transports for the swarm.
25
-// These are []ma.Protocol lists. Populated at runtime from SupportedTransportStrings
26
-var SupportedTransportProtocols = [][]ma.Protocol{}
27
-
28
-func init() {
29
- // initialize SupportedTransportProtocols
30
- transports := make([][]ma.Protocol, len(SupportedTransportStrings))
31
- for _, s := range SupportedTransportStrings {
32
- t, err := ma.ProtocolsWithString(s)
33
- if err != nil {
34
- panic(err) // important to fix this in the codebase
35
- }
36
- transports = append(transports, t)
37
- }
38
- SupportedTransportProtocols = transports
39
-}
40
-
41
-// FilterAddrs is a filter that removes certain addresses
42
-// from a list. the addresses removed are those known NOT
43
-// to work with swarm. Namely, addresses with UTP.
44
-func FilterAddrs(a []ma.Multiaddr) []ma.Multiaddr {
45
- b := make([]ma.Multiaddr, 0, len(a))
46
- for _, addr := range a {
47
- if AddrUsable(addr) {
48
- b = append(b, addr)
49
- }
50
- }
51
- return b
52
-}
53
-
54
-// AddrUsable returns whether the swarm can use this addr.
55
-func AddrUsable(a ma.Multiaddr) bool {
56
- // test the address protocol list is in SupportedTransportProtocols
57
-
58
- matches := func(a, b []ma.Protocol) bool {
59
- if len(a) != len(b) {
60
- return false
61
- }
62
-
63
- for i := range a {
64
- if a[i].Code != b[i].Code {
65
- return false
66
- }
67
- }
68
- return true
69
- }
70
-
71
- transport := a.Protocols()
72
- for _, supported := range SupportedTransportProtocols {
73
- if matches(supported, transport) {
74
- return true
75
- }
76
- }
77
-
78
- return false
79
-}
80
-
81
-// ListenAddresses returns a list of addresses at which this swarm listens.
82
-func (s *Swarm) ListenAddresses() []ma.Multiaddr {
83
- listeners := s.swarm.Listeners()
84
- addrs := make([]ma.Multiaddr, 0, len(listeners))
85
- for _, l := range listeners {
86
- if l2, ok := l.NetListener().(conn.Listener); ok {
87
- addrs = append(addrs, l2.Multiaddr())
88
- }
89
- }
90
- return addrs
91
-}
92
-
93
-// InterfaceListenAddresses returns a list of addresses at which this swarm
94
-// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
95
-// use the known local interfaces.
96
-func InterfaceListenAddresses(s *Swarm) ([]ma.Multiaddr, error) {
97
- return resolveUnspecifiedAddresses(s.ListenAddresses())
98
-}
99
-
100
-// resolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
101
-// use the known local interfaces.
102
-func resolveUnspecifiedAddresses(unspecifiedAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
103
- var outputAddrs []ma.Multiaddr
104
-
105
- // todo optimize: only fetch these if we have a "any" addr.
106
- ifaceAddrs, err := interfaceAddresses()
107
- if err != nil {
108
- return nil, err
109
- }
110
-
111
- for _, a := range unspecifiedAddrs {
112
-
113
- // split address into its components
114
- split := ma.Split(a)
115
-
116
- // if first component (ip) is not unspecified, use it as is.
117
- if !manet.IsIPUnspecified(split[0]) {
118
- outputAddrs = append(outputAddrs, a)
119
- continue
120
- }
121
-
122
- // unspecified? add one address per interface.
123
- for _, ia := range ifaceAddrs {
124
- split[0] = ia
125
- joined := ma.Join(split...)
126
- outputAddrs = append(outputAddrs, joined)
127
- }
128
- }
129
-
130
- log.Event(context.TODO(), "interfaceListenAddresses", func() eventlog.Loggable {
131
- var addrs []string
132
- for _, addr := range outputAddrs {
133
- addrs = append(addrs, addr.String())
134
- }
135
- return eventlog.Metadata{"addresses": addrs}
136
- }())
137
- log.Debug("InterfaceListenAddresses:", outputAddrs)
138
- return outputAddrs, nil
139
-}
140
-
141
-// interfaceAddresses returns a list of addresses associated with local machine
142
-func interfaceAddresses() ([]ma.Multiaddr, error) {
143
- maddrs, err := manet.InterfaceMultiaddrs()
144
- if err != nil {
145
- return nil, err
146
- }
147
-
148
- var nonLoopback []ma.Multiaddr
149
- for _, a := range maddrs {
150
- if !manet.IsIPLoopback(a) {
151
- nonLoopback = append(nonLoopback, a)
152
- }
153
- }
154
-
155
- return nonLoopback, nil
156
-}
157
-
158
-// addrInList returns whether or not an address is part of a list.
159
-// this is useful to check if NAT is happening (or other bugs?)
160
-func addrInList(addr ma.Multiaddr, list []ma.Multiaddr) bool {
161
- for _, addr2 := range list {
162
- if addr.Equal(addr2) {
163
- return true
164
- }
165
- }
166
- return false
167
-}
168
-
169
-// checkNATWarning checks if our observed addresses differ. if so,
170
-// informs the user that certain things might not work yet
171
-func checkNATWarning(s *Swarm, observed ma.Multiaddr, expected ma.Multiaddr) {
172
- if observed.Equal(expected) {
173
- return
174
- }
175
-
176
- listen, err := InterfaceListenAddresses(s)
177
- if err != nil {
178
- log.Errorf("Error retrieving swarm.InterfaceListenAddresses: %s", err)
179
- return
180
- }
181
-
182
- if !addrInList(observed, listen) { // probably a nat
183
- log.Warningf(natWarning, observed, listen)
184
- }
185
-}
186
-
187
-const natWarning = `Remote peer observed our address to be: %s
188
-The local addresses are: %s
189
-Thus, connection is going through NAT, and other connections may fail.
190
-
191
-IPFS NAT traversal is still under development. Please bug us on github or irc to fix this.
192
-Baby steps: http://jbenet.static.s3.amazonaws.com/271dfcf/baby-steps.gif
193
-`
p2p/net/swarm/addr/addr.go
new
+258
@@ -0,0 +1,258 @@
1
+package addrutil
2
+
3
+import (
4
+ "fmt"
5
+
6
+ eventlog "github.com/jbenet/go-ipfs/util/eventlog"
7
+
8
+ context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
9
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10
+ manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
11
+)
12
+
13
+var log = eventlog.Logger("p2p/net/swarm/addr")
14
+
15
+// SupportedTransportStrings is the list of supported transports for the swarm.
16
+// These are strings of encapsulated multiaddr protocols. E.g.:
17
+// /ip4/tcp
18
+var SupportedTransportStrings = []string{
19
+ "/ip4/tcp",
20
+ "/ip6/tcp",
21
+ // "/ip4/udp/utp", disabled because the lib is broken
22
+ // "/ip6/udp/utp", disabled because the lib is broken
23
+ // "/ip4/udp/udt", disabled because the lib doesnt work on arm
24
+ // "/ip6/udp/udt", disabled because the lib doesnt work on arm
25
+}
26
+
27
+// SupportedTransportProtocols is the list of supported transports for the swarm.
28
+// These are []ma.Protocol lists. Populated at runtime from SupportedTransportStrings
29
+var SupportedTransportProtocols = [][]ma.Protocol{}
30
+
31
+func init() {
32
+ // initialize SupportedTransportProtocols
33
+ transports := make([][]ma.Protocol, len(SupportedTransportStrings))
34
+ for _, s := range SupportedTransportStrings {
35
+ t, err := ma.ProtocolsWithString(s)
36
+ if err != nil {
37
+ panic(err) // important to fix this in the codebase
38
+ }
39
+ transports = append(transports, t)
40
+ }
41
+ SupportedTransportProtocols = transports
42
+}
43
+
44
+// FilterAddrs is a filter that removes certain addresses
45
+// from a list. the addresses removed are those known NOT
46
+// to work with our network. Namely, addresses with UTP.
47
+func FilterAddrs(a []ma.Multiaddr) []ma.Multiaddr {
48
+ b := make([]ma.Multiaddr, 0, len(a))
49
+ for _, addr := range a {
50
+ if AddrUsable(addr, false) {
51
+ b = append(b, addr)
52
+ }
53
+ }
54
+ return b
55
+}
56
+
57
+// AddrOverNonLocalIP returns whether the addr uses a non-local ip link
58
+func AddrOverNonLocalIP(a ma.Multiaddr) bool {
59
+ split := ma.Split(a)
60
+ if len(split) < 1 {
61
+ return false
62
+ }
63
+ if manet.IsIP6LinkLocal(split[0]) {
64
+ return false
65
+ }
66
+ return true
67
+}
68
+
69
+// AddrUsable returns whether our network can use this addr.
70
+// We only use the transports in SupportedTransportStrings,
71
+// and we do not link local addresses. Loopback is ok
72
+// as we need to be able to connect to multiple ipfs nodes
73
+// in the same machine.
74
+func AddrUsable(a ma.Multiaddr, partial bool) bool {
75
+
76
+ if !AddrOverNonLocalIP(a) {
77
+ return false
78
+ }
79
+
80
+ // test the address protocol list is in SupportedTransportProtocols
81
+ matches := func(supported, test []ma.Protocol) bool {
82
+ if len(test) > len(supported) {
83
+ return false
84
+ }
85
+
86
+ // when partial, it's ok if test < supported.
87
+ if !partial && len(supported) != len(test) {
88
+ return false
89
+ }
90
+
91
+ for i := range test {
92
+ if supported[i].Code != test[i].Code {
93
+ return false
94
+ }
95
+ }
96
+ return true
97
+ }
98
+
99
+ transport := a.Protocols()
100
+ for _, supported := range SupportedTransportProtocols {
101
+ if matches(supported, transport) {
102
+ return true
103
+ }
104
+ }
105
+
106
+ return false
107
+}
108
+
109
+// ResolveUnspecifiedAddress expands an unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
110
+// use the known local interfaces. If ifaceAddr is nil, we request interface addresses
111
+// from the network stack. (this is so you can provide a cached value if resolving many addrs)
112
+func ResolveUnspecifiedAddress(resolve ma.Multiaddr, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
113
+ // split address into its components
114
+ split := ma.Split(resolve)
115
+
116
+ // if first component (ip) is not unspecified, use it as is.
117
+ if !manet.IsIPUnspecified(split[0]) {
118
+ return []ma.Multiaddr{resolve}, nil
119
+ }
120
+
121
+ out := make([]ma.Multiaddr, 0, len(ifaceAddrs))
122
+ for _, ia := range ifaceAddrs {
123
+ // must match the first protocol to be resolve.
124
+ if ia.Protocols()[0].Code != resolve.Protocols()[0].Code {
125
+ continue
126
+ }
127
+
128
+ split[0] = ia
129
+ joined := ma.Join(split...)
130
+ out = append(out, joined)
131
+ log.Debug("adding resolved addr:", resolve, joined, out)
132
+ }
133
+ if len(out) < 1 {
134
+ return nil, fmt.Errorf("failed to resolve: %s", resolve)
135
+ }
136
+ return out, nil
137
+}
138
+
139
+// ResolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
140
+// use the known local interfaces.
141
+func ResolveUnspecifiedAddresses(unspecAddrs, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
142
+
143
+ // todo optimize: only fetch these if we have a "any" addr.
144
+ if len(ifaceAddrs) < 1 {
145
+ var err error
146
+ ifaceAddrs, err = InterfaceAddresses()
147
+ if err != nil {
148
+ return nil, err
149
+ }
150
+ // log.Debug("InterfaceAddresses:", ifaceAddrs)
151
+ }
152
+
153
+ var outputAddrs []ma.Multiaddr
154
+ for _, a := range unspecAddrs {
155
+ // unspecified?
156
+ resolved, err := ResolveUnspecifiedAddress(a, ifaceAddrs)
157
+ if err != nil {
158
+ continue // optimistic. if we cant resolve anything, we'll know at the bottom.
159
+ }
160
+ // log.Debug("resolved:", a, resolved)
161
+ outputAddrs = append(outputAddrs, resolved...)
162
+ }
163
+
164
+ if len(outputAddrs) < 1 {
165
+ return nil, fmt.Errorf("failed to specify addrs: %s", unspecAddrs)
166
+ }
167
+
168
+ log.Event(context.TODO(), "interfaceListenAddresses", func() eventlog.Loggable {
169
+ var addrs []string
170
+ for _, addr := range outputAddrs {
171
+ addrs = append(addrs, addr.String())
172
+ }
173
+ return eventlog.Metadata{"addresses": addrs}
174
+ }())
175
+
176
+ log.Debug("ResolveUnspecifiedAddresses:", unspecAddrs, ifaceAddrs, outputAddrs)
177
+ return outputAddrs, nil
178
+}
179
+
180
+// InterfaceAddresses returns a list of addresses associated with local machine
181
+// Note: we do not return link local addresses. IP loopback is ok, because we
182
+// may be connecting to other nodes in the same machine.
183
+func InterfaceAddresses() ([]ma.Multiaddr, error) {
184
+ maddrs, err := manet.InterfaceMultiaddrs()
185
+ if err != nil {
186
+ return nil, err
187
+ }
188
+ log.Debug("InterfaceAddresses: from manet:", maddrs)
189
+
190
+ var out []ma.Multiaddr
191
+ for _, a := range maddrs {
192
+ if !AddrUsable(a, true) { // partial
193
+ // log.Debug("InterfaceAddresses: skipping unusable:", a)
194
+ continue
195
+ }
196
+
197
+ out = append(out, a)
198
+ }
199
+
200
+ log.Debug("InterfaceAddresses: usable:", out)
201
+ return out, nil
202
+}
203
+
204
+// AddrInList returns whether or not an address is part of a list.
205
+// this is useful to check if NAT is happening (or other bugs?)
206
+func AddrInList(addr ma.Multiaddr, list []ma.Multiaddr) bool {
207
+ for _, addr2 := range list {
208
+ if addr.Equal(addr2) {
209
+ return true
210
+ }
211
+ }
212
+ return false
213
+}
214
+
215
+// AddrIsShareableOnWAN returns whether the given address should be shareable on the
216
+// wide area network (wide internet).
217
+func AddrIsShareableOnWAN(addr ma.Multiaddr) bool {
218
+ s := ma.Split(addr)
219
+ if len(s) < 1 {
220
+ return false
221
+ }
222
+ a := s[0]
223
+ if manet.IsIPLoopback(a) || manet.IsIP6LinkLocal(a) || manet.IsIPUnspecified(a) {
224
+ return false
225
+ }
226
+ return manet.IsThinWaist(a)
227
+}
228
+
229
+// WANShareableAddrs filters addresses based on whether they're shareable on WAN
230
+func WANShareableAddrs(inp []ma.Multiaddr) []ma.Multiaddr {
231
+ out := make([]ma.Multiaddr, 0, len(inp))
232
+ for _, a := range inp {
233
+ if AddrIsShareableOnWAN(a) {
234
+ out = append(out, a)
235
+ }
236
+ }
237
+ return out
238
+}
239
+
240
+// CheckNATWarning checks if our observed addresses differ. if so,
241
+// informs the user that certain things might not work yet
242
+func CheckNATWarning(observed, expected ma.Multiaddr, listen []ma.Multiaddr) {
243
+ if observed.Equal(expected) {
244
+ return
245
+ }
246
+
247
+ if !AddrInList(observed, listen) { // probably a nat
248
+ log.Warningf(natWarning, observed, listen)
249
+ }
250
+}
251
+
252
+const natWarning = `Remote peer observed our address to be: %s
253
+The local addresses are: %s
254
+Thus, connection is going through NAT, and other connections may fail.
255
+
256
+IPFS NAT traversal is still under development. Please bug us on github or irc to fix this.
257
+Baby steps: http://jbenet.static.s3.amazonaws.com/271dfcf/baby-steps.gif
258
+`
p2p/net/swarm/addr/addr_test.go
new
+198
@@ -0,0 +1,198 @@
1
+package addrutil
2
+
3
+import (
4
+ "testing"
5
+
6
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7
+ manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
8
+)
9
+
10
+func newMultiaddr(t *testing.T, s string) ma.Multiaddr {
11
+ maddr, err := ma.NewMultiaddr(s)
12
+ if err != nil {
13
+ t.Fatal(err)
14
+ }
15
+ return maddr
16
+}
17
+
18
+func TestFilterAddrs(t *testing.T) {
19
+
20
+ bad := []ma.Multiaddr{
21
+ newMultiaddr(t, "/ip4/1.2.3.4/udp/1234"), // unreliable
22
+ newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/sctp/1234"), // not in manet
23
+ newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/utp"), // utp is broken
24
+ newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/udt"), // udt is broken on arm
25
+ newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), // link local
26
+ newMultiaddr(t, "/ip6/fe80::100/tcp/1234"), // link local
27
+ }
28
+
29
+ good := []ma.Multiaddr{
30
+ newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"),
31
+ newMultiaddr(t, "/ip6/::1/tcp/1234"),
32
+ }
33
+
34
+ goodAndBad := append(good, bad...)
35
+
36
+ // test filters
37
+
38
+ for _, a := range bad {
39
+ if AddrUsable(a, false) {
40
+ t.Errorf("addr %s should be unusable", a)
41
+ }
42
+ if AddrUsable(a, true) {
43
+ t.Errorf("addr %s should be unusable", a)
44
+ }
45
+ }
46
+
47
+ for _, a := range good {
48
+ if !AddrUsable(a, false) {
49
+ t.Errorf("addr %s should be usable", a)
50
+ }
51
+ if !AddrUsable(a, true) {
52
+ t.Errorf("addr %s should be usable", a)
53
+ }
54
+ }
55
+
56
+ subtestAddrsEqual(t, FilterAddrs(bad), []ma.Multiaddr{})
57
+ subtestAddrsEqual(t, FilterAddrs(good), good)
58
+ subtestAddrsEqual(t, FilterAddrs(goodAndBad), good)
59
+}
60
+
61
+func subtestAddrsEqual(t *testing.T, a, b []ma.Multiaddr) {
62
+ if len(a) != len(b) {
63
+ t.Error(t)
64
+ }
65
+
66
+ in := func(addr ma.Multiaddr, l []ma.Multiaddr) bool {
67
+ for _, addr2 := range l {
68
+ if addr.Equal(addr2) {
69
+ return true
70
+ }
71
+ }
72
+ return false
73
+ }
74
+
75
+ for _, aa := range a {
76
+ if !in(aa, b) {
77
+ t.Errorf("%s not in %s", aa, b)
78
+ }
79
+ }
80
+}
81
+
82
+func TestInterfaceAddrs(t *testing.T) {
83
+ addrs, err := InterfaceAddresses()
84
+ if err != nil {
85
+ t.Fatal(err)
86
+ }
87
+
88
+ if len(addrs) < 1 {
89
+ t.Error("no addresses")
90
+ }
91
+
92
+ for _, a := range addrs {
93
+ if manet.IsIP6LinkLocal(a) {
94
+ t.Error("should not return ip link local addresses", a)
95
+ }
96
+ }
97
+
98
+ if len(addrs) < 1 {
99
+ t.Error("no good interface addrs")
100
+ }
101
+}
102
+
103
+func TestResolvingAddrs(t *testing.T) {
104
+
105
+ unspec := []ma.Multiaddr{
106
+ newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"),
107
+ newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"),
108
+ newMultiaddr(t, "/ip6/::/tcp/1234"),
109
+ newMultiaddr(t, "/ip6/::100/tcp/1234"),
110
+ }
111
+
112
+ iface := []ma.Multiaddr{
113
+ newMultiaddr(t, "/ip4/127.0.0.1"),
114
+ newMultiaddr(t, "/ip4/10.20.30.40"),
115
+ newMultiaddr(t, "/ip6/::1"),
116
+ newMultiaddr(t, "/ip6/::f"),
117
+ }
118
+
119
+ spec := []ma.Multiaddr{
120
+ newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"),
121
+ newMultiaddr(t, "/ip4/10.20.30.40/tcp/1234"),
122
+ newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"),
123
+ newMultiaddr(t, "/ip6/::1/tcp/1234"),
124
+ newMultiaddr(t, "/ip6/::f/tcp/1234"),
125
+ newMultiaddr(t, "/ip6/::100/tcp/1234"),
126
+ }
127
+
128
+ actual, err := ResolveUnspecifiedAddresses(unspec, iface)
129
+ if err != nil {
130
+ t.Fatal(err)
131
+ }
132
+
133
+ for i, a := range actual {
134
+ if !a.Equal(spec[i]) {
135
+ t.Error(a, " != ", spec[i])
136
+ }
137
+ }
138
+
139
+ ip4u := []ma.Multiaddr{newMultiaddr(t, "/ip4/0.0.0.0")}
140
+ ip4i := []ma.Multiaddr{newMultiaddr(t, "/ip4/1.2.3.4")}
141
+
142
+ ip6u := []ma.Multiaddr{newMultiaddr(t, "/ip6/::")}
143
+ ip6i := []ma.Multiaddr{newMultiaddr(t, "/ip6/::1")}
144
+
145
+ if _, err := ResolveUnspecifiedAddress(ip4u[0], ip6i); err == nil {
146
+ t.Fatal("should have failed")
147
+ }
148
+ if _, err := ResolveUnspecifiedAddress(ip6u[0], ip4i); err == nil {
149
+ t.Fatal("should have failed")
150
+ }
151
+
152
+ if _, err := ResolveUnspecifiedAddresses(ip6u, ip4i); err == nil {
153
+ t.Fatal("should have failed")
154
+ }
155
+ if _, err := ResolveUnspecifiedAddresses(ip4u, ip6i); err == nil {
156
+ t.Fatal("should have failed")
157
+ }
158
+
159
+}
160
+
161
+func TestWANShareable(t *testing.T) {
162
+
163
+ wanok := []ma.Multiaddr{
164
+ newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"),
165
+ newMultiaddr(t, "/ip6/abcd::1/tcp/1234"),
166
+ }
167
+
168
+ wanbad := []ma.Multiaddr{
169
+ newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"),
170
+ newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"),
171
+ newMultiaddr(t, "/ip6/::1/tcp/1234"),
172
+ newMultiaddr(t, "/ip6/::/tcp/1234"),
173
+ newMultiaddr(t, "/ip6/fe80::1/tcp/1234"),
174
+ newMultiaddr(t, "/ip6/fe80::/tcp/1234"),
175
+ }
176
+
177
+ for _, a := range wanok {
178
+ if !AddrIsShareableOnWAN(a) {
179
+ t.Error("should be true", a)
180
+ }
181
+ }
182
+
183
+ for _, a := range wanbad {
184
+ if AddrIsShareableOnWAN(a) {
185
+ t.Error("should be false", a)
186
+ }
187
+ }
188
+
189
+ wanok2 := WANShareableAddrs(wanok)
190
+ if len(wanok) != len(wanok2) {
191
+ t.Error("should be the same")
192
+ }
193
+
194
+ wanbad2 := WANShareableAddrs(wanbad)
195
+ if len(wanbad2) != 0 {
196
+ t.Error("should be zero")
197
+ }
198
+}
p2p/net/swarm/swarm.go
+11
@@ -3,7 +3,10 @@
3
package swarm
4
5
import (
6
+ "fmt"
7
+
8
inet "github.com/jbenet/go-ipfs/p2p/net"
9
+ addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
10
peer "github.com/jbenet/go-ipfs/p2p/peer"
11
eventlog "github.com/jbenet/go-ipfs/util/eventlog"
12
@@ -37,6 +40,14 @@ type Swarm struct {
40
func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr,
41
local peer.ID, peers peer.Peerstore) (*Swarm, error) {
42
43
+ if len(listenAddrs) > 0 {
44
+ filtered := addrutil.FilterAddrs(listenAddrs)
45
+ if len(filtered) < 1 {
46
+ return nil, fmt.Errorf("swarm cannot use any addr in: %s", listenAddrs)
47
+ }
48
+ listenAddrs = filtered
49
+ }
50
+
51
s := &Swarm{
52
swarm: ps.NewSwarm(PSTransport),
53
local: local,
p2p/net/swarm/swarm_addr.go
new
+39
@@ -0,0 +1,39 @@
1
+package swarm
2
+
3
+import (
4
+ conn "github.com/jbenet/go-ipfs/p2p/net/conn"
5
+ addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
6
+
7
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8
+)
9
+
10
+// ListenAddresses returns a list of addresses at which this swarm listens.
11
+func (s *Swarm) ListenAddresses() []ma.Multiaddr {
12
+ listeners := s.swarm.Listeners()
13
+ addrs := make([]ma.Multiaddr, 0, len(listeners))
14
+ for _, l := range listeners {
15
+ if l2, ok := l.NetListener().(conn.Listener); ok {
16
+ addrs = append(addrs, l2.Multiaddr())
17
+ }
18
+ }
19
+ return addrs
20
+}
21
+
22
+// InterfaceListenAddresses returns a list of addresses at which this swarm
23
+// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
24
+// use the known local interfaces.
25
+func InterfaceListenAddresses(s *Swarm) ([]ma.Multiaddr, error) {
26
+ return addrutil.ResolveUnspecifiedAddresses(s.ListenAddresses(), nil)
27
+}
28
+
29
+// checkNATWarning checks if our observed addresses differ. if so,
30
+// informs the user that certain things might not work yet
31
+func checkNATWarning(s *Swarm, observed ma.Multiaddr, expected ma.Multiaddr) {
32
+ listen, err := InterfaceListenAddresses(s)
33
+ if err != nil {
34
+ log.Errorf("Error retrieving swarm.InterfaceListenAddresses: %s", err)
35
+ return
36
+ }
37
+
38
+ addrutil.CheckNATWarning(observed, expected, listen)
39
+}
p2p/net/swarm/swarm_addr_test.go
renamed
+34
-5
@@ -3,6 +3,7 @@ package swarm
3
import (
4
"testing"
5
6
+ addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
7
peer "github.com/jbenet/go-ipfs/p2p/peer"
8
testutil "github.com/jbenet/go-ipfs/util/testutil"
9
@@ -25,6 +26,8 @@ func TestFilterAddrs(t *testing.T) {
26
m("/ip4/1.2.3.4/udp/1234/sctp/1234"), // not in manet
27
m("/ip4/1.2.3.4/udp/1234/utp"), // utp is broken
28
m("/ip4/1.2.3.4/udp/1234/udt"), // udt is broken on arm
29
+ m("/ip6/fe80::1/tcp/1234"), // link local
30
+ m("/ip6/fe80::100/tcp/1234"), // link local
31
}
32
33
good := []ma.Multiaddr{
@@ -37,20 +40,20 @@ func TestFilterAddrs(t *testing.T) {
40
// test filters
41
42
for _, a := range bad {
40
- if AddrUsable(a) {
43
+ if addrutil.AddrUsable(a, true) {
44
t.Errorf("addr %s should be unusable", a)
45
}
46
}
47
48
for _, a := range good {
46
- if !AddrUsable(a) {
49
+ if !addrutil.AddrUsable(a, true) {
50
t.Errorf("addr %s should be usable", a)
51
}
52
}
53
51
- subtestAddrsEqual(t, FilterAddrs(bad), []ma.Multiaddr{})
52
- subtestAddrsEqual(t, FilterAddrs(good), good)
53
- subtestAddrsEqual(t, FilterAddrs(goodAndBad), good)
54
+ subtestAddrsEqual(t, addrutil.FilterAddrs(bad), []ma.Multiaddr{})
55
+ subtestAddrsEqual(t, addrutil.FilterAddrs(good), good)
56
+ subtestAddrsEqual(t, addrutil.FilterAddrs(goodAndBad), good)
57
58
// now test it with swarm
59
@@ -95,3 +98,29 @@ func subtestAddrsEqual(t *testing.T, a, b []ma.Multiaddr) {
98
}
99
}
100
}
101
+
102
+func TestDialBadAddrs(t *testing.T) {
103
+
104
+ m := func(s string) ma.Multiaddr {
105
+ maddr, err := ma.NewMultiaddr(s)
106
+ if err != nil {
107
+ t.Fatal(err)
108
+ }
109
+ return maddr
110
+ }
111
+
112
+ ctx := context.Background()
113
+ s := makeSwarms(ctx, t, 1)[0]
114
+
115
+ test := func(a ma.Multiaddr) {
116
+ p := testutil.RandPeerIDFatal(t)
117
+ s.peers.AddAddress(p, a)
118
+ if _, err := s.Dial(ctx, p); err == nil {
119
+ t.Error("swarm should not dial: %s", m)
120
+ }
121
+ }
122
+
123
+ test(m("/ip6/fe80::1")) // link local
124
+ test(m("/ip6/fe80::100")) // link local
125
+ test(m("/ip4/127.0.0.1/udp/1234/utp")) // utp
126
+}
p2p/net/swarm/swarm_dial.go
+6
@@ -5,6 +5,7 @@ import (
5
"fmt"
6
7
conn "github.com/jbenet/go-ipfs/p2p/net/conn"
8
+ addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
9
peer "github.com/jbenet/go-ipfs/p2p/peer"
10
lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"
11
@@ -38,6 +39,8 @@ func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) {
39
}
40
41
remoteAddrs := s.peers.Addresses(p)
42
+ // make sure we can use the addresses.
43
+ remoteAddrs = addrutil.FilterAddrs(remoteAddrs)
44
if len(remoteAddrs) == 0 {
45
return nil, errors.New("peer has no addresses")
46
}
@@ -67,6 +70,9 @@ func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) {
70
if err != nil {
71
return nil, err
72
}
73
+ if connC == nil {
74
+ err = fmt.Errorf("failed to dial %s", p)
75
+ }
76
77
// ok try to setup the new connection.
78
swarmC, err := dialConnSetup(ctx, s, connC)
p2p/net/swarm/swarm_listen.go
+4
-1
@@ -4,6 +4,7 @@ import (
4
"fmt"
5
6
conn "github.com/jbenet/go-ipfs/p2p/net/conn"
7
+ addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
8
lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"
9
10
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
@@ -16,7 +17,7 @@ import (
17
func (s *Swarm) listen(addrs []ma.Multiaddr) error {
18
19
for _, addr := range addrs {
19
- if !AddrUsable(addr) {
20
+ if !addrutil.AddrUsable(addr, true) {
21
return fmt.Errorf("cannot use addr: %s", addr)
22
}
23
}
@@ -59,10 +60,12 @@ func (s *Swarm) setupListener(maddr ma.Multiaddr) error {
60
// may be fine for sk to be nil, just log a warning.
61
log.Warning("Listener not given PrivateKey, so WILL NOT SECURE conns.")
62
}
63
+ log.Infof("Swarm Listening at %s", maddr)
64
list, err := conn.Listen(s.cg.Context(), maddr, s.local, sk)
65
if err != nil {
66
return err
67
}
68
+ log.Infof("Swarm Listening at %s", s.ListenAddresses())
69
70
// AddListener to the peerstream Listener. this will begin accepting connections
71
// and streams!
routing/dht/dht.go
+14
-5
@@ -66,8 +66,13 @@ func NewDHT(ctx context.Context, h host.Host, dstore ds.ThreadSafeDatastore) *Ip
66
dht.peerstore = h.Peerstore()
67
dht.ContextGroup = ctxgroup.WithContext(ctx)
68
dht.host = h
69
- h.SetStreamHandler(ProtocolDHT, dht.handleNewStream)
69
70
+ // sanity check. this should **never** happen
71
+ if len(dht.peerstore.Addresses(dht.self)) < 1 {
72
+ panic("attempt to initialize dht without addresses for self")
73
+ }
74
+
75
+ h.SetStreamHandler(ProtocolDHT, dht.handleNewStream)
76
dht.providers = NewProviderManager(dht.Context(), dht.self)
77
dht.AddChildGroup(dht.providers)
78
@@ -132,19 +137,23 @@ func (dht *IpfsDHT) putValueToPeer(ctx context.Context, p peer.ID,
137
// can provide the value of 'key'
138
func (dht *IpfsDHT) putProvider(ctx context.Context, p peer.ID, key string) error {
139
135
- pmes := pb.NewMessage(pb.Message_ADD_PROVIDER, string(key), 0)
136
-
140
// add self as the provider
141
pi := dht.peerstore.PeerInfo(dht.self)
139
- pmes.ProviderPeers = pb.PeerInfosToPBPeers(dht.host.Network(), []peer.PeerInfo{pi})
142
+ // // only share WAN-friendly addresses ??
143
+ // pi.Addrs = addrutil.WANShareableAddrs(pi.Addrs)
144
+ if len(pi.Addrs) < 1 {
145
+ log.Errorf("%s putProvider: %s for %s error: no wan-friendly addresses", dht.self, p, u.Key(key), pi.Addrs)
146
+ return fmt.Errorf("no known addresses for self. cannot put provider.")
147
+ }
148
149
+ pmes := pb.NewMessage(pb.Message_ADD_PROVIDER, string(key), 0)
150
+ pmes.ProviderPeers = pb.PeerInfosToPBPeers(dht.host.Network(), []peer.PeerInfo{pi})
151
err := dht.sendMessage(ctx, p, pmes)
152
if err != nil {
153
return err
154
}
155
156
log.Debugf("%s putProvider: %s for %s (%s)", dht.self, p, u.Key(key), pi.Addrs)
147
-
157
return nil
158
}
159