structs.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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 nat
  7. import (
  8. "fmt"
  9. "log/slog"
  10. "net"
  11. "strconv"
  12. "sync"
  13. "time"
  14. )
  15. type MappingChangeSubscriber func()
  16. type Mapping struct {
  17. protocol Protocol
  18. ipVersion IPVersion
  19. address Address
  20. extAddresses map[string][]Address // NAT ID -> Address
  21. expires time.Time
  22. subscribers []MappingChangeSubscriber
  23. mut sync.RWMutex
  24. }
  25. func (m *Mapping) setAddressLocked(id string, addresses []Address) {
  26. slog.Info("New external port opened", "protocol", m.protocol, "external", addresses, "local", m.address, "gateway", id)
  27. m.extAddresses[id] = addresses
  28. }
  29. func (m *Mapping) removeAddressLocked(id string) {
  30. addresses, ok := m.extAddresses[id]
  31. if ok {
  32. slog.Info("Removing external open port", "protocol", m.protocol, "external", addresses, "gateway", id)
  33. delete(m.extAddresses, id)
  34. }
  35. }
  36. func (m *Mapping) clearAddresses() {
  37. m.mut.Lock()
  38. change := len(m.extAddresses) > 0
  39. for id, addr := range m.extAddresses {
  40. l.Debugf("Clearing mapping %s: ID: %s Address: %s", m, id, addr)
  41. delete(m.extAddresses, id)
  42. }
  43. m.expires = time.Time{}
  44. m.mut.Unlock()
  45. if change {
  46. m.notify()
  47. }
  48. }
  49. func (m *Mapping) notify() {
  50. m.mut.RLock()
  51. for _, subscriber := range m.subscribers {
  52. subscriber()
  53. }
  54. m.mut.RUnlock()
  55. }
  56. func (m *Mapping) Protocol() Protocol {
  57. return m.protocol
  58. }
  59. func (m *Mapping) Address() Address {
  60. return m.address
  61. }
  62. func (m *Mapping) ExternalAddresses() []Address {
  63. m.mut.RLock()
  64. addrs := make([]Address, 0, len(m.extAddresses))
  65. for _, addr := range m.extAddresses {
  66. addrs = append(addrs, addr...)
  67. }
  68. m.mut.RUnlock()
  69. return addrs
  70. }
  71. func (m *Mapping) OnChanged(subscribed MappingChangeSubscriber) {
  72. m.mut.Lock()
  73. m.subscribers = append(m.subscribers, subscribed)
  74. m.mut.Unlock()
  75. }
  76. func (m *Mapping) String() string {
  77. return fmt.Sprintf("%s/%s", m.address, m.protocol)
  78. }
  79. func (m *Mapping) GoString() string {
  80. return m.String()
  81. }
  82. // Checks if the mappings local IP address matches the IP address of the gateway
  83. // For example, if we are explicitly listening on 192.168.0.12, there is no
  84. // point trying to acquire a mapping on a gateway to which the local IP is
  85. // 10.0.0.1. Fallback to true if any of the IPs is not there.
  86. func (m *Mapping) validGateway(ip net.IP) bool {
  87. if m.address.IP == nil || ip == nil || m.address.IP.IsUnspecified() || ip.IsUnspecified() {
  88. return true
  89. }
  90. return m.address.IP.Equal(ip)
  91. }
  92. // Address is essentially net.TCPAddr yet is more general, and has a few helper
  93. // methods which reduce boilerplate code.
  94. type Address struct {
  95. IP net.IP
  96. Port int
  97. }
  98. func (a Address) Equal(b Address) bool {
  99. return a.Port == b.Port && a.IP.Equal(b.IP)
  100. }
  101. func (a Address) String() string {
  102. var ipStr string
  103. if a.IP == nil {
  104. ipStr = net.IPv4zero.String()
  105. } else {
  106. ipStr = a.IP.String()
  107. }
  108. return net.JoinHostPort(ipStr, strconv.Itoa(a.Port))
  109. }
  110. func (a Address) GoString() string {
  111. return a.String()
  112. }