Skip to contentSkip to conversation

policy routing fixes

PATCH In review Patrick McHardy 2 participants 3 messages Apr 22, 2003 – Apr 30, 2003

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 3/3 policy routing fixes

This patch corrects routing in REJECT, MIRROR and ip_route_me_harder. Currently netfilter does not obey rules like "from x.x.x.x/x lookup x" because it src=0 when doing routing lookups for non-local addresses. With this patch, netfilter uses ip_route_input if source if non-local. Also route_me_harder doesn't return the exact error anymore, noone seemed to care about it. i also removed the printks, i think a missing route is nothing so abnormal it justifies confusing the user, and almost everyone i know has asked me at least once "what the hell is ip_route_me_harder" ;). This patch is incremental to the two i sent before.

Best regards,
Patrick

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.1103 -> 1.1104
# net/ipv4/netfilter/ipt_REJECT.c 1.11 -> 1.12
# net/core/netfilter.c 1.7 -> 1.8
# net/ipv4/netfilter/ipt_MIRROR.c 1.4 -> 1.5
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/04/22 [email protected] 1.1104
# [NETFILTER] make netfilter policy-routing aware
# --------------------------------------------
#

net/core/netfilter.c +43 -45
diff -Nru a/net/core/netfilter.c b/net/core/netfilter.c
@@ -563,64 +563,62 @@
 {
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct rtable *rt;
-	struct rt_key key = { dst:iph->daddr,
-			      src:iph->saddr,
-			      oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
-			      tos:RT_TOS(iph->tos)|RTO_CONN,
+	struct rt_key key = {};
+	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 be appear on the NF_IP_LOCAL_OUT hook.
+	 */
+	if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
+		key.dst = iph->daddr;
+		key.src = iph->saddr;
+		key.oif = (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0;
+		key.tos = RT_TOS(iph->tos);
 #ifdef CONFIG_IP_ROUTE_FWMARK
-			      fwmark:(*pskb)->nfmark
+		key.fwmark = (*pskb)->nfmark;
 #endif
-			    };
-	struct net_device *dev_src = NULL;
-	int err;
-
-	/* accomodate 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(key.src && !(dev_src = ip_dev_find(key.src)))
-		key.src = 0;
-
-	if ((err=ip_route_output_key(&rt, &key)) != 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->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, &key) != 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. */
+		key.dst = iph->saddr;
+		if (ip_route_output_key(&rt, &key) != 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;
 }
 #endif /*CONFIG_INET*/
 
net/ipv4/netfilter/ipt_MIRROR.c +33 -6
diff -Nru a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR.c
@@ -40,15 +40,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 dst_entry *odst;
+	struct rt_key key = {};
 	struct rtable *rt;
 
-	/* Backwards */
-	if (ip_route_output(&rt, iph->saddr, iph->daddr,
-			    RT_TOS(iph->tos), 0))
-		return NULL;
+	if (local) {
+		key.dst = iph->saddr;
+		key.src = iph->daddr;
+		key.tos = RT_TOS(iph->tos);
+
+		if (ip_route_output_key(&rt, &key) != 0)
+			return NULL;
+	} else {
+		/* non-local src, find valid iif to satisfy
+		 * rp-filter when calling ip_route_input. */
+		key.dst = iph->daddr;
+		if (ip_route_output_key(&rt, &key) != 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;
 }
@@ -111,7 +138,7 @@
 		ip_decrease_ttl(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;
net/ipv4/netfilter/ipt_REJECT.c +41 -4

57 lines not on this page · raw message

#1 lore raw
Quoted 1 line · Patrick McHardy

This patch corrects routing in REJECT, MIRROR and ip_route_me_harder.

thanks, I will put this into 'pending'. The change is intrusive enough to have this fix in patch-o-matic for a while before submitting it to the kernel.

Quoted 2 lines

Best regards,
Patrick

Signature · 5 lines
- Harald Welte <[email protected]>             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
#2 lore raw
Quoted 4 lines · Harald Welte

thanks, I will put this into 'pending'. The change is intrusive enough to have this fix in patch-o-matic for a while before submitting it to the kernel.

Hi Harald,
i just wanted to make sure you didn't forgot. I see the first patch in CVS and some new stuff, but the second and third one are still missing ..

Best regards,
Patrick