[libvirt] [PATCH] network: allow DHCP/DNS/TFTP explicitly in OUTPUT rules

Daniel P. Berrangé posted 1 patch 4 years, 6 months ago
Test syntax-check passed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20190927161655.7101-1-berrange@redhat.com
src/libvirt_private.syms                      |  2 +
src/network/bridge_driver_linux.c             | 29 ++++++++++---
src/util/viriptables.c                        | 36 ++++++++++++++++
src/util/viriptables.h                        |  8 ++++
.../nat-default-linux.args                    | 21 ++++++++++
.../nat-ipv6-linux.args                       | 42 +++++++++++++++++++
.../nat-many-ips-linux.args                   | 21 ++++++++++
.../nat-no-dhcp-linux.args                    | 42 +++++++++++++++++++
.../nat-tftp-linux.args                       | 28 +++++++++++++
.../route-default-linux.args                  | 21 ++++++++++
10 files changed, 244 insertions(+), 6 deletions(-)
[libvirt] [PATCH] network: allow DHCP/DNS/TFTP explicitly in OUTPUT rules
Posted by Daniel P. Berrangé 4 years, 6 months ago
From: Malina Salina <malina.salina@protonmail.com>

While the default iptables setup used by Fedora/RHEL distros
only restricts traffic on the INPUT and/or FORWARD rules,
some users might have custom firewalls that restrict the
OUTPUT rules too.

These can prevent DHCP/DNS/TFTP responses from dnsmasq
from reaching the guest VMs. We should thus whitelist
these protocols in the OUTPUT chain, as well as the
INPUT chain.

Signed-off-by: Malina Salina <malina.salina@protonmail.com>

Initial patch then modified to add unit tests and IPv6
support

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 src/libvirt_private.syms                      |  2 +
 src/network/bridge_driver_linux.c             | 29 ++++++++++---
 src/util/viriptables.c                        | 36 ++++++++++++++++
 src/util/viriptables.h                        |  8 ++++
 .../nat-default-linux.args                    | 21 ++++++++++
 .../nat-ipv6-linux.args                       | 42 +++++++++++++++++++
 .../nat-many-ips-linux.args                   | 21 ++++++++++
 .../nat-no-dhcp-linux.args                    | 42 +++++++++++++++++++
 .../nat-tftp-linux.args                       | 28 +++++++++++++
 .../route-default-linux.args                  | 21 ++++++++++
 10 files changed, 244 insertions(+), 6 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 7b681fac64..83b97af364 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2186,6 +2186,7 @@ iptablesAddForwardRejectIn;
 iptablesAddForwardRejectOut;
 iptablesAddOutputFixUdpChecksum;
 iptablesAddTcpInput;
+iptablesAddTcpOutput;
 iptablesAddUdpInput;
 iptablesAddUdpOutput;
 iptablesRemoveDontMasquerade;
@@ -2198,6 +2199,7 @@ iptablesRemoveForwardRejectIn;
 iptablesRemoveForwardRejectOut;
 iptablesRemoveOutputFixUdpChecksum;
 iptablesRemoveTcpInput;
+iptablesRemoveTcpOutput;
 iptablesRemoveUdpInput;
 iptablesRemoveUdpOutput;
 iptablesSetDeletePrivate;
diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c
index 35459c10d1..0b6ff45b17 100644
--- a/src/network/bridge_driver_linux.c
+++ b/src/network/bridge_driver_linux.c
@@ -553,18 +553,23 @@ networkAddGeneralIPv4FirewallRules(virFirewallPtr fw,
             break;
     }
 
-    /* allow DHCP requests through to dnsmasq */
+    /* allow DHCP requests through to dnsmasq & back out */
     iptablesAddTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
     iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
+    iptablesAddTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
     iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
 
-    /* allow DNS requests through to dnsmasq */
+    /* allow DNS requests through to dnsmasq & back out */
     iptablesAddTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
     iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+    iptablesAddTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+    iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
 
