diff --git a/p2p/host/basic/natmgr.go b/p2p/host/basic/natmgr.go index 8844b0791e305eedba7f3f25c33142aad2c2fb50..1a780356b50d91d9cf08d1fd9f1b9c2761115ee8 100644 --- a/p2p/host/basic/natmgr.go +++ b/p2p/host/basic/natmgr.go @@ -4,7 +4,7 @@ import ( "context" "sync" - inat "github.com/libp2p/go-libp2p/p2p/nat" + inat "github.com/libp2p/go-libp2p-nat" goprocess "github.com/jbenet/goprocess" lgbl "github.com/libp2p/go-libp2p-loggables" diff --git a/p2p/nat/mapping.go b/p2p/nat/mapping.go deleted file mode 100644 index b03b002d0005320d4dfe5f035caa3e9fc784fbfe..0000000000000000000000000000000000000000 --- a/p2p/nat/mapping.go +++ /dev/null @@ -1,143 +0,0 @@ -package nat - -import ( - "fmt" - "sync" - "time" - - "github.com/jbenet/goprocess" - ma "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr-net" -) - -// Mapping represents a port mapping in a NAT. -type Mapping interface { - // NAT returns the NAT object this Mapping belongs to. - NAT() *NAT - - // Protocol returns the protocol of this port mapping. This is either - // "tcp" or "udp" as no other protocols are likely to be NAT-supported. - Protocol() string - - // InternalPort returns the internal device port. Mapping will continue to - // try to map InternalPort() to an external facing port. - InternalPort() int - - // ExternalPort returns the external facing port. If the mapping is not - // established, port will be 0 - ExternalPort() int - - // InternalAddr returns the internal address. - InternalAddr() ma.Multiaddr - - // ExternalAddr returns the external facing address. If the mapping is not - // established, addr will be nil, and and ErrNoMapping will be returned. - ExternalAddr() (addr ma.Multiaddr, err error) - - // Close closes the port mapping - Close() error -} - -// keeps republishing -type mapping struct { - sync.Mutex // guards all fields - - nat *NAT - proto string - intport int - extport int - permanent bool - intaddr ma.Multiaddr - proc goprocess.Process - - comment string - - cached ma.Multiaddr - cacheTime time.Time - cacheLk sync.Mutex -} - -func (m *mapping) NAT() *NAT { - m.Lock() - defer m.Unlock() - return m.nat -} - -func (m *mapping) Protocol() string { - m.Lock() - defer m.Unlock() - return m.proto -} - -func (m *mapping) InternalPort() int { - m.Lock() - defer m.Unlock() - return m.intport -} - -func (m *mapping) ExternalPort() int { - m.Lock() - defer m.Unlock() - return m.extport -} - -func (m *mapping) setExternalPort(p int) { - m.Lock() - defer m.Unlock() - m.extport = p -} - -func (m *mapping) InternalAddr() ma.Multiaddr { - m.Lock() - defer m.Unlock() - return m.intaddr -} - -func (m *mapping) ExternalAddr() (ma.Multiaddr, error) { - m.cacheLk.Lock() - ctime := m.cacheTime - cval := m.cached - m.cacheLk.Unlock() - if time.Since(ctime) < CacheTime { - return cval, nil - } - - if m.ExternalPort() == 0 { // dont even try right now. - return nil, ErrNoMapping - } - - m.nat.natmu.Lock() - ip, err := m.nat.nat.GetExternalAddress() - m.nat.natmu.Unlock() - if err != nil { - return nil, err - } - - ipmaddr, err := manet.FromIP(ip) - if err != nil { - return nil, fmt.Errorf("error parsing ip") - } - - // call m.ExternalPort again, as mapping may have changed under our feet. (tocttou) - extport := m.ExternalPort() - if extport == 0 { - return nil, ErrNoMapping - } - - tcp, err := ma.NewMultiaddr(fmt.Sprintf("/%s/%d", m.Protocol(), extport)) - if err != nil { - return nil, err - } - - maddr2 := ipmaddr.Encapsulate(tcp) - - m.cacheLk.Lock() - m.cached = maddr2 - m.cacheTime = time.Now() - m.cacheLk.Unlock() - return maddr2, nil -} - -func (m *mapping) Close() error { - return m.proc.Close() -} diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go deleted file mode 100644 index 602667a3fc9d0808c9607a796d9e3afb2bcf77bb..0000000000000000000000000000000000000000 --- a/p2p/nat/nat.go +++ /dev/null @@ -1,288 +0,0 @@ -package nat - -import ( - "errors" - "fmt" - "strconv" - "strings" - "sync" - "time" - - nat "github.com/fd/go-nat" - logging "github.com/ipfs/go-log" - goprocess "github.com/jbenet/goprocess" - periodic "github.com/jbenet/goprocess/periodic" - ma "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr-net" -) - -var ( - // ErrNoMapping signals no mapping exists for an address - ErrNoMapping = errors.New("mapping not established") -) - -var log = logging.Logger("nat") - -// MappingDuration is a default port mapping duration. -// Port mappings are renewed every (MappingDuration / 3) -const MappingDuration = time.Second * 60 - -// CacheTime is the time a mapping will cache an external address for -const CacheTime = time.Second * 15 - -// DiscoverNAT looks for a NAT device in the network and -// returns an object that can manage port mappings. -func DiscoverNAT() *NAT { - nat, err := nat.DiscoverGateway() - if err != nil { - log.Debug("DiscoverGateway error:", err) - return nil - } - addr, err := nat.GetDeviceAddress() - if err != nil { - log.Debug("DiscoverGateway address error:", err) - } else { - log.Debug("DiscoverGateway address:", addr) - } - return newNAT(nat) -} - -// NAT is an object that manages address port mappings in -// NATs (Network Address Translators). It is a long-running -// service that will periodically renew port mappings, -// and keep an up-to-date list of all the external addresses. -type NAT struct { - natmu sync.Mutex - nat nat.NAT - proc goprocess.Process // manages nat mappings lifecycle - - mappingmu sync.RWMutex // guards mappings - mappings map[*mapping]struct{} - - Notifier -} - -func newNAT(realNAT nat.NAT) *NAT { - return &NAT{ - nat: realNAT, - proc: goprocess.WithParent(goprocess.Background()), - mappings: make(map[*mapping]struct{}), - } -} - -// Close shuts down all port mappings. NAT can no longer be used. -func (nat *NAT) Close() error { - return nat.proc.Close() -} - -// Process returns the nat's life-cycle manager, for making it listen -// to close signals. -func (nat *NAT) Process() goprocess.Process { - return nat.proc -} - -// Mappings returns a slice of all NAT mappings -func (nat *NAT) Mappings() []Mapping { - nat.mappingmu.Lock() - maps2 := make([]Mapping, 0, len(nat.mappings)) - for m := range nat.mappings { - maps2 = append(maps2, m) - } - nat.mappingmu.Unlock() - return maps2 -} - -func (nat *NAT) addMapping(m *mapping) { - // make mapping automatically close when nat is closed. - nat.proc.AddChild(m.proc) - - nat.mappingmu.Lock() - nat.mappings[m] = struct{}{} - nat.mappingmu.Unlock() -} - -func (nat *NAT) rmMapping(m *mapping) { - nat.mappingmu.Lock() - delete(nat.mappings, m) - nat.mappingmu.Unlock() -} - -// NewMapping attemps to construct a mapping on protocol and internal port -// It will also periodically renew the mapping until the returned Mapping -// -- or its parent NAT -- is Closed. -// -// May not succeed, and mappings may change over time; -// NAT devices may not respect our port requests, and even lie. -// Clients should not store the mapped results, but rather always -// poll our object for the latest mappings. -func (nat *NAT) NewMapping(maddr ma.Multiaddr) (Mapping, error) { - if nat == nil { - return nil, fmt.Errorf("no nat available") - } - - network, addr, err := manet.DialArgs(maddr) - if err != nil { - return nil, fmt.Errorf("DialArgs failed on addr:", maddr.String()) - } - - switch network { - case "tcp", "tcp4", "tcp6": - network = "tcp" - case "udp", "udp4", "udp6": - network = "udp" - default: - return nil, fmt.Errorf("transport not supported by NAT: %s", network) - } - - intports := strings.Split(addr, ":")[1] - intport, err := strconv.Atoi(intports) - if err != nil { - return nil, err - } - - m := &mapping{ - nat: nat, - proto: network, - intport: intport, - intaddr: maddr, - } - m.proc = goprocess.WithTeardown(func() error { - nat.rmMapping(m) - return nil - }) - nat.addMapping(m) - - m.proc.AddChild(periodic.Every(MappingDuration/3, func(worker goprocess.Process) { - nat.establishMapping(m) - })) - - // do it once synchronously, so first mapping is done right away, and before exiting, - // allowing users -- in the optimistic case -- to use results right after. - nat.establishMapping(m) - return m, nil -} - -func (nat *NAT) establishMapping(m *mapping) { - oldport := m.ExternalPort() - - log.Debugf("Attempting port map: %s/%d", m.Protocol(), m.InternalPort()) - comment := "libp2p" - if m.comment != "" { - comment = "libp2p-" + m.comment - } - - nat.natmu.Lock() - newport, err := nat.nat.AddPortMapping(m.Protocol(), m.InternalPort(), comment, MappingDuration) - if err != nil { - // Some hardware does not support mappings with timeout, so try that - newport, err = nat.nat.AddPortMapping(m.Protocol(), m.InternalPort(), comment, 0) - } - nat.natmu.Unlock() - - failure := func() { - m.setExternalPort(0) // clear mapping - // TODO: log.Event - log.Warningf("failed to establish port mapping: %s", err) - nat.Notifier.notifyAll(func(n Notifiee) { - n.MappingFailed(nat, m, oldport, err) - }) - - // we do not close if the mapping failed, - // because it may work again next time. - } - - if err != nil || newport == 0 { - failure() - return - } - - m.setExternalPort(newport) - ext, err := m.ExternalAddr() - if err != nil { - log.Debugf("NAT Mapping addr error: %s %s", m.InternalAddr(), err) - failure() - return - } - - log.Debugf("NAT Mapping: %s --> %s", m.InternalAddr(), ext) - if oldport != 0 && newport != oldport { - log.Debugf("failed to renew same port mapping: ch %d -> %d", oldport, newport) - nat.Notifier.notifyAll(func(n Notifiee) { - n.MappingChanged(nat, m, oldport, newport) - }) - } - - nat.Notifier.notifyAll(func(n Notifiee) { - n.MappingSuccess(nat, m) - }) -} - -// PortMapAddrs attempts to open (and continue to keep open) -// port mappings for given addrs. This function blocks until -// all addresses have been tried. This allows clients to -// retrieve results immediately after: -// -// nat.PortMapAddrs(addrs) -// mapped := nat.ExternalAddrs() -// -// Some may not succeed, and mappings may change over time; -// NAT devices may not respect our port requests, and even lie. -// Clients should not store the mapped results, but rather always -// poll our object for the latest mappings. -func (nat *NAT) PortMapAddrs(addrs []ma.Multiaddr) { - // spin off addr mappings independently. - var wg sync.WaitGroup - for _, addr := range addrs { - // do all of them concurrently - wg.Add(1) - go func() { - defer wg.Done() - nat.NewMapping(addr) - }() - } - wg.Wait() -} - -// MappedAddrs returns address mappings NAT believes have been -// successfully established. Unsuccessful mappings are nil. This is: -// -// map[internalAddr]externalAddr -// -// This set of mappings _may not_ be correct, as NAT devices are finicky. -// Consider this with _best effort_ semantics. -func (nat *NAT) MappedAddrs() map[ma.Multiaddr]ma.Multiaddr { - - mappings := nat.Mappings() - addrmap := make(map[ma.Multiaddr]ma.Multiaddr, len(mappings)) - - for _, m := range mappings { - i := m.InternalAddr() - e, err := m.ExternalAddr() - if err != nil { - addrmap[i] = nil - } else { - addrmap[i] = e - } - } - return addrmap -} - -// ExternalAddrs returns a list of addresses that NAT believes have -// been successfully established. Unsuccessful mappings are omitted, -// so nat.ExternalAddrs() may return less addresses than nat.InternalAddrs(). -// To see which addresses are mapped, use nat.MappedAddrs(). -// -// This set of mappings _may not_ be correct, as NAT devices are finicky. -// Consider this with _best effort_ semantics. -func (nat *NAT) ExternalAddrs() []ma.Multiaddr { - mappings := nat.Mappings() - addrs := make([]ma.Multiaddr, 0, len(mappings)) - for _, m := range mappings { - a, err := m.ExternalAddr() - if err != nil { - continue // this mapping not currently successful. - } - addrs = append(addrs, a) - } - return addrs -} diff --git a/p2p/nat/notifier.go b/p2p/nat/notifier.go deleted file mode 100644 index 462a78b953e9607d470a9b42d46615e41d73ef6a..0000000000000000000000000000000000000000 --- a/p2p/nat/notifier.go +++ /dev/null @@ -1,47 +0,0 @@ -package nat - -import ( - notifier "github.com/whyrusleeping/go-notifier" -) - -// Notifier is an object that assists NAT in notifying listeners. -// It is implemented using thirdparty/notifier -type Notifier struct { - n notifier.Notifier -} - -func (n *Notifier) notifyAll(notify func(n Notifiee)) { - n.n.NotifyAll(func(n notifier.Notifiee) { - notify(n.(Notifiee)) - }) -} - -// Notify signs up notifiee to listen to NAT events. -func (n *Notifier) Notify(notifiee Notifiee) { - n.n.Notify(n) -} - -// StopNotify stops signaling events to notifiee. -func (n *Notifier) StopNotify(notifiee Notifiee) { - n.n.StopNotify(notifiee) -} - -// Notifiee is an interface objects must implement to listen to NAT events. -type Notifiee interface { - - // Called every time a successful mapping happens - // Warning: the port mapping may have changed. If that is the - // case, both MappingSuccess and MappingChanged are called. - MappingSuccess(nat *NAT, m Mapping) - - // Called when mapping a port succeeds, but the mapping is - // with a different port than an earlier success. - MappingChanged(nat *NAT, m Mapping, oldport int, newport int) - - // Called when a port mapping fails. NAT will continue attempting after - // the next period. To stop trying, use: mapping.Close(). After this failure, - // mapping.ExternalPort() will be zero, and nat.ExternalAddrs() will not - // return the address for this mapping. With luck, the next attempt will - // succeed, without the client needing to do anything. - MappingFailed(nat *NAT, m Mapping, oldport int, err error) -} diff --git a/p2p/protocol/relay/relay.go b/p2p/protocol/relay/relay.go index dabda1ae644d6dd46560c2f58aa6cc388c7f2513..1256ff9343f87268c3515c96d7e5be64ea4e3658 100644 --- a/p2p/protocol/relay/relay.go +++ b/p2p/protocol/relay/relay.go @@ -9,10 +9,10 @@ import ( host "github.com/libp2p/go-libp2p-host" logging "github.com/ipfs/go-log" - mh "github.com/jbenet/go-multihash" inet "github.com/libp2p/go-libp2p-net" peer "github.com/libp2p/go-libp2p-peer" protocol "github.com/libp2p/go-libp2p-protocol" + mh "github.com/multiformats/go-multihash" ) var log = logging.Logger("protocol/relay") diff --git a/package.json b/package.json index ca78bcea52d6b7ac948a9212c75ecc135548beac..a4caf4588856afa968f702066b5399c608d7666f 100644 --- a/package.json +++ b/package.json @@ -38,11 +38,6 @@ "name": "go-multistream", "version": "0.3.1" }, - { - "hash": "QmYabcy8kaP658zZRZHLqRquJ37ycNWr4qhBL25tUodZWc", - "name": "go-nat", - "version": "0.0.0" - }, { "hash": "QmQHGMVmrsgmqUG8ih3puNXUJneSpi13dkcZpzLKkskUkH", "name": "go-detect-race", @@ -248,6 +243,12 @@ "hash": "QmeAfPWBWDQq9qjQ5oiWhaFs7oEsfB6FyEj5VxNdc2r34q", "name": "go-libp2p-swarm", "version": "1.0.0" + }, + { + "author": "whyrusleeping", + "hash": "QmPpncQ3L4bC3rnwLBrgEomygs5RbnFejb68GgsecxbMiL", + "name": "go-libp2p-nat", + "version": "0.0.0" } ], "gxVersion": "0.4.0",