Browse code

libnetwork: Support IPv6 in arrangeUserFilterRule()

Fixes #44451.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>

Albin Kerouanton authored on 2022/12/28 21:21:07
Showing 3 changed files
... ...
@@ -1299,3 +1299,23 @@ func (c *controller) iptablesEnabled() bool {
1299 1299
 	}
1300 1300
 	return enabled
1301 1301
 }
1302
+
1303
+func (c *controller) ip6tablesEnabled() bool {
1304
+	c.Lock()
1305
+	defer c.Unlock()
1306
+
1307
+	if c.cfg == nil {
1308
+		return false
1309
+	}
1310
+	// parse map cfg["bridge"]["generic"]["EnableIP6Table"]
1311
+	cfgBridge, ok := c.cfg.DriverCfg["bridge"].(map[string]interface{})
1312
+	if !ok {
1313
+		return false
1314
+	}
1315
+	cfgGeneric, ok := cfgBridge[netlabel.GenericData].(options.Generic)
1316
+	if !ok {
1317
+		return false
1318
+	}
1319
+	enabled, _ := cfgGeneric["EnableIP6Tables"].(bool)
1320
+	return enabled
1321
+}
... ...
@@ -21,24 +21,40 @@ func setupArrangeUserFilterRule(c *controller) {
21 21
 // IPTableForwarding is disabled, because it contains rules configured by user that
22 22
 // are beyond docker engine's control.
23 23
 func arrangeUserFilterRule() {
24
-	if ctrl == nil || !ctrl.iptablesEnabled() {
25
-		return
26
-	}
27
-	// TODO IPv6 support
28
-	iptable := iptables.GetIptable(iptables.IPv4)
29
-	_, err := iptable.NewChain(userChain, iptables.Filter, false)
30
-	if err != nil {
31
-		logrus.Warnf("Failed to create %s chain: %v", userChain, err)
24
+	if ctrl == nil {
32 25
 		return
33 26
 	}
34 27
 
35
-	if err = iptable.AddReturnRule(userChain); err != nil {
36
-		logrus.Warnf("Failed to add the RETURN rule for %s: %v", userChain, err)
37
-		return
28
+	conds := []struct {
29
+		ipVer iptables.IPVersion
30
+		cond  bool
31
+	}{
32
+		{ipVer: iptables.IPv4, cond: ctrl.iptablesEnabled()},
33
+		{ipVer: iptables.IPv6, cond: ctrl.ip6tablesEnabled()},
38 34
 	}
39 35
 
40
-	err = iptable.EnsureJumpRule("FORWARD", userChain)
41
-	if err != nil {
42
-		logrus.Warnf("Failed to ensure the jump rule for %s: %v", userChain, err)
36
+	for _, ipVerCond := range conds {
37
+		cond := ipVerCond.cond
38
+		if !cond {
39
+			continue
40
+		}
41
+
42
+		ipVer := ipVerCond.ipVer
43
+		iptable := iptables.GetIptable(ipVer)
44
+		_, err := iptable.NewChain(userChain, iptables.Filter, false)
45
+		if err != nil {
46
+			logrus.WithError(err).Warnf("Failed to create %s %v chain", userChain, ipVer)
47
+			return
48
+		}
49
+
50
+		if err = iptable.AddReturnRule(userChain); err != nil {
51
+			logrus.WithError(err).Warnf("Failed to add the RETURN rule for %s %v", userChain, ipVer)
52
+			return
53
+		}
54
+
55
+		err = iptable.EnsureJumpRule("FORWARD", userChain)
56
+		if err != nil {
57
+			logrus.WithError(err).Warnf("Failed to ensure the jump rule for %s %v", userChain, ipVer)
58
+		}
43 59
 	}
44 60
 }
... ...
@@ -18,7 +18,8 @@ const (
18 18
 )
19 19
 
20 20
 func TestUserChain(t *testing.T) {
21
-	iptable := iptables.GetIptable(iptables.IPv4)
21
+	iptable4 := iptables.GetIptable(iptables.IPv4)
22
+	iptable6 := iptables.GetIptable(iptables.IPv6)
22 23
 
23 24
 	tests := []struct {
24 25
 		iptables  bool
... ...
@@ -57,32 +58,40 @@ func TestUserChain(t *testing.T) {
57 57
 			c := nc.(*controller)
58 58
 			c.cfg.DriverCfg["bridge"] = map[string]interface{}{
59 59
 				netlabel.GenericData: options.Generic{
60
-					"EnableIPTables": tc.iptables,
60
+					"EnableIPTables":  tc.iptables,
61
+					"EnableIP6Tables": tc.iptables,
61 62
 				},
62 63
 			}
63 64
 
64 65
 			// init. condition, FORWARD chain empty DOCKER-USER not exist
65
-			assert.DeepEqual(t, getRules(t, fwdChainName), []string{"-P FORWARD ACCEPT"})
66
+			assert.DeepEqual(t, getRules(t, iptables.IPv4, fwdChainName), []string{"-P FORWARD ACCEPT"})
67
+			assert.DeepEqual(t, getRules(t, iptables.IPv6, fwdChainName), []string{"-P FORWARD ACCEPT"})
66 68
 
67 69
 			if tc.insert {
68
-				_, err = iptable.Raw("-A", fwdChainName, "-j", "DROP")
70
+				_, err = iptable4.Raw("-A", fwdChainName, "-j", "DROP")
71
+				assert.NilError(t, err)
72
+				_, err = iptable6.Raw("-A", fwdChainName, "-j", "DROP")
69 73
 				assert.NilError(t, err)
70 74
 			}
71 75
 			arrangeUserFilterRule()
72 76
 
73
-			assert.DeepEqual(t, getRules(t, fwdChainName), tc.fwdChain)
77
+			assert.DeepEqual(t, getRules(t, iptables.IPv4, fwdChainName), tc.fwdChain)
78
+			assert.DeepEqual(t, getRules(t, iptables.IPv6, fwdChainName), tc.fwdChain)
74 79
 			if tc.userChain != nil {
75
-				assert.DeepEqual(t, getRules(t, usrChainName), tc.userChain)
80
+				assert.DeepEqual(t, getRules(t, iptables.IPv4, usrChainName), tc.userChain)
81
+				assert.DeepEqual(t, getRules(t, iptables.IPv6, usrChainName), tc.userChain)
76 82
 			} else {
77
-				_, err := iptable.Raw("-S", usrChainName)
78
-				assert.Assert(t, err != nil, "chain %v: created unexpectedly", usrChainName)
83
+				_, err := iptable4.Raw("-S", usrChainName)
84
+				assert.Assert(t, err != nil, "ipv4 chain %v: created unexpectedly", usrChainName)
85
+				_, err = iptable6.Raw("-S", usrChainName)
86
+				assert.Assert(t, err != nil, "ipv6 chain %v: created unexpectedly", usrChainName)
79 87
 			}
80 88
 		})
81 89
 	}
82 90
 }
83 91
 
84
-func getRules(t *testing.T, chain string) []string {
85
-	iptable := iptables.GetIptable(iptables.IPv4)
92
+func getRules(t *testing.T, ipVer iptables.IPVersion, chain string) []string {
93
+	iptable := iptables.GetIptable(ipVer)
86 94
 
87 95
 	t.Helper()
88 96
 	output, err := iptable.Raw("-S", chain)
... ...
@@ -96,10 +105,13 @@ func getRules(t *testing.T, chain string) []string {
96 96
 }
97 97
 
98 98
 func resetIptables(t *testing.T) {
99
-	iptable := iptables.GetIptable(iptables.IPv4)
100
-
101 99
 	t.Helper()
102
-	_, err := iptable.Raw("-F", fwdChainName)
103
-	assert.NilError(t, err)
104
-	_ = iptable.RemoveExistingChain(usrChainName, "")
100
+
101
+	for _, ipVer := range []iptables.IPVersion{iptables.IPv4, iptables.IPv6} {
102
+		iptable := iptables.GetIptable(ipVer)
103
+
104
+		_, err := iptable.Raw("-F", fwdChainName)
105
+		assert.Check(t, err)
106
+		_ = iptable.RemoveExistingChain(usrChainName, "")
107
+	}
105 108
 }