tun_bsd_dev.go 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. //go:build (openbsd || netbsd) && !e2e_testing
  2. package overlay
  3. import (
  4. "errors"
  5. "fmt"
  6. "log/slog"
  7. "os"
  8. "regexp"
  9. "runtime"
  10. "golang.org/x/sys/unix"
  11. )
  12. var deviceNameRE = regexp.MustCompile(`^tun[0-9]+$`)
  13. // tunDevNeedsRestart is true when tun.dev asks for a particular tun that isn't the running one. Anything else takes the
  14. // first free one, and the one we have will do
  15. func tunDevNeedsRestart(name, running string) bool {
  16. return deviceNameRE.MatchString(name) && name != running
  17. }
  18. // openTun opens /dev/name, or the first /dev/tunN nothing else has open when name is empty or not tunN
  19. func openTun(l *slog.Logger, name string) (int, string, error) {
  20. if name != "" && !deviceNameRE.MatchString(name) {
  21. // The name doesn't mean anything here, so like darwin a bad one isn't worth refusing to start over
  22. l.Warn("interface name must be tun[0-9]+ on "+runtime.GOOS+", ignoring", "name", name)
  23. name = ""
  24. }
  25. if name != "" {
  26. fd, err := unix.Open("/dev/"+name, os.O_RDWR, 0)
  27. return fd, name, err
  28. }
  29. for i := 0; ; i++ {
  30. name = fmt.Sprintf("tun%d", i)
  31. fd, err := unix.Open("/dev/"+name, os.O_RDWR, 0)
  32. if err == nil {
  33. return fd, name, nil
  34. }
  35. if !errors.Is(err, unix.EBUSY) {
  36. return -1, "", fmt.Errorf("no free tun device, %s: %w", name, err)
  37. }
  38. }
  39. }