service.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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. "context"
  9. "fmt"
  10. "hash/fnv"
  11. "math/rand"
  12. "net"
  13. stdsync "sync"
  14. "time"
  15. "github.com/syncthing/syncthing/lib/config"
  16. "github.com/syncthing/syncthing/lib/protocol"
  17. "github.com/syncthing/syncthing/lib/sync"
  18. )
  19. // Service runs a loop for discovery of IGDs (Internet Gateway Devices) and
  20. // setup/renewal of a port mapping.
  21. type Service struct {
  22. id protocol.DeviceID
  23. cfg config.Wrapper
  24. processScheduled chan struct{}
  25. mappings []*Mapping
  26. enabled bool
  27. mut sync.RWMutex
  28. }
  29. func NewService(id protocol.DeviceID, cfg config.Wrapper) *Service {
  30. s := &Service{
  31. id: id,
  32. cfg: cfg,
  33. processScheduled: make(chan struct{}, 1),
  34. mut: sync.NewRWMutex(),
  35. }
  36. cfgCopy := cfg.RawCopy()
  37. s.CommitConfiguration(cfgCopy, cfgCopy)
  38. return s
  39. }
  40. func (s *Service) VerifyConfiguration(from, to config.Configuration) error {
  41. return nil
  42. }
  43. func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
  44. s.mut.Lock()
  45. if !s.enabled && to.Options.NATEnabled {
  46. l.Debugln("Starting NAT service")
  47. s.enabled = true
  48. s.scheduleProcess()
  49. } else if s.enabled && !to.Options.NATEnabled {
  50. l.Debugln("Stopping NAT service")
  51. s.enabled = false
  52. }
  53. s.mut.Unlock()
  54. return true
  55. }
  56. func (s *Service) Serve(ctx context.Context) error {
  57. s.cfg.Subscribe(s)
  58. defer s.cfg.Unsubscribe(s)
  59. announce := stdsync.Once{}
  60. timer := time.NewTimer(0)
  61. for {
  62. select {
  63. case <-timer.C:
  64. case <-s.processScheduled:
  65. if !timer.Stop() {
  66. select {
  67. case <-timer.C:
  68. default:
  69. }
  70. }
  71. case <-ctx.Done():
  72. timer.Stop()
  73. s.mut.RLock()
  74. for _, mapping := range s.mappings {
  75. mapping.clearAddresses()
  76. }
  77. s.mut.RUnlock()
  78. return ctx.Err()
  79. }
  80. s.mut.RLock()
  81. enabled := s.enabled
  82. s.mut.RUnlock()
  83. if !enabled {
  84. continue
  85. }
  86. found, renewIn := s.process(ctx)
  87. timer.Reset(renewIn)
  88. if found != -1 {
  89. announce.Do(func() {
  90. suffix := "s"
  91. if found == 1 {
  92. suffix = ""
  93. }
  94. l.Infoln("Detected", found, "NAT service"+suffix)
  95. })
  96. }
  97. }
  98. }
  99. func (s *Service) process(ctx context.Context) (int, time.Duration) {
  100. // toRenew are mappings which are due for renewal
  101. // toUpdate are the remaining mappings, which will only be updated if one of
  102. // the old IGDs has gone away, or a new IGD has appeared, but only if we
  103. // actually need to perform a renewal.
  104. var toRenew, toUpdate []*Mapping
  105. renewIn := time.Duration(s.cfg.Options().NATRenewalM) * time.Minute
  106. if renewIn == 0 {
  107. // We always want to do renewal so lets just pick a nice sane number.
  108. renewIn = 30 * time.Minute
  109. }
  110. s.mut.RLock()
  111. for _, mapping := range s.mappings {
  112. if mapping.expires.Before(time.Now()) {
  113. toRenew = append(toRenew, mapping)
  114. } else {
  115. toUpdate = append(toUpdate, mapping)
  116. mappingRenewIn := time.Until(mapping.expires)
  117. if mappingRenewIn < renewIn {
  118. renewIn = mappingRenewIn
  119. }
  120. }
  121. }
  122. s.mut.RUnlock()
  123. // Don't do anything, unless we really need to renew
  124. if len(toRenew) == 0 {
  125. return -1, renewIn
  126. }
  127. nats := discoverAll(ctx, time.Duration(s.cfg.Options().NATRenewalM)*time.Minute, time.Duration(s.cfg.Options().NATTimeoutS)*time.Second)
  128. for _, mapping := range toRenew {
  129. s.updateMapping(ctx, mapping, nats, true)
  130. }
  131. for _, mapping := range toUpdate {
  132. s.updateMapping(ctx, mapping, nats, false)
  133. }
  134. return len(nats), renewIn
  135. }
  136. func (s *Service) scheduleProcess() {
  137. select {
  138. case s.processScheduled <- struct{}{}: // 1-buffered
  139. default:
  140. }
  141. }
  142. func (s *Service) NewMapping(protocol Protocol, ip net.IP, port int) *Mapping {
  143. mapping := &Mapping{
  144. protocol: protocol,
  145. address: Address{
  146. IP: ip,
  147. Port: port,
  148. },
  149. extAddresses: make(map[string]Address),
  150. mut: sync.NewRWMutex(),
  151. }
  152. s.mut.Lock()
  153. s.mappings = append(s.mappings, mapping)
  154. s.mut.Unlock()
  155. s.scheduleProcess()
  156. return mapping
  157. }
  158. // RemoveMapping does not actually remove the mapping from the IGD, it just
  159. // internally removes it which stops renewing the mapping. Also, it clears any
  160. // existing mapped addresses from the mapping, which as a result should cause
  161. // discovery to reannounce the new addresses.
  162. func (s *Service) RemoveMapping(mapping *Mapping) {
  163. s.mut.Lock()
  164. defer s.mut.Unlock()
  165. for i, existing := range s.mappings {
  166. if existing == mapping {
  167. mapping.clearAddresses()
  168. last := len(s.mappings) - 1
  169. s.mappings[i] = s.mappings[last]
  170. s.mappings[last] = nil
  171. s.mappings = s.mappings[:last]
  172. return
  173. }
  174. }
  175. }
  176. // updateMapping compares the addresses of the existing mapping versus the natds
  177. // discovered, and removes any addresses of natds that do not exist, or tries to
  178. // acquire mappings for natds which the mapping was unaware of before.
  179. // Optionally takes renew flag which indicates whether or not we should renew
  180. // mappings with existing natds
  181. func (s *Service) updateMapping(ctx context.Context, mapping *Mapping, nats map[string]Device, renew bool) {
  182. var added, removed []Address
  183. renewalTime := time.Duration(s.cfg.Options().NATRenewalM) * time.Minute
  184. mapping.expires = time.Now().Add(renewalTime)
  185. newAdded, newRemoved := s.verifyExistingMappings(ctx, mapping, nats, renew)
  186. added = append(added, newAdded...)
  187. removed = append(removed, newRemoved...)
  188. newAdded, newRemoved = s.acquireNewMappings(ctx, mapping, nats)
  189. added = append(added, newAdded...)
  190. removed = append(removed, newRemoved...)
  191. if len(added) > 0 || len(removed) > 0 {
  192. mapping.notify(added, removed)
  193. }
  194. }
  195. func (s *Service) verifyExistingMappings(ctx context.Context, mapping *Mapping, nats map[string]Device, renew bool) ([]Address, []Address) {
  196. var added, removed []Address
  197. leaseTime := time.Duration(s.cfg.Options().NATLeaseM) * time.Minute
  198. for id, address := range mapping.addressMap() {
  199. select {
  200. case <-ctx.Done():
  201. return nil, nil
  202. default:
  203. }
  204. // Delete addresses for NATDevice's that do not exist anymore
  205. nat, ok := nats[id]
  206. if !ok {
  207. mapping.removeAddress(id)
  208. removed = append(removed, address)
  209. continue
  210. } else if renew {
  211. // Only perform renewals on the nat's that have the right local IP
  212. // address
  213. localIP := nat.GetLocalIPAddress()
  214. if !mapping.validGateway(localIP) {
  215. l.Debugf("Skipping %s for %s because of IP mismatch. %s != %s", id, mapping, mapping.address.IP, localIP)
  216. continue
  217. }
  218. l.Debugf("Renewing %s -> %s mapping on %s", mapping, address, id)
  219. addr, err := s.tryNATDevice(ctx, nat, mapping.address.Port, address.Port, leaseTime)
  220. if err != nil {
  221. l.Debugf("Failed to renew %s -> mapping on %s", mapping, address, id)
  222. mapping.removeAddress(id)
  223. removed = append(removed, address)
  224. continue
  225. }
  226. l.Debugf("Renewed %s -> %s mapping on %s", mapping, address, id)
  227. if !addr.Equal(address) {
  228. mapping.removeAddress(id)
  229. mapping.setAddress(id, addr)
  230. removed = append(removed, address)
  231. added = append(added, address)
  232. }
  233. }
  234. }
  235. return added, removed
  236. }
  237. func (s *Service) acquireNewMappings(ctx context.Context, mapping *Mapping, nats map[string]Device) ([]Address, []Address) {
  238. var added, removed []Address
  239. leaseTime := time.Duration(s.cfg.Options().NATLeaseM) * time.Minute
  240. addrMap := mapping.addressMap()
  241. for id, nat := range nats {
  242. select {
  243. case <-ctx.Done():
  244. return nil, nil
  245. default:
  246. }
  247. if _, ok := addrMap[id]; ok {
  248. continue
  249. }
  250. // Only perform mappings on the nat's that have the right local IP
  251. // address
  252. localIP := nat.GetLocalIPAddress()
  253. if !mapping.validGateway(localIP) {
  254. l.Debugf("Skipping %s for %s because of IP mismatch. %s != %s", id, mapping, mapping.address.IP, localIP)
  255. continue
  256. }
  257. l.Debugf("Acquiring %s mapping on %s", mapping, id)
  258. addr, err := s.tryNATDevice(ctx, nat, mapping.address.Port, 0, leaseTime)
  259. if err != nil {
  260. l.Debugf("Failed to acquire %s mapping on %s", mapping, id)
  261. continue
  262. }
  263. l.Debugf("Acquired %s -> %s mapping on %s", mapping, addr, id)
  264. mapping.setAddress(id, addr)
  265. added = append(added, addr)
  266. }
  267. return added, removed
  268. }
  269. // tryNATDevice tries to acquire a port mapping for the given internal address to
  270. // the given external port. If external port is 0, picks a pseudo-random port.
  271. func (s *Service) tryNATDevice(ctx context.Context, natd Device, intPort, extPort int, leaseTime time.Duration) (Address, error) {
  272. var err error
  273. var port int
  274. // Generate a predictable random which is based on device ID + local port + hash of the device ID
  275. // number so that the ports we'd try to acquire for the mapping would always be the same for the
  276. // same device trying to get the same internal port.
  277. predictableRand := rand.New(rand.NewSource(int64(s.id.Short()) + int64(intPort) + hash(natd.ID())))
  278. if extPort != 0 {
  279. // First try renewing our existing mapping, if we have one.
  280. name := fmt.Sprintf("syncthing-%d", extPort)
  281. port, err = natd.AddPortMapping(ctx, TCP, intPort, extPort, name, leaseTime)
  282. if err == nil {
  283. extPort = port
  284. goto findIP
  285. }
  286. l.Debugln("Error extending lease on", natd.ID(), err)
  287. }
  288. for i := 0; i < 10; i++ {
  289. select {
  290. case <-ctx.Done():
  291. return Address{}, ctx.Err()
  292. default:
  293. }
  294. // Then try up to ten random ports.
  295. extPort = 1024 + predictableRand.Intn(65535-1024)
  296. name := fmt.Sprintf("syncthing-%d", extPort)
  297. port, err = natd.AddPortMapping(ctx, TCP, intPort, extPort, name, leaseTime)
  298. if err == nil {
  299. extPort = port
  300. goto findIP
  301. }
  302. l.Debugln("Error getting new lease on", natd.ID(), err)
  303. }
  304. return Address{}, err
  305. findIP:
  306. ip, err := natd.GetExternalIPAddress(ctx)
  307. if err != nil {
  308. l.Debugln("Error getting external ip on", natd.ID(), err)
  309. ip = nil
  310. }
  311. return Address{
  312. IP: ip,
  313. Port: extPort,
  314. }, nil
  315. }
  316. func (s *Service) String() string {
  317. return fmt.Sprintf("nat.Service@%p", s)
  318. }
  319. func hash(input string) int64 {
  320. h := fnv.New64a()
  321. h.Write([]byte(input))
  322. return int64(h.Sum64())
  323. }