[PATCH 2.6] iptables MIRROR target fixes

From: Harald Welte (laforge@netfilter.org)
Date: Fri Jul 25 2003 - 15:52:17 EST


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 <kaber@trash.net>

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 <laforge@gnumonks.org>
                 - decrement and check TTL if not called from FORWARD hook
+ 18 Jul 2003 Harald Welte <laforge@netfilter.org>
+ - 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 <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netdevice.h>
 #include <linux/route.h>
-struct in_device;
 #include <net/route.h>
 
 #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 <laforge@netfilter.org>             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


- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Jul 31 2003 - 22:00:27 EST