linuxdnsfight.go 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. //go:build linux && !android
  4. // Package linuxdnsfight provides Linux support for detecting DNS fights
  5. // (inotify watching of /etc/resolv.conf).
  6. package linuxdnsfight
  7. import (
  8. "context"
  9. "fmt"
  10. "github.com/illarion/gonotify/v3"
  11. "tailscale.com/net/dns"
  12. )
  13. func init() {
  14. dns.HookWatchFile.Set(watchFile)
  15. }
  16. // watchFile sets up an inotify watch for a given directory and
  17. // calls the callback function every time a particular file is changed.
  18. // The filename should be located in the provided directory.
  19. func watchFile(ctx context.Context, dir, filename string, cb func()) error {
  20. ctx, cancel := context.WithCancel(ctx)
  21. defer cancel()
  22. const events = gonotify.IN_ATTRIB |
  23. gonotify.IN_CLOSE_WRITE |
  24. gonotify.IN_CREATE |
  25. gonotify.IN_DELETE |
  26. gonotify.IN_MODIFY |
  27. gonotify.IN_MOVE
  28. watcher, err := gonotify.NewDirWatcher(ctx, events, dir)
  29. if err != nil {
  30. return fmt.Errorf("NewDirWatcher: %w", err)
  31. }
  32. for {
  33. select {
  34. case event := <-watcher.C:
  35. if event.Name == filename {
  36. cb()
  37. }
  38. case <-ctx.Done():
  39. return ctx.Err()
  40. }
  41. }
  42. }