firewall_darwin.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package firewall
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io/ioutil"
  6. "log"
  7. "os"
  8. "regexp"
  9. "strings"
  10. "github.com/bettercap/bettercap/core"
  11. "github.com/bettercap/bettercap/network"
  12. "github.com/evilsocket/islazy/str"
  13. )
  14. var (
  15. sysCtlParser = regexp.MustCompile(`([^:]+):\s*(.+)`)
  16. pfFilePath = fmt.Sprintf("/tmp/bcap_pf_%d.conf", os.Getpid())
  17. )
  18. type PfFirewall struct {
  19. iface *network.Endpoint
  20. filename string
  21. forwarding bool
  22. enabled bool
  23. }
  24. func Make(iface *network.Endpoint) FirewallManager {
  25. firewall := &PfFirewall{
  26. iface: iface,
  27. filename: pfFilePath,
  28. forwarding: false,
  29. enabled: false,
  30. }
  31. firewall.forwarding = firewall.IsForwardingEnabled()
  32. return firewall
  33. }
  34. func (f PfFirewall) sysCtlRead(param string) (string, error) {
  35. if out, err := core.Exec("sysctl", []string{param}); err != nil {
  36. return "", err
  37. } else if m := sysCtlParser.FindStringSubmatch(out); len(m) == 3 && m[1] == param {
  38. return m[2], nil
  39. } else {
  40. return "", fmt.Errorf("Unexpected sysctl output: %s", out)
  41. }
  42. }
  43. func (f PfFirewall) sysCtlWrite(param string, value string) (string, error) {
  44. args := []string{"-w", fmt.Sprintf("%s=%s", param, value)}
  45. _, err := core.Exec("sysctl", args)
  46. if err != nil {
  47. return "", err
  48. }
  49. // make sure we actually wrote the value
  50. if out, err := f.sysCtlRead(param); err != nil {
  51. return "", err
  52. } else if out != value {
  53. return "", fmt.Errorf("Expected value for '%s' is %s, found %s", param, value, out)
  54. } else {
  55. return out, nil
  56. }
  57. }
  58. func (f PfFirewall) IsForwardingEnabled() bool {
  59. out, err := f.sysCtlRead("net.inet.ip.forwarding")
  60. if err != nil {
  61. log.Printf("ERROR: %s", err)
  62. return false
  63. }
  64. return strings.HasSuffix(out, ": 1")
  65. }
  66. func (f PfFirewall) enableParam(param string, enabled bool) error {
  67. var value string
  68. if enabled {
  69. value = "1"
  70. } else {
  71. value = "0"
  72. }
  73. if _, err := f.sysCtlWrite(param, value); err != nil {
  74. return err
  75. } else {
  76. return nil
  77. }
  78. }
  79. func (f PfFirewall) EnableForwarding(enabled bool) error {
  80. return f.enableParam("net.inet.ip.forwarding", enabled)
  81. }
  82. func (f PfFirewall) generateRule(r *Redirection) string {
  83. src_a := "any"
  84. dst_a := "any"
  85. if r.SrcAddress != "" {
  86. src_a = r.SrcAddress
  87. }
  88. if r.DstAddress != "" {
  89. dst_a = r.DstAddress
  90. }
  91. return fmt.Sprintf("rdr pass on %s proto %s from any to %s port %d -> %s port %d",
  92. r.Interface, r.Protocol, src_a, r.SrcPort, dst_a, r.DstPort)
  93. }
  94. func (f *PfFirewall) enable(enabled bool) {
  95. f.enabled = enabled
  96. if enabled {
  97. core.Exec("pfctl", []string{"-e"})
  98. } else {
  99. core.Exec("pfctl", []string{"-d"})
  100. }
  101. }
  102. func (f PfFirewall) EnableRedirection(r *Redirection, enabled bool) error {
  103. rule := f.generateRule(r)
  104. if enabled {
  105. fd, err := os.OpenFile(f.filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
  106. if err != nil {
  107. return err
  108. }
  109. defer fd.Close()
  110. if _, err = fd.WriteString(rule + "\n"); err != nil {
  111. return err
  112. }
  113. // enable pf
  114. f.enable(true)
  115. // load the rule
  116. if _, err := core.Exec("pfctl", []string{"-f", f.filename}); err != nil {
  117. return err
  118. }
  119. } else {
  120. fd, err := os.Open(f.filename)
  121. if err == nil {
  122. defer fd.Close()
  123. lines := ""
  124. scanner := bufio.NewScanner(fd)
  125. for scanner.Scan() {
  126. line := str.Trim(scanner.Text())
  127. if line != rule {
  128. lines += line + "\n"
  129. }
  130. }
  131. if str.Trim(lines) == "" {
  132. os.Remove(f.filename)
  133. f.enable(false)
  134. } else {
  135. ioutil.WriteFile(f.filename, []byte(lines), 0600)
  136. }
  137. }
  138. }
  139. return nil
  140. }
  141. func (f PfFirewall) Restore() {
  142. f.EnableForwarding(f.forwarding)
  143. if f.enabled {
  144. f.enable(false)
  145. }
  146. os.Remove(f.filename)
  147. }