return 0;
}
-static const char networkLocalMulticastIPv4[] = "224.0.0.0/24";
-static const char networkLocalMulticastIPv6[] = "ff02::/16";
-static const char networkLocalBroadcast[] = "255.255.255.255/32";
-static int
-networkAddMasqueradingFirewallRules(virFirewall *fw,
- virNetworkDef *def,
- virNetworkIPDef *ipdef)
-{
- int prefix = virNetworkIPDefPrefix(ipdef);
- const char *forwardIf = virNetworkDefForwardIf(def, 0);
- bool isIPv4 = VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET);
-
- if (prefix < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Invalid prefix or netmask for '%1$s'"),
- def->bridge);
- return -1;
- }
-
- /* allow forwarding packets from the bridge interface */
- if (iptablesAddForwardAllowOut(fw,
- &ipdef->address,
- prefix,
- def->bridge,
- forwardIf) < 0)
- return -1;
-
- /* allow forwarding packets to the bridge interface if they are
- * part of an existing connection
- */
- if (iptablesAddForwardAllowRelatedIn(fw,
- &ipdef->address,
- prefix,
- def->bridge,
- forwardIf) < 0)
- return -1;
-
- /*
- * Enable masquerading.
- *
- * We need to end up with 5 rules in the table in this order
- *
- * 1. do not masquerade packets targeting 224.0.0.0/24
- * 2. do not masquerade packets targeting 255.255.255.255/32
- * 3. masquerade protocol=tcp with sport mapping restriction
- * 4. masquerade protocol=udp with sport mapping restriction
- * 5. generic, masquerade any protocol
- *
- * 224.0.0.0/24 is the local network multicast range. Packets are not
- * forwarded outside.
- *
- * 255.255.255.255/32 is the broadcast address of any local network. Again,
- * such packets are never forwarded, but strict DHCP clients don't accept
- * DHCP replies with changed source ports.
- *
- * 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(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- &def->forward.addr,
- &def->forward.port,
- NULL) < 0)
- return -1;
-
- /* UDP with a source port restriction */
- if (iptablesAddForwardMasquerade(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- &def->forward.addr,
- &def->forward.port,
- "udp") < 0)
- return -1;
-
- /* TCP with a source port restriction */
- if (iptablesAddForwardMasquerade(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- &def->forward.addr,
- &def->forward.port,
- "tcp") < 0)
- return -1;
-
- /* exempt local network broadcast address as destination */
- if (isIPv4 &&
- iptablesAddDontMasquerade(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- networkLocalBroadcast) < 0)
- return -1;
-
- /* exempt local multicast range as destination */
- if (iptablesAddDontMasquerade(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- isIPv4 ? networkLocalMulticastIPv4 :
- networkLocalMulticastIPv6) < 0)
- return -1;
-
- return 0;
-}
-
-static int
-networkRemoveMasqueradingFirewallRules(virFirewall *fw,
- virNetworkDef *def,
- virNetworkIPDef *ipdef)
-{
- int prefix = virNetworkIPDefPrefix(ipdef);
- const char *forwardIf = virNetworkDefForwardIf(def, 0);
- bool isIPv4 = VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET);
-
- if (prefix < 0)
- return 0;
-
- if (iptablesRemoveDontMasquerade(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- isIPv4 ? networkLocalMulticastIPv4 :
- networkLocalMulticastIPv6) < 0)
- return -1;
-
- if (isIPv4 &&
- iptablesRemoveDontMasquerade(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- networkLocalBroadcast) < 0)
- return -1;
-
- if (iptablesRemoveForwardMasquerade(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- &def->forward.addr,
- &def->forward.port,
- "tcp") < 0)
- return -1;
-
- if (iptablesRemoveForwardMasquerade(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- &def->forward.addr,
- &def->forward.port,
- "udp") < 0)
- return -1;
-
- if (iptablesRemoveForwardMasquerade(fw,
- &ipdef->address,
- prefix,
- forwardIf,
- &def->forward.addr,
- &def->forward.port,
- NULL) < 0)
- return -1;
-
- if (iptablesRemoveForwardAllowRelatedIn(fw,
- &ipdef->address,
- prefix,
- def->bridge,
- forwardIf) < 0)
- return -1;
-
- if (iptablesRemoveForwardAllowOut(fw,
- &ipdef->address,
- prefix,
- def->bridge,
- forwardIf) < 0)
- return -1;
-
- return 0;
-}
-
-
-static int
-networkAddRoutingFirewallRules(virFirewall *fw,
- virNetworkDef *def,
- virNetworkIPDef *ipdef)
-{
- int prefix = virNetworkIPDefPrefix(ipdef);
- const char *forwardIf = virNetworkDefForwardIf(def, 0);
-
- if (prefix < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Invalid prefix or netmask for '%1$s'"),
- def->bridge);
- return -1;
- }
-
- /* allow routing packets from the bridge interface */
- if (iptablesAddForwardAllowOut(fw,
- &ipdef->address,
- prefix,
- def->bridge,
- forwardIf) < 0)
- return -1;
-
- /* allow routing packets to the bridge interface */
- if (iptablesAddForwardAllowIn(fw,
- &ipdef->address,
- prefix,
- def->bridge,
- forwardIf) < 0)
- return -1;
-
- return 0;
-}
-
-
-static int
-networkRemoveRoutingFirewallRules(virFirewall *fw,
- virNetworkDef *def,
- virNetworkIPDef *ipdef)
-{
- int prefix = virNetworkIPDefPrefix(ipdef);
- const char *forwardIf = virNetworkDefForwardIf(def, 0);
-
- if (prefix < 0)
- return 0;
-
- if (iptablesRemoveForwardAllowIn(fw,
- &ipdef->address,
- prefix,
- def->bridge,
- forwardIf) < 0)
- return -1;
-
- if (iptablesRemoveForwardAllowOut(fw,
- &ipdef->address,
- prefix,
- def->bridge,
- forwardIf) < 0)
- return -1;
-
- return 0;
-}
-
-
-static void
-networkAddGeneralIPv4FirewallRules(virFirewall *fw,
- virNetworkDef *def)
-{
- size_t i;
- virNetworkIPDef *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(def, AF_INET, i));
- i++) {
- if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
- break;
- }
-
- /* allow DHCP requests through to dnsmasq & back out */
- iptablesAddTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
- iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
- iptablesAddTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
- iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
-
- /* allow DNS requests through to dnsmasq & back out */
- iptablesAddTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
- iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
- iptablesAddTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
- iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
-
- /* allow TFTP requests through to dnsmasq if necessary & back out */
- if (ipv4def && ipv4def->tftproot) {
- iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
- iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
- }
-
- /* Catch all rules to block forwarding to/from bridges */
- iptablesAddForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
- iptablesAddForwardRejectIn(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
-
- /* Allow traffic between guests on the same bridge */
- iptablesAddForwardAllowCross(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
-}
-
-static void
-networkRemoveGeneralIPv4FirewallRules(virFirewall *fw,
- virNetworkDef *def)
-{
- size_t i;
- virNetworkIPDef *ipv4def;
-
- for (i = 0;
- (ipv4def = virNetworkDefGetIPByIndex(def, AF_INET, i));
- i++) {
- if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
- break;
- }
-
- iptablesRemoveForwardAllowCross(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
- iptablesRemoveForwardRejectIn(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
- iptablesRemoveForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
-
- if (ipv4def && ipv4def->tftproot) {
- iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
- iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
- }
-
- iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
- iptablesRemoveTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
- iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
- iptablesRemoveTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
-
- iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
- iptablesRemoveTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
- iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
- iptablesRemoveTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
-}
-
-
-/* Add all once/network rules required for IPv6.
- * If no IPv6 addresses are defined and <network ipv6='yes'> is
- * specified, then allow IPv6 communications between virtual systems.
- * If any IPv6 addresses are defined, then add the rules for regular operation.
- */
-static void
-networkAddGeneralIPv6FirewallRules(virFirewall *fw,
- virNetworkDef *def)
-{
- if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0) &&
- !def->ipv6nogw) {
- return;
- }
-
- /* Catch all rules to block forwarding to/from bridges */
- iptablesAddForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
- iptablesAddForwardRejectIn(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
-
- /* Allow traffic between guests on the same bridge */
- iptablesAddForwardAllowCross(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
-
- if (virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
- /* allow DNS over IPv6 & back out */
- iptablesAddTcpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
- iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
- iptablesAddTcpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
- iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
- /* allow DHCPv6 & back out */
- iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 547);
- iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 546);
- }
-}
-
-static void
-networkRemoveGeneralIPv6FirewallRules(virFirewall *fw,
- virNetworkDef *def)
+int
+networkAddFirewallRules(virNetworkDef *def)
{
- if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0) &&
- !def->ipv6nogw) {
- return;
- }
-
- if (virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
- iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 546);
- iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 547);
- iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
- iptablesRemoveTcpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
- iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
- iptablesRemoveTcpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
- }
-
- /* the following rules are there if no IPv6 address has been defined
- * but def->ipv6nogw == true
- */
- iptablesRemoveForwardAllowCross(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
- iptablesRemoveForwardRejectIn(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
- iptablesRemoveForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
-}
-
-
-static void
-networkAddGeneralFirewallRules(virFirewall *fw,
- virNetworkDef *def)
-{
- networkAddGeneralIPv4FirewallRules(fw, def);
- networkAddGeneralIPv6FirewallRules(fw, def);
-}
-
-
-static void
-networkRemoveGeneralFirewallRules(virFirewall *fw,
- virNetworkDef *def)
-{
- networkRemoveGeneralIPv4FirewallRules(fw, def);
- networkRemoveGeneralIPv6FirewallRules(fw, def);
-}
-
-static void
-networkAddChecksumFirewallRules(virFirewall *fw,
- virNetworkDef *def)
-{
- size_t i;
- virNetworkIPDef *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(def, AF_INET, i));
- i++) {
- if (ipv4def->nranges || ipv4def->nhosts)
- break;
- }
-
- /* 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)
- iptablesAddOutputFixUdpChecksum(fw, def->bridge, 68);
-}
-
-
-static void
-networkRemoveChecksumFirewallRules(virFirewall *fw,
- virNetworkDef *def)
-{
- size_t i;
- virNetworkIPDef *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(def, AF_INET, i));
- i++) {
- if (ipv4def->nranges || ipv4def->nhosts)
- break;
- }
-
- if (ipv4def)
- iptablesRemoveOutputFixUdpChecksum(fw, def->bridge, 68);
-}
-
-
-static int
-networkAddIPSpecificFirewallRules(virFirewall *fw,
- virNetworkDef *def,
- virNetworkIPDef *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 (def->forward.type == VIR_NETWORK_FORWARD_NAT) {
- if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET) ||
- def->forward.natIPv6 == VIR_TRISTATE_BOOL_YES)
- return networkAddMasqueradingFirewallRules(fw, def, ipdef);
- else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
- return networkAddRoutingFirewallRules(fw, def, ipdef);
- } else if (def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
- return networkAddRoutingFirewallRules(fw, def, ipdef);
- }
- return 0;
-}
-
-
-static int
-networkRemoveIPSpecificFirewallRules(virFirewall *fw,
- virNetworkDef *def,
- virNetworkIPDef *ipdef)
-{
- if (def->forward.type == VIR_NETWORK_FORWARD_NAT) {
- if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET) ||
- def->forward.natIPv6 == VIR_TRISTATE_BOOL_YES)
- return networkRemoveMasqueradingFirewallRules(fw, def, ipdef);
- else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
- return networkRemoveRoutingFirewallRules(fw, def, ipdef);
- } else if (def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
- return networkRemoveRoutingFirewallRules(fw, def, ipdef);
- }
- return 0;
-}
-
-
-/* Add all rules for all ip addresses (and general rules) on a network */
-int networkAddFirewallRules(virNetworkDef *def)
-{
- size_t i;
- virNetworkIPDef *ipdef;
- g_autoptr(virFirewall) fw = virFirewallNew();
-
if (virOnce(&createdOnce, networkSetupPrivateChains) < 0)
return -1;
}
}
- virFirewallStartTransaction(fw, 0);
-
- networkAddGeneralFirewallRules(fw, def);
-
- for (i = 0;
- (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
- i++) {
- if (networkAddIPSpecificFirewallRules(fw, def, ipdef) < 0)
- return -1;
- }
-
- virFirewallStartRollback(fw, 0);
-
- for (i = 0;
- (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
- i++) {
- if (networkRemoveIPSpecificFirewallRules(fw, def, ipdef) < 0)
- return -1;
- }
- networkRemoveGeneralFirewallRules(fw, def);
-
- virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
- networkAddChecksumFirewallRules(fw, def);
-
- return virFirewallApply(fw);
+ return iptablesAddFirewallRules(def);
}
-/* Remove all rules for all ip addresses (and general rules) on a network */
-void networkRemoveFirewallRules(virNetworkDef *def)
-{
- size_t i;
- virNetworkIPDef *ipdef;
- g_autoptr(virFirewall) fw = virFirewallNew();
-
- virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
- networkRemoveChecksumFirewallRules(fw, def);
-
- virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
- for (i = 0;
- (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
- i++) {
- if (networkRemoveIPSpecificFirewallRules(fw, def, ipdef) < 0)
- return;
- }
- networkRemoveGeneralFirewallRules(fw, def);
-
- virFirewallApply(fw);
+void
+networkRemoveFirewallRules(virNetworkDef *def)
+{
+ iptablesRemoveFirewallRules(def);
}
/*
- * network_iptables.c: helper APIs for managing iptables in network driver
+ * network_iptables.c: iptables-based firewall implementation for
+ * virtual networks.
*
* Copyright (C) 2007-2014 Red Hat, Inc.
*
{
iptablesOutputFixUdpChecksum(fw, iface, port, VIR_NETFILTER_DELETE);
}
+
+
+static const char networkLocalMulticastIPv4[] = "224.0.0.0/24";
+static const char networkLocalMulticastIPv6[] = "ff02::/16";
+static const char networkLocalBroadcast[] = "255.255.255.255/32";
+
+static int
+iptablesAddMasqueradingFirewallRules(virFirewall *fw,
+ virNetworkDef *def,
+ virNetworkIPDef *ipdef)
+{
+ int prefix = virNetworkIPDefPrefix(ipdef);
+ const char *forwardIf = virNetworkDefForwardIf(def, 0);
+ bool isIPv4 = VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET);
+
+ if (prefix < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Invalid prefix or netmask for '%1$s'"),
+ def->bridge);
+ return -1;
+ }
+
+ /* allow forwarding packets from the bridge interface */
+ if (iptablesAddForwardAllowOut(fw,
+ &ipdef->address,
+ prefix,
+ def->bridge,
+ forwardIf) < 0)
+ return -1;
+
+ /* allow forwarding packets to the bridge interface if they are
+ * part of an existing connection
+ */
+ if (iptablesAddForwardAllowRelatedIn(fw,
+ &ipdef->address,
+ prefix,
+ def->bridge,
+ forwardIf) < 0)
+ return -1;
+
+ /*
+ * Enable masquerading.
+ *
+ * We need to end up with 5 rules in the table in this order
+ *
+ * 1. do not masquerade packets targeting 224.0.0.0/24
+ * 2. do not masquerade packets targeting 255.255.255.255/32
+ * 3. masquerade protocol=tcp with sport mapping restriction
+ * 4. masquerade protocol=udp with sport mapping restriction
+ * 5. generic, masquerade any protocol
+ *
+ * 224.0.0.0/24 is the local network multicast range. Packets are not
+ * forwarded outside.
+ *
+ * 255.255.255.255/32 is the broadcast address of any local network. Again,
+ * such packets are never forwarded, but strict DHCP clients don't accept
+ * DHCP replies with changed source ports.
+ *
+ * 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(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ &def->forward.addr,
+ &def->forward.port,
+ NULL) < 0)
+ return -1;
+
+ /* UDP with a source port restriction */
+ if (iptablesAddForwardMasquerade(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ &def->forward.addr,
+ &def->forward.port,
+ "udp") < 0)
+ return -1;
+
+ /* TCP with a source port restriction */
+ if (iptablesAddForwardMasquerade(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ &def->forward.addr,
+ &def->forward.port,
+ "tcp") < 0)
+ return -1;
+
+ /* exempt local network broadcast address as destination */
+ if (isIPv4 &&
+ iptablesAddDontMasquerade(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ networkLocalBroadcast) < 0)
+ return -1;
+
+ /* exempt local multicast range as destination */
+ if (iptablesAddDontMasquerade(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ isIPv4 ? networkLocalMulticastIPv4 :
+ networkLocalMulticastIPv6) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+iptablesRemoveMasqueradingFirewallRules(virFirewall *fw,
+ virNetworkDef *def,
+ virNetworkIPDef *ipdef)
+{
+ int prefix = virNetworkIPDefPrefix(ipdef);
+ const char *forwardIf = virNetworkDefForwardIf(def, 0);
+ bool isIPv4 = VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET);
+
+ if (prefix < 0)
+ return 0;
+
+ if (iptablesRemoveDontMasquerade(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ isIPv4 ? networkLocalMulticastIPv4 :
+ networkLocalMulticastIPv6) < 0)
+ return -1;
+
+ if (isIPv4 &&
+ iptablesRemoveDontMasquerade(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ networkLocalBroadcast) < 0)
+ return -1;
+
+ if (iptablesRemoveForwardMasquerade(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ &def->forward.addr,
+ &def->forward.port,
+ "tcp") < 0)
+ return -1;
+
+ if (iptablesRemoveForwardMasquerade(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ &def->forward.addr,
+ &def->forward.port,
+ "udp") < 0)
+ return -1;
+
+ if (iptablesRemoveForwardMasquerade(fw,
+ &ipdef->address,
+ prefix,
+ forwardIf,
+ &def->forward.addr,
+ &def->forward.port,
+ NULL) < 0)
+ return -1;
+
+ if (iptablesRemoveForwardAllowRelatedIn(fw,
+ &ipdef->address,
+ prefix,
+ def->bridge,
+ forwardIf) < 0)
+ return -1;
+
+ if (iptablesRemoveForwardAllowOut(fw,
+ &ipdef->address,
+ prefix,
+ def->bridge,
+ forwardIf) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+iptablesAddRoutingFirewallRules(virFirewall *fw,
+ virNetworkDef *def,
+ virNetworkIPDef *ipdef)
+{
+ int prefix = virNetworkIPDefPrefix(ipdef);
+ const char *forwardIf = virNetworkDefForwardIf(def, 0);
+
+ if (prefix < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Invalid prefix or netmask for '%1$s'"),
+ def->bridge);
+ return -1;
+ }
+
+ /* allow routing packets from the bridge interface */
+ if (iptablesAddForwardAllowOut(fw,
+ &ipdef->address,
+ prefix,
+ def->bridge,
+ forwardIf) < 0)
+ return -1;
+
+ /* allow routing packets to the bridge interface */
+ if (iptablesAddForwardAllowIn(fw,
+ &ipdef->address,
+ prefix,
+ def->bridge,
+ forwardIf) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+iptablesRemoveRoutingFirewallRules(virFirewall *fw,
+ virNetworkDef *def,
+ virNetworkIPDef *ipdef)
+{
+ int prefix = virNetworkIPDefPrefix(ipdef);
+ const char *forwardIf = virNetworkDefForwardIf(def, 0);
+
+ if (prefix < 0)
+ return 0;
+
+ if (iptablesRemoveForwardAllowIn(fw,
+ &ipdef->address,
+ prefix,
+ def->bridge,
+ forwardIf) < 0)
+ return -1;
+
+ if (iptablesRemoveForwardAllowOut(fw,
+ &ipdef->address,
+ prefix,
+ def->bridge,
+ forwardIf) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static void
+iptablesAddGeneralIPv4FirewallRules(virFirewall *fw,
+ virNetworkDef *def)
+{
+ size_t i;
+ virNetworkIPDef *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(def, AF_INET, i));
+ i++) {
+ if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
+ break;
+ }
+
+ /* allow DHCP requests through to dnsmasq & back out */
+ iptablesAddTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
+ iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
+ iptablesAddTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
+ iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
+
+ /* allow DNS requests through to dnsmasq & back out */
+ iptablesAddTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+ iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+ iptablesAddTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+ iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+
+ /* allow TFTP requests through to dnsmasq if necessary & back out */
+ if (ipv4def && ipv4def->tftproot) {
+ iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
+ iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
+ }
+
+ /* Catch all rules to block forwarding to/from bridges */
+ iptablesAddForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
+ iptablesAddForwardRejectIn(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
+
+ /* Allow traffic between guests on the same bridge */
+ iptablesAddForwardAllowCross(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
+}
+
+static void
+iptablesRemoveGeneralIPv4FirewallRules(virFirewall *fw,
+ virNetworkDef *def)
+{
+ size_t i;
+ virNetworkIPDef *ipv4def;
+
+ for (i = 0;
+ (ipv4def = virNetworkDefGetIPByIndex(def, AF_INET, i));
+ i++) {
+ if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
+ break;
+ }
+
+ iptablesRemoveForwardAllowCross(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
+ iptablesRemoveForwardRejectIn(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
+ iptablesRemoveForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge);
+
+ if (ipv4def && ipv4def->tftproot) {
+ iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
+ iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 69);
+ }
+
+ iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+ iptablesRemoveTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+ iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+ iptablesRemoveTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 53);
+
+ iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
+ iptablesRemoveTcpOutput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 68);
+ iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
+ iptablesRemoveTcpInput(fw, VIR_FIREWALL_LAYER_IPV4, def->bridge, 67);
+}
+
+
+/* Add all once/network rules required for IPv6.
+ * If no IPv6 addresses are defined and <network ipv6='yes'> is
+ * specified, then allow IPv6 communications between virtual systems.
+ * If any IPv6 addresses are defined, then add the rules for regular operation.
+ */
+static void
+iptablesAddGeneralIPv6FirewallRules(virFirewall *fw,
+ virNetworkDef *def)
+{
+ if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0) &&
+ !def->ipv6nogw) {
+ return;
+ }
+
+ /* Catch all rules to block forwarding to/from bridges */
+ iptablesAddForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
+ iptablesAddForwardRejectIn(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
+
+ /* Allow traffic between guests on the same bridge */
+ iptablesAddForwardAllowCross(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
+
+ if (virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
+ /* allow DNS over IPv6 & back out */
+ iptablesAddTcpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+ iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+ iptablesAddTcpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+ iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+ /* allow DHCPv6 & back out */
+ iptablesAddUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 547);
+ iptablesAddUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 546);
+ }
+}
+
+static void
+iptablesRemoveGeneralIPv6FirewallRules(virFirewall *fw,
+ virNetworkDef *def)
+{
+ if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0) &&
+ !def->ipv6nogw) {
+ return;
+ }
+
+ if (virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
+ iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 546);
+ iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 547);
+ iptablesRemoveUdpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+ iptablesRemoveTcpOutput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+ iptablesRemoveUdpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+ iptablesRemoveTcpInput(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge, 53);
+ }
+
+ /* the following rules are there if no IPv6 address has been defined
+ * but def->ipv6nogw == true
+ */
+ iptablesRemoveForwardAllowCross(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
+ iptablesRemoveForwardRejectIn(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
+ iptablesRemoveForwardRejectOut(fw, VIR_FIREWALL_LAYER_IPV6, def->bridge);
+}
+
+
+static void
+iptablesAddGeneralFirewallRules(virFirewall *fw,
+ virNetworkDef *def)
+{
+ iptablesAddGeneralIPv4FirewallRules(fw, def);
+ iptablesAddGeneralIPv6FirewallRules(fw, def);
+}
+
+
+static void
+iptablesRemoveGeneralFirewallRules(virFirewall *fw,
+ virNetworkDef *def)
+{
+ iptablesRemoveGeneralIPv4FirewallRules(fw, def);
+ iptablesRemoveGeneralIPv6FirewallRules(fw, def);
+}
+
+static void
+iptablesAddChecksumFirewallRules(virFirewall *fw,
+ virNetworkDef *def)
+{
+ size_t i;
+ virNetworkIPDef *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(def, AF_INET, i));
+ i++) {
+ if (ipv4def->nranges || ipv4def->nhosts)
+ break;
+ }
+
+ /* 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)
+ iptablesAddOutputFixUdpChecksum(fw, def->bridge, 68);
+}
+
+
+static void
+iptablesRemoveChecksumFirewallRules(virFirewall *fw,
+ virNetworkDef *def)
+{
+ size_t i;
+ virNetworkIPDef *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(def, AF_INET, i));
+ i++) {
+ if (ipv4def->nranges || ipv4def->nhosts)
+ break;
+ }
+
+ if (ipv4def)
+ iptablesRemoveOutputFixUdpChecksum(fw, def->bridge, 68);
+}
+
+
+static int
+iptablesAddIPSpecificFirewallRules(virFirewall *fw,
+ virNetworkDef *def,
+ virNetworkIPDef *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 (def->forward.type == VIR_NETWORK_FORWARD_NAT) {
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET) ||
+ def->forward.natIPv6 == VIR_TRISTATE_BOOL_YES)
+ return iptablesAddMasqueradingFirewallRules(fw, def, ipdef);
+ else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
+ return iptablesAddRoutingFirewallRules(fw, def, ipdef);
+ } else if (def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
+ return iptablesAddRoutingFirewallRules(fw, def, ipdef);
+ }
+ return 0;
+}
+
+
+static int
+iptablesRemoveIPSpecificFirewallRules(virFirewall *fw,
+ virNetworkDef *def,
+ virNetworkIPDef *ipdef)
+{
+ if (def->forward.type == VIR_NETWORK_FORWARD_NAT) {
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET) ||
+ def->forward.natIPv6 == VIR_TRISTATE_BOOL_YES)
+ return iptablesRemoveMasqueradingFirewallRules(fw, def, ipdef);
+ else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
+ return iptablesRemoveRoutingFirewallRules(fw, def, ipdef);
+ } else if (def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
+ return iptablesRemoveRoutingFirewallRules(fw, def, ipdef);
+ }
+ return 0;
+}
+
+
+/* Add all rules for all ip addresses (and general rules) on a network */
+int
+iptablesAddFirewallRules(virNetworkDef *def)
+{
+ size_t i;
+ virNetworkIPDef *ipdef;
+ g_autoptr(virFirewall) fw = virFirewallNew();
+
+ virFirewallStartTransaction(fw, 0);
+
+ iptablesAddGeneralFirewallRules(fw, def);
+
+ for (i = 0;
+ (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
+ i++) {
+ if (iptablesAddIPSpecificFirewallRules(fw, def, ipdef) < 0)
+ return -1;
+ }
+
+ virFirewallStartRollback(fw, 0);
+
+ for (i = 0;
+ (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
+ i++) {
+ if (iptablesRemoveIPSpecificFirewallRules(fw, def, ipdef) < 0)
+ return -1;
+ }
+ iptablesRemoveGeneralFirewallRules(fw, def);
+
+ virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
+ iptablesAddChecksumFirewallRules(fw, def);
+
+ return virFirewallApply(fw);
+}
+
+/* Remove all rules for all ip addresses (and general rules) on a network */
+void
+iptablesRemoveFirewallRules(virNetworkDef *def)
+{
+ size_t i;
+ virNetworkIPDef *ipdef;
+ g_autoptr(virFirewall) fw = virFirewallNew();
+
+ virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
+ iptablesRemoveChecksumFirewallRules(fw, def);
+
+ virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
+
+ for (i = 0;
+ (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
+ i++) {
+ if (iptablesRemoveIPSpecificFirewallRules(fw, def, ipdef) < 0)
+ return;
+ }
+ iptablesRemoveGeneralFirewallRules(fw, def);
+
+ virFirewallApply(fw);
+}
#include "virsocketaddr.h"
#include "virfirewall.h"
+#include "network_conf.h"
-int iptablesSetupPrivateChains (virFirewallLayer layer);
+int iptablesAddFirewallRules(virNetworkDef *def);
+
+void iptablesRemoveFirewallRules(virNetworkDef *def);
+
+int iptablesSetupPrivateChains(virFirewallLayer layer);
void iptablesAddTcpInput (virFirewall *fw,
virFirewallLayer layer,