[PATCH 2.6] netfilter policy routing fixes

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


Hi Dave!

This is the 2nd of my 2.6 merge of the recent bugfixes (all tested
against 2.4.22-pre7). You might need to apply them incrementally
(didn't test it in a different order).

Author: Patrick McHardy <kaber@trash.net>

This patch fixes some issues with iptables REJECT and MIRROR targets
when combined with policy routing / rp_filter.

Please apply,

diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.0-test1-nftest2/net/ipv4/netfilter/ipt_MIRROR.c linux-2.6.0-test1-nftest3/net/ipv4/netfilter/ipt_MIRROR.c
--- linux-2.6.0-test1-nftest2/net/ipv4/netfilter/ipt_MIRROR.c 2003-07-19 16:05:13.000000000 +0200
+++ linux-2.6.0-test1-nftest3/net/ipv4/netfilter/ipt_MIRROR.c 2003-07-19 16:13:56.000000000 +0200
@@ -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
@@ -43,17 +46,42 @@
 #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 @@
                 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;
diff -Nru --exclude .depend --exclude '*.o' --exclude '*.ko' --exclude '*.ver' --exclude '.*.flags' --exclude '*.orig' --exclude '*.rej' --exclude '*.cmd' --exclude '*.mod.c' --exclude '*~' linux-2.6.0-test1-nftest2/net/ipv4/netfilter/ipt_REJECT.c linux-2.6.0-test1-nftest3/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.6.0-test1-nftest2/net/ipv4/netfilter/ipt_REJECT.c 2003-07-19 14:14:23.000000000 +0200
+++ linux-2.6.0-test1-nftest3/net/ipv4/netfilter/ipt_REJECT.c 2003-07-19 16:13:32.000000000 +0200
@@ -35,6 +35,46 @@
         }
 }
 
+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 @@
                          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
--- linux-2.6.0-test1-nftest2/net/core/netfilter.c 2003-07-14 05:33:59.000000000 +0200
+++ linux-2.6.0-test1-nftest3/net/core/netfilter.c 2003-07-19 16:21:26.000000000 +0200
@@ -625,66 +625,62 @@
 {
         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,
+ 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
- .fwmark = (*pskb)->nfmark
+ fl.nl_u.ip4_u.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,
-#ifdef CONFIG_IP_ROUTE_FWMARK
- (*pskb)->nfmark,
-#else
- 0UL,
-#endif
- err);
- goto out;
- }
-
- /* Drop old route. */
- dst_release((*pskb)->dst);
+ if (ip_route_output_key(&rt, &fl) != 0)
+ return -1;
 
- (*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)

-- 
- 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