1
0

netchange.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. package udp
  2. import (
  3. "context"
  4. "log/slog"
  5. "github.com/slackhq/nebula/config"
  6. )
  7. // NetworkChangeMonitor rebinds the udp listener when the local network moves out from under it.
  8. //
  9. // Detection lives here in the udp package, next to the socket it concerns and the platform matrix that already knows
  10. // which sockets go stale. What to do about a change — updating the lighthouse, requerying tunnels — is not the udp
  11. // package's business, so Start takes the reaction as a plain function. Passing it at Start rather than holding it
  12. // keeps this package from referencing whatever owns the rebind.
  13. //
  14. // On platforms whose sockets do not go stale, watchNetworkChanges hands back a nil channel and Start returns.
  15. type NetworkChangeMonitor struct {
  16. l *slog.Logger
  17. ctx context.Context
  18. enabled bool
  19. }
  20. // NewNetworkChangeMonitor builds a monitor for local network changes. The returned monitor is always usable: Start
  21. // is safe to call unconditionally, it no-ops when disabled or on a platform that does not need it.
  22. func NewNetworkChangeMonitor(ctx context.Context, l *slog.Logger, c *config.C) *NetworkChangeMonitor {
  23. return &NetworkChangeMonitor{
  24. l: l,
  25. ctx: ctx,
  26. enabled: c.GetBool("listen.rebind_on_network_change", true),
  27. }
  28. }
  29. // Start watches for network changes until the context is cancelled, calling rebind once per settled change. It
  30. // blocks, so callers run it in a goroutine, and it no-ops when disabled, unsupported, or with nothing to rebind.
  31. func (m *NetworkChangeMonitor) Start(rebind func()) {
  32. if !m.enabled || rebind == nil || m.ctx.Err() != nil {
  33. return
  34. }
  35. changes, err := watchNetworkChanges(m.ctx, m.l)
  36. if err != nil {
  37. // Not fatal. Everything else still works, we just won't notice a network change on our own.
  38. m.l.Error("Failed to watch for network changes, will not rebind the udp listener when the network moves",
  39. "error", err,
  40. )
  41. return
  42. }
  43. if changes == nil {
  44. // This platform's sockets don't go stale, so there is nothing to watch for.
  45. return
  46. }
  47. m.l.Info("Watching for network changes to rebind the udp listener")
  48. for range changes {
  49. m.l.Info("Local network changed, rebinding the udp listener")
  50. rebind()
  51. }
  52. }