Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
p2p
go-p2p-addrutil
Commits
e4fdc396
Commit
e4fdc396
authored
Sep 30, 2015
by
Juan Batiz-Benet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
move to p2p dir
parents
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
507 additions
and
0 deletions
+507
-0
addr.go
addr.go
+275
-0
addr_test.go
addr_test.go
+232
-0
No files found.
addr.go
0 → 100644
View file @
e4fdc396
package
addrutil
import
(
"fmt"
logging
"github.com/ipfs/go-ipfs/vendor/go-log-v1.0.0"
ma
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
manet
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
context
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
)
var
log
=
logging
.
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, according to filter.
// if filter returns true, the address is kept.
func
FilterAddrs
(
a
[]
ma
.
Multiaddr
,
filter
func
(
ma
.
Multiaddr
)
bool
)
[]
ma
.
Multiaddr
{
b
:=
make
([]
ma
.
Multiaddr
,
0
,
len
(
a
))
for
_
,
addr
:=
range
a
{
if
filter
(
addr
)
{
b
=
append
(
b
,
addr
)
}
}
return
b
}
// FilterUsableAddrs removes certain addresses
// from a list. the addresses removed are those known NOT
// to work with our network. Namely, addresses with UTP.
func
FilterUsableAddrs
(
a
[]
ma
.
Multiaddr
)
[]
ma
.
Multiaddr
{
return
FilterAddrs
(
a
,
func
(
m
ma
.
Multiaddr
)
bool
{
return
AddrUsable
(
m
,
false
)
})
}
// 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
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
}
// 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
()
logging
.
Loggable
{
var
addrs
[]
string
for
_
,
addr
:=
range
outputAddrs
{
addrs
=
append
(
addrs
,
addr
.
String
())
}
return
logging
.
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
{
return
FilterAddrs
(
inp
,
AddrIsShareableOnWAN
)
}
// Subtract filters out all addrs in b from a
func
Subtract
(
a
,
b
[]
ma
.
Multiaddr
)
[]
ma
.
Multiaddr
{
return
FilterAddrs
(
a
,
func
(
m
ma
.
Multiaddr
)
bool
{
for
_
,
bb
:=
range
b
{
if
m
.
Equal
(
bb
)
{
return
false
}
}
return
true
})
}
// 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
`
addr_test.go
0 → 100644
View file @
e4fdc396
package
addrutil
import
(
"testing"
ma
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
manet
"github.com/ipfs/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
,
FilterUsableAddrs
(
bad
),
[]
ma
.
Multiaddr
{})
subtestAddrsEqual
(
t
,
FilterUsableAddrs
(
good
),
good
)
subtestAddrsEqual
(
t
,
FilterUsableAddrs
(
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"
)
}
}
func
TestSubtract
(
t
*
testing
.
T
)
{
a
:=
[]
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"
),
}
b
:=
[]
ma
.
Multiaddr
{
newMultiaddr
(
t
,
"/ip4/127.0.0.1/tcp/1234"
),
newMultiaddr
(
t
,
"/ip6/::1/tcp/1234"
),
newMultiaddr
(
t
,
"/ip6/fe80::1/tcp/1234"
),
}
c1
:=
[]
ma
.
Multiaddr
{
newMultiaddr
(
t
,
"/ip4/0.0.0.0/tcp/1234"
),
newMultiaddr
(
t
,
"/ip6/::/tcp/1234"
),
newMultiaddr
(
t
,
"/ip6/fe80::/tcp/1234"
),
}
c2
:=
Subtract
(
a
,
b
)
if
len
(
c1
)
!=
len
(
c2
)
{
t
.
Error
(
"should be the same"
)
}
for
i
,
ca
:=
range
c1
{
if
!
c2
[
i
]
.
Equal
(
ca
)
{
t
.
Error
(
"should be the same"
,
ca
,
c2
[
i
])
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment