The functions - iptablesAddDontMasquerade(), - iptablesRemoveDontMasquerade() handle exceptions in the masquerading implemented in the POSTROUTING chain of the "nat" table. Such exceptions should be added as chronologically latest, logically top-most rules. The bridge driver will call these functions beginning with the next patch: some special destination IP addresses always refer to the local subnetwork, even though they don't match any practical subnetwork's netmask. Packets from virbrN targeting such IP addresses are never routed outwards, but the current rules treat them as non-virbrN-destined packets and masquerade them. This causes problems for some receivers on virbrN. Signed-off-by: Laszlo Ersek <lersek@xxxxxxxxxx> --- v2->v3: - Rename iptables(Add|Remove)ForwardDontMasquerade to iptables(Add|Remove)DontMasquerade [Laine]. - Pass (address, prefix) pairs as both source and destination parameters to these functions. - Introduce virPfxSocketAddr structure for simpler handling of said (address, prefix) pairs. src/util/viriptables.h | 11 +++++++ src/util/viriptables.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 2 ++ 3 files changed, 95 insertions(+) diff --git a/src/util/viriptables.h b/src/util/viriptables.h index 447f4a8..fcff5f8 100644 --- a/src/util/viriptables.h +++ b/src/util/viriptables.h @@ -26,6 +26,11 @@ # include "virsocketaddr.h" +typedef struct { + virSocketAddr addr; + unsigned int prefix; +} virPfxSocketAddr; + int iptablesAddTcpInput (int family, const char *iface, int port); @@ -94,6 +99,12 @@ int iptablesRemoveForwardMasquerade (virSocketAddr *netaddr, virSocketAddrRangePtr addr, virPortRangePtr port, const char *protocol); +int iptablesAddDontMasquerade (const virPfxSocketAddr *src, + const char *physdev, + const virPfxSocketAddr *dst); +int iptablesRemoveDontMasquerade (const virPfxSocketAddr *src, + const char *physdev, + const virPfxSocketAddr *dst); int iptablesAddOutputFixUdpChecksum (const char *iface, int port); int iptablesRemoveOutputFixUdpChecksum (const char *iface, diff --git a/src/util/viriptables.c b/src/util/viriptables.c index 52e2bde..90fe900 100644 --- a/src/util/viriptables.c +++ b/src/util/viriptables.c @@ -832,6 +832,88 @@ iptablesRemoveForwardMasquerade(virSocketAddr *netaddr, } +/* Don't masquerade traffic coming from the network associated with the bridge + * if said traffic targets @destaddr/@destprefix. + */ +static int +iptablesDontMasquerade(const virPfxSocketAddr *src, + const char *physdev, + const virPfxSocketAddr *dst, + int action) +{ + int ret = -1; + char *srcStr = NULL; + char *dstStr = NULL; + virCommandPtr cmd = NULL; + + if (!(srcStr = iptablesFormatNetwork(&src->addr, src->prefix))) + return -1; + + if (!(dstStr = iptablesFormatNetwork(&dst->addr, dst->prefix))) + goto cleanup; + + if (!VIR_SOCKET_ADDR_IS_FAMILY(&src->addr, AF_INET)) { + /* Higher level code *should* guaranteee it's impossible to get here. */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Attempted to NAT '%s'. NAT is only supported for IPv4."), + srcStr); + goto cleanup; + } + + cmd = iptablesCommandNew("nat", "POSTROUTING", AF_INET, action); + + if (physdev && physdev[0]) + virCommandAddArgList(cmd, "--out-interface", physdev, NULL); + + virCommandAddArgList(cmd, "--source", srcStr, "--destination", dstStr, + "--jump", "RETURN", NULL); + ret = virCommandRun(cmd, NULL); +cleanup: + virCommandFree(cmd); + VIR_FREE(dstStr); + VIR_FREE(srcStr); + return ret; +} + +/** + * iptablesAddDontMasquerade: + * @src: the source network address and prefix + * @physdev: the physical output device or NULL + * @destaddr: the destination network address and prefix + * + * Add rules to the "nat" IP table to avoid masquerading from @src/srcprefix to + * @dst/dstprefix on @physdev. + * + * Returns 0 in case of success and -1 on failure. + */ +int +iptablesAddDontMasquerade(const virPfxSocketAddr *src, + const char *physdev, + const virPfxSocketAddr *dst) +{ + return iptablesDontMasquerade(src, physdev, dst, ADD); +} + +/** + * iptablesRemoveDontMasquerade: + * @src: the source network address and prefix + * @physdev: the physical output device or NULL + * @destaddr: the destination network address and prefix + * + * Remove rules from the "nat" IP table that prevent masquerading from + * @src/srcprefix to @dst/dstprefix on @physdev. + * + * Returns 0 in case of success and -1 on failure. + */ +int +iptablesRemoveDontMasquerade(const virPfxSocketAddr *src, + const char *physdev, + const virPfxSocketAddr *dst) +{ + return iptablesDontMasquerade(src, physdev, dst, REMOVE); +} + + static int iptablesOutputFixUdpChecksum(const char *iface, int port, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 50e2f48..fb212ce 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1446,6 +1446,7 @@ virInitctlSetRunLevel; # util/viriptables.h +iptablesAddDontMasquerade; iptablesAddForwardAllowCross; iptablesAddForwardAllowIn; iptablesAddForwardAllowOut; @@ -1456,6 +1457,7 @@ iptablesAddForwardRejectOut; iptablesAddOutputFixUdpChecksum; iptablesAddTcpInput; iptablesAddUdpInput; +iptablesRemoveDontMasquerade; iptablesRemoveForwardAllowCross; iptablesRemoveForwardAllowIn; iptablesRemoveForwardAllowOut; -- 1.8.3.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list