net: add support for specifying port range for forward mode nat

Let users set the port range to be used for forward mode NAT:

...
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
...

Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
Signed-off-by: Laine Stump <laine@laine.org>
This commit is contained in:
Natanael Copa 2013-02-19 11:44:15 +01:00 committed by Laine Stump
parent 905629f47e
commit 1716e7a6c5
6 changed files with 128 additions and 21 deletions

View File

@ -138,9 +138,11 @@
0.4.2</span> 0.4.2</span>
<p><span class="since">Since 1.0.3</span> it is possible to <p><span class="since">Since 1.0.3</span> it is possible to
specify a public IPv4 address range to be used for the NAT by specify a public IPv4 address and port range to be used for
using the <code>&lt;nat&gt;</code> and the NAT by using the <code>&lt;nat&gt;</code> subelement.
<code>&lt;address&gt;</code> subelements. The address range is set with the <code>&lt;address&gt;</code>
subelements and <code>start</code> and <code>stop</code>
attributes:
<pre> <pre>
... ...
&lt;forward mode='nat'&gt; &lt;forward mode='nat'&gt;
@ -154,6 +156,19 @@
<code>start</code> and <code>end</code> attributes to <code>start</code> and <code>end</code> attributes to
the same value. the same value.
</p> </p>
<p>
The port range to be used for the <code>&lt;nat&gt;</code> can
be set via the subelement <code>&lt;port&gt;</code>:
<pre>
...
&lt;forward mode='nat'&gt;
&lt;nat&gt;
&lt;port start='500' end='1000'/&gt;
&lt;/nat&gt;
&lt;/forward&gt;
...
</pre>
</p>
</dd> </dd>
<dt><code>route</code></dt> <dt><code>route</code></dt>

View File

@ -1332,7 +1332,8 @@ virNetworkForwardNatDefParseXML(const char *networkName,
{ {
int ret = -1; int ret = -1;
xmlNodePtr *natAddrNodes = NULL; xmlNodePtr *natAddrNodes = NULL;
int nNatAddrs; xmlNodePtr *natPortNodes = NULL;
int nNatAddrs, nNatPorts;
char *addrStart = NULL; char *addrStart = NULL;
char *addrEnd = NULL; char *addrEnd = NULL;
xmlNodePtr save = ctxt->node; xmlNodePtr save = ctxt->node;
@ -1389,6 +1390,36 @@ virNetworkForwardNatDefParseXML(const char *networkName,
goto cleanup; goto cleanup;
} }
/* ports for SNAT and MASQUERADE */
nNatPorts = virXPathNodeSet("./port", ctxt, &natPortNodes);
if (nNatPorts < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("invalid <port> element found in <forward> of "
"network %s"), networkName);
goto cleanup;
} else if (nNatPorts > 1) {
virReportError(VIR_ERR_XML_ERROR,
_("Only one <port> element is allowed in <nat> in "
"<forward> 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 <port> "
"in <nat> in <forward> 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 <port> in "
"<nat> in <forward> in network %s"), networkName);
goto cleanup;
}
}
ret = 0; ret = 0;
cleanup: cleanup:
@ -2193,16 +2224,25 @@ virNetworkForwardNatDefFormat(virBufferPtr buf,
goto cleanup; goto cleanup;
} }
if (!addrEnd && !addrStart) if (!addrEnd && !addrStart && !fwd->portStart && !fwd->portEnd)
return 0; return 0;
virBufferAddLit(buf, "<nat>\n"); virBufferAddLit(buf, "<nat>\n");
virBufferAdjustIndent(buf, 2); virBufferAdjustIndent(buf, 2);
virBufferAsprintf(buf, "<address start='%s'", addrStart); if (addrStart) {
if (addrEnd) virBufferAsprintf(buf, "<address start='%s'", addrStart);
virBufferAsprintf(buf, " end='%s'", addrEnd); if (addrEnd)
virBufferAddLit(buf, "/>\n"); virBufferAsprintf(buf, " end='%s'", addrEnd);
virBufferAddLit(buf, "/>\n");
}
if (fwd->portStart || fwd->portEnd) {
virBufferAsprintf(buf, "<port start='%d'", fwd->portStart);
if (fwd->portEnd)
virBufferAsprintf(buf, " end='%d'", fwd->portEnd);
virBufferAddLit(buf, "/>\n");
}
virBufferAdjustIndent(buf, -2); virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</nat>\n"); virBufferAddLit(buf, "</nat>\n");
@ -2260,7 +2300,9 @@ virNetworkDefFormatInternal(virBufferPtr buf,
} }
shortforward = !(def->forward.nifs || def->forward.npfs shortforward = !(def->forward.nifs || def->forward.npfs
|| VIR_SOCKET_ADDR_VALID(&def->forward.addrStart) || 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 ? "/" : ""); virBufferAsprintf(buf, "%s>\n", shortforward ? "/" : "");
virBufferAdjustIndent(buf, 2); virBufferAdjustIndent(buf, 2);

View File

@ -175,8 +175,9 @@ struct _virNetworkForwardDef {
size_t nifs; size_t nifs;
virNetworkForwardIfDefPtr ifs; virNetworkForwardIfDefPtr ifs;
/* adresses for SNAT */ /* ranges for NAT */
virSocketAddr addrStart, addrEnd; virSocketAddr addrStart, addrEnd;
unsigned int portStart, portEnd;
}; };
typedef struct _virPortGroupDef virPortGroupDef; typedef struct _virPortGroupDef virPortGroupDef;

