interface.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. package nebula
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "net/netip"
  8. "runtime"
  9. "sync"
  10. "sync/atomic"
  11. "time"
  12. "github.com/gaissmai/bart"
  13. "github.com/rcrowley/go-metrics"
  14. "github.com/sirupsen/logrus"
  15. "github.com/slackhq/nebula/config"
  16. "github.com/slackhq/nebula/firewall"
  17. "github.com/slackhq/nebula/header"
  18. "github.com/slackhq/nebula/overlay"
  19. "github.com/slackhq/nebula/packet"
  20. "github.com/slackhq/nebula/udp"
  21. )
  22. const (
  23. mtu = 9001
  24. inboundBatchSize = 32
  25. outboundBatchSize = 32
  26. batchFlushInterval = 50 * time.Microsecond
  27. maxOutstandingBatches = 1028
  28. )
  29. type InterfaceConfig struct {
  30. HostMap *HostMap
  31. Outside udp.Conn
  32. Inside overlay.Device
  33. pki *PKI
  34. Cipher string
  35. Firewall *Firewall
  36. ServeDns bool
  37. HandshakeManager *HandshakeManager
  38. lightHouse *LightHouse
  39. connectionManager *connectionManager
  40. DropLocalBroadcast bool
  41. DropMulticast bool
  42. routines int
  43. MessageMetrics *MessageMetrics
  44. version string
  45. relayManager *relayManager
  46. punchy *Punchy
  47. tryPromoteEvery uint32
  48. reQueryEvery uint32
  49. reQueryWait time.Duration
  50. ConntrackCacheTimeout time.Duration
  51. l *logrus.Logger
  52. }
  53. type Interface struct {
  54. hostMap *HostMap
  55. outside udp.Conn
  56. inside overlay.Device
  57. pki *PKI
  58. firewall *Firewall
  59. connectionManager *connectionManager
  60. handshakeManager *HandshakeManager
  61. serveDns bool
  62. createTime time.Time
  63. lightHouse *LightHouse
  64. myBroadcastAddrsTable *bart.Lite
  65. myVpnAddrs []netip.Addr // A list of addresses assigned to us via our certificate
  66. myVpnAddrsTable *bart.Lite
  67. myVpnNetworks []netip.Prefix // A list of networks assigned to us via our certificate
  68. myVpnNetworksTable *bart.Lite
  69. dropLocalBroadcast bool
  70. dropMulticast bool
  71. routines int
  72. disconnectInvalid atomic.Bool
  73. closed atomic.Bool
  74. relayManager *relayManager
  75. tryPromoteEvery atomic.Uint32
  76. reQueryEvery atomic.Uint32
  77. reQueryWait atomic.Int64
  78. sendRecvErrorConfig sendRecvErrorConfig
  79. // rebindCount is used to decide if an active tunnel should trigger a punch notification through a lighthouse
  80. rebindCount int8
  81. version string
  82. conntrackCacheTimeout time.Duration
  83. writers []udp.Conn
  84. readers []io.ReadWriteCloser
  85. wg sync.WaitGroup
  86. metricHandshakes metrics.Histogram
  87. messageMetrics *MessageMetrics
  88. cachedPacketMetrics *cachedPacketMetrics
  89. l *logrus.Logger
  90. inPool sync.Pool
  91. inbound []chan *packetBatch
  92. outPool sync.Pool
  93. outbound []chan *outboundBatch
  94. packetBatchPool sync.Pool
  95. outboundBatchPool sync.Pool
  96. }
  97. type packetBatch struct {
  98. packets []*packet.Packet
  99. }
  100. func newPacketBatch() *packetBatch {
  101. return &packetBatch{
  102. packets: make([]*packet.Packet, 0, inboundBatchSize),
  103. }
  104. }
  105. func (b *packetBatch) add(p *packet.Packet) {
  106. b.packets = append(b.packets, p)
  107. }
  108. func (b *packetBatch) reset() {
  109. for i := range b.packets {
  110. b.packets[i] = nil
  111. }
  112. b.packets = b.packets[:0]
  113. }
  114. func (f *Interface) getPacketBatch() *packetBatch {
  115. if v := f.packetBatchPool.Get(); v != nil {
  116. b := v.(*packetBatch)
  117. b.reset()
  118. return b
  119. }
  120. return newPacketBatch()
  121. }
  122. func (f *Interface) releasePacketBatch(b *packetBatch) {
  123. b.reset()
  124. f.packetBatchPool.Put(b)
  125. }
  126. type outboundBatch struct {
  127. payloads []*[]byte
  128. }
  129. func newOutboundBatch() *outboundBatch {
  130. return &outboundBatch{payloads: make([]*[]byte, 0, outboundBatchSize)}
  131. }
  132. func (b *outboundBatch) add(buf *[]byte) {
  133. b.payloads = append(b.payloads, buf)
  134. }
  135. func (b *outboundBatch) reset() {
  136. for i := range b.payloads {
  137. b.payloads[i] = nil
  138. }
  139. b.payloads = b.payloads[:0]
  140. }
  141. func (f *Interface) getOutboundBatch() *outboundBatch {
  142. if v := f.outboundBatchPool.Get(); v != nil {
  143. b := v.(*outboundBatch)
  144. b.reset()
  145. return b
  146. }
  147. return newOutboundBatch()
  148. }
  149. func (f *Interface) releaseOutboundBatch(b *outboundBatch) {
  150. b.reset()
  151. f.outboundBatchPool.Put(b)
  152. }
  153. type EncWriter interface {
  154. SendVia(via *HostInfo,
  155. relay *Relay,
  156. ad,
  157. nb,
  158. out []byte,
  159. nocopy bool,
  160. )
  161. SendMessageToVpnAddr(t header.MessageType, st header.MessageSubType, vpnAddr netip.Addr, p, nb, out []byte)
  162. SendMessageToHostInfo(t header.MessageType, st header.MessageSubType, hostinfo *HostInfo, p, nb, out []byte)
  163. Handshake(vpnAddr netip.Addr)
  164. GetHostInfo(vpnAddr netip.Addr) *HostInfo
  165. GetCertState() *CertState
  166. }
  167. type sendRecvErrorConfig uint8
  168. const (
  169. sendRecvErrorAlways sendRecvErrorConfig = iota
  170. sendRecvErrorNever
  171. sendRecvErrorPrivate
  172. )
  173. func (s sendRecvErrorConfig) ShouldSendRecvError(endpoint netip.AddrPort) bool {
  174. switch s {
  175. case sendRecvErrorPrivate:
  176. return endpoint.Addr().IsPrivate()
  177. case sendRecvErrorAlways:
  178. return true
  179. case sendRecvErrorNever:
  180. return false
  181. default:
  182. panic(fmt.Errorf("invalid sendRecvErrorConfig value: %d", s))
  183. }
  184. }
  185. func (s sendRecvErrorConfig) String() string {
  186. switch s {
  187. case sendRecvErrorAlways:
  188. return "always"
  189. case sendRecvErrorNever:
  190. return "never"
  191. case sendRecvErrorPrivate:
  192. return "private"
  193. default:
  194. return fmt.Sprintf("invalid(%d)", s)
  195. }
  196. }
  197. func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) {
  198. if c.Outside == nil {
  199. return nil, errors.New("no outside connection")
  200. }
  201. if c.Inside == nil {
  202. return nil, errors.New("no inside interface (tun)")
  203. }
  204. if c.pki == nil {
  205. return nil, errors.New("no certificate state")
  206. }
  207. if c.Firewall == nil {
  208. return nil, errors.New("no firewall rules")
  209. }
  210. if c.connectionManager == nil {
  211. return nil, errors.New("no connection manager")
  212. }
  213. cs := c.pki.getCertState()
  214. ifce := &Interface{
  215. pki: c.pki,
  216. hostMap: c.HostMap,
  217. outside: c.Outside,
  218. inside: c.Inside,
  219. firewall: c.Firewall,
  220. serveDns: c.ServeDns,
  221. handshakeManager: c.HandshakeManager,
  222. createTime: time.Now(),
  223. lightHouse: c.lightHouse,
  224. dropLocalBroadcast: c.DropLocalBroadcast,
  225. dropMulticast: c.DropMulticast,
  226. routines: c.routines,
  227. version: c.version,
  228. writers: make([]udp.Conn, c.routines),
  229. readers: make([]io.ReadWriteCloser, c.routines),
  230. myVpnNetworks: cs.myVpnNetworks,
  231. myVpnNetworksTable: cs.myVpnNetworksTable,
  232. myVpnAddrs: cs.myVpnAddrs,
  233. myVpnAddrsTable: cs.myVpnAddrsTable,
  234. myBroadcastAddrsTable: cs.myVpnBroadcastAddrsTable,
  235. relayManager: c.relayManager,
  236. connectionManager: c.connectionManager,
  237. conntrackCacheTimeout: c.ConntrackCacheTimeout,
  238. metricHandshakes: metrics.GetOrRegisterHistogram("handshakes", nil, metrics.NewExpDecaySample(1028, 0.015)),
  239. messageMetrics: c.MessageMetrics,
  240. cachedPacketMetrics: &cachedPacketMetrics{
  241. sent: metrics.GetOrRegisterCounter("hostinfo.cached_packets.sent", nil),
  242. dropped: metrics.GetOrRegisterCounter("hostinfo.cached_packets.dropped", nil),
  243. },
  244. //TODO: configurable size
  245. inbound: make([]chan *packetBatch, c.routines),
  246. outbound: make([]chan *outboundBatch, c.routines),
  247. l: c.l,
  248. }
  249. for i := 0; i < c.routines; i++ {
  250. ifce.inbound[i] = make(chan *packetBatch, maxOutstandingBatches)
  251. ifce.outbound[i] = make(chan *outboundBatch, maxOutstandingBatches)
  252. }
  253. ifce.inPool = sync.Pool{New: func() any {
  254. return packet.New()
  255. }}
  256. ifce.outPool = sync.Pool{New: func() any {
  257. t := make([]byte, mtu)
  258. return &t
  259. }}
  260. ifce.packetBatchPool = sync.Pool{New: func() any {
  261. return newPacketBatch()
  262. }}
  263. ifce.outboundBatchPool = sync.Pool{New: func() any {
  264. return newOutboundBatch()
  265. }}
  266. ifce.tryPromoteEvery.Store(c.tryPromoteEvery)
  267. ifce.reQueryEvery.Store(c.reQueryEvery)
  268. ifce.reQueryWait.Store(int64(c.reQueryWait))
  269. ifce.connectionManager.intf = ifce
  270. return ifce, nil
  271. }
  272. // activate creates the interface on the host. After the interface is created, any
  273. // other services that want to bind listeners to its IP may do so successfully. However,
  274. // the interface isn't going to process anything until run() is called.
  275. func (f *Interface) activate() error {
  276. // actually turn on tun dev
  277. addr, err := f.outside.LocalAddr()
  278. if err != nil {
  279. f.l.WithError(err).Error("Failed to get udp listen address")
  280. }
  281. f.l.WithField("interface", f.inside.Name()).WithField("networks", f.myVpnNetworks).
  282. WithField("build", f.version).WithField("udpAddr", addr).
  283. WithField("boringcrypto", boringEnabled()).
  284. Info("Nebula interface is active")
  285. metrics.GetOrRegisterGauge("routines", nil).Update(int64(f.routines))
  286. // Prepare n tun queues
  287. var reader io.ReadWriteCloser = f.inside
  288. for i := 0; i < f.routines; i++ {
  289. if i > 0 {
  290. reader, err = f.inside.NewMultiQueueReader()
  291. if err != nil {
  292. return err
  293. }
  294. }
  295. f.readers[i] = reader
  296. }
  297. if err = f.inside.Activate(); err != nil {
  298. f.inside.Close()
  299. return err
  300. }
  301. return nil
  302. }
  303. func (f *Interface) run(c context.Context) (func(), error) {
  304. for i := 0; i < f.routines; i++ {
  305. // Launch n queues to read packets from udp
  306. f.wg.Add(1)
  307. go f.listenOut(i)
  308. // Launch n queues to read packets from tun dev
  309. f.wg.Add(1)
  310. go f.listenIn(f.readers[i], i)
  311. // Launch n queues to read packets from tun dev
  312. f.wg.Add(1)
  313. go f.workerIn(i, c)
  314. // Launch n queues to read packets from tun dev
  315. f.wg.Add(1)
  316. go f.workerOut(i, c)
  317. }
  318. return f.wg.Wait, nil
  319. }
  320. func (f *Interface) listenOut(i int) {
  321. runtime.LockOSThread()
  322. var li udp.Conn
  323. if i > 0 {
  324. li = f.writers[i]
  325. } else {
  326. li = f.outside
  327. }
  328. batch := f.getPacketBatch()
  329. lastFlush := time.Now()
  330. flush := func(force bool) {
  331. if len(batch.packets) == 0 {
  332. if force {
  333. f.releasePacketBatch(batch)
  334. }
  335. return
  336. }
  337. f.inbound[i] <- batch
  338. batch = f.getPacketBatch()
  339. lastFlush = time.Now()
  340. }
  341. err := li.ListenOut(func(fromUdpAddr netip.AddrPort, payload []byte) {
  342. p := f.inPool.Get().(*packet.Packet)
  343. p.Payload = p.Payload[:mtu]
  344. copy(p.Payload, payload)
  345. p.Payload = p.Payload[:len(payload)]
  346. p.Addr = fromUdpAddr
  347. batch.add(p)
  348. if len(batch.packets) >= inboundBatchSize || time.Since(lastFlush) >= batchFlushInterval {
  349. flush(false)
  350. }
  351. })
  352. if len(batch.packets) > 0 {
  353. f.inbound[i] <- batch
  354. } else {
  355. f.releasePacketBatch(batch)
  356. }
  357. if err != nil && !f.closed.Load() {
  358. f.l.WithError(err).Error("Error while reading packet inbound packet, closing")
  359. //TODO: Trigger Control to close
  360. }
  361. f.l.Debugf("underlay reader %v is done", i)
  362. f.wg.Done()
  363. }
  364. func (f *Interface) listenIn(reader io.ReadWriteCloser, i int) {
  365. runtime.LockOSThread()
  366. batch := f.getOutboundBatch()
  367. lastFlush := time.Now()
  368. flush := func(force bool) {
  369. if len(batch.payloads) == 0 {
  370. if force {
  371. f.releaseOutboundBatch(batch)
  372. }
  373. return
  374. }
  375. f.outbound[i] <- batch
  376. batch = f.getOutboundBatch()
  377. lastFlush = time.Now()
  378. }
  379. for {
  380. p := f.outPool.Get().(*[]byte)
  381. *p = (*p)[:mtu]
  382. n, err := reader.Read(*p)
  383. if err != nil {
  384. if !f.closed.Load() {
  385. f.l.WithError(err).Error("Error while reading outbound packet, closing")
  386. //TODO: Trigger Control to close
  387. }
  388. break
  389. }
  390. *p = (*p)[:n]
  391. batch.add(p)
  392. if len(batch.payloads) >= outboundBatchSize || time.Since(lastFlush) >= batchFlushInterval {
  393. flush(false)
  394. }
  395. }
  396. if len(batch.payloads) > 0 {
  397. f.outbound[i] <- batch
  398. } else {
  399. f.releaseOutboundBatch(batch)
  400. }
  401. f.l.Debugf("overlay reader %v is done", i)
  402. f.wg.Done()
  403. }
  404. func (f *Interface) workerIn(i int, ctx context.Context) {
  405. lhh := f.lightHouse.NewRequestHandler()
  406. conntrackCache := firewall.NewConntrackCacheTicker(f.conntrackCacheTimeout)
  407. fwPacket2 := &firewall.Packet{}
  408. nb2 := make([]byte, 12, 12)
  409. result2 := make([]byte, mtu)
  410. h := &header.H{}
  411. for {
  412. select {
  413. case batch := <-f.inbound[i]:
  414. for _, p := range batch.packets {
  415. f.readOutsidePackets(p.Addr, nil, result2[:0], p.Payload, h, fwPacket2, lhh, nb2, i, conntrackCache.Get(f.l))
  416. p.Payload = p.Payload[:mtu]
  417. f.inPool.Put(p)
  418. }
  419. f.releasePacketBatch(batch)
  420. case <-ctx.Done():
  421. f.wg.Done()
  422. return
  423. }
  424. }
  425. }
  426. func (f *Interface) workerOut(i int, ctx context.Context) {
  427. conntrackCache := firewall.NewConntrackCacheTicker(f.conntrackCacheTimeout)
  428. fwPacket1 := &firewall.Packet{}
  429. nb1 := make([]byte, 12, 12)
  430. result1 := make([]byte, mtu)
  431. for {
  432. select {
  433. case batch := <-f.outbound[i]:
  434. for _, data := range batch.payloads {
  435. f.consumeInsidePacket(*data, fwPacket1, nb1, result1, i, conntrackCache.Get(f.l))
  436. *data = (*data)[:mtu]
  437. f.outPool.Put(data)
  438. }
  439. f.releaseOutboundBatch(batch)
  440. case <-ctx.Done():
  441. f.wg.Done()
  442. return
  443. }
  444. }
  445. }
  446. func (f *Interface) RegisterConfigChangeCallbacks(c *config.C) {
  447. c.RegisterReloadCallback(f.reloadFirewall)
  448. c.RegisterReloadCallback(f.reloadSendRecvError)
  449. c.RegisterReloadCallback(f.reloadDisconnectInvalid)
  450. c.RegisterReloadCallback(f.reloadMisc)
  451. for _, udpConn := range f.writers {
  452. c.RegisterReloadCallback(udpConn.ReloadConfig)
  453. }
  454. }
  455. func (f *Interface) reloadDisconnectInvalid(c *config.C) {
  456. initial := c.InitialLoad()
  457. if initial || c.HasChanged("pki.disconnect_invalid") {
  458. f.disconnectInvalid.Store(c.GetBool("pki.disconnect_invalid", true))
  459. if !initial {
  460. f.l.Infof("pki.disconnect_invalid changed to %v", f.disconnectInvalid.Load())
  461. }
  462. }
  463. }
  464. func (f *Interface) reloadFirewall(c *config.C) {
  465. //TODO: need to trigger/detect if the certificate changed too
  466. if c.HasChanged("firewall") == false {
  467. f.l.Debug("No firewall config change detected")
  468. return
  469. }
  470. fw, err := NewFirewallFromConfig(f.l, f.pki.getCertState(), c)
  471. if err != nil {
  472. f.l.WithError(err).Error("Error while creating firewall during reload")
  473. return
  474. }
  475. oldFw := f.firewall
  476. conntrack := oldFw.Conntrack
  477. conntrack.Lock()
  478. defer conntrack.Unlock()
  479. fw.rulesVersion = oldFw.rulesVersion + 1
  480. // If rulesVersion is back to zero, we have wrapped all the way around. Be
  481. // safe and just reset conntrack in this case.
  482. if fw.rulesVersion == 0 {
  483. f.l.WithField("firewallHashes", fw.GetRuleHashes()).
  484. WithField("oldFirewallHashes", oldFw.GetRuleHashes()).
  485. WithField("rulesVersion", fw.rulesVersion).
  486. Warn("firewall rulesVersion has overflowed, resetting conntrack")
  487. } else {
  488. fw.Conntrack = conntrack
  489. }
  490. f.firewall = fw
  491. oldFw.Destroy()
  492. f.l.WithField("firewallHashes", fw.GetRuleHashes()).
  493. WithField("oldFirewallHashes", oldFw.GetRuleHashes()).
  494. WithField("rulesVersion", fw.rulesVersion).
  495. Info("New firewall has been installed")
  496. }
  497. func (f *Interface) reloadSendRecvError(c *config.C) {
  498. if c.InitialLoad() || c.HasChanged("listen.send_recv_error") {
  499. stringValue := c.GetString("listen.send_recv_error", "always")
  500. switch stringValue {
  501. case "always":
  502. f.sendRecvErrorConfig = sendRecvErrorAlways
  503. case "never":
  504. f.sendRecvErrorConfig = sendRecvErrorNever
  505. case "private":
  506. f.sendRecvErrorConfig = sendRecvErrorPrivate
  507. default:
  508. if c.GetBool("listen.send_recv_error", true) {
  509. f.sendRecvErrorConfig = sendRecvErrorAlways
  510. } else {
  511. f.sendRecvErrorConfig = sendRecvErrorNever
  512. }
  513. }
  514. f.l.WithField("sendRecvError", f.sendRecvErrorConfig.String()).
  515. Info("Loaded send_recv_error config")
  516. }
  517. }
  518. func (f *Interface) reloadMisc(c *config.C) {
  519. if c.HasChanged("counters.try_promote") {
  520. n := c.GetUint32("counters.try_promote", defaultPromoteEvery)
  521. f.tryPromoteEvery.Store(n)
  522. f.l.Info("counters.try_promote has changed")
  523. }
  524. if c.HasChanged("counters.requery_every_packets") {
  525. n := c.GetUint32("counters.requery_every_packets", defaultReQueryEvery)
  526. f.reQueryEvery.Store(n)
  527. f.l.Info("counters.requery_every_packets has changed")
  528. }
  529. if c.HasChanged("timers.requery_wait_duration") {
  530. n := c.GetDuration("timers.requery_wait_duration", defaultReQueryWait)
  531. f.reQueryWait.Store(int64(n))
  532. f.l.Info("timers.requery_wait_duration has changed")
  533. }
  534. }
  535. func (f *Interface) emitStats(ctx context.Context, i time.Duration) {
  536. ticker := time.NewTicker(i)
  537. defer ticker.Stop()
  538. udpStats := udp.NewUDPStatsEmitter(f.writers)
  539. certExpirationGauge := metrics.GetOrRegisterGauge("certificate.ttl_seconds", nil)
  540. certInitiatingVersion := metrics.GetOrRegisterGauge("certificate.initiating_version", nil)
  541. certMaxVersion := metrics.GetOrRegisterGauge("certificate.max_version", nil)
  542. for {
  543. select {
  544. case <-ctx.Done():
  545. return
  546. case <-ticker.C:
  547. f.firewall.EmitStats()
  548. f.handshakeManager.EmitStats()
  549. udpStats()
  550. certState := f.pki.getCertState()
  551. defaultCrt := certState.GetDefaultCertificate()
  552. certExpirationGauge.Update(int64(defaultCrt.NotAfter().Sub(time.Now()) / time.Second))
  553. certInitiatingVersion.Update(int64(defaultCrt.Version()))
  554. // Report the max certificate version we are capable of using
  555. if certState.v2Cert != nil {
  556. certMaxVersion.Update(int64(certState.v2Cert.Version()))
  557. } else {
  558. certMaxVersion.Update(int64(certState.v1Cert.Version()))
  559. }
  560. }
  561. }
  562. }
  563. func (f *Interface) GetHostInfo(vpnIp netip.Addr) *HostInfo {
  564. return f.hostMap.QueryVpnAddr(vpnIp)
  565. }
  566. func (f *Interface) GetCertState() *CertState {
  567. return f.pki.getCertState()
  568. }
  569. func (f *Interface) Close() error {
  570. f.closed.Store(true)
  571. // Release the udp readers
  572. for _, u := range f.writers {
  573. err := u.Close()
  574. if err != nil {
  575. f.l.WithError(err).Error("Error while closing udp socket")
  576. }
  577. }
  578. // Release the tun readers
  579. for _, u := range f.readers {
  580. err := u.Close()
  581. if err != nil {
  582. f.l.WithError(err).Error("Error while closing tun device")
  583. }
  584. }
  585. return nil
  586. }