Allow setting a range of public ip addresses to be used as source address for forward mode nat: ... <forward mode='nat'> <nat> <address start='1.2.3.4' end='1.2.3.10'/> </nat> </forward> ... Signed-off-by: Natanael Copa <ncopa@xxxxxxxxxxxxxxx> --- docs/formatnetwork.html.in | 13 ++++++++ src/conf/network_conf.c | 72 ++++++++++++++++++++++++++++++++++++++++++--- src/conf/network_conf.h | 4 +-- src/network/bridge_driver.c | 8 +++++ src/util/viriptables.c | 21 ++++++++++--- src/util/viriptables.h | 2 ++ 6 files changed, 110 insertions(+), 10 deletions(-) diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 4ab1a75..608fce1 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -148,6 +148,19 @@ </forward> ... </pre> + An address range can be set with the subelement + <code><address></code>. The range which will be + used in a round-robin: + <pre> +... + <forward mode='nat'> + <nat> + <address start='1.2.3.4' end='1.2.3.10'/> + </nat> + </forward> +... + </pre> + </p> </dd> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index a9aa139..fb57b70 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -1331,7 +1331,10 @@ virNetworkForwardNatDefParseXML(const char *networkName, virNetworkForwardDefPtr def) { int ret = -1; + xmlNodePtr *natAddrNodes = NULL; + int nNatAddrs; char *addr_start = NULL; + char *addr_end = NULL; xmlNodePtr save = ctxt->node; ctxt->node = node; @@ -1346,6 +1349,35 @@ virNetworkForwardNatDefParseXML(const char *networkName, /* addresses for SNAT */ addr_start = virXPathString("string(./@address)", ctxt); + nNatAddrs = virXPathNodeSet("./address", ctxt, &natAddrNodes); + if (nNatAddrs < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid <address> element found in <forward> of " + "network %s"), networkName); + goto cleanup; + } else if (nNatAddrs > 1) { + virReportError(VIR_ERR_XML_ERROR, + _("Only one <address> element is allowed in <nat> in " + "<forward> in network %s"), networkName); + goto cleanup; + } else if (nNatAddrs == 1) { + if (addr_start != NULL) { + virReportError(VIR_ERR_XML_ERROR, + _("the <nat> 'address' attribute cannot be used " + "when <address> sub-elements are present in " + "<forward> in network %s"), networkName); + goto cleanup; + } + addr_start = virXMLPropString(*natAddrNodes, "start"); + if (addr_start == NULL) { + virReportError(VIR_ERR_XML_ERROR, + _("missing 'start' attribute in <address> element in <nat> in " + "<forward> in network %s"), networkName); + goto cleanup; + } + addr_end = virXMLPropString(*natAddrNodes, "end"); + } + if (addr_start && virSocketAddrParse(&def->addr_start, addr_start, AF_INET) < 0) { virReportError(VIR_ERR_XML_ERROR, _("Bad ipv4 address '%s' in <nat> in <forward> in " @@ -1353,10 +1385,18 @@ virNetworkForwardNatDefParseXML(const char *networkName, goto cleanup; } + if (addr_end && virSocketAddrParse(&def->addr_end, addr_end, AF_INET) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Bad ipv4 address '%s' in <nat> in <forward> in " + "network '%s'"), addr_end, networkName); + goto cleanup; + } + ret = 0; cleanup: VIR_FREE(addr_start); + VIR_FREE(addr_end); ctxt->node = save; return ret; } @@ -2139,6 +2179,7 @@ virNatDefFormat(virBufferPtr buf, const virNetworkForwardDefPtr fwd) { char *addr_start = NULL; + char *addr_end = NULL; int ret = -1; if (VIR_SOCKET_ADDR_VALID(&fwd->addr_start)) { @@ -2147,17 +2188,39 @@ virNatDefFormat(virBufferPtr buf, goto cleanup; } - if (!addr_start) + if (VIR_SOCKET_ADDR_VALID(&fwd->addr_end)) { + addr_end = virSocketAddrFormat(&fwd->addr_end); + if (!addr_end) + goto cleanup; + } + + if (!addr_end && !addr_start) return 0; virBufferAddLit(buf, "<nat"); - virBufferAsprintf(buf, " address='%s'", addr_start); - virBufferAsprintf(buf, "/>\n"); + if (addr_start && !addr_end) + virBufferAsprintf(buf, " address='%s'", addr_start); + if (!addr_end) { + virBufferAsprintf(buf, "/>\n"); + ret = 0; + goto cleanup; + } + + virBufferAsprintf(buf, ">\n"); + virBufferAdjustIndent(buf, 2); + + if (addr_end) + virBufferAsprintf(buf, "<address start='%s' end='%s'/>\n", + addr_start, addr_end); + + virBufferAdjustIndent(buf, -2); + virBufferAsprintf(buf, "</nat>\n"); ret = 0; cleanup: VIR_FREE(addr_start); + VIR_FREE(addr_end); return ret; } @@ -2206,7 +2269,8 @@ virNetworkDefFormatInternal(virBufferPtr buf, virBufferAddLit(buf, " managed='no'"); } shortforward = !(def->forward.nifs || def->forward.npfs - || VIR_SOCKET_ADDR_VALID(&def->forward.addr_start)); + || VIR_SOCKET_ADDR_VALID(&def->forward.addr_start) + || VIR_SOCKET_ADDR_VALID(&def->forward.addr_end)); virBufferAsprintf(buf, "%s>\n", shortforward ? "/" : ""); virBufferAdjustIndent(buf, 2); diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 4a5ce92..1a598e3 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -175,8 +175,8 @@ struct _virNetworkForwardDef { size_t nifs; virNetworkForwardIfDefPtr ifs; - /* adress for SNAT */ - virSocketAddr addr_start; + /* adresses for SNAT */ + virSocketAddr addr_start, addr_end; }; typedef struct _virPortGroupDef virPortGroupDef; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 05ef19c..d444ddb 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1591,6 +1591,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver, prefix, forwardIf, &network->def->forward.addr_start, + &network->def->forward.addr_end, NULL) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, forwardIf ? @@ -1606,6 +1607,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver, prefix, forwardIf, &network->def->forward.addr_start, + &network->def->forward.addr_end, "udp") < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, forwardIf ? @@ -1621,6 +1623,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver, prefix, forwardIf, &network->def->forward.addr_start, + &network->def->forward.addr_end, "tcp") < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, forwardIf ? @@ -1638,6 +1641,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver, prefix, forwardIf, &network->def->forward.addr_start, + &network->def->forward.addr_end, "udp"); masqerr4: iptablesRemoveForwardMasquerade(driver->iptables, @@ -1645,6 +1649,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver, prefix, forwardIf, &network->def->forward.addr_start, + &network->def->forward.addr_end, NULL); masqerr3: iptablesRemoveForwardAllowRelatedIn(driver->iptables, @@ -1676,18 +1681,21 @@ networkRemoveMasqueradingIptablesRules(struct network_driver *driver, prefix, forwardIf, &network->def->forward.addr_start, + &network->def->forward.addr_end, "tcp"); iptablesRemoveForwardMasquerade(driver->iptables, &ipdef->address, prefix, forwardIf, &network->def->forward.addr_start, + &network->def->forward.addr_end, "udp"); iptablesRemoveForwardMasquerade(driver->iptables, &ipdef->address, prefix, forwardIf, &network->def->forward.addr_start, + &network->def->forward.addr_end, NULL); iptablesRemoveForwardAllowRelatedIn(driver->iptables, diff --git a/src/util/viriptables.c b/src/util/viriptables.c index 12d1b2e..f2d15bf 100644 --- a/src/util/viriptables.c +++ b/src/util/viriptables.c @@ -806,12 +806,14 @@ iptablesForwardMasquerade(iptablesContext *ctx, unsigned int prefix, const char *physdev, virSocketAddr *addr_start, + virSocketAddr *addr_end, const char *protocol, int action) { int ret = -1; char *networkstr = NULL; char *addr_start_str = NULL; + char *addr_end_str = NULL; virCommandPtr cmd = NULL; if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) @@ -829,6 +831,11 @@ iptablesForwardMasquerade(iptablesContext *ctx, addr_start_str = virSocketAddrFormat(addr_start); if (!addr_start_str) goto cleanup; + if (VIR_SOCKET_ADDR_IS_FAMILY(addr_end, AF_INET)) { + addr_end_str = virSocketAddrFormat(addr_end); + if (!addr_end_str) + goto cleanup; + } } cmd = iptablesCommandNew(ctx->nat_postrouting, AF_INET, action); @@ -850,8 +857,12 @@ iptablesForwardMasquerade(iptablesContext *ctx, memset(tmpstr, 0, sizeof(tmpstr)); if (protocol && protocol[0]) portstr = ":1024-65535"; - - snprintf(tmpstr, sizeof(tmpstr), "%s%s", addr_start_str, portstr); + if (addr_end_str && addr_end_str[0]) { + snprintf(tmpstr, sizeof(tmpstr), "%s-%s%s", + addr_start_str, addr_end_str, portstr); + } else { + snprintf(tmpstr, sizeof(tmpstr), "%s%s", addr_start_str, portstr); + } virCommandAddArgList(cmd, "--jump", "SNAT", "--to-source", tmpstr, NULL); @@ -887,9 +898,10 @@ iptablesAddForwardMasquerade(iptablesContext *ctx, unsigned int prefix, const char *physdev, virSocketAddr *addr_start, + virSocketAddr *addr_end, const char *protocol) { - return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, addr_start, protocol, ADD); + return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, addr_start, addr_end, protocol, ADD); } /** @@ -911,9 +923,10 @@ iptablesRemoveForwardMasquerade(iptablesContext *ctx, unsigned int prefix, const char *physdev, virSocketAddr *addr_start, + virSocketAddr *addr_end, const char *protocol) { - return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, addr_start, protocol, REMOVE); + return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, addr_start, addr_end, protocol, REMOVE); } diff --git a/src/util/viriptables.h b/src/util/viriptables.h index b75a5ea..4241380 100644 --- a/src/util/viriptables.h +++ b/src/util/viriptables.h @@ -108,12 +108,14 @@ int iptablesAddForwardMasquerade (iptablesContext *ctx, unsigned int prefix, const char *physdev, virSocketAddr *addr_start, + virSocketAddr *addr_end, const char *protocol); int iptablesRemoveForwardMasquerade (iptablesContext *ctx, virSocketAddr *netaddr, unsigned int prefix, const char *physdev, virSocketAddr *addr_start, + virSocketAddr *addr_end, const char *protocol); int iptablesAddOutputFixUdpChecksum (iptablesContext *ctx, const char *iface, -- 1.8.1.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list