[libvirt] [PATCH v2] bridge driver: extract platform specifics

* Move platform specific things (e.g. firewalling and route collision checks) into bridge_driver_platform * Create two platform specific implementations: - bridge_driver_linux: Linux implementation using iptables, it's actually the code moved from bridge_driver.c - bridge_driver_nop: dumb implementation that does nothing --- src/network/bridge_driver_platform.h | 79 ++++ src/network/bridge_driver.c | 708 +-------------------------------- src/network/bridge_driver_linux.c | 709 ++++++++++++++++++++++++++++++++++ src/network/bridge_driver_nop.c | 78 ++++ src/network/bridge_driver_platform.c | 32 ++ po/POTFILES.in | 1 + src/Makefile.am | 5 +- 7 files changed, 903 insertions(+), 709 deletions(-) create mode 100644 src/network/bridge_driver_platform.h create mode 100644 src/network/bridge_driver_linux.c create mode 100644 src/network/bridge_driver_nop.c create mode 100644 src/network/bridge_driver_platform.c diff --git a/src/network/bridge_driver_platform.h b/src/network/bridge_driver_platform.h new file mode 100644 index 0000000..289ab79 --- /dev/null +++ b/src/network/bridge_driver_platform.h @@ -0,0 +1,79 @@ +/* + * bridge_driver.h: platform specific routines for bridge driver + * + * Copyright (C) 2006-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_BRIDGE_DRIVER_PLATFORM_H__ +# define __VIR_BRIDGE_DRIVER_PLATFORM_H__ + +# include "internal.h" +# include "virlog.h" +# include "virthread.h" +# include "virdnsmasq.h" +# include "network_conf.h" + +/* Main driver state */ +struct _virNetworkDriverState { + virMutex lock; + + virNetworkObjList networks; + + char *networkConfigDir; + char *networkAutostartDir; + char *stateDir; + char *pidDir; + char *dnsmasqStateDir; + char *radvdStateDir; + dnsmasqCapsPtr dnsmasqCaps; +}; + +typedef struct _virNetworkDriverState virNetworkDriverState; +typedef virNetworkDriverState *virNetworkDriverStatePtr; + +int networkCheckRouteCollision(virNetworkObjPtr network); + +int networkAddMasqueradingFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef); + +void networkRemoveMasqueradingFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef); + +int networkAddRoutingFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef); + +void networkRemoveRoutingFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef); + +int networkAddGeneralFirewallRules(virNetworkObjPtr network); + +void networkRemoveGeneralFirewallRules(virNetworkObjPtr network); + +int networkAddIpSpecificFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef); + +void networkRemoveIpSpecificFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef); + +int networkAddFirewallRules(virNetworkObjPtr network); + +void networkRemoveFirewallRules(virNetworkObjPtr network); + +#endif /* __VIR_BRIDGE_DRIVER_PLATFORM_H__ */ diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 0bb57ea..a1b0dd5 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -45,6 +45,7 @@ #include "virerror.h" #include "datatypes.h" #include "bridge_driver.h" +#include "bridge_driver_platform.h" #include "network_conf.h" #include "device_conf.h" #include "driver.h" @@ -69,24 +70,6 @@ #define VIR_FROM_THIS VIR_FROM_NETWORK -/* Main driver state */ -struct _virNetworkDriverState { - virMutex lock; - - virNetworkObjList networks; - - char *networkConfigDir; - char *networkAutostartDir; - char *stateDir; - char *pidDir; - char *dnsmasqStateDir; - char *radvdStateDir; - dnsmasqCapsPtr dnsmasqCaps; -}; - -typedef struct _virNetworkDriverState virNetworkDriverState; -typedef virNetworkDriverState *virNetworkDriverStatePtr; - static void networkDriverLock(virNetworkDriverStatePtr driver) { virMutexLock(&driver->lock); @@ -1507,597 +1490,6 @@ networkRefreshDaemons(virNetworkDriverStatePtr driver) } } -static int -networkAddMasqueradingFirewallRules(virNetworkObjPtr network, - virNetworkIpDefPtr ipdef) -{ - int prefix = virNetworkIpDefPrefix(ipdef); - const char *forwardIf = virNetworkDefForwardIf(network->def, 0); - - if (prefix < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Invalid prefix or netmask for '%s'"), - network->def->bridge); - goto masqerr1; - } - - /* allow forwarding packets from the bridge interface */ - if (iptablesAddForwardAllowOut(&ipdef->address, - prefix, - network->def->bridge, - forwardIf) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to allow forwarding from '%s'"), - network->def->bridge); - goto masqerr1; - } - - /* allow forwarding packets to the bridge interface if they are - * part of an existing connection - */ - if (iptablesAddForwardAllowRelatedIn(&ipdef->address, - prefix, - network->def->bridge, - forwardIf) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to allow forwarding to '%s'"), - network->def->bridge); - goto masqerr2; - } - - /* - * Enable masquerading. - * - * We need to end up with 3 rules in the table in this order - * - * 1. protocol=tcp with sport mapping restriction - * 2. protocol=udp with sport mapping restriction - * 3. generic any protocol - * - * The sport mappings are required, because default IPtables - * MASQUERADE maintain port numbers unchanged where possible. - * - * NFS can be configured to only "trust" port numbers < 1023. - * - * Guests using NAT thus need to be prevented from having port - * numbers < 1023, otherwise they can bypass the NFS "security" - * check on the source port number. - * - * Since we use '--insert' to add rules to the header of the - * chain, we actually need to add them in the reverse of the - * order just mentioned ! - */ - - /* First the generic masquerade rule for other protocols */ - if (iptablesAddForwardMasquerade(&ipdef->address, - prefix, - forwardIf, - &network->def->forward.addr, - &network->def->forward.port, - NULL) < 0) { - if (forwardIf) - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to enable masquerading to %s"), - forwardIf); - else - virReportError(VIR_ERR_SYSTEM_ERROR, "%s", - _("failed to add iptables rule to enable masquerading")); - goto masqerr3; - } - - /* UDP with a source port restriction */ - if (iptablesAddForwardMasquerade(&ipdef->address, - prefix, - forwardIf, - &network->def->forward.addr, - &network->def->forward.port, - "udp") < 0) { - if (forwardIf) - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to enable UDP masquerading to %s"), - forwardIf); - else - virReportError(VIR_ERR_SYSTEM_ERROR, "%s", - _("failed to add iptables rule to enable UDP masquerading")); - goto masqerr4; - } - - /* TCP with a source port restriction */ - if (iptablesAddForwardMasquerade(&ipdef->address, - prefix, - forwardIf, - &network->def->forward.addr, - &network->def->forward.port, - "tcp") < 0) { - if (forwardIf) - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to enable TCP masquerading to %s"), - forwardIf); - else - virReportError(VIR_ERR_SYSTEM_ERROR, "%s", - _("failed to add iptables rule to enable TCP masquerading")); - goto masqerr5; - } - - return 0; - - masqerr5: - iptablesRemoveForwardMasquerade(&ipdef->address, - prefix, - forwardIf, - &network->def->forward.addr, - &network->def->forward.port, - "udp"); - masqerr4: - iptablesRemoveForwardMasquerade(&ipdef->address, - prefix, - forwardIf, - &network->def->forward.addr, - &network->def->forward.port, - NULL); - masqerr3: - iptablesRemoveForwardAllowRelatedIn(&ipdef->address, - prefix, - network->def->bridge, - forwardIf); - masqerr2: - iptablesRemoveForwardAllowOut(&ipdef->address, - prefix, - network->def->bridge, - forwardIf); - masqerr1: - return -1; -} - -static void -networkRemoveMasqueradingFirewallRules(virNetworkObjPtr network, - virNetworkIpDefPtr ipdef) -{ - int prefix = virNetworkIpDefPrefix(ipdef); - const char *forwardIf = virNetworkDefForwardIf(network->def, 0); - - if (prefix >= 0) { - iptablesRemoveForwardMasquerade(&ipdef->address, - prefix, - forwardIf, - &network->def->forward.addr, - &network->def->forward.port, - "tcp"); - iptablesRemoveForwardMasquerade(&ipdef->address, - prefix, - forwardIf, - &network->def->forward.addr, - &network->def->forward.port, - "udp"); - iptablesRemoveForwardMasquerade(&ipdef->address, - prefix, - forwardIf, - &network->def->forward.addr, - &network->def->forward.port, - NULL); - - iptablesRemoveForwardAllowRelatedIn(&ipdef->address, - prefix, - network->def->bridge, - forwardIf); - iptablesRemoveForwardAllowOut(&ipdef->address, - prefix, - network->def->bridge, - forwardIf); - } -} - -static int -networkAddRoutingFirewallRules(virNetworkObjPtr network, - virNetworkIpDefPtr ipdef) -{ - int prefix = virNetworkIpDefPrefix(ipdef); - const char *forwardIf = virNetworkDefForwardIf(network->def, 0); - - if (prefix < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Invalid prefix or netmask for '%s'"), - network->def->bridge); - goto routeerr1; - } - - /* allow routing packets from the bridge interface */ - if (iptablesAddForwardAllowOut(&ipdef->address, - prefix, - network->def->bridge, - forwardIf) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to allow routing from '%s'"), - network->def->bridge); - goto routeerr1; - } - - /* allow routing packets to the bridge interface */ - if (iptablesAddForwardAllowIn(&ipdef->address, - prefix, - network->def->bridge, - forwardIf) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to allow routing to '%s'"), - network->def->bridge); - goto routeerr2; - } - - return 0; - -routeerr2: - iptablesRemoveForwardAllowOut(&ipdef->address, - prefix, - network->def->bridge, - forwardIf); -routeerr1: - return -1; -} - -static void -networkRemoveRoutingFirewallRules(virNetworkObjPtr network, - virNetworkIpDefPtr ipdef) -{ - int prefix = virNetworkIpDefPrefix(ipdef); - const char *forwardIf = virNetworkDefForwardIf(network->def, 0); - - if (prefix >= 0) { - iptablesRemoveForwardAllowIn(&ipdef->address, - prefix, - network->def->bridge, - forwardIf); - - iptablesRemoveForwardAllowOut(&ipdef->address, - prefix, - network->def->bridge, - forwardIf); - } -} - -/* Add all once/network rules required for IPv6. - * If no IPv6 addresses are defined and <network ipv6='yes'> is - * specified, then allow IPv6 commuinications between virtual systems. - * If any IPv6 addresses are defined, then add the rules for regular operation. - */ -static int -networkAddGeneralIp6tablesRules(virNetworkObjPtr network) -{ - - if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) && - !network->def->ipv6nogw) { - return 0; - } - - /* Catch all rules to block forwarding to/from bridges */ - - if (iptablesAddForwardRejectOut(AF_INET6, network->def->bridge) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add ip6tables rule to block outbound traffic from '%s'"), - network->def->bridge); - goto err1; - } - - if (iptablesAddForwardRejectIn(AF_INET6, network->def->bridge) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add ip6tables rule to block inbound traffic to '%s'"), - network->def->bridge); - goto err2; - } - - /* Allow traffic between guests on the same bridge */ - if (iptablesAddForwardAllowCross(AF_INET6, network->def->bridge) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add ip6tables rule to allow cross bridge traffic on '%s'"), - network->def->bridge); - goto err3; - } - - /* if no IPv6 addresses are defined, we are done. */ - if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) - return 0; - - /* allow DNS over IPv6 */ - if (iptablesAddTcpInput(AF_INET6, network->def->bridge, 53) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add ip6tables rule to allow DNS requests from '%s'"), - network->def->bridge); - goto err4; - } - - if (iptablesAddUdpInput(AF_INET6, network->def->bridge, 53) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add ip6tables rule to allow DNS requests from '%s'"), - network->def->bridge); - goto err5; - } - - if (iptablesAddUdpInput(AF_INET6, network->def->bridge, 547) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add ip6tables rule to allow DHCP6 requests from '%s'"), - network->def->bridge); - goto err6; - } - - return 0; - - /* unwind in reverse order from the point of failure */ -err6: - iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 53); -err5: - iptablesRemoveTcpInput(AF_INET6, network->def->bridge, 53); -err4: - iptablesRemoveForwardAllowCross(AF_INET6, network->def->bridge); -err3: - iptablesRemoveForwardRejectIn(AF_INET6, network->def->bridge); -err2: - iptablesRemoveForwardRejectOut(AF_INET6, network->def->bridge); -err1: - return -1; -} - -static void -networkRemoveGeneralIp6tablesRules(virNetworkObjPtr network) -{ - if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) && - !network->def->ipv6nogw) { - return; - } - if (virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) { - iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 547); - iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 53); - iptablesRemoveTcpInput(AF_INET6, network->def->bridge, 53); - } - - /* the following rules are there if no IPv6 address has been defined - * but network->def->ipv6nogw == true - */ - iptablesRemoveForwardAllowCross(AF_INET6, network->def->bridge); - iptablesRemoveForwardRejectIn(AF_INET6, network->def->bridge); - iptablesRemoveForwardRejectOut(AF_INET6, network->def->bridge); -} - -static int -networkAddGeneralFirewallRules(virNetworkObjPtr network) -{ - size_t i; - virNetworkIpDefPtr ipv4def; - - /* First look for first IPv4 address that has dhcp or tftpboot defined. */ - /* We support dhcp config on 1 IPv4 interface only. */ - for (i = 0; - (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, i)); - i++) { - if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot) - break; - } - - /* allow DHCP requests through to dnsmasq */ - - if (iptablesAddTcpInput(AF_INET, network->def->bridge, 67) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to allow DHCP requests from '%s'"), - network->def->bridge); - goto err1; - } - - if (iptablesAddUdpInput(AF_INET, network->def->bridge, 67) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to allow DHCP requests from '%s'"), - network->def->bridge); - goto err2; - } - - /* 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 - * aborting, since not all iptables implementations support it). - */ - - if (ipv4def && (ipv4def->nranges || ipv4def->nhosts) && - (iptablesAddOutputFixUdpChecksum(network->def->bridge, 68) < 0)) { - VIR_WARN("Could not add rule to fixup DHCP response checksums " - "on network '%s'.", network->def->name); - VIR_WARN("May need to update iptables package & kernel to support CHECKSUM rule."); - } - - /* allow DNS requests through to dnsmasq */ - if (iptablesAddTcpInput(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 err3; - } - - 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; - } - - /* allow TFTP requests through to dnsmasq if necessary */ - if (ipv4def && ipv4def->tftproot && - iptablesAddUdpInput(AF_INET, network->def->bridge, 69) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to allow TFTP requests from '%s'"), - network->def->bridge); - goto err5; - } - - /* Catch all rules to block forwarding to/from bridges */ - - if (iptablesAddForwardRejectOut(AF_INET, network->def->bridge) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to block outbound traffic from '%s'"), - network->def->bridge); - goto err6; - } - - 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; - } - - /* Allow traffic between guests on the same bridge */ - if (iptablesAddForwardAllowCross(AF_INET, network->def->bridge) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("failed to add iptables rule to allow cross bridge traffic on '%s'"), - network->def->bridge); - goto err8; - } - - /* add IPv6 general rules, if needed */ - if (networkAddGeneralIp6tablesRules(network) < 0) { - goto err9; - } - - return 0; - - /* unwind in reverse order from the point of failure */ -err9: - iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge); -err8: - iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge); -err7: - iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge); -err6: - if (ipv4def && ipv4def->tftproot) { - iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69); - } -err5: - iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53); -err4: - iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53); -err3: - iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67); -err2: - iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67); -err1: - return -1; -} - -static void -networkRemoveGeneralFirewallRules(virNetworkObjPtr network) -{ - size_t i; - virNetworkIpDefPtr ipv4def; - - networkRemoveGeneralIp6tablesRules(network); - - for (i = 0; - (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, i)); - i++) { - if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot) - break; - } - - iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge); - iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge); - iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge); - if (ipv4def && ipv4def->tftproot) { - iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69); - } - iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53); - iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53); - if (ipv4def && (ipv4def->nranges || ipv4def->nhosts)) { - iptablesRemoveOutputFixUdpChecksum(network->def->bridge, 68); - } - iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67); - iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67); -} - -static int -networkAddIpSpecificFirewallRules(virNetworkObjPtr network, - virNetworkIpDefPtr ipdef) -{ - /* NB: in the case of IPv6, routing rules are added when the - * forward mode is NAT. This is because IPv6 has no NAT. - */ - - if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) { - if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) - return networkAddMasqueradingFirewallRules(network, ipdef); - else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) - return networkAddRoutingFirewallRules(network, ipdef); - } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) { - return networkAddRoutingFirewallRules(network, ipdef); - } - return 0; -} - -static void -networkRemoveIpSpecificFirewallRules(virNetworkObjPtr network, - virNetworkIpDefPtr ipdef) -{ - if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) { - if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) - networkRemoveMasqueradingFirewallRules(network, ipdef); - else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) - networkRemoveRoutingFirewallRules(network, ipdef); - } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) { - networkRemoveRoutingFirewallRules(network, ipdef); - } -} - -/* Add all rules for all ip addresses (and general rules) on a network */ -static int -networkAddFirewallRules(virNetworkObjPtr network) -{ - size_t i, j; - virNetworkIpDefPtr ipdef; - virErrorPtr orig_error; - - /* Add "once per network" rules */ - if (networkAddGeneralFirewallRules(network) < 0) - return -1; - - for (i = 0; - (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i)); - i++) { - /* Add address-specific iptables rules */ - if (networkAddIpSpecificFirewallRules(network, ipdef) < 0) { - goto err; - } - } - return 0; - -err: - /* store the previous error message before attempting removal of rules */ - orig_error = virSaveLastError(); - - /* The final failed call to networkAddIpSpecificFirewallRules will - * have removed any rules it created, but we need to remove those - * added for previous IP addresses. - */ - for (j = 0; j < i; j++) { - if ((ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, j))) - networkRemoveIpSpecificFirewallRules(network, ipdef); - } - networkRemoveGeneralFirewallRules(network); - - /* return the original error */ - virSetError(orig_error); - virFreeError(orig_error); - return -1; -} - -/* Remove all rules for all ip addresses (and general rules) on a network */ -static void -networkRemoveFirewallRules(virNetworkObjPtr network) -{ - size_t i; - virNetworkIpDefPtr ipdef; - - for (i = 0; - (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i)); - i++) { - networkRemoveIpSpecificFirewallRules(network, ipdef); - } - networkRemoveGeneralFirewallRules(network); -} - static void networkReloadFirewallRules(virNetworkDriverStatePtr driver) { @@ -2206,104 +1598,6 @@ cleanup: return ret; } -#define PROC_NET_ROUTE "/proc/net/route" - -/* XXX: This function can be a lot more exhaustive, there are certainly - * other scenarios where we can ruin host network connectivity. - * XXX: Using a proper library is preferred over parsing /proc - */ -static int -networkCheckRouteCollision(virNetworkObjPtr network) -{ - int ret = 0, len; - char *cur, *buf = NULL; - /* allow for up to 100000 routes (each line is 128 bytes) */ - enum {MAX_ROUTE_SIZE = 128*100000}; - - /* Read whole routing table into memory */ - if ((len = virFileReadAll(PROC_NET_ROUTE, MAX_ROUTE_SIZE, &buf)) < 0) - goto out; - - /* Dropping the last character shouldn't hurt */ - if (len > 0) - buf[len-1] = '\0'; - - VIR_DEBUG("%s output:\n%s", PROC_NET_ROUTE, buf); - - if (!STRPREFIX(buf, "Iface")) - goto out; - - /* First line is just headings, skip it */ - cur = strchr(buf, '\n'); - if (cur) - cur++; - - while (cur) { - char iface[17], dest[128], mask[128]; - unsigned int addr_val, mask_val; - virNetworkIpDefPtr ipdef; - int num; - size_t i; - - /* NUL-terminate the line, so sscanf doesn't go beyond a newline. */ - char *nl = strchr(cur, '\n'); - if (nl) { - *nl++ = '\0'; - } - - num = sscanf(cur, "%16s %127s %*s %*s %*s %*s %*s %127s", - iface, dest, mask); - cur = nl; - - if (num != 3) { - VIR_DEBUG("Failed to parse %s", PROC_NET_ROUTE); - continue; - } - - if (virStrToLong_ui(dest, NULL, 16, &addr_val) < 0) { - VIR_DEBUG("Failed to convert network address %s to uint", dest); - continue; - } - - if (virStrToLong_ui(mask, NULL, 16, &mask_val) < 0) { - VIR_DEBUG("Failed to convert network mask %s to uint", mask); - continue; - } - - addr_val &= mask_val; - - for (i = 0; - (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i)); - i++) { - - unsigned int net_dest; - virSocketAddr netmask; - - if (virNetworkIpDefNetmask(ipdef, &netmask) < 0) { - VIR_WARN("Failed to get netmask of '%s'", - network->def->bridge); - continue; - } - - net_dest = (ipdef->address.data.inet4.sin_addr.s_addr & - netmask.data.inet4.sin_addr.s_addr); - - if ((net_dest == addr_val) && - (netmask.data.inet4.sin_addr.s_addr == mask_val)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Network is already in use by interface %s"), - iface); - ret = -1; - goto out; - } - } - } - -out: - VIR_FREE(buf); - return ret; -} - /* add an IP address to a bridge */ static int networkAddAddrToBridge(virNetworkObjPtr network, diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c new file mode 100644 index 0000000..80430a8 --- /dev/null +++ b/src/network/bridge_driver_linux.c @@ -0,0 +1,709 @@ +/* + * bridge_driver_linux.c: Linux implementation of bridge driver + * + * Copyright (C) 2006-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include "viralloc.h" +#include "virfile.h" +#include "viriptables.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +#define PROC_NET_ROUTE "/proc/net/route" + +/* XXX: This function can be a lot more exhaustive, there are certainly + * other scenarios where we can ruin host network connectivity. + * XXX: Using a proper library is preferred over parsing /proc + */ +int networkCheckRouteCollision(virNetworkObjPtr network) +{ + int ret = 0, len; + char *cur, *buf = NULL; + /* allow for up to 100000 routes (each line is 128 bytes) */ + enum {MAX_ROUTE_SIZE = 128*100000}; + + /* Read whole routing table into memory */ + if ((len = virFileReadAll(PROC_NET_ROUTE, MAX_ROUTE_SIZE, &buf)) < 0) + goto out; + + /* Dropping the last character shouldn't hurt */ + if (len > 0) + buf[len-1] = '\0'; + + VIR_DEBUG("%s output:\n%s", PROC_NET_ROUTE, buf); + + if (!STRPREFIX(buf, "Iface")) + goto out; + + /* First line is just headings, skip it */ + cur = strchr(buf, '\n'); + if (cur) + cur++; + + while (cur) { + char iface[17], dest[128], mask[128]; + unsigned int addr_val, mask_val; + virNetworkIpDefPtr ipdef; + int num; + size_t i; + + /* NUL-terminate the line, so sscanf doesn't go beyond a newline. */ + char *nl = strchr(cur, '\n'); + if (nl) { + *nl++ = '\0'; + } + + num = sscanf(cur, "%16s %127s %*s %*s %*s %*s %*s %127s", + iface, dest, mask); + cur = nl; + + if (num != 3) { + VIR_DEBUG("Failed to parse %s", PROC_NET_ROUTE); + continue; + } + + if (virStrToLong_ui(dest, NULL, 16, &addr_val) < 0) { + VIR_DEBUG("Failed to convert network address %s to uint", dest); + continue; + } + + if (virStrToLong_ui(mask, NULL, 16, &mask_val) < 0) { + VIR_DEBUG("Failed to convert network mask %s to uint", mask); + continue; + } + + addr_val &= mask_val; + + for (i = 0; + (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i)); + i++) { + + unsigned int net_dest; + virSocketAddr netmask; + + if (virNetworkIpDefNetmask(ipdef, &netmask) < 0) { + VIR_WARN("Failed to get netmask of '%s'", + network->def->bridge); + continue; + } + + net_dest = (ipdef->address.data.inet4.sin_addr.s_addr & + netmask.data.inet4.sin_addr.s_addr); + + if ((net_dest == addr_val) && + (netmask.data.inet4.sin_addr.s_addr == mask_val)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Network is already in use by interface %s"), + iface); + ret = -1; + goto out; + } + } + } + +out: + VIR_FREE(buf); + return ret; +} + +int networkAddMasqueradingFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef) +{ + int prefix = virNetworkIpDefPrefix(ipdef); + const char *forwardIf = virNetworkDefForwardIf(network->def, 0); + + if (prefix < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid prefix or netmask for '%s'"), + network->def->bridge); + goto masqerr1; + } + + /* allow forwarding packets from the bridge interface */ + if (iptablesAddForwardAllowOut(&ipdef->address, + prefix, + network->def->bridge, + forwardIf) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to allow forwarding from '%s'"), + network->def->bridge); + goto masqerr1; + } + + /* allow forwarding packets to the bridge interface if they are + * part of an existing connection + */ + if (iptablesAddForwardAllowRelatedIn(&ipdef->address, + prefix, + network->def->bridge, + forwardIf) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to allow forwarding to '%s'"), + network->def->bridge); + goto masqerr2; + } + + /* + * Enable masquerading. + * + * We need to end up with 3 rules in the table in this order + * + * 1. protocol=tcp with sport mapping restriction + * 2. protocol=udp with sport mapping restriction + * 3. generic any protocol + * + * The sport mappings are required, because default IPtables + * MASQUERADE maintain port numbers unchanged where possible. + * + * NFS can be configured to only "trust" port numbers < 1023. + * + * Guests using NAT thus need to be prevented from having port + * numbers < 1023, otherwise they can bypass the NFS "security" + * check on the source port number. + * + * Since we use '--insert' to add rules to the header of the + * chain, we actually need to add them in the reverse of the + * order just mentioned ! + */ + + /* First the generic masquerade rule for other protocols */ + if (iptablesAddForwardMasquerade(&ipdef->address, + prefix, + forwardIf, + &network->def->forward.addr, + &network->def->forward.port, + NULL) < 0) { + if (forwardIf) + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to enable masquerading to %s"), + forwardIf); + else + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to add iptables rule to enable masquerading")); + goto masqerr3; + } + + /* UDP with a source port restriction */ + if (iptablesAddForwardMasquerade(&ipdef->address, + prefix, + forwardIf, + &network->def->forward.addr, + &network->def->forward.port, + "udp") < 0) { + if (forwardIf) + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to enable UDP masquerading to %s"), + forwardIf); + else + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to add iptables rule to enable UDP masquerading")); + goto masqerr4; + } + + /* TCP with a source port restriction */ + if (iptablesAddForwardMasquerade(&ipdef->address, + prefix, + forwardIf, + &network->def->forward.addr, + &network->def->forward.port, + "tcp") < 0) { + if (forwardIf) + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to enable TCP masquerading to %s"), + forwardIf); + else + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("failed to add iptables rule to enable TCP masquerading")); + goto masqerr5; + } + + return 0; + + masqerr5: + iptablesRemoveForwardMasquerade(&ipdef->address, + prefix, + forwardIf, + &network->def->forward.addr, + &network->def->forward.port, + "udp"); + masqerr4: + iptablesRemoveForwardMasquerade(&ipdef->address, + prefix, + forwardIf, + &network->def->forward.addr, + &network->def->forward.port, + NULL); + masqerr3: + iptablesRemoveForwardAllowRelatedIn(&ipdef->address, + prefix, + network->def->bridge, + forwardIf); + masqerr2: + iptablesRemoveForwardAllowOut(&ipdef->address, + prefix, + network->def->bridge, + forwardIf); + masqerr1: + return -1; +} + +void networkRemoveMasqueradingFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef) +{ + int prefix = virNetworkIpDefPrefix(ipdef); + const char *forwardIf = virNetworkDefForwardIf(network->def, 0); + + if (prefix >= 0) { + iptablesRemoveForwardMasquerade(&ipdef->address, + prefix, + forwardIf, + &network->def->forward.addr, + &network->def->forward.port, + "tcp"); + iptablesRemoveForwardMasquerade(&ipdef->address, + prefix, + forwardIf, + &network->def->forward.addr, + &network->def->forward.port, + "udp"); + iptablesRemoveForwardMasquerade(&ipdef->address, + prefix, + forwardIf, + &network->def->forward.addr, + &network->def->forward.port, + NULL); + + iptablesRemoveForwardAllowRelatedIn(&ipdef->address, + prefix, + network->def->bridge, + forwardIf); + iptablesRemoveForwardAllowOut(&ipdef->address, + prefix, + network->def->bridge, + forwardIf); + } +} + +int networkAddRoutingFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef) +{ + int prefix = virNetworkIpDefPrefix(ipdef); + const char *forwardIf = virNetworkDefForwardIf(network->def, 0); + + if (prefix < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid prefix or netmask for '%s'"), + network->def->bridge); + goto routeerr1; + } + + /* allow routing packets from the bridge interface */ + if (iptablesAddForwardAllowOut(&ipdef->address, + prefix, + network->def->bridge, + forwardIf) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to allow routing from '%s'"), + network->def->bridge); + goto routeerr1; + } + + /* allow routing packets to the bridge interface */ + if (iptablesAddForwardAllowIn(&ipdef->address, + prefix, + network->def->bridge, + forwardIf) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to allow routing to '%s'"), + network->def->bridge); + goto routeerr2; + } + + return 0; + +routeerr2: + iptablesRemoveForwardAllowOut(&ipdef->address, + prefix, + network->def->bridge, + forwardIf); +routeerr1: + return -1; +} + +void networkRemoveRoutingFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef) +{ + int prefix = virNetworkIpDefPrefix(ipdef); + const char *forwardIf = virNetworkDefForwardIf(network->def, 0); + + if (prefix >= 0) { + iptablesRemoveForwardAllowIn(&ipdef->address, + prefix, + network->def->bridge, + forwardIf); + + iptablesRemoveForwardAllowOut(&ipdef->address, + prefix, + network->def->bridge, + forwardIf); + } +} + +/* Add all once/network rules required for IPv6. + * If no IPv6 addresses are defined and <network ipv6='yes'> is + * specified, then allow IPv6 commuinications between virtual systems. + * If any IPv6 addresses are defined, then add the rules for regular operation. + */ +static int +networkAddGeneralIp6tablesRules(virNetworkObjPtr network) +{ + + if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) && + !network->def->ipv6nogw) { + return 0; + } + + /* Catch all rules to block forwarding to/from bridges */ + + if (iptablesAddForwardRejectOut(AF_INET6, network->def->bridge) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add ip6tables rule to block outbound traffic from '%s'"), + network->def->bridge); + goto err1; + } + + if (iptablesAddForwardRejectIn(AF_INET6, network->def->bridge) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add ip6tables rule to block inbound traffic to '%s'"), + network->def->bridge); + goto err2; + } + + /* Allow traffic between guests on the same bridge */ + if (iptablesAddForwardAllowCross(AF_INET6, network->def->bridge) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add ip6tables rule to allow cross bridge traffic on '%s'"), + network->def->bridge); + goto err3; + } + + /* if no IPv6 addresses are defined, we are done. */ + if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) + return 0; + + /* allow DNS over IPv6 */ + if (iptablesAddTcpInput(AF_INET6, network->def->bridge, 53) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add ip6tables rule to allow DNS requests from '%s'"), + network->def->bridge); + goto err4; + } + + if (iptablesAddUdpInput(AF_INET6, network->def->bridge, 53) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add ip6tables rule to allow DNS requests from '%s'"), + network->def->bridge); + goto err5; + } + + if (iptablesAddUdpInput(AF_INET6, network->def->bridge, 547) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add ip6tables rule to allow DHCP6 requests from '%s'"), + network->def->bridge); + goto err6; + } + + return 0; + + /* unwind in reverse order from the point of failure */ +err6: + iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 53); +err5: + iptablesRemoveTcpInput(AF_INET6, network->def->bridge, 53); +err4: + iptablesRemoveForwardAllowCross(AF_INET6, network->def->bridge); +err3: + iptablesRemoveForwardRejectIn(AF_INET6, network->def->bridge); +err2: + iptablesRemoveForwardRejectOut(AF_INET6, network->def->bridge); +err1: + return -1; +} + +static void +networkRemoveGeneralIp6tablesRules(virNetworkObjPtr network) +{ + if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) && + !network->def->ipv6nogw) { + return; + } + if (virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) { + iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 547); + iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 53); + iptablesRemoveTcpInput(AF_INET6, network->def->bridge, 53); + } + + /* the following rules are there if no IPv6 address has been defined + * but network->def->ipv6nogw == true + */ + iptablesRemoveForwardAllowCross(AF_INET6, network->def->bridge); + iptablesRemoveForwardRejectIn(AF_INET6, network->def->bridge); + iptablesRemoveForwardRejectOut(AF_INET6, network->def->bridge); +} + +int networkAddGeneralFirewallRules(virNetworkObjPtr network) +{ + size_t i; + virNetworkIpDefPtr ipv4def; + + /* First look for first IPv4 address that has dhcp or tftpboot defined. */ + /* We support dhcp config on 1 IPv4 interface only. */ + for (i = 0; + (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, i)); + i++) { + if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot) + break; + } + + /* allow DHCP requests through to dnsmasq */ + + if (iptablesAddTcpInput(AF_INET, network->def->bridge, 67) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to allow DHCP requests from '%s'"), + network->def->bridge); + goto err1; + } + + if (iptablesAddUdpInput(AF_INET, network->def->bridge, 67) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to allow DHCP requests from '%s'"), + network->def->bridge); + goto err2; + } + + /* 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 + * aborting, since not all iptables implementations support it). + */ + + if (ipv4def && (ipv4def->nranges || ipv4def->nhosts) && + (iptablesAddOutputFixUdpChecksum(network->def->bridge, 68) < 0)) { + VIR_WARN("Could not add rule to fixup DHCP response checksums " + "on network '%s'.", network->def->name); + VIR_WARN("May need to update iptables package & kernel to support CHECKSUM rule."); + } + + /* allow DNS requests through to dnsmasq */ + if (iptablesAddTcpInput(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 err3; + } + + 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; + } + + /* allow TFTP requests through to dnsmasq if necessary */ + if (ipv4def && ipv4def->tftproot && + iptablesAddUdpInput(AF_INET, network->def->bridge, 69) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to allow TFTP requests from '%s'"), + network->def->bridge); + goto err5; + } + + /* Catch all rules to block forwarding to/from bridges */ + + if (iptablesAddForwardRejectOut(AF_INET, network->def->bridge) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to block outbound traffic from '%s'"), + network->def->bridge); + goto err6; + } + + 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; + } + + /* Allow traffic between guests on the same bridge */ + if (iptablesAddForwardAllowCross(AF_INET, network->def->bridge) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add iptables rule to allow cross bridge traffic on '%s'"), + network->def->bridge); + goto err8; + } + + /* add IPv6 general rules, if needed */ + if (networkAddGeneralIp6tablesRules(network) < 0) { + goto err9; + } + + return 0; + + /* unwind in reverse order from the point of failure */ +err9: + iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge); +err8: + iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge); +err7: + iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge); +err6: + if (ipv4def && ipv4def->tftproot) { + iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69); + } +err5: + iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53); +err4: + iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53); +err3: + iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67); +err2: + iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67); +err1: + return -1; +} + +void networkRemoveGeneralFirewallRules(virNetworkObjPtr network) +{ + size_t i; + virNetworkIpDefPtr ipv4def; + + networkRemoveGeneralIp6tablesRules(network); + + for (i = 0; + (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, i)); + i++) { + if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot) + break; + } + + iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge); + iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge); + iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge); + if (ipv4def && ipv4def->tftproot) { + iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69); + } + iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53); + iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53); + if (ipv4def && (ipv4def->nranges || ipv4def->nhosts)) { + iptablesRemoveOutputFixUdpChecksum(network->def->bridge, 68); + } + iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67); + iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67); +} + +int networkAddIpSpecificFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef) +{ + /* NB: in the case of IPv6, routing rules are added when the + * forward mode is NAT. This is because IPv6 has no NAT. + */ + + if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) { + if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) + return networkAddMasqueradingFirewallRules(network, ipdef); + else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) + return networkAddRoutingFirewallRules(network, ipdef); + } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) { + return networkAddRoutingFirewallRules(network, ipdef); + } + return 0; +} + +void networkRemoveIpSpecificFirewallRules(virNetworkObjPtr network, + virNetworkIpDefPtr ipdef) +{ + if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) { + if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) + networkRemoveMasqueradingFirewallRules(network, ipdef); + else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) + networkRemoveRoutingFirewallRules(network, ipdef); + } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) { + networkRemoveRoutingFirewallRules(network, ipdef); + } +} + +/* Add all rules for all ip addresses (and general rules) on a network */ +int networkAddFirewallRules(virNetworkObjPtr network) +{ + size_t i, j; + virNetworkIpDefPtr ipdef; + virErrorPtr orig_error; + + /* Add "once per network" rules */ + if (networkAddGeneralFirewallRules(network) < 0) + return -1; + + for (i = 0; + (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i)); + i++) { + /* Add address-specific iptables rules */ + if (networkAddIpSpecificFirewallRules(network, ipdef) < 0) { + goto err; + } + } + return 0; + +err: + /* store the previous error message before attempting removal of rules */ + orig_error = virSaveLastError(); + + /* The final failed call to networkAddIpSpecificFirewallRules will + * have removed any rules it created, but we need to remove those + * added for previous IP addresses. + */ + for (j = 0; j < i; j++) { + if ((ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, j))) + networkRemoveIpSpecificFirewallRules(network, ipdef); + } + networkRemoveGeneralFirewallRules(network); + + /* return the original error */ + virSetError(orig_error); + virFreeError(orig_error); + return -1; +} + +/* Remove all rules for all ip addresses (and general rules) on a network */ +void networkRemoveFirewallRules(virNetworkObjPtr network) +{ + size_t i; + virNetworkIpDefPtr ipdef; + + for (i = 0; + (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i)); + i++) { + networkRemoveIpSpecificFirewallRules(network, ipdef); + } + networkRemoveGeneralFirewallRules(network); +} diff --git a/src/network/bridge_driver_nop.c b/src/network/bridge_driver_nop.c new file mode 100644 index 0000000..f983402 --- /dev/null +++ b/src/network/bridge_driver_nop.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2006-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +int networkCheckRouteCollision(virNetworkObjPtr network) +{ + return 0; +} + +int networkAddMasqueradingFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED, + virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED) +{ + return 0; +} + +void networkRemoveMasqueradingFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED, + virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED) +{ +} + +int networkAddRoutingFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED, + virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED) +{ + return 0; +} + +void networkRemoveRoutingFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED, + virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED) +{ +} + +int networkAddGeneralFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED) +{ + return 0; +} + +void networkRemoveGeneralFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED) +{ +} + +int networkAddIpSpecificFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED, + virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED) +{ + return 0; +} + +void networkRemoveIpSpecificFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED, + virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED) +{ +} + +int networkAddFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED) +{ + return 0; +} + +void networkRemoveFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED) +{ +} diff --git a/src/network/bridge_driver_platform.c b/src/network/bridge_driver_platform.c new file mode 100644 index 0000000..1d2fc02 --- /dev/null +++ b/src/network/bridge_driver_platform.c @@ -0,0 +1,32 @@ +/* + * bridge_driver_platform.c: platform specific part of bridge driver + * + * Copyright (C) 2006-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include "bridge_driver_platform.h" + +#if defined(__linux__) +# include "bridge_driver_linux.c" +#else +# include "bridge_driver_nop.c" +#endif diff --git a/po/POTFILES.in b/po/POTFILES.in index 1fd84af..24b32db 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -70,6 +70,7 @@ src/lxc/lxc_process.c src/libxl/libxl_driver.c src/libxl/libxl_conf.c src/network/bridge_driver.c +src/network/bridge_driver_linux.c src/node_device/node_device_driver.c src/node_device/node_device_hal.c src/node_device/node_device_linux_sysfs.c diff --git a/src/Makefile.am b/src/Makefile.am index 84372cb..80309fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -725,8 +725,9 @@ PARALLELS_DRIVER_SOURCES = \ parallels/parallels_storage.c \ parallels/parallels_network.c -NETWORK_DRIVER_SOURCES = \ - network/bridge_driver.h network/bridge_driver.c +NETWORK_DRIVER_SOURCES = \ + network/bridge_driver.h network/bridge_driver.c \ + network/bridge_driver_platform.h network/bridge_driver_platform.c INTERFACE_DRIVER_SOURCES = -- 1.7.9.5

Hi Eric! Any chance you could take a look at it? I know that patches could hang much longer, but this one blocks my further work on making bridge driver work on FreeBSD. After we're done with the split, you will be able to rest from me for some time because proper FreeBSD implementation will not be very fast ;) Roman Bogorodskiy wrote:
* Move platform specific things (e.g. firewalling and route collision checks) into bridge_driver_platform * Create two platform specific implementations: - bridge_driver_linux: Linux implementation using iptables, it's actually the code moved from bridge_driver.c - bridge_driver_nop: dumb implementation that does nothing --- src/network/bridge_driver_platform.h | 79 ++++ src/network/bridge_driver.c | 708 +-------------------------------- src/network/bridge_driver_linux.c | 709 ++++++++++++++++++++++++++++++++++ src/network/bridge_driver_nop.c | 78 ++++ src/network/bridge_driver_platform.c | 32 ++ po/POTFILES.in | 1 + src/Makefile.am | 5 +- 7 files changed, 903 insertions(+), 709 deletions(-) create mode 100644 src/network/bridge_driver_platform.h create mode 100644 src/network/bridge_driver_linux.c create mode 100644 src/network/bridge_driver_nop.c create mode 100644 src/network/bridge_driver_platform.c
Roman Bogorodskiy

On 07/24/2013 06:22 AM, Roman Bogorodskiy wrote:
* Move platform specific things (e.g. firewalling and route collision checks) into bridge_driver_platform * Create two platform specific implementations: - bridge_driver_linux: Linux implementation using iptables, it's actually the code moved from bridge_driver.c - bridge_driver_nop: dumb implementation that does nothing --- src/network/bridge_driver_platform.h | 79 ++++ src/network/bridge_driver.c | 708 +-------------------------------- src/network/bridge_driver_linux.c | 709 ++++++++++++++++++++++++++++++++++ src/network/bridge_driver_nop.c | 78 ++++ src/network/bridge_driver_platform.c | 32 ++ po/POTFILES.in | 1 + src/Makefile.am | 5 +- 7 files changed, 903 insertions(+), 709 deletions(-) create mode 100644 src/network/bridge_driver_platform.h create mode 100644 src/network/bridge_driver_linux.c create mode 100644 src/network/bridge_driver_nop.c create mode 100644 src/network/bridge_driver_platform.c
You need to ensure that the new files get shipped in the tarball, or else 'make distcheck' will break.
+++ b/src/Makefile.am @@ -725,8 +725,9 @@ PARALLELS_DRIVER_SOURCES = \ parallels/parallels_storage.c \ parallels/parallels_network.c
-NETWORK_DRIVER_SOURCES = \ - network/bridge_driver.h network/bridge_driver.c +NETWORK_DRIVER_SOURCES = \ + network/bridge_driver.h network/bridge_driver.c \ + network/bridge_driver_platform.h network/bridge_driver_platform.c
Long line. Also, we've been using $(NULL) at the end of lists in new modifications, so that we don't have to remember to add a \ if we add something at the end of a multi-line list (yeah, we don't consistently use $(NULL) everywhere yet, but anytime a patch touches Makefile.am, I try to clean up what gets touched). This only tells automake to ship the wrapper file, but we also need to ship both the _linux and the _nop file. The tarball must include everything, even what wasn't used when built on your setup, so that someone else still has a complete package for their setup. But that's easy enough to fix, so ACK and pushed with this squashed in: diff --git i/src/Makefile.am w/src/Makefile.am index af8a25e..ac66ecf 100644 --- i/src/Makefile.am +++ w/src/Makefile.am @@ -727,9 +727,12 @@ PARALLELS_DRIVER_SOURCES = \ parallels/parallels_storage.c \ parallels/parallels_network.c -NETWORK_DRIVER_SOURCES = \ - network/bridge_driver.h network/bridge_driver.c \ - network/bridge_driver_platform.h network/bridge_driver_platform.c +NETWORK_DRIVER_SOURCES = \ + network/bridge_driver.h network/bridge_driver.c \ + network/bridge_driver_platform.h \ + network/bridge_driver_platform.c \ + $(NULL) +EXTRA_DIST += network/bridge_driver_linux.c network/bridge_driver_nop.c INTERFACE_DRIVER_SOURCES = -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
participants (2)
-
Eric Blake
-
Roman Bogorodskiy