* 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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list