]> git.hungrycats.org Git - linux/commitdiff
[NETFILTER]: Fix issues with REJECT and MIRROR targets wrt. policy routing.
authorPatrick McHardy <kaber@trash.net>
Fri, 25 Jul 2003 08:16:49 +0000 (01:16 -0700)
committerDavid S. Miller <davem@nuts.ninka.net>
Fri, 25 Jul 2003 08:16:49 +0000 (01:16 -0700)
net/core/netfilter.c
net/ipv4/netfilter/ipt_MIRROR.c
net/ipv4/netfilter/ipt_REJECT.c

index 1c08a5bfae90ef8065e7d8b56a2122a5a3b63135..980cd4514d6946c46712cb01e7b4c65930f863e9 100644 (file)
@@ -625,66 +625,62 @@ int ip_route_me_harder(struct sk_buff **pskb)
 {
        struct iphdr *iph = (*pskb)->nh.iph;
        struct rtable *rt;
-       struct flowi fl = { .nl_u = { .ip4_u =
-                                     { .daddr = iph->daddr,
-                                       .saddr = iph->saddr,
-                                       .tos = RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
-                                       .fwmark = (*pskb)->nfmark
-#endif
-                                     } },
-                           .oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0,
-                           };
-       struct net_device *dev_src = NULL;
-       int err;
-
-       /* accommodate ip_route_output_slow(), which expects the key src to be
-          0 or a local address; however some non-standard hacks like
-          ipt_REJECT.c:send_reset() can cause packets with foreign
-           saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */
-       if(fl.fl4_src && !(dev_src = ip_dev_find(fl.fl4_src)))
-               fl.fl4_src = 0;
-
-       if ((err=ip_route_output_key(&rt, &fl)) != 0) {
-               printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n",
-                       NIPQUAD(iph->daddr), NIPQUAD(iph->saddr),
-                       (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0,
-                       RT_TOS(iph->tos)|RTO_CONN,
+       struct flowi fl = {};
+       struct dst_entry *odst;
+       unsigned int hh_len;
+
+       /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
+        * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
+        */
+       if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
+               fl.nl_u.ip4_u.daddr = iph->daddr;
+               fl.nl_u.ip4_u.saddr = iph->saddr;
+               fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+               fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
 #ifdef CONFIG_IP_ROUTE_FWMARK
-                       (*pskb)->nfmark,
-#else
-                       0UL,
+               fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
 #endif
-                       err);
-               goto out;
-       }
+               if (ip_route_output_key(&rt, &fl) != 0)
+                       return -1;
 
-       /* Drop old route. */
-       dst_release((*pskb)->dst);
-
-       (*pskb)->dst = &rt->u.dst;
+               /* Drop old route. */
+               dst_release((*pskb)->dst);
+               (*pskb)->dst = &rt->u.dst;
+       } else {
+               /* non-local src, find valid iif to satisfy
+                * rp-filter when calling ip_route_input. */
+               fl.nl_u.ip4_u.daddr = iph->saddr;
+               if (ip_route_output_key(&rt, &fl) != 0)
+                       return -1;
+
+               odst = (*pskb)->dst;
+               if (ip_route_input(*pskb, iph->daddr, iph->saddr,
+                                  RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+                       dst_release(&rt->u.dst);
+                       return -1;
+               }
+               dst_release(&rt->u.dst);
+               dst_release(odst);
+       }
+       
+       if ((*pskb)->dst->error)
+               return -1;
 
        /* Change in oif may mean change in hh_len. */
-       if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) {
+       hh_len = (*pskb)->dst->dev->hard_header_len;
+       if (skb_headroom(*pskb) < hh_len) {
                struct sk_buff *nskb;
 
-               nskb = skb_realloc_headroom(*pskb,
-                                           (*pskb)->dst->dev->hard_header_len);
-               if (!nskb) {
-                       err = -ENOMEM;
-                       goto out;
-               }
+               nskb = skb_realloc_headroom(*pskb, hh_len);
+               if (!nskb) 
+                       return -1;
                if ((*pskb)->sk)
                        skb_set_owner_w(nskb, (*pskb)->sk);
                kfree_skb(*pskb);
                *pskb = nskb;
        }
 
-out:
-       if (dev_src)
-               dev_put(dev_src);
-
-       return err;
+       return 0;
 }
 
 int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
index 0e4d34c401ecc2ed3f1234011c65299248775cea..08539faeffe971333cb9384cea5fa63bfcce5804 100644 (file)
@@ -12,6 +12,9 @@
        18 Jul 2003 Harald Welte <laforge@netfilter.org>
                - merge Patrick McHardy's mirror fixes from 2.4.22 to
                  2.6.0-test1
