[lxc-devel] [lxd/master] Request for Comment

keyallis on Github lxc-bot at linuxcontainers.org
Mon Nov 4 22:40:04 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 573 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191104/1fcc93a8/attachment.bin>
-------------- next part --------------
From 8757a123c676a158367b345f4dd65ba3168defc3 Mon Sep 17 00:00:00 2001
From: Oscar Ward <oscarward95 at gmail.com>
Date: Thu, 31 Oct 2019 15:49:27 -0500
Subject: [PATCH 01/11] defined interface and created xtables ; does not
 include ebtables

---
 lxd/firewall/interfaces.go | 13 +++++++++++++
 lxd/firewall/xtables.go    | 40 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 lxd/firewall/interfaces.go
 create mode 100644 lxd/firewall/xtables.go

diff --git a/lxd/firewall/interfaces.go b/lxd/firewall/interfaces.go
new file mode 100644
index 0000000000..1ec9031095
--- /dev/null
+++ b/lxd/firewall/interfaces.go
@@ -0,0 +1,13 @@
+package firewall
+
+// Firewall represents an LXD firewall.
+type Firewall interface {
+	// Network
+	NetworkAppend(protocol string, comment string, table string, chain string, rule ...string) error
+	NetworkPrepend(protocol string, comment string, table string, chain string, rule ...string) error
+	NetworkClear(protocol string, comment string, table string) error
+
+	// Container
+	ContainerPrepend(protocol string, comment string, table string, chain string, rule ...string) error
+	ContainerClear(protocol string, comment string, table string, chain string, rule ...string) error
+}
diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
new file mode 100644
index 0000000000..72b419d183
--- /dev/null
+++ b/lxd/firewall/xtables.go
@@ -0,0 +1,40 @@
+package firewall
+
+import (
+	"fmt"
+
+	"github.com/lxc/lxd/lxd/iptables"
+)
+
+// NetworkAppend adds a network rule at end of ruleset.
+func NetworkAppend(protocol string, comment string, table string, chain string,
+    rule ...string) error {
+    return iptables.NetworkAppend(protocol, fmt.Sprintf("LXD network %s", comment),
+        table, chain, rule...)
+}
+
+// NetworkPrepend adds a network rule at start of ruleset.
+func NetworkPrepend(protocol string, comment string, table string, chain string,
+    rule ...string) error {
+    return iptables.NetworkPrepend(protocol, fmt.Sprintf("LXD network %s", comment),
+        table, chain, rule...)
+}
+
+// NetworkClear removes network rules.
+func NetworkClear(protocol string, comment string, table string) error {
+    return iptables.NetworkClear(protocol, fmt.Sprintf("LXD network %s", comment),
+        table)
+}
+
+// ContainerPrepend adds container rule at start of ruleset.
+func ContainerPrepend(protocol string, comment string, table string,
+    chain string, rule ...string) error {
+    return iptables.ContainerPrepend(protocol, fmt.Sprintf("LXD container %s", comment),
+        table, chain, rule...)
+}
+
+// ContainerClear removes container rules.
+func ContainerClear(protocol string, comment string, table string) error {
+    return iptables.ContainerClear(protocol, fmt.Sprintf("LXD container %s", comment),
+        table)
+}

From d993619a5cdb55cdd69a07a734e465c3b213747f Mon Sep 17 00:00:00 2001
From: Oscar Ward <oscarward95 at gmail.com>
Date: Mon, 4 Nov 2019 13:05:36 -0600
Subject: [PATCH 02/11] made notes for the interface

---
 lxd/firewall/interfaces.go | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/lxd/firewall/interfaces.go b/lxd/firewall/interfaces.go
index 1ec9031095..e11792e157 100644
--- a/lxd/firewall/interfaces.go
+++ b/lxd/firewall/interfaces.go
@@ -1,7 +1,36 @@
 package firewall
 
