The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/4820

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
The current implementation of the NAT feature in LXD causes some
issues when it should collaborate with firewall/IPsec packages. This
patch adds therefor some flexibility within LXD on how firewall
rules are handled. This espacially comes into play during restarts
of lxd(8).

The ipv[46].nat configuration options are advanced to accept the
following options:
- true|insert: the firewall rule is insert at the beginning of the
  POSTROUTING table
- false: no rule is added
- append: the iptables rule is appended at the end of the POSTROUTING
  table

To keep the configuration options backwards compatible the old value
"true" and "false" are kept.
From 0c040ded97bd8389313a000f934bf7bfba3a1232 Mon Sep 17 00:00:00 2001
From: oms-kauz <ad...@kauz.net>
Date: Sat, 21 Jul 2018 07:13:56 +0000
Subject: [PATCH] Allow NAT rule to be appended to POSTROUTING table

The current implementation of the NAT feature in LXD causes some
issues when it should collaborate with firewall/IPsec packages. This
patch adds therefor some flexibility within LXD on how firewall
rules are handled. This espacially comes into play during restarts
of lxd(8).

The ipv[46].nat configuration options are advanced to accept the
following options:
- true|insert: the firewall rule is insert at the beginning of the
  POSTROUTING table
- false: no rule is added
- append: the iptables rule is appended at the end of the POSTROUTING
  table

To keep the configuration options backwards compatible the old value
"true" and "false" are kept.
---
 doc/networks.md          |  4 ++--
 lxd/networks.go          | 16 ++++++++++++----
 lxd/networks_config.go   |  8 ++++++--
 lxd/networks_iptables.go | 13 ++++++++++---
 4 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/doc/networks.md b/doc/networks.md
index 2b29b7a0c..767708371 100644
--- a/doc/networks.md
+++ b/doc/networks.md
@@ -36,7 +36,7 @@ ipv4.dhcp.expiry                | string    | ipv4 dhcp       
      | 1h
 ipv4.dhcp.gateway               | string    | ipv4 dhcp             | 
ipv4.address              | Address of the gateway for the subnet
 ipv4.dhcp.ranges                | string    | ipv4 dhcp             | all 
addresses             | Comma separated list of IP ranges to use for DHCP 
(FIRST-LAST format)
 ipv4.firewall                   | boolean   | ipv4 address          | true     
                 | Whether to generate filtering firewall rules for this network
-ipv4.nat                        | boolean   | ipv4 address          | false    
                 | Whether to NAT (will default to true if unset and a random 
ipv4.address is generated)
+ipv4.nat                        | string    | ipv4 address          | false    
                 | Whether and how to NAT ("true" / "insert" a NAT rule is 
inserted into the NAT table, "append" a NAT rule is appended into the NAT 
table, "false" no rule generated). It will default to "true"/"insert" if unset 
and a random ipv4.address is generated)
 ipv4.routes                     | string    | ipv4 address          | -        
                 | Comma separated list of additional IPv4 CIDR subnets to 
route to the bridge
 ipv4.routing                    | boolean   | ipv4 address          | true     
                 | Whether to route traffic in and out of the bridge
 ipv6.address                    | string    | standard mode         | random 
unused subnet      | IPv6 address for the bridge (CIDR notation). Use "none" to 
turn off IPv6 or "auto" to generate a new one
@@ -45,7 +45,7 @@ ipv6.dhcp.expiry                | string    | ipv6 dhcp       
      | 1h
 ipv6.dhcp.ranges                | string    | ipv6 stateful dhcp    | all 
addresses             | Comma separated list of IPv6 ranges to use for DHCP 
(FIRST-LAST format)
 ipv6.dhcp.stateful              | boolean   | ipv6 dhcp             | false    
                 | Whether to allocate addresses using DHCP
 ipv6.firewall                   | boolean   | ipv6 address          | true     
                 | Whether to generate filtering firewall rules for this network
-ipv6.nat                        | boolean   | ipv6 address          | false    
                 | Whether to NAT (will default to true if unset and a random 
ipv6.address is generated)
+ipv6.nat                        | string    | ipv6 address          | false    
                 | Whether and how to NAT ("true" / "insert" a NAT rule is 
inserted into the NAT table, "append" a NAT rule is appended into the NAT 
table, "false" no rule generated). It will default to "true"/"insert" if unset 
and a random ipv4.address is generated)
 ipv6.routes                     | string    | ipv6 address          | -        
                 | Comma separated list of additional IPv6 CIDR subnets to 
route to the bridge
 ipv6.routing                    | boolean   | ipv6 address          | true     
                 | Whether to route traffic in and out of the bridge
 raw.dnsmasq                     | string    | -                     | -        
                 | Additional dnsmasq configuration to append to the 
configuration
diff --git a/lxd/networks.go b/lxd/networks.go
index b81963be4..1f40703ea 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -1225,8 +1225,12 @@ func (n *network) Start() error {
                }
 
                // Configure NAT
