diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index fbc9e11ae402e977fc7eb6205f93d00c3bd5c4ad..3b3de15c34d73284e87cb32c4186c976f03289df 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1293,6 +1293,7 @@ iptablesAddForwardRejectOut; iptablesAddOutputFixUdpChecksum; iptablesAddTcpInput; iptablesAddUdpInput; +iptablesAddUdpOutput; iptablesRemoveDontMasquerade; iptablesRemoveForwardAllowCross; iptablesRemoveForwardAllowIn; @@ -1304,6 +1305,7 @@ iptablesRemoveForwardRejectOut; iptablesRemoveOutputFixUdpChecksum; iptablesRemoveTcpInput; iptablesRemoveUdpInput; +iptablesRemoveUdpOutput; # util/virjson.h diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c index 066779a85526dd6c78cd4ac8440a7a718559bafc..a2f02482f10ebc598b505923006d1a40cad1ce6f 100644 --- a/src/network/bridge_driver_linux.c +++ b/src/network/bridge_driver_linux.c @@ -564,6 +564,13 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network) goto err2; } + if (iptablesAddUdpOutput(AF_INET, network->def->bridge, 68) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to allow DHCP replies to '%s'"), + network->def->bridge); + goto err3; + } + /* If we are doing local DHCP service on this network, attempt to * add a rule that will fixup the checksum of DHCP response * packets back to the guests (but report failure without @@ -582,14 +589,14 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network) virReportError(VIR_ERR_SYSTEM_ERROR, _("failed to add iptables rule to allow DNS requests from '%s'"), network->def->bridge); - goto err3; + goto err4; } if (iptablesAddUdpInput(AF_INET, network->def->bridge, 53) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, _("failed to add iptables rule to allow DNS requests from '%s'"), network->def->bridge); - goto err4; + goto err5; } /* allow TFTP requests through to dnsmasq if necessary */ @@ -598,7 +605,7 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network) virReportError(VIR_ERR_SYSTEM_ERROR, _("failed to add iptables rule to allow TFTP requests from '%s'"), network->def->bridge); - goto err5; + goto err6; } /* Catch all rules to block forwarding to/from bridges */ @@ -607,14 +614,14 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network) virReportError(VIR_ERR_SYSTEM_ERROR, _("failed to add iptables rule to block outbound traffic from '%s'"), network->def->bridge); - goto err6; + goto err7; } if (iptablesAddForwardRejectIn(AF_INET, network->def->bridge) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, _("failed to add iptables rule to block inbound traffic to '%s'"), network->def->bridge); - goto err7; + goto err8; } /* Allow traffic between guests on the same bridge */ @@ -622,31 +629,33 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network) virReportError(VIR_ERR_SYSTEM_ERROR, _("failed to add iptables rule to allow cross bridge traffic on '%s'"), network->def->bridge); - goto err8; + goto err9; } /* add IPv6 general rules, if needed */ if (networkAddGeneralIp6tablesRules(network) < 0) { - goto err9; + goto err10; } return 0; /* unwind in reverse order from the point of failure */ -err9: +err10: iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge); -err8: +err9: iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge); -err7: +err8: iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge); -err6: +err7: if (ipv4def && ipv4def->tftproot) { iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69); } -err5: +err6: iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53); -err4: +err5: iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53); +err4: + iptablesRemoveUdpOutput(AF_INET, network->def->bridge, 68); err3: iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67); err2: @@ -680,6 +689,7 @@ void networkRemoveGeneralFirewallRules(virNetworkObjPtr network) if (ipv4def && (ipv4def->nranges || ipv4def->nhosts)) { iptablesRemoveOutputFixUdpChecksum(network->def->bridge, 68); } + iptablesRemoveUdpOutput(AF_INET, network->def->bridge, 68); iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67); iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67); } diff --git a/src/util/viriptables.c b/src/util/viriptables.c index a1711bb36e0fe651ee212c5bc62b4994b63aefb2..9b78d86b6bf912db5ca4ddc1ec2f342bdee05e92 100644 --- a/src/util/viriptables.c +++ b/src/util/viriptables.c @@ -184,6 +184,28 @@ iptablesInput(int family, NULL); } +static int +iptablesOutput(int family, + const char *iface, + int port, + int action, + int tcp) +{ + char portstr[32]; + + snprintf(portstr, sizeof(portstr), "%d", port); + portstr[sizeof(portstr) - 1] = '\0'; + + return iptablesAddRemoveRule("filter", "OUTPUT", + family, + action, + "--out-interface", iface, + "--protocol", tcp ? "tcp" : "udp", + "--destination-port", portstr, + "--jump", "ACCEPT", + NULL); +} + /** * iptablesAddTcpInput: * @ctx: pointer to the IP table context @@ -262,6 +284,45 @@ iptablesRemoveUdpInput(int family, return iptablesInput(family, iface, port, REMOVE, 0); } +/** + * iptablesAddUdpOutput: + * @ctx: pointer to the IP table context + * @iface: the interface name + * @port: the UDP port to add + * + * Add an output to the IP table allowing access to the given @port from + * the given @iface interface for UDP packets + * + * Returns 0 in case of success or an error code in case of error + */ + +int +iptablesAddUdpOutput(int family, + const char *iface, + int port) +{ + return iptablesOutput(family, iface, port, ADD, 0); +} + +/** + * iptablesRemoveUdpOutput: + * @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 UDP packets + * + * Returns 0 in case of success or an error code in case of error + */ +int +iptablesRemoveUdpOutput(int family, + const char *iface, + int port) +{ + return iptablesOutput(family, iface, port, REMOVE, 0); +} + static char *iptablesFormatNetwork(virSocketAddr *netaddr, unsigned int prefix) diff --git a/src/util/viriptables.h b/src/util/viriptables.h index 6dfb9920c6ce170f913e7eee12d978e74b06cc6a..2f9a2129a15a71ffb36d7a0ebeea9a2602ad64b0 100644 --- a/src/util/viriptables.h +++ b/src/util/viriptables.h @@ -40,6 +40,13 @@ int iptablesRemoveUdpInput (int family, const char *iface, int port); +int iptablesAddUdpOutput (int family, + const char *iface, + int port); +int iptablesRemoveUdpOutput (int family, + const char *iface, + int port); + int iptablesAddForwardAllowOut (virSocketAddr *netaddr, unsigned int prefix, const char *iface,