Hi Dave! This is the first of my 2.6 merge of the recent bugfixes (all tested against 2.6.0-test1). You might need to apply them incrementally (didn't test it in a different order). Author: Patrick McHardy This patch fixes various problems with the experimental iptables MIRROR target: - check TTL before rewriting so icmp_send gets clean packet - skb_copy_expand(skb) for tcpdump and asymmetric routing - inline some function - remove unneccessary 'struct in_device' declaration - remove RTO_CONN Please apply, --- linux-2.6.0-test1-nftest/net/ipv4/netfilter/ipt_MIRROR.c 2003-07-14 05:39:23.000000000 +0200 +++ linux-2.6.0-test1-nftest2/net/ipv4/netfilter/ipt_MIRROR.c 2003-07-19 16:05:13.000000000 +0200 @@ -9,6 +9,9 @@ Changes: 25 Aug 2001 Harald Welte - decrement and check TTL if not called from FORWARD hook + 18 Jul 2003 Harald Welte + - merge Patrick McHardy's mirror fixes from 2.4.22 to + 2.6.0-test1 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -32,7 +35,6 @@ #include #include #include -struct in_device; #include #if 0 @@ -41,46 +43,33 @@ #define DEBUGP(format, args...) #endif -static int route_mirror(struct sk_buff *skb) +static inline struct rtable *route_mirror(struct sk_buff *skb) { struct iphdr *iph = skb->nh.iph; struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr, .saddr = iph->daddr, - .tos = RT_TOS(iph->tos) | RTO_CONN } } }; + .tos = RT_TOS(iph->tos) } } }; struct rtable *rt; /* Backwards */ - if (ip_route_output_key(&rt, &fl)) { - return 0; - } + if (ip_route_output_key(&rt, &fl)) + return NULL; - /* check if the interface we are leaving by is the same as the - one we arrived on */ - if (skb->dev == rt->u.dst.dev) { - /* Drop old route. */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; - return 1; - } - return 0; + return rt; } -static int ip_rewrite(struct sk_buff **pskb) +static inline void ip_rewrite(struct sk_buff *skb) { u32 odaddr, osaddr; - if (!skb_ip_make_writable(pskb, sizeof(struct iphdr))) - return 0; + odaddr = skb->nh.iph->saddr; + osaddr = skb->nh.iph->daddr; - odaddr = (*pskb)->nh.iph->saddr; - osaddr = (*pskb)->nh.iph->daddr; - - (*pskb)->nfcache |= NFC_ALTERED; + skb->nfcache |= NFC_ALTERED; /* Rewrite IP header */ - (*pskb)->nh.iph->daddr = odaddr; - (*pskb)->nh.iph->saddr = osaddr; - return 1; + skb->nh.iph->daddr = odaddr; + skb->nh.iph->saddr = osaddr; } /* Stolen from ip_finish_output2 */ @@ -113,31 +102,51 @@ const void *targinfo, void *userinfo) { - if (((*pskb)->dst != NULL) && route_mirror(*pskb)) { - if (!ip_rewrite(pskb)) - return NF_DROP; + struct rtable *rt; + struct sk_buff *nskb; + unsigned int hh_len; - /* If we are not at FORWARD hook (INPUT/PREROUTING), - * the TTL isn't decreased by the IP stack */ - if (hooknum != NF_IP_FORWARD) { - if ((*pskb)->nh.iph->ttl <= 1) { - /* this will traverse normal stack, and - * thus call conntrack on the icmp packet */ - icmp_send(*pskb, ICMP_TIME_EXCEEDED, - ICMP_EXC_TTL, 0); - return NF_DROP; - } - /* Made writable by ip_rewrite */ - ip_decrease_ttl((*pskb)->nh.iph); + /* Make skb writable */ + if (!skb_ip_make_writable(pskb, sizeof(struct iphdr))) + return 0; + + /* If we are not at FORWARD hook (INPUT/PREROUTING), + * the TTL isn't decreased by the IP stack */ + if (hooknum != NF_IP_FORWARD) { + if ((*pskb)->nh.iph->ttl <= 1) { + /* this will traverse normal stack, and + * thus call conntrack on the icmp packet */ + icmp_send(*pskb, ICMP_TIME_EXCEEDED, + ICMP_EXC_TTL, 0); + return NF_DROP; } + ip_decrease_ttl((*pskb)->nh.iph); + } - /* Don't let conntrack code see this packet: - it will think we are starting a new - connection! --RR */ - ip_direct_send(*pskb); + if ((rt = route_mirror(*pskb)) == NULL) + return NF_DROP; - return NF_STOLEN; + hh_len = (rt->u.dst.dev->hard_header_len + 15) & ~15; + + /* Copy skb (even if skb is about to be dropped, we can't just + * clone it because there may be other things, such as tcpdump, + * interested in it). We also need to expand headroom in case + * hh_len of incoming interface < hh_len of outgoing interface */ + nskb = skb_copy_expand(*pskb, hh_len, skb_tailroom(*pskb), GFP_ATOMIC); + if (nskb == NULL) { + dst_release(&rt->u.dst); + return NF_DROP; } + + dst_release(nskb->dst); + nskb->dst = &rt->u.dst; + + ip_rewrite(nskb); + /* Don't let conntrack code see this packet: + * it will think we are starting a new + * connection! --RR */ + ip_direct_send(*pskb); + return NF_DROP; } -- - Harald Welte 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