-    /* allow TFTP requests through to dnsmasq if necessary */
-    if (ipv4def && ipv4def->tftproot)
+    /* allow TFTP requests through to dnsmasq if necessary & back out*/
+    if (ipv4def && ipv4def->tftproot) {
         iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
+        iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
+    }
 
     /* Catch all rules to block forwarding to/from bridges */
     iptablesAddForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
@@ -592,13 +597,18 @@ networkRemoveGeneralIPv4FirewallRules(virFirewallPtr fw,
     iptablesRemoveForwardRejectIn(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
     iptablesRemoveForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
 
-    if (ipv4def && ipv4def->tftproot)
+    if (ipv4def && ipv4def->tftproot) {
         iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
+        iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
+    }
 
     iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
     iptablesRemoveTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+    iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+    iptablesRemoveTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
 
     iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
+    iptablesRemoveTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
     iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
     iptablesRemoveTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
 }
@@ -626,10 +636,14 @@ networkAddGeneralIPv6FirewallRules(virFirewallPtr fw,
     iptablesAddForwardAllowCross(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
 
     if (virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
-        /* allow DNS over IPv6 */
+        /* allow DNS over IPv6 & back out */
         iptablesAddTcpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
         iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+        iptablesAddTcpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+        iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+        /* allow DHCPv6 & back out */
         iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 547);
+        iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 546);
     }
 }
 
@@ -643,7 +657,10 @@ networkRemoveGeneralIPv6FirewallRules(virFirewallPtr fw,
     }
 
     if (virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
+        iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 546);
         iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 547);
+        iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+        iptablesRemoveTcpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
         iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
         iptablesRemoveTcpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
     }
diff --git a/src/util/viriptables.c b/src/util/viriptables.c
index 0e3c0ad73a..46d0c3df7a 100644
--- a/src/util/viriptables.c
+++ b/src/util/viriptables.c
@@ -303,6 +303,42 @@ iptablesRemoveUdpInput(virFirewallPtr fw,
     iptablesInput(fw, layer, deletePrivate, iface, port, REMOVE, 0);
 }
 
