MASQUERADE handling of device events
Subsystems (4)
PATCH 1/1 MASQUERADE handling of device events
As discussed in recent days, MASQUERADE target handling of device events is broken in a couple of ways:
1) when ppp interfaces cycle, conntracks with old ip addresses are not flushed
2) an 'ip addr add' on an interface used for masquerading flushes all conntracks associated with that interface
The below patch addresses these issues by changing from using ifindex comparisons to verifying that the masquerading ip still exists on the box.
To achieve this, two changes were required to core networking code (thus the linux-net cc):
1) export inet_confirm_addr
2) change inet_ifa_match to use ifa_local instead of ifa_address. Since ifa_local != ifa_address on ppp interfaces, inet_ifa_match could not be used to verify ppp interface addresses without this change.
Comments?
Phil
include/linux/inetdevice.h +1 -1
@@ -114,7 +114,7 @@static __inline__int inet_ifa_match (u32 addr,struct in_ifaddr *ifa) { -return !((addr^ifa->ifa_address)&ifa->ifa_mask); +return !((addr^ifa->ifa_local)&ifa->ifa_mask); }/*
net/ipv4/devinet.c +1 -0
@@ -1493,6 +1493,7 @@EXPORT_SYMBOL (devinet_ioctl);EXPORT_SYMBOL (in_dev_finish_destroy); +EXPORT_SYMBOL (inet_confirm_addr);EXPORT_SYMBOL (inet_select_addr);EXPORT_SYMBOL (inetdev_by_index);EXPORT_SYMBOL (register_inetaddr_notifier);
net/ipv4/netfilter/ipt_MASQUERADE.c +8 -10
@@ -118,16 +118,15 @@ }static inline int -device_cmp (const struct ip_conntrack *i,void *_ina) +device_cmp (const struct ip_conntrack *i,void *junk) {int ret =0 ; -struct in_ifaddr *ina = _ina;READ_LOCK (&masq_lock); -/* If it's masquerading out this interface with a different address, -or we don't know the new address of this interface. */ -if (i->nat.masq_index == ina->ifa_dev->dev->ifindex - && i->tuplehash[IP_CT_DIR_REPLY ].tuple.dst.ip != ina->ifa_address) +/* If masquerading this conntrack but the masquerading ip +no longer exists locally, drop conntrack. */ +if (i->nat.masq_index && !(inet_confirm_addr (NULL ,0 , + i->tuplehash[IP_CT_DIR_REPLY ].tuple.dst.ip,RT_SCOPE_HOST ))) ret =1 ;READ_UNLOCK (&masq_lock);
@@ -150,11 +149,10 @@ unsigned long event, void *ptr) { -/* For some configurations, interfaces often come back with -* the same address. If not, clean up old conntrack -* entries. */ +/* In some configurations, interfaces come back with the +* same address. If not, clean up old conntrack entries. */ if (event ==NETDEV_UP ) -ip_ct_selective_cleanup (device_cmp, ptr); +ip_ct_selective_cleanup (device_cmp,NULL );else if (event ==NETDEV_DOWN )ip_ct_selective_cleanup (connect_unassure, ptr);
Quoted 11 lines · Phil Oester
To achieve this, two changes were required to core networking code (thus the linux-net cc):
1) export
inet_confirm_addr2) change
inet_ifa_matchto useifa_localinstead ofifa_address. Sinceifa_local!=ifa_addresson ppp interfaces,inet_ifa_matchcould not be used to verify ppp interface addresses without this change.Comments?
Looks fine to me, but maybe we should also utilize the fact that nat.masq_index with this change only needs to be a boolean flag "this connection is masqueraded", allowing us to cut down a little on the conntrack entry size.
Regards
Henrik
[added explicit Cc to Dave]
Quoted 6 lines · Phil Oester
The below patch addresses these issues by changing from using ifindex comparisons to verifying that the masquerading ip still exists on the box.
To achieve this, two changes were required to core networking code (thus the linux-net cc):
Thanks, Phil.
I think this solution is about the best we can get.
Any other comments?
Dave: would the two changes below be acceptable for you?
Quoted 6 lines
1) export
inet_confirm_addr2) change
inet_ifa_matchto useifa_localinstead ofifa_address. Sinceifa_local!=ifa_addresson ppp interfaces,inet_ifa_matchcould not be used to verify ppp interface addresses without this change.
Signature · 5 lines
- Harald Welte <[email protected]> http://www.netfilter.org/ ============================================================================ "Fragmentation is like classful addressing -- an interesting early architectural error that shows how much experimentation was going on while IP was being designed." -- Paul Vixie
Quoted 6 lines · Phil Oester
As discussed in recent days, MASQUERADE target handling of device events is broken in a couple of ways:
1) when ppp interfaces cycle, conntracks with old ip addresses are not flushed
Quoted 7 lines
2) an 'ip addr add' on an interface used for masquerading flushes all conntracks associated with that interface
The below patch addresses these issues by changing from using ifindex comparisons to verifying that the masquerading ip still exists on the box.
But without the ifindex comparison, a situation like this can happen:
ppp0 goes down
ppp1 goes down
ppp0 comes up again, same IP as before
ppp1 connections get killed
ppp1 comes up again
So we should keep this.
Regards
Patrick
Quoted 69 lines
------------------------------------------------------------------------
diff -ru
linux-orig/include/linux/inetdevice.hlinux-diff/include/linux/inetdevice.hinclude/linux/inetdevice.h +1
-1@@ -114,7 +114,7 @@static __inline__int inet_ifa_match (u32 addr,struct in_ifaddr *ifa) { -return !((addr^ifa->ifa_address)&ifa->ifa_mask); +return !((addr^ifa->ifa_local)&ifa->ifa_mask); }/* diff -ru
linux-orig/net/ipv4/devinet.clinux-diff/net/ipv4/devinet.cnet/ipv4/devinet.c +1
-0@@ -1493,6 +1493,7 @@EXPORT_SYMBOL (devinet_ioctl);EXPORT_SYMBOL (in_dev_finish_destroy); +EXPORT_SYMBOL (inet_confirm_addr);EXPORT_SYMBOL (inet_select_addr);EXPORT_SYMBOL (inetdev_by_index);EXPORT_SYMBOL (register_inetaddr_notifier);diff -ru
linux-orig/net/ipv4/netfilter/ipt_MASQUERADE.clinux-diff/net/ipv4/netfilter/ipt_MASQUERADE.cnet/ipv4/netfilter/ipt_MASQUERADE.c +0
-0@@ -118,16 +118,15 @@ }static inline int
net/ipv4/netfilter/ipt_MASQUERADE.c +1
-1-device_cmp(const struct ip_conntrack *i, void *_ina) +device_cmp(const struct ip_conntrack *i, void *junk){ int ret = 0;net/ipv4/netfilter/ipt_MASQUERADE.c +0
-1-struct in_ifaddr *ina = _ina;READ_LOCK(&masq_lock);net/ipv4/netfilter/ipt_MASQUERADE.c +4
-4-/* If it's masquerading out this interface with a different address, -or we don't know the new address of this interface. */ -if (i->nat.masq_index == ina->ifa_dev->dev->ifindex - && i->tuplehash[IP_CT_DIR_REPLY ].tuple.dst.ip != ina->ifa_address) +/* If masquerading this conntrack but the masquerading ip +no longer exists locally, drop conntrack. */ +if (i->nat.masq_index && !(inet_confirm_addr (NULL ,0 , + i->tuplehash[IP_CT_DIR_REPLY ].tuple.dst.ip,RT_SCOPE_HOST )))ret = 1; READ_UNLOCK(&masq_lock);net/ipv4/netfilter/ipt_MASQUERADE.c +3
-4@@ -150,11 +149,10 @@ unsigned long event, void *ptr) { -/* For some configurations, interfaces often come back with -* the same address. If not, clean up old conntrack -* entries. */ +/* In some configurations, interfaces come back with the +* same address. If not, clean up old conntrack entries. */ if (event ==NETDEV_UP ) -ip_ct_selective_cleanup (device_cmp, ptr); +ip_ct_selective_cleanup (device_cmp,NULL );else if (event ==NETDEV_DOWN )ip_ct_selective_cleanup (connect_unassure, ptr);
Quoted 9 lines · Patrick McHardy
But without the ifindex comparison, a situation like this can happen:
ppp0 goes down
ppp1 goes down
ppp0 comes up again, same IP as before
ppp1 connections get killed
ppp1 comes up againSo we should keep this.
But ifindex is meaningless on ppp interfaces - it is incremented on each cycle. So there is no way to say that the original ppp1 is the same interface as the new ppp1.
ifindex just cannot be used reliably.
Phil
Quoted 10 lines · Phil Oester
Quoted 8 lines · Patrick McHardy
But without the ifindex comparison, a situation like this can happen:
ppp0 goes down
ppp1 goes down
ppp0 comes up again, same IP as before
ppp1 connections get killed
ppp1 comes up again
Quoted 9 lines
Quoted 2 lines
So we should keep this.
But ifindex is meaningless on ppp interfaces - it is incremented on each cycle. So there is no way to say that the original ppp1 is the same interface as the new ppp1.
ifindex just cannot be used reliably.
Of course, I wasn't thinking :) Then what about Henrik's suggestion, replacing masq_index by a new status bit ?
Regards
Patrick
Quoted 4 lines · Patrick McHardy
Quoted 2 lines
ifindex just cannot be used reliably.
Of course, I wasn't thinking :) Then what about Henrik's suggestion, replacing
masq_indexby a new status bit ?
It's a great idea, and will reduce the size of struct ip_conntrack. But I think it should be done in a separate cleanup patch - really would like to get this one merged up to fix the masq issues.
Phil
Quoted 3 lines · Phil Oester
It's a great idea, and will reduce the size of struct
ip_conntrack. But I think it should be done in a separate cleanup patch - really would like to get this one merged up to fix the masq issues.
Actually masq_index is still used in connect_unassure, and thus can't be removed completely. In cases where the interface goes down permanently, clearing the assured bit makes sense, so guess this behaviour should be maintained.
Phil
Quoted 9 lines · Phil Oester
Quoted 5 lines · Phil Oester
It's a great idea, and will reduce the size of struct
ip_conntrack. But I think it should be done in a separate cleanup patch - really would like to get this one merged up to fix the masq issues.
Quoted 6 lines
Actually
masq_indexis still used inconnect_unassure, and thus can't be removed completely. In cases where the interface goes down permanently, clearing the assured bit makes sense, so guess this behaviour should be maintained.
You're right. I have to admit, I'm not too happy about the unpredictable behaviour we get with this patch and multiple ppp devices. So one last attempt to convince people. The old behaviour was to kill conntracks once the device goes down. I think killing conntracks when the IP is deleted makes more sense. Since the IP has to be deleted manually, except when the device goes away, people can simply not delete IP addresses for devices that don't go away, than nothing will get removed. pppd can be taught to keep the device alive. The attached patch adds a program alloc-ppp to pre-allocate ppp-devices and teaches pppd to attach to them. The device never goes away, if ppp doesn't delete the IP address the conntracks won't be killed. It could easily be integrated in a more handy way in pppd. So this could also be done entirely in userspace, without the unpredictable behaviour.
Regards
Patrick
pppd/alloc-ppp.c +64 -0
@@ -0,0 +1,64 @@ + + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#include <sys/ioctl.h> + +#include <asm/types.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/route.h> +#include <netinet/if_ether.h> + + +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> + + + +int main (int argc,char ** argv ) { + +int ndev =0 ; +int n =0 ; +int ppp_dev_fd =0 ; + +if ( argc !=2 ) { +fprintf (stderr,"use \"%s <n>\" to allocate n ppp devices\n" , argv[0 ]); +exit (1 ); + } + + ndev =atoi (argv[1 ]); + +if ( ndev <=0 ) { +fprintf (stderr,"argument must b a number > 0 not %s\n" , argv[1 ]); +exit (1 ); + } + +for ( n =0 ; n < ndev; n ++ ) { +int ifunit = n; +int res =0 ; + +if ( (ppp_dev_fd =open ("/dev/ppp" ,O_RDWR )) <0 ) { +perror ("can not open /dev/ppp :" ); +exit (2 ); + } + + res =ioctl (ppp_dev_fd,PPPIOCNEWUNIT , &ifunit); +if ( res <0 ) { +fprintf (stderr,"can not allocate ppp device %d : %s \n" , + n ,strerror (errno) ); + } + } + +while (1 ==1 ) { +sleep (3600 ); + } + +exit (0 ); +} +
pppd/Makefile.linux +7 -2
@@ -8,7 +8,7 @@ MANDIR = $(DESTDIR)/usr/man INCDIR = $(DESTDIR)/usr/include -TARGETS = pppd +TARGETS = pppd alloc-ppp PPPDSRCS = main.c magic.c fsm.c lcp.c ipcp.c upap.c chap-new.c md5.c ccp.c \ ecp.c ipxcp.c auth.c options.c sys-linux.c md4.c chap_ms.c \
@@ -196,10 +196,11 @@ all: $(TARGETS) -install: pppd +install: pppd alloc-ppp mkdir -p $(BINDIR) $(MANDIR) $(EXTRAINSTALL) $(INSTALL) -s -c -m 555 pppd $(BINDIR)/pppd + $(INSTALL) -s -c -m 555 alloc-ppp $(BINDIR)/alloc-ppp if chgrp pppusers $(BINDIR)/pppd 2>/dev/null; then \ chmod o-rx,u+s $(BINDIR)/pppd; fi $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8
@@ -207,6 +208,9 @@ pppd: $(PPPDOBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS) +alloc-ppp: alloc-ppp.o + $(CC) $(CFLAGS) -o alloc-ppp alloc-ppp.o + srp-entry: srp-entry.c $(CC) $(CFLAGS) $(LDFLAGS) -o $@ srp-entry.c $(LIBS)
@@ -216,6 +220,7 @@ clean: rm -f $(PPPDOBJS) $(EXTRACLEAN) $(TARGETS) *~ #* core + rm -f alloc-ppp.o alloc-ppp depend: $(CPP) -M $(CFLAGS) $(PPPDSRCS) >.depend
pppd/sys-linux.c +15 -0
@@ -639,6 +639,21 @@warn ("Couldn't set /dev/ppp to nonblock: %m" ); ifunit = req_unit; + +/* +* try to attach to an alread existing ppp device. We should +* get an EFAULT if the ppp interface is in use by another pppd. +*/ +if (ifunit >=0 ) { + x =ioctl (ppp_dev_fd,PPPIOCATTACH , &ifunit); +if (x <0 ) { +/* warn and continue to create a new device */ +warn ("Couldn't attatch to unit %d as it does not exist" , req_unit); + }else { +return x; + } + } + x =ioctl (ppp_dev_fd,PPPIOCNEWUNIT , &ifunit);if (x <0 && req_unit >=0 && errno ==EEXIST ) {warn ("Couldn't allocate PPP unit %d as it is already in use" , req_unit);
Quoted 5 lines · Patrick McHardy
You're right. I have to admit, I'm not too happy about the unpredictable behaviour we get with this patch and multiple ppp devices. So one last attempt to convince people. The old behaviour was to kill conntracks once the device goes down. I think killing conntracks when the IP is deleted makes more sense. Since the IP has to be deleted manually, except when
Quoted 8 lines
the device goes away, people can simply not delete IP addresses for devices that don't go away, than nothing will get removed. pppd can be taught to keep the device alive. The attached patch adds a program alloc-ppp to pre-allocate ppp-devices and teaches pppd to attach to them. The device never goes away, if ppp doesn't delete the IP address the conntracks won't be killed. It could easily be integrated in a more handy way in pppd. So this could also be done entirely in userspace, without the unpredictable behaviour.
Is this the unpredictable behaviour you refer to:
ppp0 down -> clear assured bit on ppp0 conntracks
ppp1 down -> clear assured bit on ppp1 conntracks
ppp0 up with same ip -> all ppp1 conntracks get cleared since that ip
no longer exists on box
ppp1 up with same ip -> loser
Not much we can do about that except revert to the old behaviour of dropping all conntracks on interface down, but that does seem silly for 'mostly static' pppoe users.
Obviously I'd vote for the 'friendlier' method, but bottom line is current behaviour is broken and should be fixed somehow...
Phil
Quoted 19 lines · Phil Oester
Quoted 5 lines · Patrick McHardy
You're right. I have to admit, I'm not too happy about the unpredictable behaviour we get with this patch and multiple ppp devices. So one last attempt to convince people. The old behaviour was to kill conntracks once the device goes down. I think killing conntracks when the IP is deleted makes more sense. Since the IP has to be deleted manually, except when
Quoted 10 lines
the device goes away, people can simply not delete IP addresses for devices that don't go away, than nothing will get removed. pppd can be taught to keep the device alive. The attached patch adds a program alloc-ppp to pre-allocate ppp-devices and teaches pppd to attach to them. The device never goes away, if ppp doesn't delete the IP address the conntracks won't be killed. It could easily be integrated in a more handy way in pppd. So this could also be done entirely in userspace, without the unpredictable behaviour.
Quoted 9 lines
Is this the unpredictable behaviour you refer to:
ppp0 down -> clear assured bit on ppp0 conntracks
ppp1 down -> clear assured bit on ppp1 conntracks
ppp0 up with same ip -> all ppp1 conntracks get cleared since that ip
no longer exists on box
ppp1 up with same ip -> loser
Yes. It gives unpredictable behaviour and no way to avoid it. If ppp1 comes up first - ppp0 is the loser. If only one goes down at a time - nobody looses.
Quoted 8 lines
Not much we can do about that except revert to the old behaviour of dropping all conntracks on interface down, but that does seem silly for 'mostly static' pppoe users.
Obviously I'd vote for the 'friendlier' method, but bottom line is current behaviour is broken and should be fixed somehow...
I think deterministic behaviour is more friendly than something working only under certain conditions and doing strange stuff the remaining time. I would like to hear Harald's opinion.
Regards
Patrick
David S. Miller
maintainerQuoted 3 lines · On Mon, 8 Nov 2004 14:50:25 +0100 Harald Welte <[email protected]> wrote:
Dave: would the two changes below be acceptable for you?
Quoted 1 line
1) export
inet_confirm_addr
This one I think is OK.
Quoted 4 lines
Quoted 4 lines
2) change
inet_ifa_matchto useifa_localinstead ofifa_address. Sinceifa_local!=ifa_addresson ppp interfaces,inet_ifa_matchcould not be used to verify ppp interface addresses without this change.
This one on the other hand is a serious semantic change and needs more careful thought. ifa_address is used for a reason, and people expecting that are going to break if we change things this way.
A study of at least the net/ipv4/devinet.c shows that this ifa_address vs. ifa_local distinction is definitely on purpose. I really don't think we can make this suggested change therefore.
Quoted 8 lines · Phil Oester
As discussed in recent days, MASQUERADE target handling of device events is broken in a couple of ways:
1) when ppp interfaces cycle, conntracks with old ip addresses are not flushed
2) an 'ip addr add' on an interface used for masquerading flushes all conntracks associated with that interface
Sorry, just caught up with this reversion in 2.6.10-rc2-bk* (was trying to figure out why my nfsim testcase was failing: this explains it).
We had numerous complaints about the old behaviour: several people with small (or clever?) ISPs actually got the same IP address most of the time, and the old code was damaging them. It also registered two callbacks which AFAICT is unnecessary.
This patch bloats conntrack, but is worth it IMHO. Most importantly, Phil, does it work for you?
Rusty.
Name: Reliable Masquerading Connection Removal
Status: Compiles, Untested
The MASQUERADE target use to destroy connections when an interface went down. We changed this to merely remove the ASSURED bit, and destroy them if the same interface came up with a different IP address. Unfortunately, as Phil Oester pointed out, that code was crap for PPP connections, since we (1) compared ifa_address instead of ifa_local, (2) identified interfaces by ifindex, which increments as a PPP device downs and ups, and (3) caused all connections to be flushed when we added an IP address.
So that code was reverted after 2.6.10-rc2.
This code stores the interface name, rather than trying to use the ifindex, and only deletes connections if *no* ifa_local on the interface matches the connection, so simply adding a new IP address is a NOOP.
include/linux/netfilter_ipv4/ip_conntrack.h +1 -1
@@ -193,7 +193,7 @@union ip_conntrack_nat_help help;#if defined(CONFIG_IP_NF_TARGET_MASQUERADE ) || \ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE ) -int masq_index; +char masq_iface[IFNAMSIZ ]; #endif } nat;#endif /* CONFIG_IP_NF_NAT_NEEDED */
net/ipv4/netfilter/ipt_MASQUERADE.c +37 -36
116 lines not on this page · raw message
Signature · 1 line
A bad analogy is like a leaky screwdriver -- Richard Braakman
Quoted 9 lines · Rusty Russell
The MASQUERADE target use to destroy connections when an interface went down. We changed this to merely remove the ASSURED bit, and destroy them if the same interface came up with a different IP address. Unfortunately, as Phil Oester pointed out, that code was crap for PPP connections, since we (1) compared
ifa_addressinstead ofifa_local, (2) identified interfaces by ifindex, which increments as a PPP device downs and ups, and (3) caused all connections to be flushed when we added an IP address.
Quoted 6 lines
So that code was reverted after 2.6.10-rc2.
This code stores the interface name, rather than trying to use the ifindex, and only deletes connections if *no*
ifa_localon the interface matches the connection, so simply adding a new IP address is a NOOP.
But even using the interface name is unreliable. Consider the user who uses multiple PPP connections. Both go down at the same time, and come back with the 'old' ppp1 now named ppp0. Or consider a PopTop PPTP server which has dozens of ppp interfaces (although using masq here is admittedly unlikely).
Perhaps my original patch which special-cased ppp would be better?
http://lists.netfilter.org/pipermail/netfilter-devel/2004-November/017294.html
Phil
Quoted 12 lines · Phil Oester
Quoted 11 lines · Rusty Russell
The MASQUERADE target use to destroy connections when an interface went down. We changed this to merely remove the ASSURED bit, and destroy them if the same interface came up with a different IP address. Unfortunately, as Phil Oester pointed out, that code was crap for PPP connections, since we (1) compared
ifa_addressinstead ofifa_local, (2) identified interfaces by ifindex, which increments as a PPP device downs and ups, and (3) caused all connections to be flushed when we added an IP address.So that code was reverted after 2.6.10-rc2.
Quoted 8 lines
Quoted 4 lines
This code stores the interface name, rather than trying to use the ifindex, and only deletes connections if *no*
ifa_localon the interface matches the connection, so simply adding a new IP address is a NOOP.But even using the interface name is unreliable. Consider the user who uses multiple PPP connections. Both go down at the same time, and come back with the 'old' ppp1 now named ppp0.
Sure, in which case the connections will be dropped, as they would be in the naive case. This entire idea is best-effort, like NAT itself 8)
I think it's worth trying, at least, but obviously the core team can override me.
Quoted 1 line
Perhaps my original patch which special-cased ppp would be better?
Drawing a link between point-to-point and addresses being static is wrong, IMHO.
Rusty.
Signature · 1 line
A bad analogy is like a leaky screwdriver -- Richard Braakman
Quoted 2 lines · Rusty Russell
Drawing a link between point-to-point and addresses being static is wrong, IMHO.
Agreed.
This discussion is equally important on Ethernet with dynamic IP assignment. Here the interface name is defenitely static.
As already discussed very many times MASQUERADE is a best effort to handle the common "dial up like" with dynamic Internet IP assignment scenarios in an easy manner. A multiple PPP situation is more of an exception than rule to this, and in addition userspace has the option of using statically reserved PPP devices for the connections in question to make the proposed MASQUERADE fully predictable in such situations.
Regards
Henrik
Quoted 10 lines · Henrik Nordstrom
Quoted 2 lines · Rusty Russell
Drawing a link between point-to-point and addresses being static is wrong, IMHO.
Agreed.
This discussion is equally important on Ethernet with dynamic IP assignment. Here the interface name is defenitely static.
Quoted 6 lines
As already discussed very many times MASQUERADE is a best effort to handle the common "dial up like" with dynamic Internet IP assignment scenarios in an easy manner. A multiple PPP situation is more of an exception than rule to this, and in addition userspace has the option of using statically reserved PPP devices for the connections in question to make the proposed MASQUERADE fully predictable in such situations.
Being the guy who proposed the original change to Rusty during the workshop 2003, I eventually step up to support this view. :-) IMHO, the goal of the MASQUERADE target is trying to deal as nicely as possible with the common cases.
I think it should be kept that way, no matter it may have some side effect for uncommon or obscur setups, as long as the potential corner cases are clearly documented.
The more complex scenarios should always be able to use something else than MASQUERADE.
Herve
Signature · 4 lines
_ (°= Hervé Eychenne //) v_/_ WallFire project: http://www.wallfire.org/