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 }