2003-07-25 20:47:32

by Harald Welte

[permalink] [raw]
Subject: [PATCH 2.6] iptables MIRROR target fixes

Hi Dave!

This is the first of my 2.6 merge of the recent bugfixes (all tested
against 2.6.0-test1). You might need to apply them incrementally
(didn't test it in a different order).

Author: Patrick McHardy <[email protected]>

This patch fixes various problems with the experimental
iptables 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

Please apply,


--- linux-2.6.0-test1-nftest/net/ipv4/netfilter/ipt_MIRROR.c 2003-07-14 05:39:23.000000000 +0200
+++ linux-2.6.0-test1-nftest2/net/ipv4/netfilter/ipt_MIRROR.c 2003-07-19 16:05:13.000000000 +0200
@@ -9,6 +9,9 @@
Changes:
25 Aug 2001 Harald Welte <[email protected]>
- decrement and check TTL if not called from FORWARD hook
+ 18 Jul 2003 Harald Welte <[email protected]>
+ - 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
under the terms of the GNU General Public License as published by the
@@ -32,7 +35,6 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netdevice.h>
#include <linux/route.h>
-struct in_device;
#include <net/route.h>

#if 0
@@ -41,46 +43,33 @@
#define DEBUGP(format, args...)
#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 flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
.saddr = iph->daddr,
- .tos = RT_TOS(iph->tos) | RTO_CONN } } };
+ .tos = RT_TOS(iph->tos) } } };
struct rtable *rt;

/* Backwards */
- if (ip_route_output_key(&rt, &fl)) {
- return 0;
- }
+ if (ip_route_output_key(&rt, &fl))
+ return NULL;

- /* check if the interface we are leaving by is the same as the
- 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;
+ return rt;
}

-static int ip_rewrite(struct sk_buff **pskb)
+static inline void ip_rewrite(struct sk_buff *skb)
{
u32 odaddr, osaddr;

- if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
- return 0;
+ odaddr = skb->nh.iph->saddr;
+ osaddr = skb->nh.iph->daddr;

- odaddr = (*pskb)->nh.iph->saddr;
- osaddr = (*pskb)->nh.iph->daddr;
-
- (*pskb)->nfcache |= NFC_ALTERED;
+ skb->nfcache |= NFC_ALTERED;

/* Rewrite IP header */
- (*pskb)->nh.iph->daddr = odaddr;
- (*pskb)->nh.iph->saddr = osaddr;
- return 1;
+ skb->nh.iph->daddr = odaddr;
+ skb->nh.iph->saddr = osaddr;
}

/* Stolen from ip_finish_output2 */
@@ -113,31 +102,51 @@
const void *targinfo,
void *userinfo)
{
- if (((*pskb)->dst != NULL) && route_mirror(*pskb)) {
- if (!ip_rewrite(pskb))
- return NF_DROP;
+ struct rtable *rt;
+ struct sk_buff *nskb;
+ unsigned int hh_len;

- /* If we are not at FORWARD hook (INPUT/PREROUTING),
- * the TTL isn't decreased by the IP stack */
- if (hooknum != NF_IP_FORWARD) {
- if ((*pskb)->nh.iph->ttl <= 1) {
- /* this will traverse normal stack, and
- * thus call conntrack on the icmp packet */
- icmp_send(*pskb, ICMP_TIME_EXCEEDED,
- ICMP_EXC_TTL, 0);
- return NF_DROP;
- }
- /* Made writable by ip_rewrite */
- ip_decrease_ttl((*pskb)->nh.iph);
+ /* Make skb writable */
+ if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
+ return 0;
+
+ /* If we are not at FORWARD hook (INPUT/PREROUTING),
+ * the TTL isn't decreased by the IP stack */
+ if (hooknum != NF_IP_FORWARD) {
+ if ((*pskb)->nh.iph->ttl <= 1) {
+ /* this will traverse normal stack, and
+ * thus call conntrack on the icmp packet */
+ icmp_send(*pskb, ICMP_TIME_EXCEEDED,
+ ICMP_EXC_TTL, 0);
+ return NF_DROP;
}
+ ip_decrease_ttl((*pskb)->nh.iph);
+ }

- /* Don't let conntrack code see this packet:
- it will think we are starting a new
- connection! --RR */
- ip_direct_send(*pskb);
+ if ((rt = route_mirror(*pskb)) == NULL)
+ return NF_DROP;

- 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;
}

--
- 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


Attachments:
(No filename) (5.14 kB)
(No filename) (189.00 B)
Download all attachments