structs.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Copyright (C) 2015 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package upnp
  7. import (
  8. "fmt"
  9. "net"
  10. "sync"
  11. "time"
  12. )
  13. type MappingChangeSubscriber func(*Mapping, []Address, []Address)
  14. type Mapping struct {
  15. protocol Protocol
  16. address Address
  17. extAddresses map[string]Address // NAT ID -> Address
  18. expires time.Time
  19. subscribers []MappingChangeSubscriber
  20. mut sync.RWMutex
  21. ll levelLogger
  22. }
  23. func (m *Mapping) setAddress(id string, address Address) {
  24. m.mut.Lock()
  25. if existing, ok := m.extAddresses[id]; !ok || !existing.Equal(address) {
  26. m.ll.Infof("New NAT port mapping: external %s address %s to local address %s.", m.protocol, address, m.address)
  27. m.extAddresses[id] = address
  28. }
  29. m.mut.Unlock()
  30. }
  31. func (m *Mapping) removeAddress(id string) {
  32. m.mut.Lock()
  33. addr, ok := m.extAddresses[id]
  34. if ok {
  35. m.ll.Infof("Removing NAT port mapping: external %s address %s, NAT %s is no longer available.", m.protocol, addr, id)
  36. delete(m.extAddresses, id)
  37. }
  38. m.mut.Unlock()
  39. }
  40. func (m *Mapping) clearAddresses() {
  41. m.mut.Lock()
  42. var removed []Address
  43. for id, addr := range m.extAddresses {
  44. m.ll.Infof("Clearing mapping %s: ID: %s Address: %s", m, id, addr)
  45. removed = append(removed, addr)
  46. delete(m.extAddresses, id)
  47. }
  48. m.expires = time.Time{}
  49. m.mut.Unlock()
  50. if len(removed) > 0 {
  51. m.notify(nil, removed)
  52. }
  53. }
  54. func (m *Mapping) notify(added, removed []Address) {
  55. m.mut.RLock()
  56. for _, subscriber := range m.subscribers {
  57. subscriber(m, added, removed)
  58. }
  59. m.mut.RUnlock()
  60. }
  61. func (m *Mapping) addressMap() map[string]Address {
  62. m.mut.RLock()
  63. addrMap := m.extAddresses
  64. m.mut.RUnlock()
  65. return addrMap
  66. }
  67. func (m *Mapping) Protocol() Protocol {
  68. return m.protocol
  69. }
  70. func (m *Mapping) Address() Address {
  71. return m.address
  72. }
  73. func (m *Mapping) ExternalAddresses() []Address {
  74. m.mut.RLock()
  75. addrs := make([]Address, 0, len(m.extAddresses))
  76. for _, addr := range m.extAddresses {
  77. addrs = append(addrs, addr)
  78. }
  79. m.mut.RUnlock()
  80. return addrs
  81. }
  82. func (m *Mapping) OnChanged(subscribed MappingChangeSubscriber) {
  83. m.mut.Lock()
  84. m.subscribers = append(m.subscribers, subscribed)
  85. m.mut.Unlock()
  86. }
  87. func (m *Mapping) String() string {
  88. return fmt.Sprintf("%s %s", m.protocol, m.address)
  89. }
  90. func (m *Mapping) GoString() string {
  91. return m.String()
  92. }
  93. // Checks if the mappings local IP address matches the IP address of the gateway
  94. // For example, if we are explicitly listening on 192.168.0.12, there is no
  95. // point trying to acquire a mapping on a gateway to which the local IP is
  96. // 10.0.0.1. Fallback to true if any of the IPs is not there.
  97. func (m *Mapping) validGateway(ip net.IP) bool {
  98. if m.address.IP == nil || ip == nil || m.address.IP.IsUnspecified() || ip.IsUnspecified() {
  99. return true
  100. }
  101. return m.address.IP.Equal(ip)
  102. }
  103. // Address is essentially net.TCPAddr yet is more general, and has a few helper
  104. // methods which reduce boilerplate code.
  105. type Address struct {
  106. IP net.IP
  107. Port int
  108. }
  109. func (a Address) Equal(b Address) bool {
  110. return a.Port == b.Port && a.IP.Equal(b.IP)
  111. }
  112. func (a Address) String() string {
  113. var ipStr string
  114. if a.IP == nil {
  115. ipStr = net.IPv4zero.String()
  116. } else {
  117. ipStr = a.IP.String()
  118. }
  119. return net.JoinHostPort(ipStr, fmt.Sprintf("%d", a.Port))
  120. }
  121. func (a Address) GoString() string {
  122. return a.String()
  123. }