iptables.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // TODO(#8502): add support for more architectures
  4. //go:build linux && (arm64 || amd64)
  5. package linuxfw
  6. import (
  7. "fmt"
  8. "os/exec"
  9. "strings"
  10. "unicode"
  11. "tailscale.com/types/logger"
  12. "tailscale.com/util/multierr"
  13. )
  14. // DebugNetfilter prints debug information about iptables rules to the
  15. // provided log function.
  16. func DebugIptables(logf logger.Logf) error {
  17. // unused.
  18. return nil
  19. }
  20. // detectIptables returns the number of iptables rules that are present in the
  21. // system, ignoring the default "ACCEPT" rule present in the standard iptables
  22. // chains.
  23. //
  24. // It only returns an error when there is no iptables binary, or when iptables -S
  25. // fails. In all other cases, it returns the number of non-default rules.
  26. //
  27. // If the iptables binary is not found, it returns an underlying exec.ErrNotFound
  28. // error.
  29. func detectIptables() (int, error) {
  30. // run "iptables -S" to get the list of rules using iptables
  31. // exec.Command returns an error if the binary is not found
  32. cmd := exec.Command("iptables", "-S")
  33. output, err := cmd.Output()
  34. ip6cmd := exec.Command("ip6tables", "-S")
  35. ip6output, ip6err := ip6cmd.Output()
  36. var allLines []string
  37. outputStr := string(output)
  38. lines := strings.Split(outputStr, "\n")
  39. ip6outputStr := string(ip6output)
  40. ip6lines := strings.Split(ip6outputStr, "\n")
  41. switch {
  42. case err == nil && ip6err == nil:
  43. allLines = append(lines, ip6lines...)
  44. case err == nil && ip6err != nil:
  45. allLines = lines
  46. case err != nil && ip6err == nil:
  47. allLines = ip6lines
  48. default:
  49. return 0, FWModeNotSupportedError{
  50. Mode: FirewallModeIPTables,
  51. Err: fmt.Errorf("iptables command run fail: %w", multierr.New(err, ip6err)),
  52. }
  53. }
  54. // count the number of non-default rules
  55. count := 0
  56. for _, line := range allLines {
  57. trimmedLine := strings.TrimLeftFunc(line, unicode.IsSpace)
  58. if line != "" && strings.HasPrefix(trimmedLine, "-A") {
  59. // if the line is not empty and starts with "-A", it is a rule appended not default
  60. count++
  61. }
  62. }
  63. // return the count of non-default rules
  64. return count, nil
  65. }