+       19 Jul 2003 Harald Welte <laforge@netfilter.org>
+               - merge Patrick McHardy's rp_filter 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
 #define DEBUGP(format, args...)
 #endif
 
-static inline struct rtable *route_mirror(struct sk_buff *skb)
+static inline struct rtable *route_mirror(struct sk_buff *skb, int local)
 {
         struct iphdr *iph = skb->nh.iph;
-       struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
-                                                .saddr = iph->daddr,
-                                                .tos = RT_TOS(iph->tos) } } };
+       struct dst_entry *odst;
+       struct flowi fl = {};
        struct rtable *rt;
 
-       /* Backwards */
-       if (ip_route_output_key(&rt, &fl))
-               return NULL;
+       if (local) {
+               fl.nl_u.ip4_u.daddr = iph->saddr;
+               fl.nl_u.ip4_u.saddr = iph->daddr;
+               fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+
+               if (ip_route_output_key(&rt, &fl) != 0)
+                       return NULL;
+       } else {
+               /* non-local src, find valid iif to satisfy
+                * rp-filter when calling ip_route_input(). */
+               fl.nl_u.ip4_u.daddr = iph->daddr;
+               if (ip_route_output_key(&rt, &fl) != 0)
+                       return NULL;
+
+               odst = skb->dst;
+               if (ip_route_input(skb, iph->saddr, iph->daddr,
+                                       RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+                       dst_release(&rt->u.dst);
+                       return NULL;
+               }
+               dst_release(&rt->u.dst);
+               rt = (struct rtable *)skb->dst;
+               skb->dst = odst;
+       }
+
+       if (rt->u.dst.error) {
+               dst_release(&rt->u.dst);
+               rt = NULL;
+       }
 
        return rt;
 }
@@ -123,7 +151,7 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb,
                ip_decrease_ttl((*pskb)->nh.iph);
        }
 
-       if ((rt = route_mirror(*pskb)) == NULL)
+       if ((rt = route_mirror(*pskb, hooknum == NF_IP_LOCAL_IN)) == NULL)
                return NF_DROP;
 
        hh_len = (rt->u.dst.dev->hard_header_len + 15) & ~15;
index b0b236642ab78c58fc9e10bfd654ecd53e472fc4..72aacefc01d4d10c4240d0ddb738fa67c15a73f7 100644 (file)
@@ -35,6 +35,46 @@ static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
        }
 }
 
+static inline struct rtable *route_reverse(struct sk_buff *skb, int local)
+{
+       struct iphdr *iph = skb->nh.iph;
+       struct dst_entry *odst;
+       struct flowi fl = {};
+       struct rtable *rt;
+
+       if (local) {
+               fl.nl_u.ip4_u.daddr = iph->saddr;
+               fl.nl_u.ip4_u.saddr = iph->daddr;
+               fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+
+               if (ip_route_output_key(&rt, &fl) != 0)
+                       return NULL;
+       } else {
+               /* non-local src, find valid iif to satisfy
+                * rp-filter when calling ip_route_input. */
+               fl.nl_u.ip4_u.daddr = iph->daddr;
+               if (ip_route_output_key(&rt, &fl) != 0)
+                       return NULL;
+
+               odst = skb->dst;
+               if (ip_route_input(skb, iph->saddr, iph->daddr,
+                                  RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+                       dst_release(&rt->u.dst);
+                       return NULL;
+               }
+               dst_release(&rt->u.dst);
+               rt = (struct rtable *)skb->dst;
+               skb->dst = odst;
+       }
+
+       if (rt->u.dst.error) {
+               dst_release(&rt->u.dst);
+               rt = NULL;
+       }
+
+       return rt;
+}
+
 /* Send RST reply */
 static void send_reset(struct sk_buff *oldskb, int local)
 {
@@ -69,18 +109,9 @@ static void send_reset(struct sk_buff *oldskb, int local)
                         csum_partial((char *)otcph, otcplen, 0)) != 0)
                return;
 
-       {
-               struct flowi fl = { .nl_u = { .ip4_u =
-                                             { .daddr = oldskb->nh.iph->saddr,
-                                               .saddr = (local ?
-                                                         oldskb->nh.iph->daddr :
-                                                         0),
-                                               .tos = RT_TOS(oldskb->nh.iph->tos) } } };
-
-       /* Routing: if not headed for us, route won't like source */
-       if (ip_route_output_key(&rt, &fl))
+       if ((rt = route_reverse(oldskb, local)) == NULL)
                return;
-       }               
+
        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