Commit c18abe7d authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[NETFILTER]: Fix issues with REJECT and MIRROR targets wrt. policy routing.

parent 96b8bc42
...@@ -625,66 +625,62 @@ int ip_route_me_harder(struct sk_buff **pskb) ...@@ -625,66 +625,62 @@ int ip_route_me_harder(struct sk_buff **pskb)
{ {
struct iphdr *iph = (*pskb)->nh.iph; struct iphdr *iph = (*pskb)->nh.iph;
struct rtable *rt; struct rtable *rt;
struct flowi fl = { .nl_u = { .ip4_u = struct flowi fl = {};
{ .daddr = iph->daddr, struct dst_entry *odst;
.saddr = iph->saddr, unsigned int hh_len;
.tos = RT_TOS(iph->tos)|RTO_CONN,
#ifdef CONFIG_IP_ROUTE_FWMARK /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
.fwmark = (*pskb)->nfmark * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
#endif */
} }, if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0, fl.nl_u.ip4_u.daddr = iph->daddr;
}; fl.nl_u.ip4_u.saddr = iph->saddr;
struct net_device *dev_src = NULL; fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
int err; fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
/* 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 #ifdef CONFIG_IP_ROUTE_FWMARK
(*pskb)->nfmark, fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
#else
0UL,
#endif #endif
err); if (ip_route_output_key(&rt, &fl) != 0)
goto out; return -1;
}
/* Drop old route. */ /* Drop old route. */
dst_release((*pskb)->dst); dst_release((*pskb)->dst);
(*pskb)->dst = &rt->u.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. */ /* 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; struct sk_buff *nskb;
nskb = skb_realloc_headroom(*pskb, nskb = skb_realloc_headroom(*pskb, hh_len);
(*pskb)->dst->dev->hard_header_len); if (!nskb)
if (!nskb) { return -1;
err = -ENOMEM;
goto out;
}
if ((*pskb)->sk) if ((*pskb)->sk)
skb_set_owner_w(nskb, (*pskb)->sk); skb_set_owner_w(nskb, (*pskb)->sk);
kfree_skb(*pskb); kfree_skb(*pskb);
*pskb = nskb; *pskb = nskb;
} }
out: return 0;
if (dev_src)
dev_put(dev_src);
return err;
} }
int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len) int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
18 Jul 2003 Harald Welte <laforge@netfilter.org> 18 Jul 2003 Harald Welte <laforge@netfilter.org>
- merge Patrick McHardy's mirror fixes from 2.4.22 to - merge Patrick McHardy's mirror fixes from 2.4.22 to
2.6.0-test1 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 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 under the terms of the GNU General Public License as published by the
...@@ -43,17 +46,42 @@ ...@@ -43,17 +46,42 @@
#define DEBUGP(format, args...) #define DEBUGP(format, args...)
#endif #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 iphdr *iph = skb->nh.iph;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr, struct dst_entry *odst;
.saddr = iph->daddr, struct flowi fl = {};
.tos = RT_TOS(iph->tos) } } };
struct rtable *rt; struct rtable *rt;
/* Backwards */ if (local) {
if (ip_route_output_key(&rt, &fl)) fl.nl_u.ip4_u.daddr = iph->saddr;
return NULL; 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; return rt;
} }
...@@ -123,7 +151,7 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb, ...@@ -123,7 +151,7 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb,
ip_decrease_ttl((*pskb)->nh.iph); 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; return NF_DROP;
hh_len = (rt->u.dst.dev->hard_header_len + 15) & ~15; hh_len = (rt->u.dst.dev->hard_header_len + 15) & ~15;
......
...@@ -35,6 +35,46 @@ static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct) ...@@ -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 */ /* Send RST reply */
static void send_reset(struct sk_buff *oldskb, int local) static void send_reset(struct sk_buff *oldskb, int local)
{ {
...@@ -69,18 +109,9 @@ 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) csum_partial((char *)otcph, otcplen, 0)) != 0)
return; return;
{ if ((rt = route_reverse(oldskb, local)) == NULL)
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))
return; return;
}
hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; 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 /* Copy skb (even if skb is about to be dropped, we can't just
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment