]> git.hungrycats.org Git - linux/commitdiff
[NETFILTER]: Fix various problems with MIRROR target.
authorPatrick McHardy <kaber@trash.net>
Fri, 25 Jul 2003 08:15:50 +0000 (01:15 -0700)
committerDavid S. Miller <davem@nuts.ninka.net>
Fri, 25 Jul 2003 08:15:50 +0000 (01:15 -0700)
- 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

net/ipv4/netfilter/ipt_MIRROR.c

index 3f8faff13dc496d1af5c7d55d481c9aa28b2b5c3..0e4d34c401ecc2ed3f1234011c65299248775cea 100644 (file)
@@ -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 @@ struct in_device;
 #define DEBUGP(format, args...)
 #endif
 
-static inroute_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 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb,
                                      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;
 }