Subject: kernel-image-2.6.8-3-686: Masquerading problem with dynamic IP interfaces Package: kernel-image-2.6.8-3-686 Version: 2.6.8-16sarge6 Severity: important Tags: patch
*** Please type your report below this line *** When using Debian Sarge with kernel-image-2.6.8-3-686 as a nat gateway with a dynamic IP interfaces like pppoe and you have OpenVPN clients or other udp based programms behind the gateway, you have the following problem after a reconnect of the pppoe interface you get a new address, but the state entry in /proc/net/ip_conntrack will stay with the old address for the udp connection. Without the attached patch the OpenVPN tunnel is not usable anymore, because the packages are send out on the pppoe interface with the wrong ip address. This bug is also mentioned here: https://bugzilla.netfilter.org/bugzilla/show_bug.cgi?id=329 I took the patch from http://www.linuxarkivet.se/mlists/netfilter-devel/0411/msg00154.html and modified it for the debian kernel. This is fixed in newer kernel versions. Regards, Oliver Seufer -- System Information: Debian Release: 3.1 Architecture: i386 (i686) Kernel: Linux 2.6.8-3-686 Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968) Versions of packages kernel-image-2.6.8-3-686 depends on: ii coreutils [fileutils] 5.2.1-2 The GNU core utilities ii initrd-tools 0.1.81.1 tools to create initrd image for p ii module-init-tools 3.2-pre1-2 tools for managing Linux kernel mo -- no debconf information
--- net/ipv4/netfilter/ipt_MASQUERADE.c 2004-08-14 07:37:15.000000000 +0200 +++ net/ipv4/netfilter/ipt_MASQUERADE.c.patched 2007-02-23 13:30:29.709425676 +0100 @@ -141,35 +141,58 @@ } static inline int -device_cmp(const struct ip_conntrack *i, void *_ina) +device_cmp(const struct ip_conntrack *i, void *ifindex) { - int ret = 0; - struct in_ifaddr *ina = _ina; + int ret; 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) - ret = 1; + ret = (i->nat.masq_index == (int)(long)ifindex); READ_UNLOCK(&masq_lock); return ret; } +static int masq_device_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + + if (event == NETDEV_DOWN) { + /* Device was downed. Search entire table for + conntracks which were associated with that device, + and forget them. */ + IP_NF_ASSERT(dev->ifindex != 0); + + ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex); + } + + return NOTIFY_DONE; +} + static int masq_inet_event(struct notifier_block *this, unsigned long event, void *ptr) { - /* For some configurations, interfaces often come back with - * the same address. If not, clean up old conntrack - * entries. */ - if (event == NETDEV_UP) - ip_ct_selective_cleanup(device_cmp, ptr); + struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; + + if (event == NETDEV_DOWN) { + /* IP address was deleted. Search entire table for + conntracks which were associated with that device, + and forget them. */ + IP_NF_ASSERT(dev->ifindex != 0); + + ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex); + + } return NOTIFY_DONE; } +static struct notifier_block masq_dev_notifier = { + .notifier_call = masq_device_event, +}; + static struct notifier_block masq_inet_notifier = { .notifier_call = masq_inet_event, }; @@ -187,9 +210,12 @@ ret = ipt_register_target(&masquerade); - if (ret == 0) + if (ret == 0) { + /* Register for device down reports */ + register_netdevice_notifier(&masq_dev_notifier); /* Register IP address change reports */ register_inetaddr_notifier(&masq_inet_notifier); + } return ret; } @@ -197,6 +223,7 @@ static void __exit fini(void) { ipt_unregister_target(&masquerade); + unregister_netdevice_notifier(&masq_dev_notifier); unregister_inetaddr_notifier(&masq_inet_notifier); }