From 1716e7a6c5178889bd42d925093715a47c458fc9 Mon Sep 17 00:00:00 2001
From: Natanael Copa
Date: Tue, 19 Feb 2013 11:44:15 +0100
Subject: [PATCH] net: add support for specifying port range for forward mode
nat
Let users set the port range to be used for forward mode NAT:
...
...
Signed-off-by: Natanael Copa
Signed-off-by: Laine Stump
---
docs/formatnetwork.html.in | 21 ++++++++++++--
src/conf/network_conf.c | 56 ++++++++++++++++++++++++++++++++-----
src/conf/network_conf.h | 3 +-
src/network/bridge_driver.c | 16 +++++++++++
src/util/viriptables.c | 49 +++++++++++++++++++++++++-------
src/util/viriptables.h | 4 +++
6 files changed, 128 insertions(+), 21 deletions(-)
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 5fbd0a9b48..adb5bb9624 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -138,9 +138,11 @@
0.4.2
Since 1.0.3 it is possible to
- specify a public IPv4 address range to be used for the NAT by
- using the <nat>
and
- <address>
subelements.
+ specify a public IPv4 address and port range to be used for
+ the NAT by using the <nat>
subelement.
+ The address range is set with the <address>
+ subelements and start
and stop
+ attributes:
...
<forward mode='nat'>
@@ -154,6 +156,19 @@
start
and end
attributes to
the same value.
+
+ The port range to be used for the <nat>
can
+ be set via the subelement <port>
:
+
+...
+ <forward mode='nat'>
+ <nat>
+ <port start='500' end='1000'/>
+ </nat>
+ </forward>
+...
+
+
route
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index c7df2a520a..dfcec0e82b 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -1332,7 +1332,8 @@ virNetworkForwardNatDefParseXML(const char *networkName,
{
int ret = -1;
xmlNodePtr *natAddrNodes = NULL;
- int nNatAddrs;
+ xmlNodePtr *natPortNodes = NULL;
+ int nNatAddrs, nNatPorts;
char *addrStart = NULL;
char *addrEnd = NULL;
xmlNodePtr save = ctxt->node;
@@ -1389,6 +1390,36 @@ virNetworkForwardNatDefParseXML(const char *networkName,
goto cleanup;
}
+ /* ports for SNAT and MASQUERADE */
+ nNatPorts = virXPathNodeSet("./port", ctxt, &natPortNodes);
+ if (nNatPorts < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid element found in of "
+ "network %s"), networkName);
+ goto cleanup;
+ } else if (nNatPorts > 1) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Only one element is allowed in in "
+ " in network %s"), networkName);
+ goto cleanup;
+ } else if (nNatPorts == 1) {
+ if (virXPathUInt("string(./port[1]/@start)", ctxt, &def->portStart) < 0
+ || def->portStart > 65535) {
+
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("Missing or invalid 'start' attribute in "
+ "in in in network %s"),
+ networkName);
+ goto cleanup;
+ }
+ if (virXPathUInt("string(./port[1]/@end)", ctxt, &def->portEnd) < 0
+ || def->portEnd > 65535 || def->portEnd < def->portStart) {
+ virReportError(VIR_ERR_XML_DETAIL,
+ _("Missing or invalid 'end' attribute in in "
+ " in in network %s"), networkName);
+ goto cleanup;
+ }
+ }
ret = 0;
cleanup:
@@ -2193,16 +2224,25 @@ virNetworkForwardNatDefFormat(virBufferPtr buf,
goto cleanup;
}
- if (!addrEnd && !addrStart)
+ if (!addrEnd && !addrStart && !fwd->portStart && !fwd->portEnd)
return 0;
virBufferAddLit(buf, "\n");
virBufferAdjustIndent(buf, 2);
- virBufferAsprintf(buf, "\n");
+ if (addrStart) {
+ virBufferAsprintf(buf, "\n");
+ }
+
+ if (fwd->portStart || fwd->portEnd) {
+ virBufferAsprintf(buf, "portStart);
+ if (fwd->portEnd)
+ virBufferAsprintf(buf, " end='%d'", fwd->portEnd);
+ virBufferAddLit(buf, "/>\n");
+ }
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "\n");
@@ -2260,7 +2300,9 @@ virNetworkDefFormatInternal(virBufferPtr buf,
}
shortforward = !(def->forward.nifs || def->forward.npfs
|| VIR_SOCKET_ADDR_VALID(&def->forward.addrStart)
- || VIR_SOCKET_ADDR_VALID(&def->forward.addrEnd));
+ || VIR_SOCKET_ADDR_VALID(&def->forward.addrEnd)
+ || def->forward.portStart
+ || def->forward.portEnd);
virBufferAsprintf(buf, "%s>\n", shortforward ? "/" : "");
virBufferAdjustIndent(buf, 2);
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 11d6c9ca18..515115bb7c 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -175,8 +175,9 @@ struct _virNetworkForwardDef {
size_t nifs;
virNetworkForwardIfDefPtr ifs;
- /* adresses for SNAT */
+ /* ranges for NAT */
virSocketAddr addrStart, addrEnd;
+ unsigned int portStart, portEnd;
};
typedef struct _virPortGroupDef virPortGroupDef;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 9f502a5ca6..cf47ec4fcb 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1589,6 +1589,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf,
&network->def->forward.addrStart,
&network->def->forward.addrEnd,
+ network->def->forward.portStart,
+ network->def->forward.portEnd,
NULL) < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR,
forwardIf ?
@@ -1605,6 +1607,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf,
&network->def->forward.addrStart,
&network->def->forward.addrEnd,
+ network->def->forward.portStart,
+ network->def->forward.portEnd,
"udp") < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR,
forwardIf ?
@@ -1621,6 +1625,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf,
&network->def->forward.addrStart,
&network->def->forward.addrEnd,
+ network->def->forward.portStart,
+ network->def->forward.portEnd,
"tcp") < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR,
forwardIf ?
@@ -1639,6 +1645,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf,
&network->def->forward.addrStart,
&network->def->forward.addrEnd,
+ network->def->forward.portStart,
+ network->def->forward.portEnd,
"udp");
masqerr4:
iptablesRemoveForwardMasquerade(driver->iptables,
@@ -1647,6 +1655,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf,
&network->def->forward.addrStart,
&network->def->forward.addrEnd,
+ network->def->forward.portStart,
+ network->def->forward.portEnd,
NULL);
masqerr3:
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
@@ -1679,6 +1689,8 @@ networkRemoveMasqueradingIptablesRules(struct network_driver *driver,
forwardIf,
&network->def->forward.addrStart,
&network->def->forward.addrEnd,
+ network->def->forward.portStart,
+ network->def->forward.portEnd,
"tcp");
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
@@ -1686,6 +1698,8 @@ networkRemoveMasqueradingIptablesRules(struct network_driver *driver,
forwardIf,
&network->def->forward.addrStart,
&network->def->forward.addrEnd,
+ network->def->forward.portStart,
+ network->def->forward.portEnd,
"udp");
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
@@ -1693,6 +1707,8 @@ networkRemoveMasqueradingIptablesRules(struct network_driver *driver,
forwardIf,
&network->def->forward.addrStart,
&network->def->forward.addrEnd,
+ network->def->forward.portStart,
+ network->def->forward.portEnd,
NULL);
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
diff --git a/src/util/viriptables.c b/src/util/viriptables.c
index 954ce8b5a9..a3b8922b64 100644
--- a/src/util/viriptables.c
+++ b/src/util/viriptables.c
@@ -807,6 +807,8 @@ iptablesForwardMasquerade(iptablesContext *ctx,
const char *physdev,
virSocketAddr *addrStart,
virSocketAddr *addrEnd,
+ unsigned int portStart,
+ unsigned int portEnd,
const char *protocol,
int action)
{
@@ -814,6 +816,7 @@ iptablesForwardMasquerade(iptablesContext *ctx,
char *networkstr = NULL;
char *addrStartStr = NULL;
char *addrEndStr = NULL;
+ char *portRangeStr = NULL;
char *natRangeStr = NULL;
virCommandPtr cmd = NULL;
@@ -848,19 +851,34 @@ iptablesForwardMasquerade(iptablesContext *ctx,
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]) {
- const char *portStr = "";
int r = 0;
- if (protocol && protocol[0])
- portStr = ":1024-65535";
-
if (addrEndStr && addrEndStr[0]) {
r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr,
- portStr);
+ portRangeStr ? portRangeStr : "");
} else {
- r = virAsprintf(&natRangeStr, "%s%s", addrStartStr, portStr);
+ r = virAsprintf(&natRangeStr, "%s%s", addrStartStr,
+ portRangeStr ? portRangeStr : "");
}
if (r < 0) {
@@ -873,8 +891,8 @@ iptablesForwardMasquerade(iptablesContext *ctx,
} else {
virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL);
- if (protocol && protocol[0])
- virCommandAddArgList(cmd, "--to-ports", "1024-65535", NULL);
+ if (portRangeStr && portRangeStr[0])
+ virCommandAddArgList(cmd, "--to-ports", &portRangeStr[1], NULL);
}
ret = virCommandRun(cmd, NULL);
@@ -883,6 +901,7 @@ cleanup:
VIR_FREE(networkstr);
VIR_FREE(addrStartStr);
VIR_FREE(addrEndStr);
+ VIR_FREE(portRangeStr);
VIR_FREE(natRangeStr);
return ret;
}
@@ -907,9 +926,14 @@ iptablesAddForwardMasquerade(iptablesContext *ctx,
const char *physdev,
virSocketAddr *addrStart,
virSocketAddr *addrEnd,
+ unsigned int portStart,
+ unsigned int portEnd,
const char *protocol)
{
- return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, addrStart, addrEnd, protocol, ADD);
+ return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev,
+ addrStart, addrEnd,
+ portStart, portEnd,
+ protocol, ADD);
}
/**
@@ -932,9 +956,14 @@ iptablesRemoveForwardMasquerade(iptablesContext *ctx,
const char *physdev,
virSocketAddr *addrStart,
virSocketAddr *addrEnd,
+ unsigned int portStart,
+ unsigned int portEnd,
const char *protocol)
{
- return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, addrStart, addrEnd, protocol, REMOVE);
+ return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev,
+ addrStart, addrEnd,
+ portStart, portEnd,
+ protocol, REMOVE);
}
diff --git a/src/util/viriptables.h b/src/util/viriptables.h
index 05362da7f8..ca6adcc058 100644
--- a/src/util/viriptables.h
+++ b/src/util/viriptables.h
@@ -109,6 +109,8 @@ int iptablesAddForwardMasquerade (iptablesContext *ctx,
const char *physdev,
virSocketAddr *addrStart,
virSocketAddr *addrEnd,
+ unsigned int portStart,
+ unsigned int portEnd,
const char *protocol);
int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
virSocketAddr *netaddr,
@@ -116,6 +118,8 @@ int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
const char *physdev,
virSocketAddr *addrStart,
virSocketAddr *addrEnd,
+ unsigned int portStart,
+ unsigned int portEnd,
const char *protocol);
int iptablesAddOutputFixUdpChecksum (iptablesContext *ctx,
const char *iface,