nat_forward_test.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package firewall
  2. import (
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "os"
  7. "os/exec"
  8. "strings"
  9. "testing"
  10. "time"
  11. )
  12. func TestDNSForwardingInNamespace(t *testing.T) {
  13. if os.Getenv("DEBTIK_NAT_INTEGRATION") != "1" {
  14. t.Skip("isolated network namespace required")
  15. }
  16. run := func(args ...string) {
  17. t.Helper()
  18. out, err := exec.Command("ip", args...).CombinedOutput()
  19. if err != nil {
  20. t.Fatalf("ip %v: %s: %v", args, out, err)
  21. }
  22. }
  23. run("link", "set", "lo", "up")
  24. run("addr", "add", "192.0.2.53/32", "dev", "lo")
  25. run("link", "add", "fwserver", "type", "veth", "peer", "name", "fwclient")
  26. run("addr", "add", "192.0.2.1/24", "dev", "fwserver")
  27. run("link", "set", "fwserver", "up")
  28. udp, err := net.ListenPacket("udp4", "192.0.2.53:1053")
  29. if err != nil {
  30. t.Fatal(err)
  31. }
  32. defer udp.Close()
  33. tcp, err := net.Listen("tcp4", "192.0.2.53:1053")
  34. if err != nil {
  35. t.Fatal(err)
  36. }
  37. defer tcp.Close()
  38. go func() {
  39. b := make([]byte, 16)
  40. n, a, e := udp.ReadFrom(b)
  41. if e == nil {
  42. udp.WriteTo(b[:n], a)
  43. }
  44. }()
  45. go func() {
  46. c, e := tcp.Accept()
  47. if e == nil {
  48. defer c.Close()
  49. b := make([]byte, 16)
  50. n, e := c.Read(b)
  51. if e == nil {
  52. c.Write(b[:n])
  53. }
  54. }
  55. }()
  56. rules := []NATRule{{ID: "nat-dns-udp", Chain: "dstnat", Action: "dst-nat", Protocol: "udp", DstPort: "53", ToAddresses: "192.0.2.53", ToPorts: "1053"}, {ID: "nat-dns-tcp", Chain: "dstnat", Action: "dst-nat", Protocol: "tcp", DstPort: "53", ToAddresses: "192.0.2.53", ToPorts: "1053"}}
  57. if err := ApplyDualStack(nil, rules, nil); err != nil {
  58. t.Fatal(err)
  59. }
  60. script := `import socket,subprocess,sys
  61. print('READY',flush=True)
  62. sys.stdin.readline()
  63. for args in [['link','set','lo','up'],['addr','add','192.0.2.2/24','dev','fwclient'],['link','set','fwclient','up'],['route','add','default','via','192.0.2.1']]: subprocess.run(['ip']+args,check=True)
  64. for typ in [socket.SOCK_DGRAM,socket.SOCK_STREAM]:
  65. s=socket.socket(socket.AF_INET,typ);s.settimeout(3);s.connect(('198.51.100.53',53));s.sendall(b'dns');assert s.recv(3)==b'dns';s.close()
  66. print('UDP and TCP forwarded successfully',flush=True)`
  67. cmd := exec.Command("unshare", "--net", "python3", "-u", "-c", script)
  68. stdin, err := cmd.StdinPipe()
  69. if err != nil {
  70. t.Fatal(err)
  71. }
  72. stdout, err := cmd.StdoutPipe()
  73. if err != nil {
  74. t.Fatal(err)
  75. }
  76. cmd.Stderr = os.Stderr
  77. if err = cmd.Start(); err != nil {
  78. t.Fatal(err)
  79. }
  80. defer func() {
  81. if cmd.ProcessState == nil {
  82. cmd.Process.Kill()
  83. cmd.Wait()
  84. }
  85. }()
  86. reader := bufio.NewReader(stdout)
  87. ready, err := reader.ReadString('\n')
  88. if err != nil || strings.TrimSpace(ready) != "READY" {
  89. t.Fatalf("client not ready: %q %v", ready, err)
  90. }
  91. run("link", "set", "fwclient", "netns", fmt.Sprint(cmd.Process.Pid))
  92. fmt.Fprintln(stdin, "go")
  93. stdin.Close()
  94. done := make(chan error, 1)
  95. go func() { done <- cmd.Wait() }()
  96. select {
  97. case err := <-done:
  98. if err != nil {
  99. t.Fatal(err)
  100. }
  101. case <-time.After(10 * time.Second):
  102. cmd.Process.Kill()
  103. t.Fatal("client timed out")
  104. }
  105. }
  106. func TestLocalOutputDNATInNamespace(t *testing.T) {
  107. if os.Getenv("DEBTIK_NAT_INTEGRATION") != "1" {
  108. t.Skip("isolated network namespace required")
  109. }
  110. if out, err := exec.Command("ip", "link", "set", "lo", "up").CombinedOutput(); err != nil {
  111. t.Fatalf("loopback: %s: %v", out, err)
  112. }
  113. server, err := net.ListenPacket("udp4", "127.0.0.2:1053")
  114. if err != nil {
  115. t.Fatal(err)
  116. }
  117. defer server.Close()
  118. go func() {
  119. b := make([]byte, 16)
  120. n, a, e := server.ReadFrom(b)
  121. if e == nil {
  122. server.WriteTo(b[:n], a)
  123. }
  124. }()
  125. rule := NATRule{ID: "nat-local", Chain: "output", Action: "dst-nat", Protocol: "udp", DstAddress: "127.0.0.1", DstPort: "53", ToAddresses: "127.0.0.2", ToPorts: "1053"}
  126. if err := ValidateRule("nat", rule); err != nil {
  127. t.Fatal(err)
  128. }
  129. if err := ApplyDualStack(nil, []NATRule{rule}, nil); err != nil {
  130. t.Fatal(err)
  131. }
  132. client, err := net.DialTimeout("udp4", "127.0.0.1:53", 2*time.Second)
  133. if err != nil {
  134. t.Fatal(err)
  135. }
  136. defer client.Close()
  137. client.SetDeadline(time.Now().Add(2 * time.Second))
  138. if _, err := client.Write([]byte("dns")); err != nil {
  139. t.Fatal(err)
  140. }
  141. b := make([]byte, 3)
  142. if n, err := client.Read(b); err != nil || string(b[:n]) != "dns" {
  143. t.Fatalf("local DNAT response %q: %v", b[:n], err)
  144. }
  145. }