1
0

netchange.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  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. if watchesNetworkChanges {
  24. c.RegisterReloadCallback(func(c *config.C, r *config.Reload) {
  25. r.RestartRequiredIfChanged("listen.rebind_on_network_change")
  26. })
  27. }
  28. return &NetworkChangeMonitor{
  29. l: l,
  30. ctx: ctx,
  31. enabled: c.GetBool("listen.rebind_on_network_change", true),
  32. }
  33. }
  34. // Start watches for network changes until the context is cancelled, calling rebind once per settled change. It
  35. // blocks, so callers run it in a goroutine, and it no-ops when disabled, unsupported, or with nothing to rebind.
  36. func (m *NetworkChangeMonitor) Start(rebind func()) {
  37. if !m.enabled || rebind == nil || m.ctx.Err() != nil {
  38. return
  39. }
  40. changes, err := watchNetworkChanges(m.ctx, m.l)
  41. if err != nil {
  42. // Not fatal. Everything else still works, we just won't notice a network change on our own.
  43. m.l.Error("Failed to watch for network changes, will not rebind the udp listener when the network moves",
  44. "error", err,
  45. )
  46. return
  47. }
  48. if changes == nil {
  49. // This platform's sockets don't go stale, so there is nothing to watch for.
  50. return
  51. }
  52. m.l.Info("Watching for network changes to rebind the udp listener")
  53. for range changes {
  54. m.l.Info("Local network changed, rebinding the udp listener")
  55. rebind()
  56. }
  57. }