-               if shared.IsTrue(n.config["ipv4.nat"]) {
-                       err = networkIptablesPrepend("ipv4", n.name, "nat", 
"POSTROUTING", "-s", subnet.String(), "!", "-d", subnet.String(), "-j", 
"MASQUERADE")
+               if !shared.StringInSlice(n.config["ipv4.nat"], []string{"", 
"false"}) {
+                       if shared.StringInSlice(n.config["ipv4.nat"], 
[]string{"true", "insert"}) {
+                               err = networkIptablesPrepend("ipv4", n.name, 
"nat", "POSTROUTING", "-s", subnet.String(), "!", "-d", subnet.String(), "-j", 
"MASQUERADE")
+                       } else { // "append"
+                               err = networkIptablesAppend("ipv4", n.name, 
"nat", "POSTROUTING", "-s", subnet.String(), "!", "-d", subnet.String(), "-j", 
"MASQUERADE")
+                       }
                        if err != nil {
                                return err
                        }
@@ -1387,8 +1391,12 @@ func (n *network) Start() error {
                }
 
                // Configure NAT
-               if shared.IsTrue(n.config["ipv6.nat"]) {
-                       err = networkIptablesPrepend("ipv6", n.name, "nat", 
"POSTROUTING", "-s", subnet.String(), "!", "-d", subnet.String(), "-j", 
"MASQUERADE")
+               if !shared.StringInSlice(n.config["ipv6.nat"], []string{"", 
"false"}) {
+                       if shared.StringInSlice(n.config["ipv6.nat"], 
[]string{"true", "insert"}) {
+                               err = networkIptablesPrepend("ipv6", n.name, 
"nat", "POSTROUTING", "-s", subnet.String(), "!", "-d", subnet.String(), "-j", 
"MASQUERADE")
+                       } else { // "append"
+                               err = networkIptablesAppend("ipv6", n.name, 
"nat", "POSTROUTING", "-s", subnet.String(), "!", "-d", subnet.String(), "-j", 
"MASQUERADE")
+                       }
                        if err != nil {
                                return err
                        }
diff --git a/lxd/networks_config.go b/lxd/networks_config.go
index 5c79a9d86..c6dfcf618 100644
--- a/lxd/networks_config.go
+++ b/lxd/networks_config.go
@@ -61,7 +61,9 @@ var networkConfigKeys = map[string]func(value string) error{
                return networkValidAddressCIDRV4(value)
        },
        "ipv4.firewall":     shared.IsBool,
-       "ipv4.nat":          shared.IsBool,
+       "ipv4.nat": func(value string) error {
+               return shared.IsOneOf(value, []string{"true", "append", 
"insert", "false"})
+       },
        "ipv4.dhcp":         shared.IsBool,
        "ipv4.dhcp.gateway": networkValidAddressV4,
        "ipv4.dhcp.expiry":  shared.IsAny,
@@ -77,7 +79,9 @@ var networkConfigKeys = map[string]func(value string) error{
                return networkValidAddressCIDRV6(value)
        },
        "ipv6.firewall":      shared.IsBool,
-       "ipv6.nat":           shared.IsBool,
+       "ipv6.nat": func(value string) error {
+               return shared.IsOneOf(value, []string{"true", "append", 
"insert", "false"})
+       },
        "ipv6.dhcp":          shared.IsBool,
        "ipv6.dhcp.expiry":   shared.IsAny,
        "ipv6.dhcp.stateful": shared.IsBool,
diff --git a/lxd/networks_iptables.go b/lxd/networks_iptables.go
index 1c0c2bc88..1dbaf65d3 100644
--- a/lxd/networks_iptables.go
+++ b/lxd/networks_iptables.go
@@ -8,7 +8,7 @@ import (
        "github.com/lxc/lxd/shared"
 )
 
-func networkIptablesPrepend(protocol string, netName string, table string, 
chain string, rule ...string) error {
+func networkIptablesConfig(protocol string, netName string, table string, 
method string, chain string, rule ...string) error {
        cmd := "iptables"
        if protocol == "ipv6" {
                cmd = "ip6tables"
@@ -34,8 +34,7 @@ func networkIptablesPrepend(protocol string, netName string, 
table string, chain
                return nil
        }
 
-       // Add the rule
-       args = append(baseArgs, []string{"-I", chain}...)
+       args = append(baseArgs, []string{method, chain}...)
        args = append(args, rule...)
        args = append(args, "-m", "comment", "--comment", 
fmt.Sprintf("generated for LXD network %s", netName))
 
@@ -47,6 +46,14 @@ func networkIptablesPrepend(protocol string, netName string, 
table string, chain
        return nil
 }
 
+func networkIptablesAppend(protocol string, netName string, table string, 
chain string, rule ...string) error {
+       return networkIptablesConfig(protocol, netName, table, "-A", chain, 
rule...)
+}
+
+func networkIptablesPrepend(protocol string, netName string, table string, 
chain string, rule ...string) error {
+       return networkIptablesConfig(protocol, netName, table, "-I", chain, 
rule...)
+}
+
 func networkIptablesClear(protocol string, netName string, table string) error 
{
        // Detect kernels that lack IPv6 support
        if !shared.PathExists("/proc/sys/net/ipv6") && protocol == "ipv6" {
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to