aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem>2002-01-23 19:35:57 +0000
committerdavem <davem>2002-01-23 19:35:57 +0000
commita95b56c87e5a57ebd5c8f0956cfab2f83b40fa99 (patch)
treee4deb57d6f77a0ca451ee5e6fa14aeb86006df25
parente3577ad1ed1573268902e0005e8230dc1d15fb8f (diff)
downloadnetdev-vger-cvs-a95b56c87e5a57ebd5c8f0956cfab2f83b40fa99.tar.gz
Move route_me_harder into a header,
fixes all cases where this duplicated function was buggy. From Harald Welte
-rw-r--r--include/linux/netfilter_ipv4.h77
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c40
-rw-r--r--net/ipv4/netfilter/ip_queue.c28
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c30
4 files changed, 79 insertions, 96 deletions
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index 3a41356db..b404b2132 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -73,4 +73,81 @@ void nf_debug_ip_finish_output2(struct sk_buff *skb);
/* 2.4 firewalling went 64 through 67. */
#define SO_ORIGINAL_DST 80
+
+/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue
+ *
+ * Ideally this would be ins some netfilter_utility module, but creating this
+ * module for just one function doesn't make sense. -HW */
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/route.h>
+#include <linux/ip.h>
+
+static inline int route_me_harder(struct sk_buff **pskb)
+{
+ 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,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ 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
+ 0,
+#endif
+ err);
+ goto out;
+ }
+
+ /* Drop old route. */
+ dst_release((*pskb)->dst);
+
+ (*pskb)->dst = &rt->u.dst;
+
+ /* Change in oif may mean change in hh_len. */
+ if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) {
+ struct sk_buff *nskb;
+
+ nskb = skb_realloc_headroom(*pskb,
+ (*pskb)->dst->dev->hard_header_len);
+ if (!nskb) {
+ err = -ENOMEM;
+ goto out;
+ }
+ 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;
+}
+
#endif /*__LINUX_IP_NETFILTER_H*/
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 50c679e63..b9c5c45ad 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -166,46 +166,6 @@ ip_nat_out(unsigned int hooknum,
return ip_nat_fn(hooknum, pskb, in, out, okfn);
}
-static int route_me_harder(struct sk_buff **pskb)
-{
- 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,
-#ifdef CONFIG_IP_ROUTE_FWMARK
- fwmark:(*pskb)->nfmark
-#endif
- };
-
- if (ip_route_output_key(&rt, &key) != 0) {
- printk("route_me_harder: No more route.\n");
- return -EINVAL;
- }
-
- /* Drop old route. */
- dst_release((*pskb)->dst);
-
- (*pskb)->dst = &rt->u.dst;
-
- /* Change in oif may mean change in hh_len. */
- if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) {
- struct sk_buff *nskb;
-
- nskb = skb_realloc_headroom(*pskb,
- (*pskb)->dst->dev
- ->hard_header_len);
- if (!nskb)
- return -ENOMEM;
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
- }
- return 0;
-}
-
static unsigned int
ip_nat_local_fn(unsigned int hooknum,
struct sk_buff **pskb,
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 06949c217..8c56b6615 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -216,32 +216,6 @@ static void ipq_destroy_queue(ipq_queue_t *q)
kfree(q);
}
-/* With a chainsaw... */
-static int route_me_harder(struct sk_buff *skb)
-{
- struct iphdr *iph = skb->nh.iph;
- struct rtable *rt;
-
- struct rt_key key = {
- dst:iph->daddr, src:iph->saddr,
- oif:skb->sk ? skb->sk->bound_dev_if : 0,
- tos:RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
- fwmark:skb->nfmark
-#endif
- };
-
- if (ip_route_output_key(&rt, &key) != 0) {
- printk("route_me_harder: No more route.\n");
- return -EINVAL;
- }
-
- /* Drop old route. */
- dst_release(skb->dst);
- skb->dst = &rt->u.dst;
- return 0;
-}
-
static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
{
int diff;
@@ -287,7 +261,7 @@ static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e)
if (!(iph->tos == e->rt_info.tos
&& iph->daddr == e->rt_info.daddr
&& iph->saddr == e->rt_info.saddr))
- return route_me_harder(e->skb);
+ return route_me_harder(&e->skb);
}
return 0;
}
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index c00a5a84b..0bb8ff796 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -129,34 +129,6 @@ ipt_route_hook(unsigned int hook,
return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL);
}
-/* FIXME: change in oif may mean change in hh_len. Check and realloc
- --RR */
-static int
-route_me_harder(struct sk_buff *skb)
-{
- struct iphdr *iph = skb->nh.iph;
- struct rtable *rt;
- struct rt_key key = { dst:iph->daddr,
- src:iph->saddr,
- oif:skb->sk ? skb->sk->bound_dev_if : 0,
- tos:RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
- fwmark:skb->nfmark
-#endif
- };
-
- if (ip_route_output_key(&rt, &key) != 0) {
- printk("route_me_harder: No more route.\n");
- return -EINVAL;
- }
-
- /* Drop old route. */
- dst_release(skb->dst);
-
- skb->dst = &rt->u.dst;
- return 0;
-}
-
static unsigned int
ipt_local_hook(unsigned int hook,
struct sk_buff **pskb,
@@ -190,7 +162,7 @@ ipt_local_hook(unsigned int hook,
|| (*pskb)->nh.iph->daddr != daddr
|| (*pskb)->nfmark != nfmark
|| (*pskb)->nh.iph->tos != tos))
- return route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+ return route_me_harder(pskb) == 0 ? ret : NF_DROP;
return ret;
}