1package nat 2 3import ( 4 "fmt" 5 "net" 6 "sync" 7 "time" 8 9 "github.com/jbenet/goprocess" 10) 11 12// Mapping represents a port mapping in a NAT. 13type Mapping interface { 14 // NAT returns the NAT object this Mapping belongs to. 15 NAT() *NAT 16 17 // Protocol returns the protocol of this port mapping. This is either 18 // "tcp" or "udp" as no other protocols are likely to be NAT-supported. 19 Protocol() string 20 21 // InternalPort returns the internal device port. Mapping will continue to 22 // try to map InternalPort() to an external facing port. 23 InternalPort() int 24 25 // ExternalPort returns the external facing port. If the mapping is not 26 // established, port will be 0 27 ExternalPort() int 28 29 // ExternalAddr returns the external facing address. If the mapping is not 30 // established, addr will be nil, and and ErrNoMapping will be returned. 31 ExternalAddr() (addr net.Addr, err error) 32 33 // Close closes the port mapping 34 Close() error 35} 36 37// keeps republishing 38type mapping struct { 39 sync.Mutex // guards all fields 40 41 nat *NAT 42 proto string 43 intport int 44 extport int 45 permanent bool 46 proc goprocess.Process 47 48 cached net.IP 49 cacheTime time.Time 50 cacheLk sync.Mutex 51} 52 53func (m *mapping) NAT() *NAT { 54 m.Lock() 55 defer m.Unlock() 56 return m.nat 57} 58 59func (m *mapping) Protocol() string { 60 m.Lock() 61 defer m.Unlock() 62 return m.proto 63} 64 65func (m *mapping) InternalPort() int { 66 m.Lock() 67 defer m.Unlock() 68 return m.intport 69} 70 71func (m *mapping) ExternalPort() int { 72 m.Lock() 73 defer m.Unlock() 74 return m.extport 75} 76 77func (m *mapping) setExternalPort(p int) { 78 m.Lock() 79 defer m.Unlock() 80 m.extport = p 81} 82 83func (m *mapping) ExternalAddr() (net.Addr, error) { 84 m.cacheLk.Lock() 85 defer m.cacheLk.Unlock() 86 oport := m.ExternalPort() 87 if oport == 0 { 88 // dont even try right now. 89 return nil, ErrNoMapping 90 } 91 92 if time.Since(m.cacheTime) >= CacheTime { 93 m.nat.natmu.Lock() 94 cval, err := m.nat.nat.GetExternalAddress() 95 m.nat.natmu.Unlock() 96 97 if err != nil { 98 return nil, err 99 } 100 101 m.cached = cval 102 m.cacheTime = time.Now() 103 } 104 switch m.Protocol() { 105 case "tcp": 106 return &net.TCPAddr{ 107 IP: m.cached, 108 Port: oport, 109 }, nil 110 case "udp": 111 return &net.UDPAddr{ 112 IP: m.cached, 113 Port: oport, 114 }, nil 115 default: 116 panic(fmt.Sprintf("invalid protocol %q", m.Protocol())) 117 } 118} 119 120func (m *mapping) Close() error { 121 return m.proc.Close() 122} 123