iptables.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  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. func detectIptables() (int, error) {
  27. // run "iptables -S" to get the list of rules using iptables
  28. // exec.Command returns an error if the binary is not found
  29. cmd := exec.Command("iptables", "-S")
  30. output, err := cmd.Output()
  31. ip6cmd := exec.Command("ip6tables", "-S")
  32. ip6output, ip6err := ip6cmd.Output()
  33. var allLines []string
  34. outputStr := string(output)
  35. lines := strings.Split(outputStr, "\n")
  36. ip6outputStr := string(ip6output)
  37. ip6lines := strings.Split(ip6outputStr, "\n")
  38. switch {
  39. case err == nil && ip6err == nil:
  40. allLines = append(lines, ip6lines...)
  41. case err == nil && ip6err != nil:
  42. allLines = lines
  43. case err != nil && ip6err == nil:
  44. allLines = ip6lines
  45. default:
  46. return 0, FWModeNotSupportedError{
  47. Mode: FirewallModeIPTables,
  48. Err: fmt.Errorf("iptables command run fail: %w", multierr.New(err, ip6err)),
  49. }
  50. }
  51. // count the number of non-default rules
  52. count := 0
  53. for _, line := range allLines {
  54. trimmedLine := strings.TrimLeftFunc(line, unicode.IsSpace)
  55. if line != "" && strings.HasPrefix(trimmedLine, "-A") {
  56. // if the line is not empty and starts with "-A", it is a rule appended not default
  57. count++
  58. }
  59. }
  60. // return the count of non-default rules
  61. return count, nil
  62. }