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(a)alpinelinux.org>
---
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