github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/p2p/nat/nat.go (about)

     1  package nat
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
    12  	manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
    13  
    14  	nat "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/fd/go-nat"
    15  	goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
    16  	periodic "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic"
    17  	eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
    18  	notifier "github.com/ipfs/go-ipfs/thirdparty/notifier"
    19  )
    20  
    21  var (
    22  	// ErrNoMapping signals no mapping exists for an address
    23  	ErrNoMapping = errors.New("mapping not established")
    24  )
    25  
    26  var log = eventlog.Logger("nat")
    27  
    28  // MappingDuration is a default port mapping duration.
    29  // Port mappings are renewed every (MappingDuration / 3)
    30  const MappingDuration = time.Second * 60
    31  
    32  // DiscoverNAT looks for a NAT device in the network and
    33  // returns an object that can manage port mappings.
    34  func DiscoverNAT() *NAT {
    35  	nat, err := nat.DiscoverGateway()
    36  	if err != nil {
    37  		log.Debug("DiscoverGateway error:", err)
    38  		return nil
    39  	}
    40  	addr, err := nat.GetDeviceAddress()
    41  	if err != nil {
    42  		log.Debug("DiscoverGateway address error:", err)
    43  	} else {
    44  		log.Debug("DiscoverGateway address:", addr)
    45  	}
    46  	return newNAT(nat)
    47  }
    48  
    49  // NAT is an object that manages address port mappings in
    50  // NATs (Network Address Translators). It is a long-running
    51  // service that will periodically renew port mappings,
    52  // and keep an up-to-date list of all the external addresses.
    53  type NAT struct {
    54  	nat  nat.NAT
    55  	proc goprocess.Process // manages nat mappings lifecycle
    56  
    57  	mappingmu sync.RWMutex // guards mappings
    58  	mappings  map[*mapping]struct{}
    59  
    60  	Notifier
    61  }
    62  
    63  func newNAT(realNAT nat.NAT) *NAT {
    64  	return &NAT{
    65  		nat:      realNAT,
    66  		proc:     goprocess.WithParent(goprocess.Background()),
    67  		mappings: make(map[*mapping]struct{}),
    68  	}
    69  }
    70  
    71  // Close shuts down all port mappings. NAT can no longer be used.
    72  func (nat *NAT) Close() error {
    73  	return nat.proc.Close()
    74  }
    75  
    76  // Process returns the nat's life-cycle manager, for making it listen
    77  // to close signals.
    78  func (nat *NAT) Process() goprocess.Process {
    79  	return nat.proc
    80  }
    81  
    82  // Notifier is an object that assists NAT in notifying listeners.
    83  // It is implemented using github.com/ipfs/go-ipfs/thirdparty/notifier
    84  type Notifier struct {
    85  	n notifier.Notifier
    86  }
    87  
    88  func (n *Notifier) notifyAll(notify func(n Notifiee)) {
    89  	n.n.NotifyAll(func(n notifier.Notifiee) {
    90  		notify(n.(Notifiee))
    91  	})
    92  }
    93  
    94  // Notify signs up notifiee to listen to NAT events.
    95  func (n *Notifier) Notify(notifiee Notifiee) {
    96  	n.n.Notify(n)
    97  }
    98  
    99  // StopNotify stops signaling events to notifiee.
   100  func (n *Notifier) StopNotify(notifiee Notifiee) {
   101  	n.n.StopNotify(notifiee)
   102  }
   103  
   104  // Notifiee is an interface objects must implement to listen to NAT events.
   105  type Notifiee interface {
   106  
   107  	// Called every time a successful mapping happens
   108  	// Warning: the port mapping may have changed. If that is the
   109  	// case, both MappingSuccess and MappingChanged are called.
   110  	MappingSuccess(nat *NAT, m Mapping)
   111  
   112  	// Called when mapping a port succeeds, but the mapping is
   113  	// with a different port than an earlier success.
   114  	MappingChanged(nat *NAT, m Mapping, oldport int, newport int)
   115  
   116  	// Called when a port mapping fails. NAT will continue attempting after
   117  	// the next period. To stop trying, use: mapping.Close(). After this failure,
   118  	// mapping.ExternalPort() will be zero, and nat.ExternalAddrs() will not
   119  	// return the address for this mapping. With luck, the next attempt will
   120  	// succeed, without the client needing to do anything.
   121  	MappingFailed(nat *NAT, m Mapping, oldport int, err error)
   122  }
   123  
   124  // Mapping represents a port mapping in a NAT.
   125  type Mapping interface {
   126  	// NAT returns the NAT object this Mapping belongs to.
   127  	NAT() *NAT
   128  
   129  	// Protocol returns the protocol of this port mapping. This is either
   130  	// "tcp" or "udp" as no other protocols are likely to be NAT-supported.
   131  	Protocol() string
   132  
   133  	// InternalPort returns the internal device port. Mapping will continue to
   134  	// try to map InternalPort() to an external facing port.
   135  	InternalPort() int
   136  
   137  	// ExternalPort returns the external facing port. If the mapping is not
   138  	// established, port will be 0
   139  	ExternalPort() int
   140  
   141  	// InternalAddr returns the internal address.
   142  	InternalAddr() ma.Multiaddr
   143  
   144  	// ExternalAddr returns the external facing address. If the mapping is not
   145  	// established, addr will be nil, and and ErrNoMapping will be returned.
   146  	ExternalAddr() (addr ma.Multiaddr, err error)
   147  
   148  	// Close closes the port mapping
   149  	Close() error
   150  }
   151  
   152  // keeps republishing
   153  type mapping struct {
   154  	sync.Mutex // guards all fields
   155  
   156  	nat     *NAT
   157  	proto   string
   158  	intport int
   159  	extport int
   160  	intaddr ma.Multiaddr
   161  	proc    goprocess.Process
   162  }
   163  
   164  func (m *mapping) NAT() *NAT {
   165  	m.Lock()
   166  	defer m.Unlock()
   167  	return m.nat
   168  }
   169  
   170  func (m *mapping) Protocol() string {
   171  	m.Lock()
   172  	defer m.Unlock()
   173  	return m.proto
   174  }
   175  
   176  func (m *mapping) InternalPort() int {
   177  	m.Lock()
   178  	defer m.Unlock()
   179  	return m.intport
   180  }
   181  
   182  func (m *mapping) ExternalPort() int {
   183  	m.Lock()
   184  	defer m.Unlock()
   185  	return m.extport
   186  }
   187  
   188  func (m *mapping) setExternalPort(p int) {
   189  	m.Lock()
   190  	defer m.Unlock()
   191  	m.extport = p
   192  }
   193  
   194  func (m *mapping) InternalAddr() ma.Multiaddr {
   195  	m.Lock()
   196  	defer m.Unlock()
   197  	return m.intaddr
   198  }
   199  
   200  func (m *mapping) ExternalAddr() (ma.Multiaddr, error) {
   201  	if m.ExternalPort() == 0 { // dont even try right now.
   202  		return nil, ErrNoMapping
   203  	}
   204  
   205  	ip, err := m.nat.nat.GetExternalAddress()
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  
   210  	ipmaddr, err := manet.FromIP(ip)
   211  	if err != nil {
   212  		return nil, fmt.Errorf("error parsing ip")
   213  	}
   214  
   215  	// call m.ExternalPort again, as mapping may have changed under our feet. (tocttou)
   216  	extport := m.ExternalPort()
   217  	if extport == 0 {
   218  		return nil, ErrNoMapping
   219  	}
   220  
   221  	tcp, err := ma.NewMultiaddr(fmt.Sprintf("/%s/%d", m.Protocol(), extport))
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	maddr2 := ipmaddr.Encapsulate(tcp)
   227  	return maddr2, nil
   228  }
   229  
   230  func (m *mapping) Close() error {
   231  	return m.proc.Close()
   232  }
   233  
   234  // Mappings returns a slice of all NAT mappings
   235  func (nat *NAT) Mappings() []Mapping {
   236  	nat.mappingmu.Lock()
   237  	maps2 := make([]Mapping, 0, len(nat.mappings))
   238  	for m := range nat.mappings {
   239  		maps2 = append(maps2, m)
   240  	}
   241  	nat.mappingmu.Unlock()
   242  	return maps2
   243  }
   244  
   245  func (nat *NAT) addMapping(m *mapping) {
   246  	// make mapping automatically close when nat is closed.
   247  	nat.proc.AddChild(m.proc)
   248  
   249  	nat.mappingmu.Lock()
   250  	nat.mappings[m] = struct{}{}
   251  	nat.mappingmu.Unlock()
   252  }
   253  
   254  func (nat *NAT) rmMapping(m *mapping) {
   255  	nat.mappingmu.Lock()
   256  	delete(nat.mappings, m)
   257  	nat.mappingmu.Unlock()
   258  }
   259  
   260  // NewMapping attemps to construct a mapping on protocol and internal port
   261  // It will also periodically renew the mapping until the returned Mapping
   262  // -- or its parent NAT -- is Closed.
   263  //
   264  // May not succeed, and mappings may change over time;
   265  // NAT devices may not respect our port requests, and even lie.
   266  // Clients should not store the mapped results, but rather always
   267  // poll our object for the latest mappings.
   268  func (nat *NAT) NewMapping(maddr ma.Multiaddr) (Mapping, error) {
   269  	if nat == nil {
   270  		return nil, fmt.Errorf("no nat available")
   271  	}
   272  
   273  	network, addr, err := manet.DialArgs(maddr)
   274  	if err != nil {
   275  		return nil, fmt.Errorf("DialArgs failed on addr:", maddr.String())
   276  	}
   277  
   278  	switch network {
   279  	case "tcp", "tcp4", "tcp6":
   280  		network = "tcp"
   281  	case "udp", "udp4", "udp6":
   282  		network = "udp"
   283  	default:
   284  		return nil, fmt.Errorf("transport not supported by NAT: %s", network)
   285  	}
   286  
   287  	intports := strings.Split(addr, ":")[1]
   288  	intport, err := strconv.Atoi(intports)
   289  	if err != nil {
   290  		return nil, err
   291  	}
   292  
   293  	m := &mapping{
   294  		nat:     nat,
   295  		proto:   network,
   296  		intport: intport,
   297  		intaddr: maddr,
   298  	}
   299  	m.proc = goprocess.WithTeardown(func() error {
   300  		nat.rmMapping(m)
   301  		return nil
   302  	})
   303  	nat.addMapping(m)
   304  
   305  	m.proc.AddChild(periodic.Every(MappingDuration/3, func(worker goprocess.Process) {
   306  		nat.establishMapping(m)
   307  	}))
   308  
   309  	// do it once synchronously, so first mapping is done right away, and before exiting,
   310  	// allowing users -- in the optimistic case -- to use results right after.
   311  	nat.establishMapping(m)
   312  	return m, nil
   313  }
   314  
   315  func (nat *NAT) establishMapping(m *mapping) {
   316  	oldport := m.ExternalPort()
   317  	log.Debugf("Attempting port map: %s/%d", m.Protocol(), m.InternalPort())
   318  	newport, err := nat.nat.AddPortMapping(m.Protocol(), m.InternalPort(), "http", MappingDuration)
   319  
   320  	failure := func() {
   321  		m.setExternalPort(0) // clear mapping
   322  		// TODO: log.Event
   323  		log.Debugf("failed to establish port mapping: %s", err)
   324  		nat.Notifier.notifyAll(func(n Notifiee) {
   325  			n.MappingFailed(nat, m, oldport, err)
   326  		})
   327  
   328  		// we do not close if the mapping failed,
   329  		// because it may work again next time.
   330  	}
   331  
   332  	if err != nil || newport == 0 {
   333  		failure()
   334  		return
   335  	}
   336  
   337  	m.setExternalPort(newport)
   338  	ext, err := m.ExternalAddr()
   339  	if err != nil {
   340  		log.Debugf("NAT Mapping addr error: %s %s", m.InternalAddr(), err)
   341  		failure()
   342  		return
   343  	}
   344  
   345  	log.Debugf("NAT Mapping: %s --> %s", m.InternalAddr(), ext)
   346  	if oldport != 0 && newport != oldport {
   347  		log.Debugf("failed to renew same port mapping: ch %d -> %d", oldport, newport)
   348  		nat.Notifier.notifyAll(func(n Notifiee) {
   349  			n.MappingChanged(nat, m, oldport, newport)
   350  		})
   351  	}
   352  
   353  	nat.Notifier.notifyAll(func(n Notifiee) {
   354  		n.MappingSuccess(nat, m)
   355  	})
   356  }
   357  
   358  // PortMapAddrs attempts to open (and continue to keep open)
   359  // port mappings for given addrs. This function blocks until
   360  // all  addresses have been tried. This allows clients to
   361  // retrieve results immediately after:
   362  //
   363  //   nat.PortMapAddrs(addrs)
   364  //   mapped := nat.ExternalAddrs()
   365  //
   366  // Some may not succeed, and mappings may change over time;
   367  // NAT devices may not respect our port requests, and even lie.
   368  // Clients should not store the mapped results, but rather always
   369  // poll our object for the latest mappings.
   370  func (nat *NAT) PortMapAddrs(addrs []ma.Multiaddr) {
   371  	// spin off addr mappings independently.
   372  	var wg sync.WaitGroup
   373  	for _, addr := range addrs {
   374  		// do all of them concurrently
   375  		wg.Add(1)
   376  		go func() {
   377  			defer wg.Done()
   378  			nat.NewMapping(addr)
   379  		}()
   380  	}
   381  	wg.Wait()
   382  }
   383  
   384  // MappedAddrs returns address mappings NAT believes have been
   385  // successfully established. Unsuccessful mappings are nil. This is:
   386  //
   387  // 		map[internalAddr]externalAddr
   388  //
   389  // This set of mappings _may not_ be correct, as NAT devices are finicky.
   390  // Consider this with _best effort_ semantics.
   391  func (nat *NAT) MappedAddrs() map[ma.Multiaddr]ma.Multiaddr {
   392  
   393  	mappings := nat.Mappings()
   394  	addrmap := make(map[ma.Multiaddr]ma.Multiaddr, len(mappings))
   395  
   396  	for _, m := range mappings {
   397  		i := m.InternalAddr()
   398  		e, err := m.ExternalAddr()
   399  		if err != nil {
   400  			addrmap[i] = nil
   401  		} else {
   402  			addrmap[i] = e
   403  		}
   404  	}
   405  	return addrmap
   406  }
   407  
   408  // ExternalAddrs returns a list of addresses that NAT believes have
   409  // been successfully established. Unsuccessful mappings are omitted,
   410  // so nat.ExternalAddrs() may return less addresses than nat.InternalAddrs().
   411  // To see which addresses are mapped, use nat.MappedAddrs().
   412  //
   413  // This set of mappings _may not_ be correct, as NAT devices are finicky.
   414  // Consider this with _best effort_ semantics.
   415  func (nat *NAT) ExternalAddrs() []ma.Multiaddr {
   416  	mappings := nat.Mappings()
   417  	addrs := make([]ma.Multiaddr, 0, len(mappings))
   418  	for _, m := range mappings {
   419  		a, err := m.ExternalAddr()
   420  		if err != nil {
   421  			continue // this mapping not currently successful.
   422  		}
   423  		addrs = append(addrs, a)
   424  	}
   425  	return addrs
   426  }