Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better nat mapping #549

Merged
merged 6 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ require (
github.com/libp2p/go-libp2p-interface-pnet v0.0.1
github.com/libp2p/go-libp2p-loggables v0.0.1
github.com/libp2p/go-libp2p-metrics v0.0.1
github.com/libp2p/go-libp2p-nat v0.0.1
github.com/libp2p/go-libp2p-nat v0.0.2
github.com/libp2p/go-libp2p-net v0.0.1
github.com/libp2p/go-libp2p-netutil v0.0.1
github.com/libp2p/go-libp2p-peer v0.0.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ github.com/libp2p/go-libp2p-metrics v0.0.1 h1:yumdPC/P2VzINdmcKZd0pciSUCpou+s0lw
github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08=
github.com/libp2p/go-libp2p-nat v0.0.1 h1:on/zju7XE+JXc8gH+vTKmIh2UJFC1K8kGnJYluQrlz4=
github.com/libp2p/go-libp2p-nat v0.0.1/go.mod h1:4L6ajyUIlJvx1Cbh5pc6Ma6vMDpKXf3GgLO5u7W0oQ4=
github.com/libp2p/go-libp2p-nat v0.0.2 h1:sKI5hiCsGFhuEKdXMsF9mywQu2qhfoIGX6a+VG6zelE=
github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ=
github.com/libp2p/go-libp2p-net v0.0.1 h1:xJ4Vh4yKF/XKb8fd1Ev0ebAGzVjMxXzrxG2kjtU+F5Q=
github.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c=
github.com/libp2p/go-libp2p-netutil v0.0.1 h1:LgD6+skofkOx8z6odD9+MZHKjupv3ng1u6KRhaADTnA=
Expand Down
156 changes: 139 additions & 17 deletions p2p/host/basic/basic_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package basichost
import (
"context"
"io"
"net"
"time"

logging "github.com/ipfs/go-log"
goprocess "github.com/jbenet/goprocess"
goprocessctx "github.com/jbenet/goprocess/context"
ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr"
inat "github.com/libp2p/go-libp2p-nat"
inet "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
Expand All @@ -17,6 +19,7 @@ import (
ping "github.com/libp2p/go-libp2p/p2p/protocol/ping"
ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
manet "github.com/multiformats/go-multiaddr-net"
msmux "github.com/multiformats/go-multistream"
)

Expand Down Expand Up @@ -485,17 +488,15 @@ func (h *BasicHost) Addrs() []ma.Multiaddr {
}

// mergeAddrs merges input address lists, leave only unique addresses
func mergeAddrs(addrLists ...[]ma.Multiaddr) (uniqueAddrs []ma.Multiaddr) {
func dedupAddrs(addrs []ma.Multiaddr) (uniqueAddrs []ma.Multiaddr) {
exists := make(map[string]bool)
for _, addrList := range addrLists {
for _, addr := range addrList {
k := string(addr.Bytes())
if exists[k] {
continue
}
exists[k] = true
uniqueAddrs = append(uniqueAddrs, addr)
for _, addr := range addrs {
k := string(addr.Bytes())
if exists[k] {
continue
}
exists[k] = true
uniqueAddrs = append(uniqueAddrs, addr)
}
return uniqueAddrs
}
Expand All @@ -507,19 +508,140 @@ func (h *BasicHost) AllAddrs() []ma.Multiaddr {
if err != nil {
log.Debug("error retrieving network interface addrs")
}
var observedAddrs []ma.Multiaddr
if h.ids != nil {
// peer observed addresses
observedAddrs = h.ids.OwnObservedAddrs()
}
var natAddrs []ma.Multiaddr
var natMappings []inat.Mapping

// natmgr is nil if we do not use nat option;
// h.natmgr.NAT() is nil if not ready, or no nat is available.
if h.natmgr != nil && h.natmgr.NAT() != nil {
natAddrs = h.natmgr.NAT().ExternalAddrs()
natMappings = h.natmgr.NAT().Mappings()
}

return mergeAddrs(listenAddrs, observedAddrs, natAddrs)
finalAddrs := listenAddrs
if len(natMappings) > 0 {

// We have successfully mapped ports on our NAT. Use those
// instead of observed addresses (mostly).

// First, generate a mapping table.
// protocol -> internal port -> external addr
ports := make(map[string]map[int]net.Addr)
for _, m := range natMappings {
addr, err := m.ExternalAddr()
if err != nil {
// mapping not ready yet.
continue
}
protoPorts, ok := ports[m.Protocol()]
if !ok {
protoPorts = make(map[int]net.Addr)
ports[m.Protocol()] = protoPorts
}
protoPorts[m.InternalPort()] = addr
}

// Next, apply this mapping to our addresses.
for _, listen := range listenAddrs {
found := false
transport, rest := ma.SplitFunc(listen, func(c ma.Component) bool {
if found {
return true
}
switch c.Protocol().Code {
case ma.P_TCP, ma.P_UDP:
found = true
}
return false
})
if !manet.IsThinWaist(transport) {
continue
}

naddr, err := manet.ToNetAddr(transport)
if err != nil {
log.Error("error parsing net multiaddr %q: %s", transport, err)
continue
}

var (
ip net.IP
iport int
protocol string
)
switch naddr := naddr.(type) {
case *net.TCPAddr:
ip = naddr.IP
iport = naddr.Port
protocol = "tcp"
case *net.UDPAddr:
ip = naddr.IP
iport = naddr.Port
protocol = "udp"
default:
continue
}

if !ip.IsGlobalUnicast() {
// We only map global unicast ports.
continue
}

mappedAddr, ok := ports[protocol][iport]
if !ok {
// Not mapped.
continue
}

mappedMaddr, err := manet.FromNetAddr(mappedAddr)
if err != nil {
log.Errorf("mapped addr can't be turned into a multiaddr %q: %s", mappedAddr, err)
continue
}

// Did the router give us a routable public addr?
if manet.IsPublicAddr(mappedMaddr) {
// Yes, use it.
extMaddr := mappedMaddr
if rest != nil {
extMaddr = ma.Join(extMaddr, rest)
}

// Add in the mapped addr.
finalAddrs = append(finalAddrs, extMaddr)
continue
}

// No. Ok, let's try our observed addresses.

// Now, check if we have any observed addresses that
// differ from the one reported by the router. Routers
// don't always give the most accurate information.
observed := h.ids.ObservedAddrsFor(listen)

if len(observed) == 0 {
continue
}

// Drop the IP from the external maddr
_, extMaddrNoIP := ma.SplitFirst(mappedMaddr)

for _, obsMaddr := range observed {
// Extract a public observed addr.
ip, _ := ma.SplitFirst(obsMaddr)
if ip == nil || !manet.IsPublicAddr(ip) {
continue
}

finalAddrs = append(finalAddrs, ma.Join(ip, extMaddrNoIP))
}
}
} else {
var observedAddrs []ma.Multiaddr
if h.ids != nil {
observedAddrs = h.ids.OwnObservedAddrs()
}
finalAddrs = append(finalAddrs, observedAddrs...)
}
return dedupAddrs(finalAddrs)
}

// Close shuts down the Host's services (network, etc).
Expand Down
Loading