+/**
+ * iptablesAddTcpOutput:
+ * @ctx: pointer to the IP table context
+ * @iface: the interface name
+ * @port: the TCP port to add
+ *
+ * Add an output to the IP table allowing access to the given @port from
+ * the given @iface interface for TCP packets
+ */
+void
+iptablesAddTcpOutput(virFirewallPtr fw,
+                     virFirewallLayer layer,
+                     const char *iface,
+                     int port)
+{
+    iptablesOutput(fw, layer, true, iface, port, ADD, 1);
+}
+
+/**
+ * iptablesRemoveTcpOutput:
+ * @ctx: pointer to the IP table context
+ * @iface: the interface name
+ * @port: the UDP port to remove
+ *
+ * Removes an output from the IP table, hence forbidding access to the given
+ * @port from the given @iface interface for TCP packets
+ */
+void
+iptablesRemoveTcpOutput(virFirewallPtr fw,
+                        virFirewallLayer layer,
+                        const char *iface,
+                        int port)
+{
+    iptablesOutput(fw, layer, deletePrivate, iface, port, REMOVE, 1);
+}
+
 /**
  * iptablesAddUdpOutput:
  * @ctx: pointer to the IP table context
diff --git a/src/util/viriptables.h b/src/util/viriptables.h
index feea988acd..07b4851013 100644
--- a/src/util/viriptables.h
+++ b/src/util/viriptables.h
@@ -45,6 +45,14 @@ void             iptablesRemoveUdpInput          (virFirewallPtr fw,
                                                   const char *iface,
                                                   int port);
 
+void             iptablesAddTcpOutput            (virFirewallPtr fw,
+                                                  virFirewallLayer layer,
+                                                  const char *iface,
+                                                  int port);
+void             iptablesRemoveTcpOutput         (virFirewallPtr fw,
+                                                  virFirewallLayer layer,
+                                                  const char *iface,
+                                                  int port);
 void             iptablesAddUdpOutput            (virFirewallPtr fw,
                                                   virFirewallLayer layer,
                                                   const char *iface,
diff --git a/tests/networkxml2firewalldata/nat-default-linux.args b/tests/networkxml2firewalldata/nat-default-linux.args
index c9d523d043..ab18f30bd0 100644
--- a/tests/networkxml2firewalldata/nat-default-linux.args
+++ b/tests/networkxml2firewalldata/nat-default-linux.args
@@ -16,6 +16,13 @@ iptables \
 --table filter \
 --insert LIBVIRT_OUT \
 --out-interface virbr0 \
+--protocol tcp \
+--destination-port 68 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
 --protocol udp \
 --destination-port 68 \
 --jump ACCEPT
@@ -35,6 +42,20 @@ iptables \
 --jump ACCEPT
 iptables \
 --table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol tcp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
 --insert LIBVIRT_FWO \
 --in-interface virbr0 \
 --jump REJECT
diff --git a/tests/networkxml2firewalldata/nat-ipv6-linux.args b/tests/networkxml2firewalldata/nat-ipv6-linux.args
index a57b9266af..05d9ee33ca 100644
--- a/tests/networkxml2firewalldata/nat-ipv6-linux.args
+++ b/tests/networkxml2firewalldata/nat-ipv6-linux.args
@@ -16,6 +16,13 @@ iptables \
 --table filter \
 --insert LIBVIRT_OUT \
 --out-interface virbr0 \
+--protocol tcp \
+--destination-port 68 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
 --protocol udp \
 --destination-port 68 \
 --jump ACCEPT
@@ -35,6 +42,20 @@ iptables \
 --jump ACCEPT
 iptables \
 --table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol tcp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
 --insert LIBVIRT_FWO \
 --in-interface virbr0 \
 --jump REJECT
@@ -81,11 +102,32 @@ ip6tables \
 --jump ACCEPT
 ip6tables \
 --table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol tcp \
+--destination-port 53 \
+--jump ACCEPT
+ip6tables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 53 \
+--jump ACCEPT
+ip6tables \
+--table filter \
 --insert LIBVIRT_INP \
 --in-interface virbr0 \
 --protocol udp \
 --destination-port 547 \
 --jump ACCEPT
+ip6tables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 546 \
+--jump ACCEPT
 iptables \
 --table filter \
 --insert LIBVIRT_FWO \
diff --git a/tests/networkxml2firewalldata/nat-many-ips-linux.args b/tests/networkxml2firewalldata/nat-many-ips-linux.args
index 1bdc43fd6a..82e1380f51 100644
--- a/tests/networkxml2firewalldata/nat-many-ips-linux.args
+++ b/tests/networkxml2firewalldata/nat-many-ips-linux.args
@@ -16,6 +16,13 @@ iptables \
 --table filter \
 --insert LIBVIRT_OUT \
 --out-interface virbr0 \
+--protocol tcp \
+--destination-port 68 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
 --protocol udp \
 --destination-port 68 \
 --jump ACCEPT
@@ -35,6 +42,20 @@ iptables \
 --jump ACCEPT
 iptables \
 --table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol tcp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
 --insert LIBVIRT_FWO \
 --in-interface virbr0 \
 --jump REJECT
diff --git a/tests/networkxml2firewalldata/nat-no-dhcp-linux.args b/tests/networkxml2firewalldata/nat-no-dhcp-linux.args
index 7d359f3824..8954cc5473 100644
--- a/tests/networkxml2firewalldata/nat-no-dhcp-linux.args
+++ b/tests/networkxml2firewalldata/nat-no-dhcp-linux.args
@@ -16,6 +16,13 @@ iptables \
 --table filter \
 --insert LIBVIRT_OUT \
 --out-interface virbr0 \
+--protocol tcp \
+--destination-port 68 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
 --protocol udp \
 --destination-port 68 \
 --jump ACCEPT
@@ -35,6 +42,20 @@ iptables \
 --jump ACCEPT
 iptables \
 --table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol tcp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
 --insert LIBVIRT_FWO \
 --in-interface virbr0 \
 --jump REJECT
@@ -81,11 +102,32 @@ ip6tables \
 --jump ACCEPT
 ip6tables \
 --table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol tcp \
+--destination-port 53 \
+--jump ACCEPT
+ip6tables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 53 \
+--jump ACCEPT
+ip6tables \
+--table filter \
 --insert LIBVIRT_INP \
 --in-interface virbr0 \
 --protocol udp \
 --destination-port 547 \
 --jump ACCEPT
+ip6tables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 546 \
+--jump ACCEPT
 iptables \
 --table filter \
 --insert LIBVIRT_FWO \
diff --git a/tests/networkxml2firewalldata/nat-tftp-linux.args b/tests/networkxml2firewalldata/nat-tftp-linux.args
index b721801b70..88e9929b62 100644
--- a/tests/networkxml2firewalldata/nat-tftp-linux.args
+++ b/tests/networkxml2firewalldata/nat-tftp-linux.args
@@ -16,6 +16,13 @@ iptables \
 --table filter \
 --insert LIBVIRT_OUT \
 --out-interface virbr0 \
+--protocol tcp \
+--destination-port 68 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
 --protocol udp \
 --destination-port 68 \
 --jump ACCEPT
@@ -35,6 +42,20 @@ iptables \
 --jump ACCEPT
 iptables \
 --table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol tcp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
 --insert LIBVIRT_INP \
 --in-interface virbr0 \
 --protocol udp \
@@ -42,6 +63,13 @@ iptables \
 --jump ACCEPT
 iptables \
 --table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 69 \
+--jump ACCEPT
+iptables \
+--table filter \
 --insert LIBVIRT_FWO \
 --in-interface virbr0 \
 --jump REJECT
diff --git a/tests/networkxml2firewalldata/route-default-linux.args b/tests/networkxml2firewalldata/route-default-linux.args
index ed3c560f74..c427d9602d 100644
--- a/tests/networkxml2firewalldata/route-default-linux.args
+++ b/tests/networkxml2firewalldata/route-default-linux.args
@@ -16,6 +16,13 @@ iptables \
 --table filter \
 --insert LIBVIRT_OUT \
 --out-interface virbr0 \
+--protocol tcp \
+--destination-port 68 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
 --protocol udp \
 --destination-port 68 \
 --jump ACCEPT
@@ -35,6 +42,20 @@ iptables \
 --jump ACCEPT
 iptables \
 --table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol tcp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
+--insert LIBVIRT_OUT \
+--out-interface virbr0 \
+--protocol udp \
+--destination-port 53 \
+--jump ACCEPT
+iptables \
+--table filter \
 --insert LIBVIRT_FWO \
 --in-interface virbr0 \
 --jump REJECT
-- 
2.21.0

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] network: allow DHCP/DNS/TFTP explicitly in OUTPUT rules
Posted by Michal Prívozník 4 years, 6 months ago
On 9/27/19 6:16 PM, Daniel P. Berrangé wrote:
> From: Malina Salina <malina.salina@protonmail.com>
> 
> While the default iptables setup used by Fedora/RHEL distros
> only restricts traffic on the INPUT and/or FORWARD rules,
> some users might have custom firewalls that restrict the
> OUTPUT rules too.
> 
> These can prevent DHCP/DNS/TFTP responses from dnsmasq
> from reaching the guest VMs. We should thus whitelist
> these protocols in the OUTPUT chain, as well as the
> INPUT chain.
> 
> Signed-off-by: Malina Salina <malina.salina@protonmail.com>
> 
> Initial patch then modified to add unit tests and IPv6
> support
> 
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
>  src/libvirt_private.syms                      |  2 +
>  src/network/bridge_driver_linux.c             | 29 ++++++++++---
>  src/util/viriptables.c                        | 36 ++++++++++++++++
>  src/util/viriptables.h                        |  8 ++++
>  .../nat-default-linux.args                    | 21 ++++++++++
>  .../nat-ipv6-linux.args                       | 42 +++++++++++++++++++
>  .../nat-many-ips-linux.args                   | 21 ++++++++++
>  .../nat-no-dhcp-linux.args                    | 42 +++++++++++++++++++
>  .../nat-tftp-linux.args                       | 28 +++++++++++++
>  .../route-default-linux.args                  | 21 ++++++++++
>  10 files changed, 244 insertions(+), 6 deletions(-)

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>

Michal

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list