/* Allow all traffic coming from the bridge, with a valid network address * to proceed to WAN */ static int iptablesForwardAllowOut(iptablesContext *ctx, virSocketAddr *netaddr, unsigned int prefix, const char *iface, const char *physdev, int action) { int ret; char *networkstr; virCommandPtr cmd = NULL; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) return -1; cmd = iptablesCommandNew(ctx->forward_filter, VIR_SOCKET_ADDR_FAMILY(netaddr), action); virCommandAddArgList(cmd, "--source", networkstr, "--in-interface", iface, NULL); if (physdev && physdev[0]) virCommandAddArgList(cmd, "--out-interface", physdev, NULL); virCommandAddArgList(cmd, "--jump", "ACCEPT", NULL); ret = iptablesCommandRunAndFree(cmd); VIR_FREE(networkstr); return ret; }
/* Allow all traffic destined to the bridge, with a valid network address */ static int iptablesForwardAllowIn(iptablesContext *ctx, virSocketAddr *netaddr, unsigned int prefix, const char *iface, const char *physdev, int action) { int ret; char *networkstr; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) return -1; if (physdev && physdev[0]) { ret = iptablesAddRemoveRule(ctx->forward_filter, VIR_SOCKET_ADDR_FAMILY(netaddr), action, "--destination", networkstr, "--in-interface", physdev, "--out-interface", iface, "--jump", "ACCEPT", NULL); } else { ret = iptablesAddRemoveRule(ctx->forward_filter, VIR_SOCKET_ADDR_FAMILY(netaddr), action, "--destination", networkstr, "--out-interface", iface, "--jump", "ACCEPT", NULL); } VIR_FREE(networkstr); return ret; }
/* Don't masquerade traffic coming from the network associated with the bridge * if said traffic targets @destaddr. */ static int iptablesForwardDontMasquerade(virSocketAddr *netaddr, unsigned int prefix, const char *physdev, const char *destaddr, int action) { int ret = -1; char *networkstr = NULL; virCommandPtr cmd = NULL; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) return -1; if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) { /* Higher level code *should* guaranteee it's impossible to get here. */ virReportError(VIR_ERR_INTERNAL_ERROR, _("Attempted to NAT '%s'. NAT is only supported for IPv4."), networkstr); goto cleanup; } cmd = iptablesCommandNew("nat", "POSTROUTING", AF_INET, action); if (physdev && physdev[0]) virCommandAddArgList(cmd, "--out-interface", physdev, NULL); virCommandAddArgList(cmd, "--source", networkstr, "--destination", destaddr, "--jump", "RETURN", NULL); ret = virCommandRun(cmd, NULL); cleanup: virCommandFree(cmd); VIR_FREE(networkstr); return ret; }
/* Allow all traffic destined to the bridge, with a valid network address */ static int iptablesForwardAllowIn(virFirewallPtr fw, virSocketAddr *netaddr, unsigned int prefix, const char *iface, const char *physdev, int action) { virFirewallLayer layer = VIR_SOCKET_ADDR_FAMILY(netaddr) == AF_INET ? VIR_FIREWALL_LAYER_IPV4 : VIR_FIREWALL_LAYER_IPV6; VIR_AUTOFREE(char *) networkstr = NULL; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) return -1; if (physdev && physdev[0]) virFirewallAddRule(fw, layer, "--table", "filter", action == ADD ? "--insert" : "--delete", "FORWARD", "--destination", networkstr, "--in-interface", physdev, "--out-interface", iface, "--jump", "ACCEPT", NULL); else virFirewallAddRule(fw, layer, "--table", "filter", action == ADD ? "--insert" : "--delete", "FORWARD", "--destination", networkstr, "--out-interface", iface, "--jump", "ACCEPT", NULL); return 0; }
/* Don't masquerade traffic coming from the network associated with the bridge * if said traffic targets @destaddr. */ static int iptablesForwardDontMasquerade(virFirewallPtr fw, virSocketAddr *netaddr, unsigned int prefix, const char *physdev, const char *destaddr, int action) { VIR_AUTOFREE(char *) networkstr = NULL; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) return -1; if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) { /* Higher level code *should* guaranteee it's impossible to get here. */ virReportError(VIR_ERR_INTERNAL_ERROR, _("Attempted to NAT '%s'. NAT is only supported for IPv4."), networkstr); return -1; } if (physdev && physdev[0]) virFirewallAddRule(fw, VIR_FIREWALL_LAYER_IPV4, "--table", "nat", action == ADD ? "--insert" : "--delete", "POSTROUTING", "--out-interface", physdev, "--source", networkstr, "--destination", destaddr, "--jump", "RETURN", NULL); else virFirewallAddRule(fw, VIR_FIREWALL_LAYER_IPV4, "--table", "nat", action == ADD ? "--insert" : "--delete", "POSTROUTING", "--source", networkstr, "--destination", destaddr, "--jump", "RETURN", NULL); return 0; }
/* Allow all traffic destined to the bridge, with a valid network address * and associated with an existing connection */ static int iptablesForwardAllowRelatedIn(virSocketAddr *netaddr, unsigned int prefix, const char *iface, const char *physdev, int action) { int ret; char *networkstr; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) return -1; if (physdev && physdev[0]) { ret = iptablesAddRemoveRule("filter", "FORWARD", VIR_SOCKET_ADDR_FAMILY(netaddr), action, "--destination", networkstr, "--in-interface", physdev, "--out-interface", iface, "--match", "conntrack", "--ctstate", "ESTABLISHED,RELATED", "--jump", "ACCEPT", NULL); } else { ret = iptablesAddRemoveRule("filter", "FORWARD", VIR_SOCKET_ADDR_FAMILY(netaddr), action, "--destination", networkstr, "--out-interface", iface, "--match", "conntrack", "--ctstate", "ESTABLISHED,RELATED", "--jump", "ACCEPT", NULL); } VIR_FREE(networkstr); return ret; }
/* Masquerade all traffic coming from the network associated * with the bridge */ static int iptablesForwardMasquerade(iptablesContext *ctx, virSocketAddr *netaddr, unsigned int prefix, const char *physdev, virSocketAddr *addrStart, virSocketAddr *addrEnd, unsigned int portStart, unsigned int portEnd, const char *protocol, int action) { int ret = -1; char *networkstr = NULL; char *addrStartStr = NULL; char *addrEndStr = NULL; char *portRangeStr = NULL; char *natRangeStr = NULL; virCommandPtr cmd = NULL; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) return -1; if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) { /* Higher level code *should* guaranteee it's impossible to get here. */ virReportError(VIR_ERR_INTERNAL_ERROR, _("Attempted to NAT '%s'. NAT is only supported for IPv4."), networkstr); goto cleanup; } if (VIR_SOCKET_ADDR_IS_FAMILY(addrStart, AF_INET)) { if (!(addrStartStr = virSocketAddrFormat(addrStart))) goto cleanup; if (VIR_SOCKET_ADDR_IS_FAMILY(addrEnd, AF_INET)) { if (!(addrEndStr = virSocketAddrFormat(addrEnd))) goto cleanup; } } cmd = iptablesCommandNew(ctx->nat_postrouting, AF_INET, action); virCommandAddArgList(cmd, "--source", networkstr, NULL); if (protocol && protocol[0]) virCommandAddArgList(cmd, "-p", protocol, NULL); virCommandAddArgList(cmd, "!", "--destination", networkstr, NULL); if (physdev && physdev[0]) virCommandAddArgList(cmd, "--out-interface", physdev, NULL); if (protocol && protocol[0]) { if (portStart == 0 && portEnd == 0) { portStart = 1024; portEnd = 65535; } if (portStart < portEnd && portEnd < 65536) { if (virAsprintf(&portRangeStr, ":%u-%u", portStart, portEnd) < 0) { virReportOOMError(); goto cleanup; } } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid port range '%u-%u'."), portStart, portEnd); } } /* Use --jump SNAT if public addr is specified */ if (addrStartStr && addrStartStr[0]) { int r = 0; if (addrEndStr && addrEndStr[0]) { r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr, portRangeStr ? portRangeStr : ""); } else { r = virAsprintf(&natRangeStr, "%s%s", addrStartStr, portRangeStr ? portRangeStr : ""); } if (r < 0) { virReportOOMError(); goto cleanup; } virCommandAddArgList(cmd, "--jump", "SNAT", "--to-source", natRangeStr, NULL); } else { virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL); if (portRangeStr && portRangeStr[0]) virCommandAddArgList(cmd, "--to-ports", &portRangeStr[1], NULL); } ret = virCommandRun(cmd, NULL); cleanup: virCommandFree(cmd); VIR_FREE(networkstr); VIR_FREE(addrStartStr); VIR_FREE(addrEndStr); VIR_FREE(portRangeStr); VIR_FREE(natRangeStr); return ret; }
/* Masquerade all traffic coming from the network associated * with the bridge */ static int iptablesForwardMasquerade(virFirewallPtr fw, virSocketAddr *netaddr, unsigned int prefix, const char *physdev, virSocketAddrRangePtr addr, virPortRangePtr port, const char *protocol, int action) { VIR_AUTOFREE(char *) networkstr = NULL; VIR_AUTOFREE(char *) addrStartStr = NULL; VIR_AUTOFREE(char *) addrEndStr = NULL; VIR_AUTOFREE(char *) portRangeStr = NULL; VIR_AUTOFREE(char *) natRangeStr = NULL; virFirewallRulePtr rule; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) return -1; if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) { /* Higher level code *should* guaranteee it's impossible to get here. */ virReportError(VIR_ERR_INTERNAL_ERROR, _("Attempted to NAT '%s'. NAT is only supported for IPv4."), networkstr); return -1; } if (VIR_SOCKET_ADDR_IS_FAMILY(&addr->start, AF_INET)) { if (!(addrStartStr = virSocketAddrFormat(&addr->start))) return -1; if (VIR_SOCKET_ADDR_IS_FAMILY(&addr->end, AF_INET)) { if (!(addrEndStr = virSocketAddrFormat(&addr->end))) return -1; } } if (protocol && protocol[0]) { rule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_IPV4, "--table", "nat", action == ADD ? "--insert" : "--delete", "POSTROUTING", "--source", networkstr, "-p", protocol, "!", "--destination", networkstr, NULL); } else { rule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_IPV4, "--table", "nat", action == ADD ? "--insert" : "--delete", "POSTROUTING", "--source", networkstr, "!", "--destination", networkstr, NULL); } if (physdev && physdev[0]) virFirewallRuleAddArgList(fw, rule, "--out-interface", physdev, NULL); if (protocol && protocol[0]) { if (port->start == 0 && port->end == 0) { port->start = 1024; port->end = 65535; } if (port->start < port->end && port->end < 65536) { if (virAsprintf(&portRangeStr, ":%u-%u", port->start, port->end) < 0) return -1; } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid port range '%u-%u'."), port->start, port->end); } } /* Use --jump SNAT if public addr is specified */ if (addrStartStr && addrStartStr[0]) { int r = 0; if (addrEndStr && addrEndStr[0]) { r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr, portRangeStr ? portRangeStr : ""); } else { r = virAsprintf(&natRangeStr, "%s%s", addrStartStr, portRangeStr ? portRangeStr : ""); } if (r < 0) return -1; virFirewallRuleAddArgList(fw, rule, "--jump", "SNAT", "--to-source", natRangeStr, NULL); } else { virFirewallRuleAddArgList(fw, rule, "--jump", "MASQUERADE", NULL); if (portRangeStr && portRangeStr[0]) virFirewallRuleAddArgList(fw, rule, "--to-ports", &portRangeStr[1], NULL); } return 0; }