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

[NETFILTER]: Fix various problems with MIRROR target.

- check TTL before rewriting so icmp_send gets clean packet
- skb_copy_expand(skb) for tcpdump and asymmetric routing
- inline some function
- remove unneccessary struct in_device declaration
- remove RTO_CONN
parent 3e93cabb
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
Changes: Changes:
25 Aug 2001 Harald Welte <laforge@gnumonks.org> 25 Aug 2001 Harald Welte <laforge@gnumonks.org>
- decrement and check TTL if not called from FORWARD hook - decrement and check TTL if not called from FORWARD hook
18 Jul 2003 Harald Welte <laforge@netfilter.org>
- merge Patrick McHardy's mirror 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
...@@ -32,7 +35,6 @@ ...@@ -32,7 +35,6 @@
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/route.h> #include <linux/route.h>
struct in_device;
#include <net/route.h> #include <net/route.h>
#if 0 #if 0
...@@ -41,46 +43,33 @@ struct in_device; ...@@ -41,46 +43,33 @@ struct in_device;
#define DEBUGP(format, args...) #define DEBUGP(format, args...)
#endif #endif
static int route_mirror(struct sk_buff *skb) static inline struct rtable *route_mirror(struct sk_buff *skb)
{ {
struct iphdr *iph = skb->nh.iph; struct iphdr *iph = skb->nh.iph;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr, struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
.saddr = iph->daddr, .saddr = iph->daddr,
.tos = RT_TOS(iph->tos) | RTO_CONN } } }; .tos = RT_TOS(iph->tos) } } };
struct rtable *rt; struct rtable *rt;
/* Backwards */ /* Backwards */
if (ip_route_output_key(&rt, &fl)) { if (ip_route_output_key(&rt, &fl))
return 0; return NULL;
}
/* check if the interface we are leaving by is the same as the return rt;
one we arrived on */
if (skb->dev == rt->u.dst.dev) {
/* Drop old route. */
dst_release(skb->dst);
skb->dst = &rt->u.dst;
return 1;
}
return 0;
} }
static int ip_rewrite(struct sk_buff **pskb) static inline void ip_rewrite(struct sk_buff *skb)
{ {
u32 odaddr, osaddr; u32 odaddr, osaddr;
if (!skb_ip_make_writable(pskb, sizeof(struct iphdr))) odaddr = skb->nh.iph->saddr;
return 0; osaddr = skb->nh.iph->daddr;
odaddr = (*pskb)->nh.iph->saddr; skb->nfcache |= NFC_ALTERED;
osaddr = (*pskb)->nh.iph->daddr;
(*pskb)->nfcache |= NFC_ALTERED;
/* Rewrite IP header */ /* Rewrite IP header */
(*pskb)->nh.iph->daddr = odaddr; skb->nh.iph->daddr = odaddr;
(*pskb)->nh.iph->saddr = osaddr; skb->nh.iph->saddr = osaddr;
return 1;
} }
/* Stolen from ip_finish_output2 */ /* Stolen from ip_finish_output2 */
...@@ -113,31 +102,51 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb, ...@@ -113,31 +102,51 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
if (((*pskb)->dst != NULL) && route_mirror(*pskb)) { struct rtable *rt;
if (!ip_rewrite(pskb)) struct sk_buff *nskb;
return NF_DROP; unsigned int hh_len;
/* If we are not at FORWARD hook (INPUT/PREROUTING), /* Make skb writable */
* the TTL isn't decreased by the IP stack */ if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
if (hooknum != NF_IP_FORWARD) { return 0;
if ((*pskb)->nh.iph->ttl <= 1) {
/* this will traverse normal stack, and /* If we are not at FORWARD hook (INPUT/PREROUTING),
* thus call conntrack on the icmp packet */ * the TTL isn't decreased by the IP stack */
icmp_send(*pskb, ICMP_TIME_EXCEEDED, if (hooknum != NF_IP_FORWARD) {
ICMP_EXC_TTL, 0); if ((*pskb)->nh.iph->ttl <= 1) {
return NF_DROP; /* this will traverse normal stack, and
} * thus call conntrack on the icmp packet */
/* Made writable by ip_rewrite */ icmp_send(*pskb, ICMP_TIME_EXCEEDED,
ip_decrease_ttl((*pskb)->nh.iph); ICMP_EXC_TTL, 0);
return NF_DROP;
} }
ip_decrease_ttl((*pskb)->nh.iph);
}
/* Don't let conntrack code see this packet: if ((rt = route_mirror(*pskb)) == NULL)
it will think we are starting a new return NF_DROP;
connection! --RR */
ip_direct_send(*pskb);
return NF_STOLEN; 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
* clone it because there may be other things, such as tcpdump,
* interested in it). We also need to expand headroom in case
* hh_len of incoming interface < hh_len of outgoing interface */
nskb = skb_copy_expand(*pskb, hh_len, skb_tailroom(*pskb), GFP_ATOMIC);
if (nskb == NULL) {
dst_release(&rt->u.dst);
return NF_DROP;
} }
dst_release(nskb->dst);
nskb->dst = &rt->u.dst;
ip_rewrite(nskb);
/* Don't let conntrack code see this packet:
* it will think we are starting a new
* connection! --RR */
ip_direct_send(*pskb);
return NF_DROP; return NF_DROP;
} }
......
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