[lxc-devel] [lxd/master] NIC Routed: Adds firewall based reverse path filtering for IPv4 and IPv6
tomponline on Github
lxc-bot at linuxcontainers.org
Mon Mar 30 12:42:33 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200330/39b1ecc7/attachment.bin>
-------------- next part --------------
From e1f77e74fbf6a636b7f78011073caf1a49826b69 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 30 Mar 2020 10:16:59 +0100
Subject: [PATCH 1/6] lxd/firewall/firewall/interface: Adds
InstanceSetupRPFilter and InstanceClearRPFilter
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/firewall/firewall_interface.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lxd/firewall/firewall_interface.go b/lxd/firewall/firewall_interface.go
index c89566e8b1..932c38ddb9 100644
--- a/lxd/firewall/firewall_interface.go
+++ b/lxd/firewall/firewall_interface.go
@@ -10,6 +10,7 @@ import (
type Firewall interface {
String() string
Compat() (bool, bool)
+
NetworkSetupForwardingPolicy(networkName string, ipVersion uint, allow bool) error
NetworkSetupOutboundNAT(networkName string, subnet *net.IPNet, srcIP net.IP, append bool) error
NetworkSetupDHCPDNSAccess(networkName string, ipVersion uint) error
@@ -21,4 +22,7 @@ type Firewall interface {
InstanceSetupProxyNAT(projectName string, instanceName string, deviceName string, listen *deviceConfig.ProxyAddress, connect *deviceConfig.ProxyAddress) error
InstanceClearProxyNAT(projectName string, instanceName string, deviceName string) error
+
+ InstanceSetupRPFilter(projectName string, instanceName string, deviceName string, hostName string) error
+ InstanceClearRPFilter(projectName string, instanceName string, deviceName string) error
}
From fbfdaa6923afd540b1e978e4e045d6a7c9794650 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 30 Mar 2020 10:17:41 +0100
Subject: [PATCH 2/6] lxd/firewall/drivers/drivers/xtables: Improves proxy NAT
rule removal errors
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/firewall/drivers/drivers_xtables.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lxd/firewall/drivers/drivers_xtables.go b/lxd/firewall/drivers/drivers_xtables.go
index 3972e82673..00b7de99c2 100644
--- a/lxd/firewall/drivers/drivers_xtables.go
+++ b/lxd/firewall/drivers/drivers_xtables.go
@@ -418,7 +418,7 @@ func (d Xtables) InstanceClearProxyNAT(projectName string, instanceName string,
}
if len(errs) > 0 {
- return err
+ return fmt.Errorf("Failed to remove proxy NAT rules for %q: %v", deviceName, errs)
}
return nil
From d52fee47c59bef1e27bb25a67b214baa3e0e9fdd Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 30 Mar 2020 10:18:08 +0100
Subject: [PATCH 3/6] lxd/firewall/drivers/drivers/xtables: Renames
iptablesConfig to iptablesAdd
To match comment.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/firewall/drivers/drivers_xtables.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lxd/firewall/drivers/drivers_xtables.go b/lxd/firewall/drivers/drivers_xtables.go
index 00b7de99c2..4c3c67dab4 100644
--- a/lxd/firewall/drivers/drivers_xtables.go
+++ b/lxd/firewall/drivers/drivers_xtables.go
@@ -544,7 +544,7 @@ func (d Xtables) matchEbtablesRule(activeRule []string, matchRule []string, dele
}
// iptablesAdd adds an iptables rule.
-func (d Xtables) iptablesConfig(ipVersion uint, comment string, table string, method string, chain string, rule ...string) error {
+func (d Xtables) iptablesAdd(ipVersion uint, comment string, table string, method string, chain string, rule ...string) error {
var cmd string
if ipVersion == 4 {
cmd = "iptables"
@@ -584,12 +584,12 @@ func (d Xtables) iptablesConfig(ipVersion uint, comment string, table string, me
// iptablesAppend appends an iptables rule.
func (d Xtables) iptablesAppend(ipVersion uint, comment string, table string, chain string, rule ...string) error {
- return d.iptablesConfig(ipVersion, comment, table, "-A", chain, rule...)
+ return d.iptablesAdd(ipVersion, comment, table, "-A", chain, rule...)
}
// iptablesPrepend prepends an iptables rule.
func (d Xtables) iptablesPrepend(ipVersion uint, comment string, table string, chain string, rule ...string) error {
- return d.iptablesConfig(ipVersion, comment, table, "-I", chain, rule...)
+ return d.iptablesAdd(ipVersion, comment, table, "-I", chain, rule...)
}
// iptablesClear clears iptables rules matching the supplied comment in the specified tables.
From 9771abdc899b2e01a3f5db87521a2f1605e54ef4 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 30 Mar 2020 10:18:32 +0100
Subject: [PATCH 4/6] lxd/firewall/drivers/drivers/xtables: Implements reverse
path filters
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/firewall/drivers/drivers_xtables.go | 46 +++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/lxd/firewall/drivers/drivers_xtables.go b/lxd/firewall/drivers/drivers_xtables.go
index 4c3c67dab4..8aea7b38da 100644
--- a/lxd/firewall/drivers/drivers_xtables.go
+++ b/lxd/firewall/drivers/drivers_xtables.go
@@ -665,3 +665,49 @@ func (d Xtables) iptablesClear(ipVersion uint, comment string, fromTables ...str
return nil
}
+
+// InstanceSetupRPFilter activates reverse path filtering for the specified instance device on the host interface.
+func (d Xtables) InstanceSetupRPFilter(projectName string, instanceName string, deviceName string, hostName string) error {
+ comment := fmt.Sprintf("%s rpfilter", d.instanceDeviceIPTablesComment(projectName, instanceName, deviceName))
+ args := []string{
+ "-m", "rpfilter",
+ "--invert",
+ "-i", hostName,
+ "-j", "DROP",
+ }
+
+ // IPv4 filter.
+ err := d.iptablesPrepend(4, comment, "raw", "PREROUTING", args...)
+ if err != nil {
+ return err
+ }
+
+ // IPv6 filter.
+ err = d.iptablesPrepend(6, comment, "raw", "PREROUTING", args...)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// InstanceClearRPFilter removes reverse path filtering for the specified instance device on the host interface.
+func (d Xtables) InstanceClearRPFilter(projectName string, instanceName string, deviceName string) error {
+ comment := fmt.Sprintf("%s rpfilter", d.instanceDeviceIPTablesComment(projectName, instanceName, deviceName))
+ errs := []error{}
+ err := d.iptablesClear(4, comment, "raw")
+ if err != nil {
+ errs = append(errs, err)
+ }
+
+ err = d.iptablesClear(6, comment, "raw")
+ if err != nil {
+ errs = append(errs, err)
+ }
+
+ if len(errs) > 0 {
+ return fmt.Errorf("Failed to remove reverse path filter rules for %q: %v", deviceName, errs)
+ }
+
+ return nil
+}
From 3e143adf08569d1b2dd80424f91a5bd6e5b8bc13 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 30 Mar 2020 11:18:26 +0100
Subject: [PATCH 5/6] lxd/device/nic/routed: Applies firewall based reverse
path filter for IPv4 and IPv6
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/device/nic_routed.go | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/lxd/device/nic_routed.go b/lxd/device/nic_routed.go
index 0e1b3a7e6e..2319ba06a2 100644
--- a/lxd/device/nic_routed.go
+++ b/lxd/device/nic_routed.go
@@ -5,6 +5,8 @@ import (
"os"
"strings"
+ "github.com/pkg/errors"
+
deviceConfig "github.com/lxc/lxd/lxd/device/config"
"github.com/lxc/lxd/lxd/instance"
"github.com/lxc/lxd/lxd/instance/instancetype"
@@ -294,6 +296,12 @@ func (d *nicRouted) postStart() error {
return err
}
+ // Apply firewall rules for reverse path filtering of IPv4 and IPv6.
+ err = d.state.Firewall.InstanceSetupRPFilter(d.inst.Project(), d.inst.Name(), d.name, v["host_name"])
+ if err != nil {
+ return errors.Wrapf(err, "Error setting up reverse path filter")
+ }
+
if d.config["ipv4.address"] != "" {
_, err := shared.RunCommand("ip", "-4", "addr", "add", fmt.Sprintf("%s/32", d.ipv4HostAddress()), "dev", v["host_name"])
if err != nil {
@@ -330,15 +338,27 @@ func (d *nicRouted) postStop() error {
v := d.volatileGet()
+ errs := []error{}
+
// This will delete the parent interface if we created it for VLAN parent.
if shared.IsTrue(v["last_state.created"]) {
parentName := network.GetHostDevice(d.config["parent"], d.config["vlan"])
err := networkRemoveInterfaceIfNeeded(d.state, parentName, d.inst, d.config["parent"], d.config["vlan"])
if err != nil {
- return err
+ errs = append(errs, err)
}
}
+ // Remove reverse path filters.
+ err := d.state.Firewall.InstanceClearRPFilter(d.inst.Project(), d.inst.Name(), d.name)
+ if err != nil {
+ errs = append(errs, err)
+ }
+
+ if len(errs) > 0 {
+ return fmt.Errorf("%v", errs)
+ }
+
return nil
}
From aeab7539562a7626bfa0748c4cb217a903d97df8 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Mon, 30 Mar 2020 13:41:34 +0100
Subject: [PATCH 6/6] lxd/firewall/drivers/drivers/nftables: Implements reverse
path filters
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/firewall/drivers/drivers_nftables.go | 38 +++++++++++++++++++
.../drivers/drivers_nftables_templates.go | 8 ++++
2 files changed, 46 insertions(+)
diff --git a/lxd/firewall/drivers/drivers_nftables.go b/lxd/firewall/drivers/drivers_nftables.go
index 8d070831af..be42a16751 100644
--- a/lxd/firewall/drivers/drivers_nftables.go
+++ b/lxd/firewall/drivers/drivers_nftables.go
@@ -471,3 +471,41 @@ func (d Nftables) removeChains(families []string, chainSuffix string, chains ...
return nil
}
+
+// InstanceSetupRPFilter activates reverse path filtering for the specified instance device on the host interface.
+func (d Nftables) InstanceSetupRPFilter(projectName string, instanceName string, deviceName string, hostName string) error {
+ deviceLabel := d.instanceDeviceLabel(projectName, instanceName, deviceName)
+ tplFields := map[string]interface{}{
+ "namespace": nftablesNamespace,
+ "chainSeparator": nftablesChainSeparator,
+ "deviceLabel": deviceLabel,
+ "hostName": hostName,
+ }
+
+ // IPv4 filter.
+ tplFields["family"] = "ip"
+ err := d.applyNftConfig(nftablesInstanceRPFilter, tplFields)
+ if err != nil {
+ return errors.Wrapf(err, "Failed adding reverse path filter rules for instance device %q (%s)", deviceLabel, tplFields["family"])
+ }
+
+ // IPv46filter.
+ tplFields["family"] = "ip6"
+ err = d.applyNftConfig(nftablesInstanceRPFilter, tplFields)
+ if err != nil {
+ return errors.Wrapf(err, "Failed adding reverse path filter rules for instance device %q (%s)", deviceLabel, tplFields["family"])
+ }
+
+ return nil
+}
+
+// InstanceClearRPFilter removes reverse path filtering for the specified instance device on the host interface.
+func (d Nftables) InstanceClearRPFilter(projectName string, instanceName string, deviceName string) error {
+ deviceLabel := d.instanceDeviceLabel(projectName, instanceName, deviceName)
+ err := d.removeChains([]string{"ip", "ip6"}, deviceLabel, "prert")
+ if err != nil {
+ return errors.Wrapf(err, "Failed clearing reverse path filter rules for instance device %q", deviceLabel)
+ }
+
+ return nil
+}
diff --git a/lxd/firewall/drivers/drivers_nftables_templates.go b/lxd/firewall/drivers/drivers_nftables_templates.go
index df60e83e58..56c7d5d5c4 100644
--- a/lxd/firewall/drivers/drivers_nftables_templates.go
+++ b/lxd/firewall/drivers/drivers_nftables_templates.go
@@ -126,3 +126,11 @@ chain fwd{{.chainSeparator}}{{.deviceLabel}} {
{{- end}}
}
`))
+
+// nftablesInstanceRPFilter defines the rules to perform reverse path filtering.
+var nftablesInstanceRPFilter = template.Must(template.New("nftablesInstanceRPFilter").Parse(`
+chain prert{{.chainSeparator}}{{.deviceLabel}} {
+ type filter hook prerouting priority -300; policy accept;
+ iif "{{.hostName}}" fib saddr . iif oif missing counter drop
+}
+`))
More information about the lxc-devel
mailing list