mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-30 01:43:23 +00:00
Fix bridge configuration when OUTPUT policy is DROP on the host
When the host is configured with very restrictive firewall (default policy is DROP for all chains, including OUTPUT), the bridge driver for Linux adds netfilter entries to allow DHCP and DNS requests to go from the VM to the dnsmasq of the host. The issue that this commit fixes is the fact that a DROP policy on the OUTPUT chain blocks the DHCP replies from the host’s dnsmasq to the VM. As DHCP replies are sent in UDP, they are not caught by any --ctstate ESTABLISHED rule and so, need to be explicitly allowed. Signed-off-by: Lénaïc Huard <lenaic@lhuard.fr.eu.org>
This commit is contained in:
parent
9a3d7a4778
commit
538daf7f3a
@ -1293,6 +1293,7 @@ iptablesAddForwardRejectOut;
|
|||||||
iptablesAddOutputFixUdpChecksum;
|
iptablesAddOutputFixUdpChecksum;
|
||||||
iptablesAddTcpInput;
|
iptablesAddTcpInput;
|
||||||
iptablesAddUdpInput;
|
iptablesAddUdpInput;
|
||||||
|
iptablesAddUdpOutput;
|
||||||
iptablesRemoveDontMasquerade;
|
iptablesRemoveDontMasquerade;
|
||||||
iptablesRemoveForwardAllowCross;
|
iptablesRemoveForwardAllowCross;
|
||||||
iptablesRemoveForwardAllowIn;
|
iptablesRemoveForwardAllowIn;
|
||||||
@ -1304,6 +1305,7 @@ iptablesRemoveForwardRejectOut;
|
|||||||
iptablesRemoveOutputFixUdpChecksum;
|
iptablesRemoveOutputFixUdpChecksum;
|
||||||
iptablesRemoveTcpInput;
|
iptablesRemoveTcpInput;
|
||||||
iptablesRemoveUdpInput;
|
iptablesRemoveUdpInput;
|
||||||
|
iptablesRemoveUdpOutput;
|
||||||
|
|
||||||
|
|
||||||
# util/virjson.h
|
# util/virjson.h
|
||||||
|
@ -564,6 +564,13 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network)
|
|||||||
goto err2;
|
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
|
/* If we are doing local DHCP service on this network, attempt to
|
||||||
* add a rule that will fixup the checksum of DHCP response
|
* add a rule that will fixup the checksum of DHCP response
|
||||||
* packets back to the guests (but report failure without
|
* packets back to the guests (but report failure without
|
||||||
@ -582,14 +589,14 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network)
|
|||||||
virReportError(VIR_ERR_SYSTEM_ERROR,
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
||||||
_("failed to add iptables rule to allow DNS requests from '%s'"),
|
_("failed to add iptables rule to allow DNS requests from '%s'"),
|
||||||
network->def->bridge);
|
network->def->bridge);
|
||||||
goto err3;
|
goto err4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iptablesAddUdpInput(AF_INET, network->def->bridge, 53) < 0) {
|
if (iptablesAddUdpInput(AF_INET, network->def->bridge, 53) < 0) {
|
||||||
virReportError(VIR_ERR_SYSTEM_ERROR,
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
||||||
_("failed to add iptables rule to allow DNS requests from '%s'"),
|
_("failed to add iptables rule to allow DNS requests from '%s'"),
|
||||||
network->def->bridge);
|
network->def->bridge);
|
||||||
goto err4;
|
goto err5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allow TFTP requests through to dnsmasq if necessary */
|
/* allow TFTP requests through to dnsmasq if necessary */
|
||||||
@ -598,7 +605,7 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network)
|
|||||||
virReportError(VIR_ERR_SYSTEM_ERROR,
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
||||||
_("failed to add iptables rule to allow TFTP requests from '%s'"),
|
_("failed to add iptables rule to allow TFTP requests from '%s'"),
|
||||||
network->def->bridge);
|
network->def->bridge);
|
||||||
goto err5;
|
goto err6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Catch all rules to block forwarding to/from bridges */
|
/* Catch all rules to block forwarding to/from bridges */
|
||||||
@ -607,14 +614,14 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network)
|
|||||||
virReportError(VIR_ERR_SYSTEM_ERROR,
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
||||||
_("failed to add iptables rule to block outbound traffic from '%s'"),
|
_("failed to add iptables rule to block outbound traffic from '%s'"),
|
||||||
network->def->bridge);
|
network->def->bridge);
|
||||||
goto err6;
|
goto err7;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iptablesAddForwardRejectIn(AF_INET, network->def->bridge) < 0) {
|
if (iptablesAddForwardRejectIn(AF_INET, network->def->bridge) < 0) {
|
||||||
virReportError(VIR_ERR_SYSTEM_ERROR,
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
||||||
_("failed to add iptables rule to block inbound traffic to '%s'"),
|
_("failed to add iptables rule to block inbound traffic to '%s'"),
|
||||||
network->def->bridge);
|
network->def->bridge);
|
||||||
goto err7;
|
goto err8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow traffic between guests on the same bridge */
|
/* Allow traffic between guests on the same bridge */
|
||||||
@ -622,31 +629,33 @@ int networkAddGeneralFirewallRules(virNetworkObjPtr network)
|
|||||||
virReportError(VIR_ERR_SYSTEM_ERROR,
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
||||||
_("failed to add iptables rule to allow cross bridge traffic on '%s'"),
|
_("failed to add iptables rule to allow cross bridge traffic on '%s'"),
|
||||||
network->def->bridge);
|
network->def->bridge);
|
||||||
goto err8;
|
goto err9;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add IPv6 general rules, if needed */
|
/* add IPv6 general rules, if needed */
|
||||||
if (networkAddGeneralIp6tablesRules(network) < 0) {
|
if (networkAddGeneralIp6tablesRules(network) < 0) {
|
||||||
goto err9;
|
goto err10;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* unwind in reverse order from the point of failure */
|
/* unwind in reverse order from the point of failure */
|
||||||
err9:
|
err10:
|
||||||
iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge);
|
iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge);
|
||||||
err8:
|
err9:
|
||||||
iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge);
|
iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge);
|
||||||
err7:
|
err8:
|
||||||
iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge);
|
iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge);
|
||||||
err6:
|
err7:
|
||||||
if (ipv4def && ipv4def->tftproot) {
|
if (ipv4def && ipv4def->tftproot) {
|
||||||
iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69);
|
iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69);
|
||||||
}
|
}
|
||||||
err5:
|
err6:
|
||||||
iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53);
|
iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53);
|
||||||
err4:
|
err5:
|
||||||
iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53);
|
iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53);
|
||||||
|
err4:
|
||||||
|
iptablesRemoveUdpOutput(AF_INET, network->def->bridge, 68);
|
||||||
err3:
|
err3:
|
||||||
iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67);
|
iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67);
|
||||||
err2:
|
err2:
|
||||||
@ -680,6 +689,7 @@ void networkRemoveGeneralFirewallRules(virNetworkObjPtr network)
|
|||||||
if (ipv4def && (ipv4def->nranges || ipv4def->nhosts)) {
|
if (ipv4def && (ipv4def->nranges || ipv4def->nhosts)) {
|
||||||
iptablesRemoveOutputFixUdpChecksum(network->def->bridge, 68);
|
iptablesRemoveOutputFixUdpChecksum(network->def->bridge, 68);
|
||||||
}
|
}
|
||||||
|
iptablesRemoveUdpOutput(AF_INET, network->def->bridge, 68);
|
||||||
iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67);
|
iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67);
|
||||||
iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67);
|
iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67);
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,28 @@ iptablesInput(int family,
|
|||||||
NULL);
|
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:
|
* iptablesAddTcpInput:
|
||||||
* @ctx: pointer to the IP table context
|
* @ctx: pointer to the IP table context
|
||||||
@ -262,6 +284,45 @@ iptablesRemoveUdpInput(int family,
|
|||||||
return iptablesInput(family, iface, port, REMOVE, 0);
|
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,
|
static char *iptablesFormatNetwork(virSocketAddr *netaddr,
|
||||||
unsigned int prefix)
|
unsigned int prefix)
|
||||||
|
@ -40,6 +40,13 @@ int iptablesRemoveUdpInput (int family,
|
|||||||
const char *iface,
|
const char *iface,
|
||||||
int port);
|
int port);
|
||||||
|
|
||||||
|
int iptablesAddUdpOutput (int family,
|
||||||
|
const char *iface,
|
||||||
|
int port);
|
||||||
|
int iptablesRemoveUdpOutput (int family,
|
||||||
|
const char *iface,
|
||||||
|
int port);
|
||||||
|
|
||||||
int iptablesAddForwardAllowOut (virSocketAddr *netaddr,
|
int iptablesAddForwardAllowOut (virSocketAddr *netaddr,
|
||||||
unsigned int prefix,
|
unsigned int prefix,
|
||||||
const char *iface,
|
const char *iface,
|
||||||
|
Loading…
Reference in New Issue
Block a user