network, and to/from the host to the guests, are
unrestricted and not NATed.<span class="since">Since
0.4.2</span>
+
+ <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
+ using the <code><nat></code> and
+ <code><address></code> subelements.
+ <pre>
+...
+ <forward mode='nat'>
+ <nat>
+ <address start='1.2.3.4' end='1.2.3.10'/>
+ </nat>
+ </forward>
+...
+ </pre>
+ An singe IPv4 address can be set by setting
+ <code>start</code> and <code>end</code> attributes to
+ the same value.
+ </p>
</dd>
<dt><code>route</code></dt>
return result;
}
+static int
+virNetworkForwardNatDefParseXML(const char *networkName,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ virNetworkForwardDefPtr def)
+{
+ int ret = -1;
+ xmlNodePtr *natAddrNodes = NULL;
+ int nNatAddrs;
+ char *addrStart = NULL;
+ char *addrEnd = NULL;
+ xmlNodePtr save = ctxt->node;
+
+ ctxt->node = node;
+
+ if (def->type != VIR_NETWORK_FORWARD_NAT) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("The <nat> element can only be used when <forward> 'mode' is 'nat' in network %s"),
+ networkName);
+ goto cleanup;
+ }
+
+ /* addresses for SNAT */
+ 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) {
+ addrStart = virXMLPropString(*natAddrNodes, "start");
+ if (addrStart == NULL) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("missing 'start' attribute in <address> element in <nat> in "
+ "<forward> in network %s"), networkName);
+ goto cleanup;
+ }
+ addrEnd = virXMLPropString(*natAddrNodes, "end");
+ if (addrEnd == NULL) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("missing 'end' attribute in <address> element in <nat> in "
+ "<forward> in network %s"), networkName);
+ goto cleanup;
+ }
+ }
+
+ if (addrStart && virSocketAddrParse(&def->addrStart, addrStart, AF_INET) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Bad ipv4 start address '%s' in <nat> in <forward> in "
+ "network '%s'"), addrStart, networkName);
+ goto cleanup;
+ }
+
+ if (addrEnd && virSocketAddrParse(&def->addrEnd, addrEnd, AF_INET) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Bad ipv4 end address '%s' in <nat> in <forward> in "
+ "network '%s'"), addrEnd, networkName);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(addrStart);
+ VIR_FREE(addrEnd);
+ VIR_FREE(natAddrNodes);
+ ctxt->node = save;
+ return ret;
+}
+
static int
virNetworkForwardDefParseXML(const char *networkName,
xmlNodePtr node,
xmlNodePtr *forwardIfNodes = NULL;
xmlNodePtr *forwardPfNodes = NULL;
xmlNodePtr *forwardAddrNodes = NULL;
- int nForwardIfs, nForwardAddrs, nForwardPfs;
+ xmlNodePtr *forwardNatNodes = NULL;
+ int nForwardIfs, nForwardAddrs, nForwardPfs, nForwardNats;
char *forwardDev = NULL;
char *forwardManaged = NULL;
char *type = NULL;
goto cleanup;
}
+ nForwardNats = virXPathNodeSet("./nat", ctxt, &forwardNatNodes);
+ if (nForwardNats < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid <nat> element found in <forward> of network %s"),
+ networkName);
+ goto cleanup;
+ } else if (nForwardNats > 1) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Only one <nat> element is allowed in <forward> of network %s"),
+ networkName);
+ goto cleanup;
+ } else if (nForwardNats == 1) {
+ if (virNetworkForwardNatDefParseXML(networkName,
+ *forwardNatNodes,
+ ctxt, def) < 0)
+ goto cleanup;
+ }
+
if (((nForwardIfs > 0) + (nForwardAddrs > 0) + (nForwardPfs > 0)) > 1) {
virReportError(VIR_ERR_XML_ERROR,
_("<address>, <interface>, and <pf> elements in <forward> "
VIR_FREE(forwardPfNodes);
VIR_FREE(forwardIfNodes);
VIR_FREE(forwardAddrNodes);
+ VIR_FREE(forwardNatNodes);
ctxt->node = save;
return ret;
}
return 0;
}
+static int
+virNetworkForwardNatDefFormat(virBufferPtr buf,
+ const virNetworkForwardDefPtr fwd)
+{
+ char *addrStart = NULL;
+ char *addrEnd = NULL;
+ int ret = -1;
+
+ if (VIR_SOCKET_ADDR_VALID(&fwd->addrStart)) {
+ addrStart = virSocketAddrFormat(&fwd->addrStart);
+ if (!addrStart)
+ goto cleanup;
+ }
+
+ if (VIR_SOCKET_ADDR_VALID(&fwd->addrEnd)) {
+ addrEnd = virSocketAddrFormat(&fwd->addrEnd);
+ if (!addrEnd)
+ goto cleanup;
+ }
+
+ if (!addrEnd && !addrStart)
+ return 0;
+
+ virBufferAddLit(buf, "<nat>\n");
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferAsprintf(buf, "<address start='%s'", addrStart);
+ if (addrEnd)
+ virBufferAsprintf(buf, " end='%s'", addrEnd);
+ virBufferAddLit(buf, "/>\n");
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</nat>\n");
+ ret = 0;
+
+cleanup:
+ VIR_FREE(addrStart);
+ VIR_FREE(addrEnd);
+ return ret;
+}
+
static int
virNetworkDefFormatInternal(virBufferPtr buf,
const virNetworkDefPtr def,
{
unsigned char *uuid;
char uuidstr[VIR_UUID_STRING_BUFLEN];
- int ii;
+ int ii, shortforward;
virBufferAddLit(buf, "<network");
if (!(flags & VIR_NETWORK_XML_INACTIVE) && (def->connections > 0)) {
else
virBufferAddLit(buf, " managed='no'");
}
- virBufferAsprintf(buf, "%s>\n",
- (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.addrEnd));
+ virBufferAsprintf(buf, "%s>\n", shortforward ? "/" : "");
virBufferAdjustIndent(buf, 2);
+ if (def->forward.type == VIR_NETWORK_FORWARD_NAT) {
+ if (virNetworkForwardNatDefFormat(buf, &def->forward) < 0)
+ goto error;
+ }
+
/* For now, hard-coded to at most 1 forward.pfs */
if (def->forward.npfs)
virBufferEscapeString(buf, "<pf dev='%s'/>\n",
}
}
virBufferAdjustIndent(buf, -2);
- if (def->forward.npfs || def->forward.nifs)
+ if (!shortforward)
virBufferAddLit(buf, "</forward>\n");
}
size_t nifs;
virNetworkForwardIfDefPtr ifs;
+
+ /* adresses for SNAT */
+ virSocketAddr addrStart, addrEnd;
};
typedef struct _virPortGroupDef virPortGroupDef;
&ipdef->address,
prefix,
forwardIf,
+ &network->def->forward.addrStart,
+ &network->def->forward.addrEnd,
NULL) < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR,
forwardIf ?
&ipdef->address,
prefix,
forwardIf,
+ &network->def->forward.addrStart,
+ &network->def->forward.addrEnd,
"udp") < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR,
forwardIf ?
&ipdef->address,
prefix,
forwardIf,
+ &network->def->forward.addrStart,
+ &network->def->forward.addrEnd,
"tcp") < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR,
forwardIf ?
&ipdef->address,
prefix,
forwardIf,
+ &network->def->forward.addrStart,
+ &network->def->forward.addrEnd,
"udp");
masqerr4:
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
forwardIf,
+ &network->def->forward.addrStart,
+ &network->def->forward.addrEnd,
NULL);
masqerr3:
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
&ipdef->address,
prefix,
forwardIf,
+ &network->def->forward.addrStart,
+ &network->def->forward.addrEnd,
"tcp");
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
forwardIf,
+ &network->def->forward.addrStart,
+ &network->def->forward.addrEnd,
"udp");
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
forwardIf,
+ &network->def->forward.addrStart,
+ &network->def->forward.addrEnd,
NULL);
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
virSocketAddr *netaddr,
unsigned int prefix,
const char *physdev,
+ virSocketAddr *addrStart,
+ virSocketAddr *addrEnd,
const char *protocol,
int action)
{
- int ret;
- char *networkstr;
+ int ret = -1;
+ char *networkstr = NULL;
+ char *addrStartStr = NULL;
+ char *addrEndStr = NULL;
+ char *natRangeStr = NULL;
virCommandPtr cmd = NULL;
if (!(networkstr = iptablesFormatNetwork(netaddr, prefix)))
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Attempted to NAT '%s'. NAT is only supported for IPv4."),
networkstr);
- VIR_FREE(networkstr);
- return -1;
+ goto cleanup;
+ }
+
+ if (VIR_SOCKET_ADDR_IS_FAMILY(addrStart, AF_INET)) {
+ if (!(addrStartStr = virSocketAddrFormat(addrStart)))
+ goto cleanup;
+ if (VIR_SOCKET_ADDR_IS_FAMILY(addrEnd, AF_INET)) {
+ if (!(addrEndStr = virSocketAddrFormat(addrEnd)))
+ goto cleanup;
+ }
}
cmd = iptablesCommandNew(ctx->nat_postrouting, AF_INET, action);
if (physdev && physdev[0])
virCommandAddArgList(cmd, "--out-interface", physdev, NULL);
- virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL);
+ /* Use --jump SNAT if public addr is specified */
+ if (addrStartStr && addrStartStr[0]) {
+ const char *portStr = "";
+ int r = 0;
- if (protocol && protocol[0])
- virCommandAddArgList(cmd, "--to-ports", "1024-65535", NULL);
+ if (protocol && protocol[0])
+ portStr = ":1024-65535";
- ret = iptablesCommandRunAndFree(cmd);
+ if (addrEndStr && addrEndStr[0]) {
+ r = virAsprintf(&natRangeStr, "%s-%s%s", addrStartStr, addrEndStr,
+ portStr);
+ } else {
+ r = virAsprintf(&natRangeStr, "%s%s", addrStartStr, portStr);
+ }
+
+ if (r < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ virCommandAddArgList(cmd, "--jump", "SNAT",
+ "--to-source", natRangeStr, NULL);
+ } else {
+ virCommandAddArgList(cmd, "--jump", "MASQUERADE", NULL);
+
+ if (protocol && protocol[0])
+ virCommandAddArgList(cmd, "--to-ports", "1024-65535", NULL);
+ }
+
+ ret = virCommandRun(cmd, NULL);
+cleanup:
+ virCommandFree(cmd);
VIR_FREE(networkstr);
+ VIR_FREE(addrStartStr);
+ VIR_FREE(addrEndStr);
+ VIR_FREE(natRangeStr);
return ret;
}
virSocketAddr *netaddr,
unsigned int prefix,
const char *physdev,
+ virSocketAddr *addrStart,
+ virSocketAddr *addrEnd,
const char *protocol)
{
- return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, protocol, ADD);
+ return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, addrStart, addrEnd, protocol, ADD);
}
/**
virSocketAddr *netaddr,
unsigned int prefix,
const char *physdev,
+ virSocketAddr *addrStart,
+ virSocketAddr *addrEnd,
const char *protocol)
{
- return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, protocol, REMOVE);
+ return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, addrStart, addrEnd, protocol, REMOVE);
}
virSocketAddr *netaddr,
unsigned int prefix,
const char *physdev,
+ virSocketAddr *addrStart,
+ virSocketAddr *addrEnd,
const char *protocol);
int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
virSocketAddr *netaddr,
unsigned int prefix,
const char *physdev,
+ virSocketAddr *addrStart,
+ virSocketAddr *addrEnd,
const char *protocol);
int iptablesAddOutputFixUdpChecksum (iptablesContext *ctx,
const char *iface,