* Functions were renamed: s/Iptables/Firewall/ to make names more general. * Platform specific things (e.g. firewalling and route collision checks) were moved into bridge_driver_platform * Created two platform specific implementations: - bridge_driver_linux: Linux implementation using iptables, it's actually the code moved from bridge_driver.c - bridge_driver_noop: dump implementation that does nothing --- po/POTFILES.in | 1 + src/Makefile.am | 5 +- src/network/bridge_driver.c | 729 +--------------------------------- src/network/bridge_driver_linux.c | 709 +++++++++++++++++++++++++++++++++ src/network/bridge_driver_noop.c | 80 ++++ src/network/bridge_driver_platform.c | 32 ++ src/network/bridge_driver_platform.h | 77 ++++ 7 files changed, 915 insertions(+), 718 deletions(-) create mode 100644 src/network/bridge_driver_linux.c create mode 100644 src/network/bridge_driver_noop.c create mode 100644 src/network/bridge_driver_platform.c create mode 100644 src/network/bridge_driver_platform.h diff --git a/po/POTFILES.in b/po/POTFILES.in index af7fd7f..b833110 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -69,6 +69,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 d9e703f..a8b47ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -722,8 +722,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 = diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index d7e90ac..0b843b6 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,22 +70,6 @@ #define VIR_FROM_THIS VIR_FROM_NETWORK -/* Main driver state */ -struct network_driver { - virMutex lock; - - virNetworkObjList networks; - - char *networkConfigDir; - char *networkAutostartDir; - char *stateDir; - char *pidDir; - char *dnsmasqStateDir; - char *radvdStateDir; - dnsmasqCapsPtr dnsmasqCaps; -}; - - static void networkDriverLock(struct network_driver *driver) { virMutexLock(&driver->lock); @@ -114,7 +99,7 @@ static int networkStartNetworkExternal(struct network_driver *driver, static int networkShutdownNetworkExternal(struct network_driver *driver, virNetworkObjPtr network); -static void networkReloadIptablesRules(struct network_driver *driver); +static void networkReloadFirewallRules(struct network_driver *driver); static void networkRefreshDaemons(struct network_driver *driver); static int networkPlugBandwidth(virNetworkObjPtr net, @@ -341,7 +326,7 @@ firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED, "Reloaded")) { VIR_DEBUG("Reload in bridge_driver because of firewalld."); - networkReloadIptablesRules(_driverState); + networkReloadFirewallRules(_driverState); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -432,7 +417,7 @@ networkStateInitialize(bool privileged, goto error; networkFindActiveConfigs(driverState); - networkReloadIptablesRules(driverState); + networkReloadFirewallRules(driverState); networkRefreshDaemons(driverState); networkAutostartConfigs(driverState); @@ -496,7 +481,7 @@ networkStateReload(void) { virNetworkLoadAllConfigs(&driverState->networks, driverState->networkConfigDir, driverState->networkAutostartDir); - networkReloadIptablesRules(driverState); + networkReloadFirewallRules(driverState); networkRefreshDaemons(driverState); networkAutostartConfigs(driverState); networkDriverUnlock(driverState); @@ -1535,599 +1520,8 @@ networkRefreshDaemons(struct network_driver *driver) } } -static int -networkAddMasqueradingIptablesRules(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 -networkRemoveMasqueradingIptablesRules(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 -networkAddRoutingIptablesRules(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 -networkRemoveRoutingIptablesRules(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 -networkAddGeneralIptablesRules(virNetworkObjPtr network) -{ - int ii; - virNetworkIpDefPtr ipv4def; - - /* First look for first IPv4 address that has dhcp or tftpboot defined. */ - /* We support dhcp config on 1 IPv4 interface only. */ - for (ii = 0; - (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii)); - ii++) { - 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 -networkRemoveGeneralIptablesRules(virNetworkObjPtr network) -{ - int ii; - virNetworkIpDefPtr ipv4def; - - networkRemoveGeneralIp6tablesRules(network); - - for (ii = 0; - (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii)); - ii++) { - 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 -networkAddIpSpecificIptablesRules(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 networkAddMasqueradingIptablesRules(network, ipdef); - else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) - return networkAddRoutingIptablesRules(network, ipdef); - } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) { - return networkAddRoutingIptablesRules(network, ipdef); - } - return 0; -} - -static void -networkRemoveIpSpecificIptablesRules(virNetworkObjPtr network, - virNetworkIpDefPtr ipdef) -{ - if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) { - if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) - networkRemoveMasqueradingIptablesRules(network, ipdef); - else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) - networkRemoveRoutingIptablesRules(network, ipdef); - } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) { - networkRemoveRoutingIptablesRules(network, ipdef); - } -} - -/* Add all rules for all ip addresses (and general rules) on a network */ -static int -networkAddIptablesRules(virNetworkObjPtr network) -{ - int ii; - virNetworkIpDefPtr ipdef; - virErrorPtr orig_error; - - /* Add "once per network" rules */ - if (networkAddGeneralIptablesRules(network) < 0) - return -1; - - for (ii = 0; - (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii)); - ii++) { - /* Add address-specific iptables rules */ - if (networkAddIpSpecificIptablesRules(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 networkAddIpSpecificIptablesRules will - * have removed any rules it created, but we need to remove those - * added for previous IP addresses. - */ - while ((--ii >= 0) && - (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii))) { - networkRemoveIpSpecificIptablesRules(network, ipdef); - } - networkRemoveGeneralIptablesRules(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 -networkRemoveIptablesRules(virNetworkObjPtr network) -{ - int ii; - virNetworkIpDefPtr ipdef; - - for (ii = 0; - (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii)); - ii++) { - networkRemoveIpSpecificIptablesRules(network, ipdef); - } - networkRemoveGeneralIptablesRules(network); -} - -static void -networkReloadIptablesRules(struct network_driver *driver) +networkReloadFirewallRules(struct network_driver *driver) { unsigned int i; @@ -2144,8 +1538,8 @@ networkReloadIptablesRules(struct network_driver *driver) /* Only the three L3 network types that are configured by libvirt * need to have iptables rules reloaded. */ - networkRemoveIptablesRules(network); - if (networkAddIptablesRules(network) < 0) { + networkRemoveFirewallRules(network); + if (networkAddFirewallRules(network) < 0) { /* failed to add but already logged */ } } @@ -2240,103 +1634,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, ii; - - /* 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 (ii = 0; - (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii)); - ii++) { - - 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, @@ -2471,7 +1768,7 @@ networkStartNetworkVirtual(struct network_driver *driver, goto err1; /* Add "once per network" rules */ - if (networkAddIptablesRules(network) < 0) + if (networkAddFirewallRules(network) < 0) goto err1; for (ii = 0; @@ -2564,7 +1861,7 @@ networkStartNetworkVirtual(struct network_driver *driver, err2: if (!save_err) save_err = virSaveLastError(); - networkRemoveIptablesRules(network); + networkRemoveFirewallRules(network); err1: if (!save_err) @@ -2622,7 +1919,7 @@ static int networkShutdownNetworkVirtual(struct network_driver *driver ATTRIBUTE ignore_value(virNetDevSetOnline(network->def->bridge, 0)); - networkRemoveIptablesRules(network); + networkRemoveFirewallRules(network); ignore_value(virNetDevBridgeDelete(network->def->bridge)); @@ -3445,8 +2742,8 @@ networkUpdate(virNetworkPtr net, network->def->forward.type == VIR_NETWORK_FORWARD_NAT || network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE)) { /* these could affect the iptables rules */ - networkRemoveIptablesRules(network); - if (networkAddIptablesRules(network) < 0) + networkRemoveFirewallRules(network); + if (networkAddFirewallRules(network) < 0) goto cleanup; } diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c new file mode 100644 index 0000000..efa3d0a --- /dev/null +++ b/src/network/bridge_driver_linux.c @@ -0,0 +1,709 @@ +/* + * bridge_driver.c: core driver methods for managing network + * + * 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, ii; + + /* 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 (ii = 0; + (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii)); + ii++) { + + 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) +{ + int ii; + virNetworkIpDefPtr ipv4def; + + /* First look for first IPv4 address that has dhcp or tftpboot defined. */ + /* We support dhcp config on 1 IPv4 interface only. */ + for (ii = 0; + (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii)); + ii++) { + 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) +{ + int ii; + virNetworkIpDefPtr ipv4def; + + networkRemoveGeneralIp6tablesRules(network); + + for (ii = 0; + (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii)); + ii++) { + 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) +{ + int ii; + virNetworkIpDefPtr ipdef; + virErrorPtr orig_error; + + /* Add "once per network" rules */ + if (networkAddGeneralFirewallRules(network) < 0) + return -1; + + for (ii = 0; + (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii)); + ii++) { + /* 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. + */ + while ((--ii >= 0) && + (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii))) { + 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) +{ + int ii; + virNetworkIpDefPtr ipdef; + + for (ii = 0; + (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii)); + ii++) { + networkRemoveIpSpecificFirewallRules(network, ipdef); + } + networkRemoveGeneralFirewallRules(network); +} diff --git a/src/network/bridge_driver_noop.c b/src/network/bridge_driver_noop.c new file mode 100644 index 0000000..90e6b12 --- /dev/null +++ b/src/network/bridge_driver_noop.c @@ -0,0 +1,80 @@ +/* + * bridge_driver.c: core driver methods for managing network + * + * 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..65a2ffd --- /dev/null +++ b/src/network/bridge_driver_platform.c @@ -0,0 +1,32 @@ +/* + * bridge_driver.c: core driver methods for managing network + * + * 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_noop.c" +#endif diff --git a/src/network/bridge_driver_platform.h b/src/network/bridge_driver_platform.h new file mode 100644 index 0000000..bab507f --- /dev/null +++ b/src/network/bridge_driver_platform.h @@ -0,0 +1,77 @@ +/* + * bridge_driver.c: core driver methods for managing network + * + * 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 network_driver { + virMutex lock; + + virNetworkObjList networks; + + char *networkConfigDir; + char *networkAutostartDir; + char *stateDir; + char *pidDir; + char *dnsmasqStateDir; + char *radvdStateDir; + dnsmasqCapsPtr dnsmasqCaps; +}; + + +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__ */ -- 1.7.9.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list