+// proxy.go:
+//   Stop() - clear both ipv4 and ipv6 instance nat
+//   setupNAT() - set ipv4 and ipv6 prerouting and output nat
+// nic_bridged.go:
+//   removeFilters() - clear ipv6 filters and set ebtables to default
+//     generateFilterEbtablesRules()
+//     matchEbtablesRule()
+//   setFilters() - set ebtables defaults and iptables defaults
+//     generateFilterEbtablesRules()
+//     generateFilterIptablesRules()
+// networks.go
+//   Setup()
+//   Stop()
+
 // Firewall represents an LXD firewall.
 type Firewall interface {
+	// Filter functions
+	// FOLLOWS: functions which utilize iptables/ebtables
+	// removeFilters() error // FIXME args (nic_bridged)
+	// setFilters() error // FIXME args (nic_bridged)
+	// Stop() error // (proxy)
+	// setupNAT() error // (proxy)
+	// Setup() error // (networks)
+	// Stop() error // (networks)
+	// needs <shared>, (m deviceConfig.Device) <deviceConfig>, (d *nicBridged)
+
+	// NOTE: requires generateFilterEbtablesRules()
+	// NOTE: requires matchEbtablesRule()
+	// NOTE: xtables will need to include shared
+	// NOTE: nicBridged may need generate/filter functions for nft
+
 	// Network
 	NetworkAppend(protocol string, comment string, table string, chain string, rule ...string) error
 	NetworkPrepend(protocol string, comment string, table string, chain string, rule ...string) error

From b0df22e49aadb3d953a0b673ef8a2b73bd8e5183 Mon Sep 17 00:00:00 2001
From: Louise Montalvo <louanmontalvo at gmail.com>
Date: Mon, 4 Nov 2019 13:57:34 -0600
Subject: [PATCH 03/11] Change Firewall interface to a more generic format ;
 add more notes

---
 lxd/firewall/interfaces.go | 34 ++++++++++++++++++++++++++-------
 lxd/firewall/xtables.go    | 39 +++++++++++++++-----------------------
 2 files changed, 42 insertions(+), 31 deletions(-)

diff --git a/lxd/firewall/interfaces.go b/lxd/firewall/interfaces.go
index e11792e157..c9ddda43fd 100644
--- a/lxd/firewall/interfaces.go
+++ b/lxd/firewall/interfaces.go
@@ -1,5 +1,10 @@
 package firewall
 
+import (
+	"github.com/lxc/lxd/lxd/device"
+	deviceConfig "github.com/lxc/lxd/lxd/device/config"
+)
+
 // proxy.go:
 //   Stop() - clear both ipv4 and ipv6 instance nat
 //   setupNAT() - set ipv4 and ipv6 prerouting and output nat
@@ -12,7 +17,19 @@ package firewall
 //     generateFilterIptablesRules()
 // networks.go
 //   Setup()
+//     - Remove existing IPv4 iptables rules: 1208
+//     - Clear iptables NAT config: 1221
+//     - Configure IPv4 firewall for DHCP/DNS: 1246
+//     - Allow IPv4 forwarding: 1271
+//     - Configure IPv4 NAT: 1371
+//     - Remove existing IPv6 iptables rules: 1411
+//     - Update IPv6 iptables DHCP/DNS overrides in the dnsmasq config: 1461
+//     - Allow IPv6 forwarding: 1505
+//     - Configure IPv6 NAT: 1565
+//     - Configure tunnel (?) NAT: 1735
 //   Stop()
+//     - Cleanup IPv4 iptables: 1985
+//     - Cleanup IPv6 iptables: 2005
 
 // Firewall represents an LXD firewall.
 type Firewall interface {
@@ -31,12 +48,15 @@ type Firewall interface {
 	// NOTE: xtables will need to include shared
 	// NOTE: nicBridged may need generate/filter functions for nft
 
-	// Network
-	NetworkAppend(protocol string, comment string, table string, chain string, rule ...string) error
-	NetworkPrepend(protocol string, comment string, table string, chain string, rule ...string) error
-	NetworkClear(protocol string, comment string, table string) error
+	// Proxy
+	ProxyStop() (*device.RunConfig, error)
+	ProxySetupNAT()
 
-	// Container
-	ContainerPrepend(protocol string, comment string, table string, chain string, rule ...string) error
-	ContainerClear(protocol string, comment string, table string, chain string, rule ...string) error
+	// NIC bridged
+	BridgeRemoveFilters(deviceConfig.Device) error
+	BridgeSetFilters(deviceConfig.Device) error
+
+	// Network
+	NetworkSetup(map[string]string) error
+	NetworkStop() error
 }
diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
index 72b419d183..d97eb5ecec 100644
--- a/lxd/firewall/xtables.go
+++ b/lxd/firewall/xtables.go
@@ -6,35 +6,26 @@ import (
 	"github.com/lxc/lxd/lxd/iptables"
 )
 
-// NetworkAppend adds a network rule at end of ruleset.
-func NetworkAppend(protocol string, comment string, table string, chain string,
-    rule ...string) error {
-    return iptables.NetworkAppend(protocol, fmt.Sprintf("LXD network %s", comment),
-        table, chain, rule...)
+// Proxy
+func ProxyStop() (*device.RunConfig, error) {
+	return nil, nil
 }
+func ProxySetupNAT() {
 
-// NetworkPrepend adds a network rule at start of ruleset.
-func NetworkPrepend(protocol string, comment string, table string, chain string,
-    rule ...string) error {
-    return iptables.NetworkPrepend(protocol, fmt.Sprintf("LXD network %s", comment),
-        table, chain, rule...)
 }
 
-// NetworkClear removes network rules.
-func NetworkClear(protocol string, comment string, table string) error {
-    return iptables.NetworkClear(protocol, fmt.Sprintf("LXD network %s", comment),
-        table)
+// NIC bridged
+func BridgeRemoveFilters(deviceConfig.Device) error {
+	return nil
 }
-
-// ContainerPrepend adds container rule at start of ruleset.
-func ContainerPrepend(protocol string, comment string, table string,
-    chain string, rule ...string) error {
-    return iptables.ContainerPrepend(protocol, fmt.Sprintf("LXD container %s", comment),
-        table, chain, rule...)
+func BridgeSetFilters(deviceConfig.Device) error {
+	return nil
 }
 
-// ContainerClear removes container rules.
-func ContainerClear(protocol string, comment string, table string) error {
-    return iptables.ContainerClear(protocol, fmt.Sprintf("LXD container %s", comment),
-        table)
+// Network
+func NetworkSetup(map[string]string) error {
+	return nil
+}
+func NetworkStop() error {
+	return nil
 }

From 27c780d52a0d74061a93e47798f631aa00793405 Mon Sep 17 00:00:00 2001
From: Danny Tran <dannytran at utexas.edu>
Date: Mon, 4 Nov 2019 14:15:01 -0600
Subject: [PATCH 04/11] Added XTables struct ; changed function casing

---
 lxd/firewall/interfaces.go | 12 ++++++------
 lxd/firewall/xtables.go    | 20 +++++++++++---------
 2 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/lxd/firewall/interfaces.go b/lxd/firewall/interfaces.go
index c9ddda43fd..4c45c3d19c 100644
--- a/lxd/firewall/interfaces.go
+++ b/lxd/firewall/interfaces.go
@@ -49,14 +49,14 @@ type Firewall interface {
 	// NOTE: nicBridged may need generate/filter functions for nft
 
 	// Proxy
-	ProxyStop() (*device.RunConfig, error)
-	ProxySetupNAT()
+	proxyStop() (*device.RunConfig, error)
+	proxySetupNAT()
 
 	// NIC bridged
-	BridgeRemoveFilters(deviceConfig.Device) error
-	BridgeSetFilters(deviceConfig.Device) error
+	bridgeRemoveFilters(deviceConfig.Device) error
+	bridgeSetFilters(deviceConfig.Device) error
 
 	// Network
-	NetworkSetup(map[string]string) error
-	NetworkStop() error
+	networkSetup(map[string]string) error
+	networkStop() error
 }
diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
index d97eb5ecec..095e58af48 100644
--- a/lxd/firewall/xtables.go
+++ b/lxd/firewall/xtables.go
@@ -1,31 +1,33 @@
 package firewall
 
 import (
-	"fmt"
-
-	"github.com/lxc/lxd/lxd/iptables"
+	"github.com/lxc/lxd/lxd/device"
+	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 )
 
+// XTables is an implmentation of LXD firewall using {ip, ip6, eb}tables
+type XTables struct {}
+
 // Proxy
-func ProxyStop() (*device.RunConfig, error) {
+func (xt *XTables) proxyStop() (*device.RunConfig, error) {
 	return nil, nil
 }
-func ProxySetupNAT() {
+func (xt *XTables) proxySetupNAT() {
 
 }
 
 // NIC bridged
-func BridgeRemoveFilters(deviceConfig.Device) error {
+func (xt *XTables) bridgeRemoveFilters(deviceConfig.Device) error {
 	return nil
 }
-func BridgeSetFilters(deviceConfig.Device) error {
+func (xt *XTables) bridgeSetFilters(deviceConfig.Device) error {
 	return nil
 }
 
 // Network
-func NetworkSetup(map[string]string) error {
+func (xt *XTables) networkSetup(map[string]string) error {
 	return nil
 }
-func NetworkStop() error {
+func (xt *XTables) networkStop() error {
 	return nil
 }

From aec3f290f22f8cefafb40446004bc6fc0e0007e6 Mon Sep 17 00:00:00 2001
From: Louise Montalvo <louanmontalvo at gmail.com>
Date: Mon, 4 Nov 2019 15:07:38 -0600
Subject: [PATCH 05/11] Update Firewall interface with lower-level clear
 functions ; change casing in Firewall interface

---
 lxd/firewall/interfaces.go | 15 ++++++++-------
 lxd/firewall/xtables.go    | 21 +++++++++++++--------
 2 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/lxd/firewall/interfaces.go b/lxd/firewall/interfaces.go
index 4c45c3d19c..3a373815b0 100644
--- a/lxd/firewall/interfaces.go
+++ b/lxd/firewall/interfaces.go
@@ -1,7 +1,6 @@
 package firewall
 
 import (
-	"github.com/lxc/lxd/lxd/device"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 )
 
@@ -48,15 +47,17 @@ type Firewall interface {
 	// NOTE: xtables will need to include shared
 	// NOTE: nicBridged may need generate/filter functions for nft
 
+	// Lower-level clear functions
+	NetworkClear(string, string, string) error
+	ContainerClear(string, string, string) error
+
 	// Proxy
-	proxyStop() (*device.RunConfig, error)
-	proxySetupNAT()
+	ProxySetupNAT()
 
 	// NIC bridged
-	bridgeRemoveFilters(deviceConfig.Device) error
-	bridgeSetFilters(deviceConfig.Device) error
+	BridgeRemoveFilters(deviceConfig.Device) error
+	BridgeSetFilters(deviceConfig.Device) error
 
 	// Network
-	networkSetup(map[string]string) error
-	networkStop() error
+	NetworkSetup(map[string]string) error
 }
diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
index 095e58af48..742e192628 100644
--- a/lxd/firewall/xtables.go
+++ b/lxd/firewall/xtables.go
@@ -8,26 +8,31 @@ import (
 // XTables is an implmentation of LXD firewall using {ip, ip6, eb}tables
 type XTables struct {}
 
+// Lower-level clear functions
+func (xt *XTables) NetworkClear(protocol string, comment string, table string) error {
+	return nil
+}
+func (xt *XTables) ContainerClear(protocol string, comment string, table string) error {
+	return nil
+}
+
 // Proxy
-func (xt *XTables) proxyStop() (*device.RunConfig, error) {
+func (xt *XTables) ProxyStop() (*device.RunConfig, error) {
 	return nil, nil
 }
-func (xt *XTables) proxySetupNAT() {
+func (xt *XTables) ProxySetupNAT() {
 
 }
 
 // NIC bridged
-func (xt *XTables) bridgeRemoveFilters(deviceConfig.Device) error {
+func (xt *XTables) BridgeRemoveFilters(deviceConfig.Device) error {
 	return nil
 }
-func (xt *XTables) bridgeSetFilters(deviceConfig.Device) error {
+func (xt *XTables) BridgeSetFilters(deviceConfig.Device) error {
 	return nil
 }
 
 // Network
-func (xt *XTables) networkSetup(map[string]string) error {
-	return nil
-}
-func (xt *XTables) networkStop() error {
+func (xt *XTables) NetworkSetup(map[string]string) error {
 	return nil
 }

From 9525e4cffde50f866577e501f58b3eba0107e4d9 Mon Sep 17 00:00:00 2001
From: Danny Tran <dannytran at utexas.edu>
Date: Mon, 4 Nov 2019 15:19:18 -0600
Subject: [PATCH 06/11] Added implementation of xtables clear functions

---
 lxd/firewall/xtables.go | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
index 742e192628..51616690a3 100644
--- a/lxd/firewall/xtables.go
+++ b/lxd/firewall/xtables.go
@@ -1,6 +1,7 @@
 package firewall
 
 import (
+	"github.com/lxc/lxd/lxd/iptables"
 	"github.com/lxc/lxd/lxd/device"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 )
@@ -9,11 +10,15 @@ import (
 type XTables struct {}
 
 // Lower-level clear functions
+
+// NetworkClear removes network rules.
 func (xt *XTables) NetworkClear(protocol string, comment string, table string) error {
-	return nil
+	return iptables.NetworkClear(protocol, comment, table)
 }
+
+// ContainerClear removes container rules.
 func (xt *XTables) ContainerClear(protocol string, comment string, table string) error {
-	return nil
+	return iptables.ContainerClear(protocol, comment, table)
 }
 
 // Proxy

From 391a6316aaa093c4030f79a9e61c65f67e02bcd6 Mon Sep 17 00:00:00 2001
From: Louise Montalvo <louanmontalvo at gmail.com>
Date: Mon, 4 Nov 2019 15:21:40 -0600
Subject: [PATCH 07/11] Remove old ProxyStop() function from the Firewall
 interface

---
 lxd/firewall/xtables.go | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
index 51616690a3..26f17f1f53 100644
--- a/lxd/firewall/xtables.go
+++ b/lxd/firewall/xtables.go
@@ -22,9 +22,6 @@ func (xt *XTables) ContainerClear(protocol string, comment string, table string)
 }
 
 // Proxy
-func (xt *XTables) ProxyStop() (*device.RunConfig, error) {
-	return nil, nil
-}
 func (xt *XTables) ProxySetupNAT() {
 
 }

From 3a3a3a9298f91662ccb50774240df7d57c430443 Mon Sep 17 00:00:00 2001
From: Oscar Ward <oscarward95 at gmail.com>
Date: Mon, 4 Nov 2019 15:39:57 -0600
Subject: [PATCH 08/11] ProxySetupNAT implemented

---
 lxd/firewall/xtables.go | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
index 26f17f1f53..72c4f2c471 100644
--- a/lxd/firewall/xtables.go
+++ b/lxd/firewall/xtables.go
@@ -1,8 +1,9 @@
 package firewall
 
 import (
+	"fmt"
 	"github.com/lxc/lxd/lxd/iptables"
-	"github.com/lxc/lxd/lxd/device"
+	//"github.com/lxc/lxd/lxd/device"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 )
 
@@ -22,8 +23,20 @@ func (xt *XTables) ContainerClear(protocol string, comment string, table string)
 }
 
 // Proxy
-func (xt *XTables) ProxySetupNAT() {
+func (xt *XTables) ProxySetupNAT(ipv string, IPAddr string, comment string, connType, address, port string, cPort string) error {
+	if IPAddr != "" {
+		err := iptables.ContainerPrepend(ipv, comment, "nat", "PREROUTING", "-p", connType, "--destination", address, "--dport", port, "-j", "DNAT", "--to-destination", fmt.Sprintf("%s:%s", IPAddr, cPort))
+		if err != nil {
+			return err
+		}
+
+		err = iptables.ContainerPrepend(ipv, comment, "nat", "OUTPUT", "-p", connType, "--destination", address, "--dport", port, "-j", "DNAT", "--to-destination", fmt.Sprintf("%s:%s", IPAddr, cPort))
+		if err != nil {
+			return err
+		}
+	}
 
+	return nil
 }
 
 // NIC bridged

From 2808a8a6400e3a8aad8a6d397feb1c9d9740fa8a Mon Sep 17 00:00:00 2001
From: Louise Montalvo <louanmontalvo at gmail.com>
Date: Mon, 4 Nov 2019 15:57:43 -0600
Subject: [PATCH 09/11] Implement BridgeRemoveFilters() for XTables

---
 lxd/firewall/xtables.go | 109 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 107 insertions(+), 2 deletions(-)

diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
index 72c4f2c471..db5fb9f786 100644
--- a/lxd/firewall/xtables.go
+++ b/lxd/firewall/xtables.go
@@ -2,9 +2,12 @@ package firewall
 
 import (
 	"fmt"
+	"net"
+	"strings"
+
 	"github.com/lxc/lxd/lxd/iptables"
-	//"github.com/lxc/lxd/lxd/device"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
+	"github.com/lxc/lxd/shared"
 )
 
 // XTables is an implmentation of LXD firewall using {ip, ip6, eb}tables
@@ -40,7 +43,47 @@ func (xt *XTables) ProxySetupNAT(ipv string, IPAddr string, comment string, conn
 }
 
 // NIC bridged
-func (xt *XTables) BridgeRemoveFilters(deviceConfig.Device) error {
+func (xt *XTables) BridgeRemoveFilters(m deviceConfig.Device, IPv4 net.IP, IPv6 net.IP) error {
+	// Get a current list of rules active on the host.
+	out, err := shared.RunCommand("ebtables", "--concurrent", "-L", "--Lmac2", "--Lx")
+	if err != nil {
+		return fmt.Errorf("Failed to remove network filters for %s: %v", m["name"], err)
+	}
+
+	// Get a list of rules that we would have applied on instance start.
+	rules := generateFilterEbtablesRules(m, IPv4, IPv6)
+
+	errs := []error{}
+	// Iterate through each active rule on the host and try and match it to one the LXD rules.
+	for _, line := range strings.Split(out, "\n") {
+		line = strings.TrimSpace(line)
+		fields := strings.Fields(line)
+		fieldsLen := len(fields)
+
+		for _, rule := range rules {
+			// Rule doesn't match if the field lenths aren't the same, move on.
+			if len(rule) != fieldsLen {
+				continue
+			}
+
+			// Check whether active rule matches one of our rules to delete.
+			if !matchEbtablesRule(fields, rule, true) {
+				continue
+			}
+
+			// If we get this far, then the current host rule matches one of our LXD
+			// rules, so we should run the modified command to delete it.
+			_, err = shared.RunCommand(fields[0], append([]string{"--concurrent"}, fields[1:]...)...)
+			if err != nil {
+				errs = append(errs, err)
+			}
+		}
+	}
+
+	if len(errs) > 0 {
+		return fmt.Errorf("Failed to remove network filters rule for %s: %v", m["name"], errs)
+	}
+
 	return nil
 }
 func (xt *XTables) BridgeSetFilters(deviceConfig.Device) error {
@@ -51,3 +94,65 @@ func (xt *XTables) BridgeSetFilters(deviceConfig.Device) error {
 func (xt *XTables) NetworkSetup(map[string]string) error {
 	return nil
 }
+
+// generateFilterEbtablesRules returns a customised set of ebtables filter rules based on the device.
+func generateFilterEbtablesRules(m deviceConfig.Device, IPv4 net.IP, IPv6 net.IP) [][]string {
+	// MAC source filtering rules. Blocks any packet coming from instance with an incorrect Ethernet source MAC.
+	// This is required for IP filtering too.
+	rules := [][]string{
+		{"ebtables", "-t", "filter", "-A", "INPUT", "-s", "!", m["hwaddr"], "-i", m["host_name"], "-j", "DROP"},
+		{"ebtables", "-t", "filter", "-A", "FORWARD", "-s", "!", m["hwaddr"], "-i", m["host_name"], "-j", "DROP"},
+	}
+
+	if shared.IsTrue(m["security.ipv4_filtering"]) && IPv4 != nil {
+		rules = append(rules,
+			// Prevent ARP MAC spoofing (prevents the instance poisoning the ARP cache of its neighbours with a MAC address that isn't its own).
+			[]string{"ebtables", "-t", "filter", "-A", "INPUT", "-p", "ARP", "-i", m["host_name"], "--arp-mac-src", "!", m["hwaddr"], "-j", "DROP"},
+			[]string{"ebtables", "-t", "filter", "-A", "FORWARD", "-p", "ARP", "-i", m["host_name"], "--arp-mac-src", "!", m["hwaddr"], "-j", "DROP"},
+			// Prevent ARP IP spoofing (prevents the instance redirecting traffic for IPs that are not its own).
+			[]string{"ebtables", "-t", "filter", "-A", "INPUT", "-p", "ARP", "-i", m["host_name"], "--arp-ip-src", "!", IPv4.String(), "-j", "DROP"},
+			[]string{"ebtables", "-t", "filter", "-A", "FORWARD", "-p", "ARP", "-i", m["host_name"], "--arp-ip-src", "!", IPv4.String(), "-j", "DROP"},
+			// Allow DHCPv4 to the host only. This must come before the IP source filtering rules below.
+			[]string{"ebtables", "-t", "filter", "-A", "INPUT", "-p", "IPv4", "-s", m["hwaddr"], "-i", m["host_name"], "--ip-src", "0.0.0.0", "--ip-dst", "255.255.255.255", "--ip-proto", "udp", "--ip-dport", "67", "-j", "ACCEPT"},
+			// IP source filtering rules. Blocks any packet coming from instance with an incorrect IP source address.
+			[]string{"ebtables", "-t", "filter", "-A", "INPUT", "-p", "IPv4", "-i", m["host_name"], "--ip-src", "!", IPv4.String(), "-j", "DROP"},
+			[]string{"ebtables", "-t", "filter", "-A", "FORWARD", "-p", "IPv4", "-i", m["host_name"], "--ip-src", "!", IPv4.String(), "-j", "DROP"},
+		)
+	}
+
+	if shared.IsTrue(m["security.ipv6_filtering"]) && IPv6 != nil {
+		rules = append(rules,
+			// Allow DHCPv6 and Router Solicitation to the host only. This must come before the IP source filtering rules below.
+			[]string{"ebtables", "-t", "filter", "-A", "INPUT", "-p", "IPv6", "-s", m["hwaddr"], "-i", m["host_name"], "--ip6-src", "fe80::/ffc0::", "--ip6-dst", "ff02::1:2/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "--ip6-proto", "udp", "--ip6-dport", "547", "-j", "ACCEPT"},
+			[]string{"ebtables", "-t", "filter", "-A", "INPUT", "-p", "IPv6", "-s", m["hwaddr"], "-i", m["host_name"], "--ip6-src", "fe80::/ffc0::", "--ip6-dst", "ff02::2/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "--ip6-proto", "ipv6-icmp", "--ip6-icmp-type", "router-solicitation", "-j", "ACCEPT"},
+			// IP source filtering rules. Blocks any packet coming from instance with an incorrect IP source address.
+			[]string{"ebtables", "-t", "filter", "-A", "INPUT", "-p", "IPv6", "-i", m["host_name"], "--ip6-src", "!", fmt.Sprintf("%s/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", IPv6.String()), "-j", "DROP"},
+			[]string{"ebtables", "-t", "filter", "-A", "FORWARD", "-p", "IPv6", "-i", m["host_name"], "--ip6-src", "!", fmt.Sprintf("%s/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", IPv6.String()), "-j", "DROP"},
+		)
+	}
+
+	return rules
+}
+
+// matchEbtablesRule compares an active rule to a supplied match rule to see if they match.
+// If deleteMode is true then the "-A" flag in the active rule will be modified to "-D" and will
+// not be part of the equality match. This allows delete commands to be generated from dumped add commands.
+func matchEbtablesRule(activeRule []string, matchRule []string, deleteMode bool) bool {
+	for i := range matchRule {
+		// Active rules will be dumped in "add" format, we need to detect
+		// this and switch it to "delete" mode if requested. If this has already been
+		// done then move on, as we don't want to break the comparison below.
+		if deleteMode && (activeRule[i] == "-A" || activeRule[i] == "-D") {
+			activeRule[i] = "-D"
+			continue
+		}
+
+		// Check the match rule field matches the active rule field.
+		// If they don't match, then this isn't one of our rules.
+		if activeRule[i] != matchRule[i] {
+			return false
+		}
+	}
+
+	return true
+}

From 103771600cf75e9f875fdb8d237c9c13b7a6fb47 Mon Sep 17 00:00:00 2001
From: Louise Montalvo <louanmontalvo at gmail.com>
Date: Mon, 4 Nov 2019 16:02:38 -0600
Subject: [PATCH 10/11] Add parameter names to the Firewall interface

---
 lxd/firewall/interfaces.go | 14 ++++++++------
 lxd/firewall/xtables.go    |  4 ++--
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/lxd/firewall/interfaces.go b/lxd/firewall/interfaces.go
index 3a373815b0..7d95f8ccec 100644
--- a/lxd/firewall/interfaces.go
+++ b/lxd/firewall/interfaces.go
@@ -1,6 +1,8 @@
 package firewall
 
 import (
+	"net"
+
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 )
 
@@ -48,16 +50,16 @@ type Firewall interface {
 	// NOTE: nicBridged may need generate/filter functions for nft
 
 	// Lower-level clear functions
-	NetworkClear(string, string, string) error
-	ContainerClear(string, string, string) error
+	NetworkClear(protocol string, comment string, table string) error
+	ContainerClear(protocol string, comment string, table string) error
 
 	// Proxy
-	ProxySetupNAT()
+	ProxySetupNAT(ipv string, IPAddr string, comment string, connType, address, port string, cPort string) error
 
 	// NIC bridged
-	BridgeRemoveFilters(deviceConfig.Device) error
-	BridgeSetFilters(deviceConfig.Device) error
+	BridgeRemoveFilters(m deviceConfig.Device, IPv4 net.IP, IPv6 net.IP) error
+	BridgeSetFilters(m deviceConfig.Device) error
 
 	// Network
-	NetworkSetup(map[string]string) error
+	NetworkSetup(oldConfig map[string]string) error
 }
diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
index db5fb9f786..b19cf3eeba 100644
--- a/lxd/firewall/xtables.go
+++ b/lxd/firewall/xtables.go
@@ -86,12 +86,12 @@ func (xt *XTables) BridgeRemoveFilters(m deviceConfig.Device, IPv4 net.IP, IPv6
 
 	return nil
 }
-func (xt *XTables) BridgeSetFilters(deviceConfig.Device) error {
+func (xt *XTables) BridgeSetFilters(m deviceConfig.Device) error {
 	return nil
 }
 
 // Network
-func (xt *XTables) NetworkSetup(map[string]string) error {
+func (xt *XTables) NetworkSetup(oldConfig map[string]string) error {
 	return nil
 }
 

From 27d1349307b1d6bbd02095343f2f089ecef4a955 Mon Sep 17 00:00:00 2001
From: Louise Montalvo <louanmontalvo at gmail.com>
Date: Mon, 4 Nov 2019 16:34:43 -0600
Subject: [PATCH 11/11] Implement BridgeSetFilters for XTables

---
 lxd/firewall/interfaces.go |  5 +--
 lxd/firewall/xtables.go    | 70 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/lxd/firewall/interfaces.go b/lxd/firewall/interfaces.go
index 7d95f8ccec..222cf0213a 100644
--- a/lxd/firewall/interfaces.go
+++ b/lxd/firewall/interfaces.go
@@ -49,16 +49,17 @@ type Firewall interface {
 	// NOTE: xtables will need to include shared
 	// NOTE: nicBridged may need generate/filter functions for nft
 
-	// Lower-level clear functions
+	// Lower-level functions
 	NetworkClear(protocol string, comment string, table string) error
 	ContainerClear(protocol string, comment string, table string) error
+	VerifyIPv6Module() error
 
 	// Proxy
 	ProxySetupNAT(ipv string, IPAddr string, comment string, connType, address, port string, cPort string) error
 
 	// NIC bridged
 	BridgeRemoveFilters(m deviceConfig.Device, IPv4 net.IP, IPv6 net.IP) error
-	BridgeSetFilters(m deviceConfig.Device) error
+	BridgeSetFilters(m deviceConfig.Device, config map[string]string, IPv4 net.IP, IPv6 net.IP, name string) error
 
 	// Network
 	NetworkSetup(oldConfig map[string]string) error
diff --git a/lxd/firewall/xtables.go b/lxd/firewall/xtables.go
index b19cf3eeba..aa03827c74 100644
--- a/lxd/firewall/xtables.go
+++ b/lxd/firewall/xtables.go
@@ -4,8 +4,10 @@ import (
 	"fmt"
 	"net"
 	"strings"
+	"encoding/hex"
 
 	"github.com/lxc/lxd/lxd/iptables"
+	"github.com/lxc/lxd/lxd/device"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 	"github.com/lxc/lxd/shared"
 )
@@ -24,6 +26,20 @@ func (xt *XTables) NetworkClear(protocol string, comment string, table string) e
 func (xt *XTables) ContainerClear(protocol string, comment string, table string) error {
 	return iptables.ContainerClear(protocol, comment, table)
 }
+func (xt *XTables) VerifyIPv6Module() error {
+	// Check br_netfilter is loaded and enabled for IPv6.
+	sysctlPath := "bridge/bridge-nf-call-ip6tables"
+	sysctlVal, err := device.NetworkSysctlGet(sysctlPath)
+	if err != nil {
+		return fmt.Errorf("Error reading net sysctl %s: %v", sysctlPath, err)
+	}
+
+	if sysctlVal != "1\n" {
+		return fmt.Errorf("security.ipv6_filtering requires br_netfilter and sysctl net.bridge.bridge-nf-call-ip6tables=1")
+	}
+
+	return nil
+}
 
 // Proxy
 func (xt *XTables) ProxySetupNAT(ipv string, IPAddr string, comment string, connType, address, port string, cPort string) error {
@@ -86,7 +102,27 @@ func (xt *XTables) BridgeRemoveFilters(m deviceConfig.Device, IPv4 net.IP, IPv6
 
 	return nil
 }
-func (xt *XTables) BridgeSetFilters(m deviceConfig.Device) error {
+func (xt *XTables) BridgeSetFilters(m deviceConfig.Device, config map[string]string, IPv4 net.IP, IPv6 net.IP, name string) error {
+	rules := generateFilterEbtablesRules(config, IPv4, IPv6)
+	for _, rule := range rules {
+		_, err := shared.RunCommand(rule[0], append([]string{"--concurrent"}, rule[1:]...)...)
+		if err != nil {
+			return err
+		}
+	}
+
+	rules, err := generateFilterIptablesRules(config, IPv6)
+	if err != nil {
+		return err
+	}
+
+	for _, rule := range rules {
+		err = iptables.ContainerPrepend(rule[0], fmt.Sprintf("%s - %s_filtering", name, rule[0]), "filter", rule[1], rule[2:]...)
+		if err != nil {
+			return err
+		}
+	}
+
 	return nil
 }
 
@@ -133,6 +169,38 @@ func generateFilterEbtablesRules(m deviceConfig.Device, IPv4 net.IP, IPv6 net.IP
 
 	return rules
 }
+// generateFilterIptablesRules returns a customised set of iptables filter rules based on the device.
+func generateFilterIptablesRules(m deviceConfig.Device, IPv6 net.IP) (rules [][]string, err error) {
+	mac, err := net.ParseMAC(m["hwaddr"])
+	if err != nil {
+		return
+	}
+
+	macHex := hex.EncodeToString(mac)
+
+	// These rules below are implemented using ip6tables because the functionality to inspect
+	// the contents of an ICMPv6 packet does not exist in ebtables (unlike for IPv4 ARP).
+	// Additionally, ip6tables doesn't really provide a nice way to do what we need here, so we
+	// have resorted to doing a raw hex comparison of the packet contents at fixed positions.
+	// If these rules are not added then it is possible to hijack traffic for another IP that is
+	// not assigned to the instance by sending a specially crafted gratuitous NDP packet with
+	// correct source address and MAC at the IP & ethernet layers, but a fraudulent IP or MAC
+	// inside the ICMPv6 NDP packet.
+	if shared.IsTrue(m["security.ipv6_filtering"]) && IPv6 != nil {
+		ipv6Hex := hex.EncodeToString(IPv6)
+
+		rules = append(rules,
+			// Prevent Neighbor Advertisement IP spoofing (prevents the instance redirecting traffic for IPs that are not its own).
+			[]string{"ipv6", "INPUT", "-i", m["parent"], "-p", "ipv6-icmp", "-m", "physdev", "--physdev-in", m["host_name"], "-m", "icmp6", "--icmpv6-type", "136", "-m", "string", "!", "--hex-string", fmt.Sprintf("|%s|", ipv6Hex), "--algo", "bm", "--from", "48", "--to", "64", "-j", "DROP"},
+			[]string{"ipv6", "FORWARD", "-i", m["parent"], "-p", "ipv6-icmp", "-m", "physdev", "--physdev-in", m["host_name"], "-m", "icmp6", "--icmpv6-type", "136", "-m", "string", "!", "--hex-string", fmt.Sprintf("|%s|", ipv6Hex), "--algo", "bm", "--from", "48", "--to", "64", "-j", "DROP"},
+			// Prevent Neighbor Advertisement MAC spoofing (prevents the instance poisoning the NDP cache of its neighbours with a MAC address that isn't its own).
+			[]string{"ipv6", "INPUT", "-i", m["parent"], "-p", "ipv6-icmp", "-m", "physdev", "--physdev-in", m["host_name"], "-m", "icmp6", "--icmpv6-type", "136", "-m", "string", "!", "--hex-string", fmt.Sprintf("|%s|", macHex), "--algo", "bm", "--from", "66", "--to", "72", "-j", "DROP"},
+			[]string{"ipv6", "FORWARD", "-i", m["parent"], "-p", "ipv6-icmp", "-m", "physdev", "--physdev-in", m["host_name"], "-m", "icmp6", "--icmpv6-type", "136", "-m", "string", "!", "--hex-string", fmt.Sprintf("|%s|", macHex), "--algo", "bm", "--from", "66", "--to", "72", "-j", "DROP"},
+		)
+	}
+
+	return
+}
 
 // matchEbtablesRule compares an active rule to a supplied match rule to see if they match.
 // If deleteMode is true then the "-A" flag in the active rule will be modified to "-D" and will


More information about the lxc-devel mailing list