From: Malina Salina <malina.salina(a)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(a)protonmail.com>
Initial patch then modified to add unit tests and IPv6
support
Signed-off-by: Daniel P. Berrangé <berrange(a)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