iptables_test.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package iptables
  2. import (
  3. "net"
  4. "os/exec"
  5. "strconv"
  6. "strings"
  7. "sync"
  8. "testing"
  9. )
  10. const chainName = "DOCKERTEST"
  11. var natChain *Chain
  12. var filterChain *Chain
  13. func TestNewChain(t *testing.T) {
  14. var err error
  15. natChain, err = NewChain(chainName, "lo", Nat, false)
  16. if err != nil {
  17. t.Fatal(err)
  18. }
  19. filterChain, err = NewChain(chainName, "lo", Filter, false)
  20. if err != nil {
  21. t.Fatal(err)
  22. }
  23. }
  24. func TestForward(t *testing.T) {
  25. ip := net.ParseIP("192.168.1.1")
  26. port := 1234
  27. dstAddr := "172.17.0.1"
  28. dstPort := 4321
  29. proto := "tcp"
  30. err := natChain.Forward(Insert, ip, port, proto, dstAddr, dstPort)
  31. if err != nil {
  32. t.Fatal(err)
  33. }
  34. dnatRule := []string{
  35. "-d", ip.String(),
  36. "-p", proto,
  37. "--dport", strconv.Itoa(port),
  38. "-j", "DNAT",
  39. "--to-destination", dstAddr + ":" + strconv.Itoa(dstPort),
  40. }
  41. if !Exists(natChain.Table, natChain.Name, dnatRule...) {
  42. t.Fatalf("DNAT rule does not exist")
  43. }
  44. filterRule := []string{
  45. "!", "-i", filterChain.Bridge,
  46. "-o", filterChain.Bridge,
  47. "-d", dstAddr,
  48. "-p", proto,
  49. "--dport", strconv.Itoa(dstPort),
  50. "-j", "ACCEPT",
  51. }
  52. if !Exists(filterChain.Table, filterChain.Name, filterRule...) {
  53. t.Fatalf("filter rule does not exist")
  54. }
  55. masqRule := []string{
  56. "-d", dstAddr,
  57. "-s", dstAddr,
  58. "-p", proto,
  59. "--dport", strconv.Itoa(dstPort),
  60. "-j", "MASQUERADE",
  61. }
  62. if !Exists(natChain.Table, "POSTROUTING", masqRule...) {
  63. t.Fatalf("MASQUERADE rule does not exist")
  64. }
  65. }
  66. func TestLink(t *testing.T) {
  67. var err error
  68. ip1 := net.ParseIP("192.168.1.1")
  69. ip2 := net.ParseIP("192.168.1.2")
  70. port := 1234
  71. proto := "tcp"
  72. err = filterChain.Link(Append, ip1, ip2, port, proto)
  73. if err != nil {
  74. t.Fatal(err)
  75. }
  76. rule1 := []string{
  77. "-i", filterChain.Bridge,
  78. "-o", filterChain.Bridge,
  79. "-p", proto,
  80. "-s", ip1.String(),
  81. "-d", ip2.String(),
  82. "--dport", strconv.Itoa(port),
  83. "-j", "ACCEPT"}
  84. if !Exists(filterChain.Table, filterChain.Name, rule1...) {
  85. t.Fatalf("rule1 does not exist")
  86. }
  87. rule2 := []string{
  88. "-i", filterChain.Bridge,
  89. "-o", filterChain.Bridge,
  90. "-p", proto,
  91. "-s", ip2.String(),
  92. "-d", ip1.String(),
  93. "--sport", strconv.Itoa(port),
  94. "-j", "ACCEPT"}
  95. if !Exists(filterChain.Table, filterChain.Name, rule2...) {
  96. t.Fatalf("rule2 does not exist")
  97. }
  98. }
  99. func TestPrerouting(t *testing.T) {
  100. args := []string{
  101. "-i", "lo",
  102. "-d", "192.168.1.1"}
  103. err := natChain.Prerouting(Insert, args...)
  104. if err != nil {
  105. t.Fatal(err)
  106. }
  107. rule := []string{
  108. "-j", natChain.Name}
  109. rule = append(rule, args...)
  110. if !Exists(natChain.Table, "PREROUTING", rule...) {
  111. t.Fatalf("rule does not exist")
  112. }
  113. delRule := append([]string{"-D", "PREROUTING", "-t", string(Nat)}, rule...)
  114. if _, err = Raw(delRule...); err != nil {
  115. t.Fatal(err)
  116. }
  117. }
  118. func TestOutput(t *testing.T) {
  119. args := []string{
  120. "-o", "lo",
  121. "-d", "192.168.1.1"}
  122. err := natChain.Output(Insert, args...)
  123. if err != nil {
  124. t.Fatal(err)
  125. }
  126. rule := []string{
  127. "-j", natChain.Name}
  128. rule = append(rule, args...)
  129. if !Exists(natChain.Table, "OUTPUT", rule...) {
  130. t.Fatalf("rule does not exist")
  131. }
  132. delRule := append([]string{"-D", "OUTPUT", "-t",
  133. string(natChain.Table)}, rule...)
  134. if _, err = Raw(delRule...); err != nil {
  135. t.Fatal(err)
  136. }
  137. }
  138. func TestConcurrencyWithWait(t *testing.T) {
  139. RunConcurrencyTest(t, true)
  140. }
  141. func TestConcurrencyNoWait(t *testing.T) {
  142. RunConcurrencyTest(t, false)
  143. }
  144. // Runs 10 concurrent rule additions. This will fail if iptables
  145. // is actually invoked simultaneously without --wait.
  146. // Note that if iptables does not support the xtable lock on this
  147. // system, then allowXlock has no effect -- it will always be off.
  148. func RunConcurrencyTest(t *testing.T, allowXlock bool) {
  149. var wg sync.WaitGroup
  150. if !allowXlock && supportsXlock {
  151. supportsXlock = false
  152. defer func() { supportsXlock = true }()
  153. }
  154. ip := net.ParseIP("192.168.1.1")
  155. port := 1234
  156. dstAddr := "172.17.0.1"
  157. dstPort := 4321
  158. proto := "tcp"
  159. for i := 0; i < 10; i++ {
  160. wg.Add(1)
  161. go func() {
  162. defer wg.Done()
  163. err := natChain.Forward(Append, ip, port, proto, dstAddr, dstPort)
  164. if err != nil {
  165. t.Fatal(err)
  166. }
  167. }()
  168. }
  169. wg.Wait()
  170. }
  171. func TestCleanup(t *testing.T) {
  172. var err error
  173. var rules []byte
  174. // Cleanup filter/FORWARD first otherwise output of iptables-save is dirty
  175. link := []string{"-t", string(filterChain.Table),
  176. string(Delete), "FORWARD",
  177. "-o", filterChain.Bridge,
  178. "-j", filterChain.Name}
  179. if _, err = Raw(link...); err != nil {
  180. t.Fatal(err)
  181. }
  182. filterChain.Remove()
  183. err = RemoveExistingChain(chainName, Nat)
  184. if err != nil {
  185. t.Fatal(err)
  186. }
  187. rules, err = exec.Command("iptables-save").Output()
  188. if err != nil {
  189. t.Fatal(err)
  190. }
  191. if strings.Contains(string(rules), chainName) {
  192. t.Fatalf("Removing chain failed. %s found in iptables-save", chainName)
  193. }
  194. }