iptables_nat in 2.4.0 prevents ICMP destination unreachables
Rusty Russell
rusty@linuxcare.com.au
Sat, 03 Jun 2000 03:55:02 +0930
In message <200005292140.WAA02502@raistlin.arm.linux.org.uk> you write:
> If I leave the ping running, and insert iptables_nat, the ICMP net
> unreachable messages stop. Checking this with tcpdump reveals that
> the machine which just loaded iptables_nat stops sending the ICMP
> error packets, which is obviously wrong since I'm asking the firewall
> to explicitly send them.
Well caught. Overzealous unconfirmed connection test: ordinarily we
won't associate ICMPs with a connection until a packet from that
connection has passed through the box. However, we should allow
locally-generated ICMP errors.
Rusty.
diff -urN -X /tmp/filesVWD1a --minimal linux-2.4.0-test1-official/include/linux/netfilter_ipv4/ip_conntrack_core.h working-2.4.0-test1/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- linux-2.4.0-test1-official/include/linux/netfilter_ipv4/ip_conntrack_core.h Fri Jun 2 15:09:24 2000
+++ working-2.4.0-test1/include/linux/netfilter_ipv4/ip_conntrack_core.h Sat Jun 3 04:10:09 2000
@@ -22,7 +22,8 @@
/* Returns conntrack if it dealt with ICMP, and filled in skb->nfct */
extern struct ip_conntrack *icmp_error_track(struct sk_buff *skb,
- enum ip_conntrack_info *ctinfo);
+ enum ip_conntrack_info *ctinfo,
+ unsigned int hooknum);
extern int get_tuple(const struct iphdr *iph, size_t len,
struct ip_conntrack_tuple *tuple,
struct ip_conntrack_protocol *protocol);
diff -urN -X /tmp/filesVWD1a --minimal linux-2.4.0-test1-official/net/ipv4/netfilter/ip_conntrack_core.c working-2.4.0-test1/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.0-test1-official/net/ipv4/netfilter/ip_conntrack_core.c Fri May 12 12:51:52 2000
+++ working-2.4.0-test1/net/ipv4/netfilter/ip_conntrack_core.c Sat Jun 3 04:12:22 2000
@@ -297,7 +289,9 @@
/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
struct ip_conntrack *
-icmp_error_track(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
+icmp_error_track(struct sk_buff *skb,
+ enum ip_conntrack_info *ctinfo,
+ unsigned int hooknum)
{
const struct iphdr *iph;
struct icmphdr *hdr;
@@ -353,7 +354,11 @@
DEBUGP("icmp_error_track: no match\n");
return NULL;
}
- if (!(h->ctrack->status & IPS_CONFIRMED)) {
+
+ /* REJECT target does this commonly, so allow locally
+ generated ICMP errors --RR */
+ if (!(h->ctrack->status & IPS_CONFIRMED)
+ && hooknum != NF_IP_LOCAL_OUT) {
DEBUGP("icmp_error_track: unconfirmed\n");
ip_conntrack_put(h->ctrack);
return NULL;
@@ -623,7 +647,7 @@
/* It may be an icmp error... */
if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP
- || !(ct = icmp_error_track(*pskb, &ctinfo))) {
+ || !(ct = icmp_error_track(*pskb, &ctinfo, hooknum))) {
if (!(ct = resolve_normal_ct(*pskb, proto, &ctinfo))) {
/* Not valid part of a connection */
return NF_ACCEPT;
diff -urN -X /tmp/filesVWD1a --minimal linux-2.4.0-test1-official/net/ipv4/netfilter/ip_fw_compat_masq.c working-2.4.0-test1/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.4.0-test1-official/net/ipv4/netfilter/ip_fw_compat_masq.c Fri May 12 12:51:52 2000
+++ working-2.4.0-test1/net/ipv4/netfilter/ip_fw_compat_masq.c Sat Jun 3 04:10:09 2000
@@ -114,7 +114,8 @@
switch (iph->protocol) {
case IPPROTO_ICMP:
/* ICMP errors. */
- if ((ct = icmp_error_track(*pskb, &ctinfo))) {
+ ct = icmp_error_track(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
+ if (ct) {
icmp_reply_translation(*pskb, ct,
NF_IP_PRE_ROUTING,
CTINFO2DIR(ctinfo));
--
Hacking time.