[libvirt] [PATCHv2 2/2] net: add support for specifying port range for forward mode nat

Laine Stump laine at laine.org
Fri Feb 15 19:34:37 UTC 2013


From: Natanael Copa <ncopa at alpinelinux.org>

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 at alpinelinux.org>
Signed-off-by: Laine Stump <laine at laine.org>
---
Differences from V1:
* rebased and resolved conflicts due to changes in PATCH 1/2
* renamed port_(start|end) to port(Start|End).
* fixed nits listed in review


 docs/formatnetwork.html.in  | 22 +++++++++++++---
 src/conf/network_conf.c     | 59 +++++++++++++++++++++++++++++++++++-------
 src/conf/network_conf.h     |  3 ++-
 src/network/bridge_driver.c | 16 ++++++++++++
 src/util/viriptables.c      | 62 +++++++++++++++++++++++++++++++--------------
 src/util/viriptables.h      |  4 +++
 6 files changed, 134 insertions(+), 32 deletions(-)

diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index cad47d0..b85d9f6 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -139,9 +139,11 @@
 
             <p>
               <span class="since">Since 1.0.3</span> it is possible to
-              specify a public IPv4 address range to be used for NAT
-              by using the <code><nat></code> element and
-              its <code><address></code> subelement.
+              specify a public IPv4 address and port range to be used for NAT
+              by using the <code><nat></code> element.
+              The address range is set with the <code><address></code>
+              subelement and <code>start</code> and <code>stop</code>
+              attributes:
             </p>
             <pre>
 ...
@@ -160,6 +162,20 @@
               egress, just don't specify any <code><nat></code>
               element.
             </p>
+            <p>
+              The port range to be used for NAT can also be set via
+              the <code><port></code> subelement
+              of <code><nat></code>:
+            </p>
+            <pre>
+...
+  <forward mode='nat'>
+    <nat>
+      <port start='500' end='1000'/>
+    </nat>
+  </forward>
+...
+            </pre>
           </dd>
 
           <dt><code>route</code></dt>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index d7b31cf..581f885 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;
@@ -1390,6 +1391,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 <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;
 
 cleanup:
@@ -2194,16 +2225,25 @@ virNetworkForwardNatDefFormat(virBufferPtr buf,
             goto cleanup;
     }
 
-    if (!addrEnd && !addrStart)
+    if (!addrEnd && !addrStart && !fwd->portStart && !fwd->portEnd)
         return 0;
 
     virBufferAddLit(buf, "<nat>\n");
     virBufferAdjustIndent(buf, 2);
 
-    virBufferAsprintf(buf, "<address start='%s'", addrStart);
-    if (addrEnd)
-        virBufferAsprintf(buf, " end='%s'", addrEnd);
-    virBufferAsprintf(buf, "/>\n");
+    if (addrStart) {
+        virBufferAsprintf(buf, "<address start='%s'", addrStart);
+        if (addrEnd)
+            virBufferAsprintf(buf, " end='%s'", addrEnd);
+        virBufferAsprintf(buf, "/>\n");
+    }
+
+    if (fwd->portStart || fwd->portEnd) {
+        virBufferAsprintf(buf, "<port start='%d'", fwd->portStart);
+        if (fwd->portEnd)
+            virBufferAsprintf(buf, " end='%d'", fwd->portEnd);
+        virBufferAsprintf(buf, "/>\n");
+    }
 
     virBufferAdjustIndent(buf, -2);
     virBufferAsprintf(buf, "</nat>\n");
@@ -2259,9 +2299,10 @@ virNetworkDefFormatInternal(virBufferPtr buf,
             else
                 virBufferAddLit(buf, " managed='no'");
         }
-        shortforward = !(def->forward.nifs || def->forward.npfs
-                         || VIR_SOCKET_ADDR_VALID(&def->forward.addrStart)
-                         || VIR_SOCKET_ADDR_VALID(&def->forward.addrEnd));
+        shortforward = !(def->forward.nifs || def->forward.npfs ||
+                         VIR_SOCKET_ADDR_VALID(&def->forward.addrStart) ||
+                         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 11d6c9c..515115b 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 9f502a5..cf47ec4 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 f8a09bf..b0951b5 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)
 {
@@ -815,6 +817,7 @@ iptablesForwardMasquerade(iptablesContext *ctx,
     char *addrStartStr = NULL;
     char *addrEndStr = NULL;
     char *addrRangeStr = NULL;
+    char *portRangeStr = NULL;
     virCommandPtr cmd = NULL;
 
     if (!(networkstr = iptablesFormatNetwork(netaddr, prefix)))
@@ -850,32 +853,44 @@ 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 > 65535) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Bad NAT port range '%u-%u'"),
+                           portStart, portEnd);
+            goto cleanup;
+        }
+        if (virAsprintf(&portRangeStr, ":%u-%u", portStart, portEnd) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
     /* Use --jump SNAT if public addr is spec1ified */
     if (addrStartStr && addrStartStr[0]) {
-        const char *portstr = "";
-
-        if (protocol && protocol[0])
-            portstr = ":1024-65535";
         if (addrEndStr && addrEndStr[0]) {
-            if (virAsprintf(&addrRangeStr, "%s-%s%s",
-                            addrStartStr, addrEndStr, portstr) < 0) {
-                virReportOOMError();
-                goto cleanup;
-            }
-        } else {
-            if (virAsprintf(&addrRangeStr, "%s%s", addrStartStr, portstr) < 0) {
+            if (virAsprintf(&addrRangeStr, "%s-%s%s", addrStartStr, addrEndStr,
+                            portRangeStr ? portRangeStr : "") < 0) {
                 virReportOOMError();
                 goto cleanup;
             }
+        } else if (virAsprintf(&addrRangeStr, "%s%s", addrStartStr,
+                               portRangeStr ? portRangeStr : "") < 0) {
+            virReportOOMError();
+            goto cleanup;
         }
         virCommandAddArgList(cmd, "--jump", "SNAT",
-                                  "--to-source", addrRangeStr, NULL);
-     } else {
-         virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL);
+                             "--to-source", addrRangeStr, NULL);
+    } 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 = iptablesCommandRunAndFree(cmd);
 cleanup:
@@ -883,6 +898,7 @@ cleanup:
     VIR_FREE(addrStartStr);
     VIR_FREE(addrEndStr);
     VIR_FREE(addrRangeStr);
+    VIR_FREE(portRangeStr);
     return ret;
 }
 
@@ -906,10 +922,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);
+                                     addrStart, addrEnd,
+                                     portStart, portEnd,
+                                     protocol, ADD);
 }
 
 /**
@@ -932,10 +952,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);
+                                     addrStart, addrEnd,
+                                     portStart, portEnd,
+                                     protocol, REMOVE);
 }
 
 
diff --git a/src/util/viriptables.h b/src/util/viriptables.h
index 05362da..ca6adcc 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,
-- 
1.7.11.7




More information about the libvir-list mailing list