Hi Dave! This is the first of a set of bugfixes (all tested against 2.4.22-pre7). You might need to apply them incrementally (didn't test it in a different order). You will receive 2.6 merges of those patches soon. 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, diff -Nru a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR.c --- a/net/ipv4/netfilter/ipt_MIRROR.c Mon Apr 21 21:26:42 2003 +++ b/net/ipv4/netfilter/ipt_MIRROR.c Mon Apr 21 21:26:42 2003 @@ -32,7 +32,6 @@ #include #include #include -struct in_device; #include #if 0 @@ -41,31 +40,20 @@ #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 rtable *rt; /* Backwards */ if (ip_route_output(&rt, iph->saddr, iph->daddr, - RT_TOS(iph->tos) | RTO_CONN, - 0)) { - return 0; - } + RT_TOS(iph->tos), 0)) + 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 void -ip_rewrite(struct sk_buff *skb) +static inline void ip_rewrite(struct sk_buff *skb) { struct iphdr *iph = skb->nh.iph; u32 odaddr = iph->saddr; @@ -105,32 +93,48 @@ const void *targinfo, void *userinfo) { - if (((*pskb)->dst != NULL) && - route_mirror(*pskb)) { - - ip_rewrite(*pskb); + 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) { - struct iphdr *iph = (*pskb)->nh.iph; - if (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(iph); + /* If we are not at FORWARD hook (INPUT/PREROUTING), + * the TTL isn't decreased by the IP stack */ + if (hooknum != NF_IP_FORWARD) { + struct iphdr *iph = (*pskb)->nh.iph; + if (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(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(nskb); + 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