View File

@ -1589,6 +1589,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf, forwardIf,
&network->def->forward.addrStart, &network->def->forward.addrStart,
&network->def->forward.addrEnd, &network->def->forward.addrEnd,
network->def->forward.portStart,
network->def->forward.portEnd,
NULL) < 0) { NULL) < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR, virReportError(VIR_ERR_SYSTEM_ERROR,
forwardIf ? forwardIf ?
@ -1605,6 +1607,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf, forwardIf,
&network->def->forward.addrStart, &network->def->forward.addrStart,
&network->def->forward.addrEnd, &network->def->forward.addrEnd,
network->def->forward.portStart,
network->def->forward.portEnd,
"udp") < 0) { "udp") < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR, virReportError(VIR_ERR_SYSTEM_ERROR,
forwardIf ? forwardIf ?
@ -1621,6 +1625,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf, forwardIf,
&network->def->forward.addrStart, &network->def->forward.addrStart,
&network->def->forward.addrEnd, &network->def->forward.addrEnd,
network->def->forward.portStart,
network->def->forward.portEnd,
"tcp") < 0) { "tcp") < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR, virReportError(VIR_ERR_SYSTEM_ERROR,
forwardIf ? forwardIf ?
@ -1639,6 +1645,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf, forwardIf,
&network->def->forward.addrStart, &network->def->forward.addrStart,
&network->def->forward.addrEnd, &network->def->forward.addrEnd,
network->def->forward.portStart,
network->def->forward.portEnd,
"udp"); "udp");
masqerr4: masqerr4:
iptablesRemoveForwardMasquerade(driver->iptables, iptablesRemoveForwardMasquerade(driver->iptables,
@ -1647,6 +1655,8 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
forwardIf, forwardIf,
&network->def->forward.addrStart, &network->def->forward.addrStart,
&network->def->forward.addrEnd, &network->def->forward.addrEnd,
network->def->forward.portStart,
network->def->forward.portEnd,
NULL); NULL);
masqerr3: masqerr3:
iptablesRemoveForwardAllowRelatedIn(driver->iptables, iptablesRemoveForwardAllowRelatedIn(driver->iptables,
@ -1679,6 +1689,8 @@ networkRemoveMasqueradingIptablesRules(struct network_driver *driver,
forwardIf, forwardIf,
&network->def->forward.addrStart, &network->def->forward.addrStart,
&network->def->forward.addrEnd, &network->def->forward.addrEnd,
network->def->forward.portStart,
network->def->forward.portEnd,
"tcp"); "tcp");
iptablesRemoveForwardMasquerade(driver->iptables, iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address, &ipdef->address,
@ -1686,6 +1698,8 @@ networkRemoveMasqueradingIptablesRules(struct network_driver *driver,
forwardIf, forwardIf,
&network->def->forward.addrStart, &network->def->forward.addrStart,
&network->def->forward.addrEnd, &network->def->forward.addrEnd,
network->def->forward.portStart,
network->def->forward.portEnd,
"udp"); "udp");
iptablesRemoveForwardMasquerade(driver->iptables, iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address, &ipdef->address,
@ -1693,6 +1707,8 @@ networkRemoveMasqueradingIptablesRules(struct network_driver *driver,
forwardIf, forwardIf,
&network->def->forward.addrStart, &network->def->forward.addrStart,
&network->def->forward.addrEnd, &network->def->forward.addrEnd,
network->def->forward.portStart,
network->def->forward.portEnd,
NULL); NULL);
iptablesRemoveForwardAllowRelatedIn(driver->iptables, iptablesRemoveForwardAllowRelatedIn(driver->iptables,

View File

@ -807,6 +807,8 @@ iptablesForwardMasquerade(iptablesContext *ctx,
const char *physdev, const char *physdev,
virSocketAddr *addrStart, virSocketAddr *addrStart,
virSocketAddr *addrEnd, virSocketAddr *addrEnd,
unsigned int portStart,
unsigned int portEnd,
const char *protocol, const char *protocol,
int action) int action)
{ {
@ -814,6 +816,7 @@ iptablesForwardMasquerade(iptablesContext *ctx,
char *networkstr = NULL; char *networkstr = NULL;
char *addrStartStr = NULL; char *addrStartStr = NULL;
char *addrEndStr = NULL; char *addrEndStr = NULL;
char *portRangeStr = NULL;
char *natRangeStr = NULL; char *natRangeStr = NULL;
virCommandPtr cmd = NULL; virCommandPtr cmd = NULL;
@ -848,19 +851,34 @@ iptablesForwardMasquerade(iptablesContext *ctx,
if (physdev && physdev[0]) if (physdev && physdev[0])
virCommandAddArgList(cmd, "--out-interface", physdev, NULL); 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 */ /* Use --jump SNAT if public addr is specified */
if (addrStartStr && addrStartStr[0]) { if (addrStartStr && addrStartStr[0]) {
const char *portStr = "";
int r = 0; int r = 0;
if (protocol && protocol[0])
portStr = ":1024-65535";
if (addrEndStr && addrEndStr[0]) { if (addrEndStr && addrEndStr[0]) {
r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr, r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr,
portStr); portRangeStr ? portRangeStr : "");
} else { } else {
r = virAsprintf(&natRangeStr, "%s%s", addrStartStr, portStr); r = virAsprintf(&natRangeStr, "%s%s", addrStartStr,
portRangeStr ? portRangeStr : "");
} }
if (r < 0) { if (r < 0) {
@ -873,8 +891,8 @@ iptablesForwardMasquerade(iptablesContext *ctx,
} else { } else {
virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL); virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL);
if (protocol && protocol[0]) if (portRangeStr && portRangeStr[0])
virCommandAddArgList(cmd, "--to-ports", "1024-65535", NULL); virCommandAddArgList(cmd, "--to-ports", &portRangeStr[1], NULL);
} }
ret = virCommandRun(cmd, NULL); ret = virCommandRun(cmd, NULL);
@ -883,6 +901,7 @@ cleanup:
VIR_FREE(networkstr); VIR_FREE(networkstr);
VIR_FREE(addrStartStr); VIR_FREE(addrStartStr);
VIR_FREE(addrEndStr); VIR_FREE(addrEndStr);
VIR_FREE(portRangeStr);
VIR_FREE(natRangeStr); VIR_FREE(natRangeStr);
return ret; return ret;
} }
@ -907,9 +926,14 @@ iptablesAddForwardMasquerade(iptablesContext *ctx,
const char *physdev, const char *physdev,
virSocketAddr *addrStart, virSocketAddr *addrStart,
virSocketAddr *addrEnd, virSocketAddr *addrEnd,
unsigned int portStart,
unsigned int portEnd,
const char *protocol) 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, const char *physdev,
virSocketAddr *addrStart, virSocketAddr *addrStart,
virSocketAddr *addrEnd, virSocketAddr *addrEnd,
unsigned int portStart,
unsigned int portEnd,
const char *protocol) 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);
} }

View File

@ -109,6 +109,8 @@ int iptablesAddForwardMasquerade (iptablesContext *ctx,
const char *physdev, const char *physdev,
virSocketAddr *addrStart, virSocketAddr *addrStart,
virSocketAddr *addrEnd, virSocketAddr *addrEnd,
unsigned int portStart,
unsigned int portEnd,
const char *protocol); const char *protocol);
int iptablesRemoveForwardMasquerade (iptablesContext *ctx, int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
virSocketAddr *netaddr, virSocketAddr *netaddr,
@ -116,6 +118,8 @@ int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
const char *physdev, const char *physdev,
virSocketAddr *addrStart, virSocketAddr *addrStart,
virSocketAddr *addrEnd, virSocketAddr *addrEnd,
unsigned int portStart,
unsigned int portEnd,
const char *protocol); const char *protocol);
int iptablesAddOutputFixUdpChecksum (iptablesContext *ctx, int iptablesAddOutputFixUdpChecksum (iptablesContext *ctx,
const char *iface, const char *iface,