setup_ip_tables_linux_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. package bridge
  2. import (
  3. "net"
  4. "testing"
  5. "github.com/docker/docker/internal/testutils/netnsutils"
  6. "github.com/docker/docker/libnetwork/driverapi"
  7. "github.com/docker/docker/libnetwork/iptables"
  8. "github.com/docker/docker/libnetwork/netlabel"
  9. "github.com/docker/docker/libnetwork/portmapper"
  10. "github.com/vishvananda/netlink"
  11. "gotest.tools/v3/assert"
  12. )
  13. const (
  14. iptablesTestBridgeIP = "192.168.42.1"
  15. )
  16. // A testRegisterer implements the driverapi.Registerer interface.
  17. type testRegisterer struct {
  18. t *testing.T
  19. d *driver
  20. }
  21. func (r *testRegisterer) RegisterDriver(name string, di driverapi.Driver, _ driverapi.Capability) error {
  22. if got, want := name, "bridge"; got != want {
  23. r.t.Fatalf("got driver name %s, want %s", got, want)
  24. }
  25. d, ok := di.(*driver)
  26. if !ok {
  27. r.t.Fatalf("got driver type %T, want %T", di, &driver{})
  28. }
  29. r.d = d
  30. return nil
  31. }
  32. func TestProgramIPTable(t *testing.T) {
  33. // Create a test bridge with a basic bridge configuration (name + IPv4).
  34. defer netnsutils.SetupTestOSContext(t)()
  35. nh, err := netlink.NewHandle()
  36. if err != nil {
  37. t.Fatal(err)
  38. }
  39. createTestBridge(getBasicTestConfig(), &bridgeInterface{nlh: nh}, t)
  40. // Store various iptables chain rules we care for.
  41. rules := []struct {
  42. rule iptRule
  43. descr string
  44. }{
  45. {iptRule{ipv: iptables.IPv4, table: iptables.Filter, chain: "FORWARD", args: []string{"-d", "127.1.2.3", "-i", "lo", "-o", "lo", "-j", "DROP"}}, "Test Loopback"},
  46. {iptRule{ipv: iptables.IPv4, table: iptables.Nat, chain: "POSTROUTING", args: []string{"-s", iptablesTestBridgeIP, "!", "-o", DefaultBridgeName, "-j", "MASQUERADE"}}, "NAT Test"},
  47. {iptRule{ipv: iptables.IPv4, table: iptables.Filter, chain: "FORWARD", args: []string{"-o", DefaultBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}}, "Test ACCEPT INCOMING"},
  48. {iptRule{ipv: iptables.IPv4, table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "!", "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test ACCEPT NON_ICC OUTGOING"},
  49. {iptRule{ipv: iptables.IPv4, table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test enable ICC"},
  50. {iptRule{ipv: iptables.IPv4, table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "DROP"}}, "Test disable ICC"},
  51. }
  52. // Assert the chain rules' insertion and removal.
  53. for _, c := range rules {
  54. assertIPTableChainProgramming(c.rule, c.descr, t)
  55. }
  56. }
  57. func TestSetupIPChains(t *testing.T) {
  58. // Create a test bridge with a basic bridge configuration (name + IPv4).
  59. defer netnsutils.SetupTestOSContext(t)()
  60. nh, err := netlink.NewHandle()
  61. if err != nil {
  62. t.Fatal(err)
  63. }
  64. driverconfig := configuration{
  65. EnableIPTables: true,
  66. }
  67. d := &driver{
  68. config: driverconfig,
  69. }
  70. assertChainConfig(d, t)
  71. config := getBasicTestConfig()
  72. br := &bridgeInterface{nlh: nh}
  73. createTestBridge(config, br, t)
  74. assertBridgeConfig(config, br, d, t)
  75. config.EnableIPMasquerade = true
  76. assertBridgeConfig(config, br, d, t)
  77. config.EnableICC = true
  78. assertBridgeConfig(config, br, d, t)
  79. config.EnableIPMasquerade = false
  80. assertBridgeConfig(config, br, d, t)
  81. }
  82. func getBasicTestConfig() *networkConfiguration {
  83. config := &networkConfiguration{
  84. BridgeName: DefaultBridgeName,
  85. AddressIPv4: &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)},
  86. }
  87. return config
  88. }
  89. func createTestBridge(config *networkConfiguration, br *bridgeInterface, t *testing.T) {
  90. if err := setupDevice(config, br); err != nil {
  91. t.Fatalf("Failed to create the testing Bridge: %s", err.Error())
  92. }
  93. if err := setupBridgeIPv4(config, br); err != nil {
  94. t.Fatalf("Failed to bring up the testing Bridge: %s", err.Error())
  95. }
  96. if config.EnableIPv6 {
  97. if err := setupBridgeIPv6(config, br); err != nil {
  98. t.Fatalf("Failed to bring up the testing Bridge: %s", err.Error())
  99. }
  100. }
  101. }
  102. // Assert base function which pushes iptables chain rules on insertion and removal.
  103. func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) {
  104. // Add
  105. if err := programChainRule(rule, descr, true); err != nil {
  106. t.Fatalf("Failed to program iptable rule %s: %s", descr, err.Error())
  107. }
  108. if !rule.Exists() {
  109. t.Fatalf("Failed to effectively program iptable rule: %s", descr)
  110. }
  111. // Remove
  112. if err := programChainRule(rule, descr, false); err != nil {
  113. t.Fatalf("Failed to remove iptable rule %s: %s", descr, err.Error())
  114. }
  115. if rule.Exists() {
  116. t.Fatalf("Failed to effectively remove iptable rule: %s", descr)
  117. }
  118. }
  119. // Assert function which create chains.
  120. func assertChainConfig(d *driver, t *testing.T) {
  121. var err error
  122. if d.config.EnableIPTables {
  123. d.natChain, d.filterChain, d.isolationChain1, d.isolationChain2, err = setupIPChains(d.config, iptables.IPv4)
  124. if err != nil {
  125. t.Fatal(err)
  126. }
  127. }
  128. if d.config.EnableIP6Tables {
  129. d.natChainV6, d.filterChainV6, d.isolationChain1V6, d.isolationChain2V6, err = setupIPChains(d.config, iptables.IPv6)
  130. if err != nil {
  131. t.Fatal(err)
  132. }
  133. }
  134. }
  135. // Assert function which pushes chains based on bridge config parameters.
  136. func assertBridgeConfig(config *networkConfiguration, br *bridgeInterface, d *driver, t *testing.T) {
  137. nw := bridgeNetwork{
  138. portMapper: portmapper.New(),
  139. portMapperV6: portmapper.New(),
  140. config: config,
  141. }
  142. nw.driver = d
  143. // Attempt programming of ip tables.
  144. err := nw.setupIP4Tables(config, br)
  145. if err != nil {
  146. t.Fatalf("%v", err)
  147. }
  148. if d.config.EnableIP6Tables {
  149. if err := nw.setupIP6Tables(config, br); err != nil {
  150. t.Fatalf("%v", err)
  151. }
  152. }
  153. }
  154. // Regression test for https://github.com/moby/moby/issues/46445
  155. func TestSetupIP6TablesWithHostIPv4(t *testing.T) {
  156. defer netnsutils.SetupTestOSContext(t)()
  157. d := newDriver()
  158. dc := &configuration{
  159. EnableIPTables: true,
  160. EnableIP6Tables: true,
  161. }
  162. if err := d.configure(map[string]interface{}{netlabel.GenericData: dc}); err != nil {
  163. t.Fatal(err)
  164. }
  165. nc := &networkConfiguration{
  166. BridgeName: DefaultBridgeName,
  167. AddressIPv4: &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)},
  168. EnableIPMasquerade: true,
  169. EnableIPv6: true,
  170. AddressIPv6: &net.IPNet{IP: net.ParseIP("2001:db8::1"), Mask: net.CIDRMask(64, 128)},
  171. HostIPv4: net.ParseIP("192.0.2.2"),
  172. }
  173. nh, err := netlink.NewHandle()
  174. if err != nil {
  175. t.Fatal(err)
  176. }
  177. br := &bridgeInterface{nlh: nh}
  178. createTestBridge(nc, br, t)
  179. assertBridgeConfig(nc, br, d, t)
  180. }
  181. func TestOutgoingNATRules(t *testing.T) {
  182. br := "br-nattest"
  183. brIPv4 := &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)}
  184. brIPv6 := &net.IPNet{IP: net.ParseIP("2001:db8::1"), Mask: net.CIDRMask(64, 128)}
  185. maskedBrIPv4 := &net.IPNet{IP: brIPv4.IP.Mask(brIPv4.Mask), Mask: brIPv4.Mask}
  186. maskedBrIPv6 := &net.IPNet{IP: brIPv6.IP.Mask(brIPv6.Mask), Mask: brIPv6.Mask}
  187. hostIPv4 := net.ParseIP("192.0.2.2")
  188. hostIPv6 := net.ParseIP("2001:db8:1::1")
  189. for _, tc := range []struct {
  190. desc string
  191. enableIPTables bool
  192. enableIP6Tables bool
  193. enableIPv6 bool
  194. enableIPMasquerade bool
  195. hostIPv4 net.IP
  196. hostIPv6 net.IP
  197. // Hairpin NAT rules are not tested here because they are orthogonal to outgoing NAT. They
  198. // exist to support the port forwarding DNAT rules: without any port forwarding there would be
  199. // no need for any hairpin NAT rules, and when there is port forwarding then hairpin NAT rules
  200. // are needed even if outgoing NAT is disabled. Hairpin NAT tests belong with the port
  201. // forwarding DNAT tests.
  202. wantIPv4Masq bool
  203. wantIPv4Snat bool
  204. wantIPv6Masq bool
  205. wantIPv6Snat bool
  206. }{
  207. {
  208. desc: "everything disabled",
  209. },
  210. {
  211. desc: "iptables/ip6tables disabled",
  212. enableIPv6: true,
  213. enableIPMasquerade: true,
  214. },
  215. {
  216. desc: "host IP with iptables/ip6tables disabled",
  217. enableIPv6: true,
  218. enableIPMasquerade: true,
  219. hostIPv4: hostIPv4,
  220. hostIPv6: hostIPv6,
  221. },
  222. {
  223. desc: "masquerade disabled, no host IP",
  224. enableIPTables: true,
  225. enableIP6Tables: true,
  226. enableIPv6: true,
  227. },
  228. {
  229. desc: "masquerade disabled, with host IP",
  230. enableIPTables: true,
  231. enableIP6Tables: true,
  232. enableIPv6: true,
  233. hostIPv4: hostIPv4,
  234. hostIPv6: hostIPv6,
  235. },
  236. {
  237. desc: "IPv4 masquerade, IPv6 disabled",
  238. enableIPTables: true,
  239. enableIPMasquerade: true,
  240. wantIPv4Masq: true,
  241. },
  242. {
  243. desc: "IPv4 SNAT, IPv6 disabled",
  244. enableIPTables: true,
  245. enableIPMasquerade: true,
  246. hostIPv4: hostIPv4,
  247. wantIPv4Snat: true,
  248. },
  249. {
  250. // Regression test for https://github.com/moby/moby/issues/46467
  251. desc: "iptables disabled, IPv6 masquerade",
  252. enableIP6Tables: true,
  253. enableIPv6: true,
  254. enableIPMasquerade: true,
  255. wantIPv6Masq: true,
  256. },
  257. {
  258. desc: "iptables disabled, IPv6 SNAT",
  259. enableIP6Tables: true,
  260. enableIPv6: true,
  261. enableIPMasquerade: true,
  262. hostIPv6: hostIPv6,
  263. wantIPv6Snat: true,
  264. },
  265. {
  266. desc: "IPv4 masquerade, IPv6 masquerade",
  267. enableIPTables: true,
  268. enableIP6Tables: true,
  269. enableIPv6: true,
  270. enableIPMasquerade: true,
  271. wantIPv4Masq: true,
  272. wantIPv6Masq: true,
  273. },
  274. {
  275. desc: "IPv4 masquerade, IPv6 SNAT",
  276. enableIPTables: true,
  277. enableIP6Tables: true,
  278. enableIPv6: true,
  279. enableIPMasquerade: true,
  280. hostIPv6: hostIPv6,
  281. wantIPv4Masq: true,
  282. wantIPv6Snat: true,
  283. },
  284. {
  285. desc: "IPv4 SNAT, IPv6 masquerade",
  286. enableIPTables: true,
  287. enableIP6Tables: true,
  288. enableIPv6: true,
  289. enableIPMasquerade: true,
  290. hostIPv4: hostIPv4,
  291. wantIPv4Snat: true,
  292. wantIPv6Masq: true,
  293. },
  294. {
  295. desc: "IPv4 SNAT, IPv6 SNAT",
  296. enableIPTables: true,
  297. enableIP6Tables: true,
  298. enableIPv6: true,
  299. enableIPMasquerade: true,
  300. hostIPv4: hostIPv4,
  301. hostIPv6: hostIPv6,
  302. wantIPv4Snat: true,
  303. wantIPv6Snat: true,
  304. },
  305. } {
  306. t.Run(tc.desc, func(t *testing.T) {
  307. defer netnsutils.SetupTestOSContext(t)()
  308. dc := &configuration{
  309. EnableIPTables: tc.enableIPTables,
  310. EnableIP6Tables: tc.enableIP6Tables,
  311. }
  312. r := &testRegisterer{t: t}
  313. if err := Register(r, map[string]interface{}{netlabel.GenericData: dc}); err != nil {
  314. t.Fatal(err)
  315. }
  316. if r.d == nil {
  317. t.Fatal("testRegisterer.RegisterDriver never called")
  318. }
  319. nc := &networkConfiguration{
  320. BridgeName: br,
  321. AddressIPv4: brIPv4,
  322. AddressIPv6: brIPv6,
  323. EnableIPv6: tc.enableIPv6,
  324. EnableIPMasquerade: tc.enableIPMasquerade,
  325. HostIPv4: tc.hostIPv4,
  326. HostIPv6: tc.hostIPv6,
  327. }
  328. ipv4Data := []driverapi.IPAMData{{Pool: maskedBrIPv4, Gateway: brIPv4}}
  329. ipv6Data := []driverapi.IPAMData{{Pool: maskedBrIPv6, Gateway: brIPv6}}
  330. if !nc.EnableIPv6 {
  331. nc.AddressIPv6 = nil
  332. ipv6Data = nil
  333. }
  334. if err := r.d.CreateNetwork("nattest", map[string]interface{}{netlabel.GenericData: nc}, nil, ipv4Data, ipv6Data); err != nil {
  335. t.Fatal(err)
  336. }
  337. defer func() {
  338. if err := r.d.DeleteNetwork("nattest"); err != nil {
  339. t.Fatal(err)
  340. }
  341. }()
  342. // Log the contents of all chains to aid troubleshooting.
  343. for _, ipv := range []iptables.IPVersion{iptables.IPv4, iptables.IPv6} {
  344. ipt := iptables.GetIptable(ipv)
  345. for _, table := range []iptables.Table{iptables.Nat, iptables.Filter, iptables.Mangle} {
  346. out, err := ipt.Raw("-t", string(table), "-S")
  347. if err != nil {
  348. t.Error(err)
  349. }
  350. t.Logf("%s: %s %s table rules:\n%s", tc.desc, ipv, table, string(out))
  351. }
  352. }
  353. for _, rc := range []struct {
  354. want bool
  355. rule iptRule
  356. }{
  357. // Rule order doesn't matter: At most one of the following IPv4 rules will exist, and the
  358. // same goes for the IPv6 rules.
  359. {tc.wantIPv4Masq, iptRule{iptables.IPv4, iptables.Nat, "POSTROUTING", []string{"-s", maskedBrIPv4.String(), "!", "-o", br, "-j", "MASQUERADE"}}},
  360. {tc.wantIPv4Snat, iptRule{iptables.IPv4, iptables.Nat, "POSTROUTING", []string{"-s", maskedBrIPv4.String(), "!", "-o", br, "-j", "SNAT", "--to-source", hostIPv4.String()}}},
  361. {tc.wantIPv6Masq, iptRule{iptables.IPv6, iptables.Nat, "POSTROUTING", []string{"-s", maskedBrIPv6.String(), "!", "-o", br, "-j", "MASQUERADE"}}},
  362. {tc.wantIPv6Snat, iptRule{iptables.IPv6, iptables.Nat, "POSTROUTING", []string{"-s", maskedBrIPv6.String(), "!", "-o", br, "-j", "SNAT", "--to-source", hostIPv6.String()}}},
  363. } {
  364. assert.Equal(t, rc.rule.Exists(), rc.want)
  365. }
  366. })
  367. }
  368. }