[libvirt] [PATCH v2 3/4] net: support a public address range for forward mode nat

Natanael Copa ncopa at alpinelinux.org
Mon Feb 4 09:45:25 UTC 2013


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 at 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




More information about the libvir-list mailing list