summaryrefslogtreecommitdiff
path: root/net/core
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2003-07-25 01:16:49 -0700
committerDavid S. Miller <davem@nuts.ninka.net>2003-07-25 01:16:49 -0700
commitc18abe7d3ec54fe21cd6fe5b75a00d7f84498546 (patch)
tree75b5e65551f5e584e6c47eadb85541772cf04a24 /net/core
parent96b8bc423661063ad79031a1782987bcd612e3d0 (diff)
[NETFILTER]: Fix issues with REJECT and MIRROR targets wrt. policy routing.
Diffstat (limited to 'net/core')
-rw-r--r--net/core/netfilter.c90
1 files changed, 43 insertions, 47 deletions
diff --git a/net/core/netfilter.c b/net/core/netfilter.c
index 1c08a5bfae90..980cd4514d69 100644
--- a/net/core/netfilter.c
+++ b/net/core/netfilter.c
@@ -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)