From 5bd47dc8bd8b44933c0888c304cd66851551a56f Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Mon, 18 Feb 2008 08:03:28 +0000
Subject: [PATCH] generic-2.4: add ip6t_REJECT support

SVN-Revision: 10482
---
 target/linux/generic-2.4/config-default       |   1 +
 .../patches/623-netfilter_ip6t_reject.patch   | 360 ++++++++++++++++++
 2 files changed, 361 insertions(+)
 create mode 100644 target/linux/generic-2.4/patches/623-netfilter_ip6t_reject.patch

diff --git a/target/linux/generic-2.4/config-default b/target/linux/generic-2.4/config-default
index 411e2c3aca..acf57937a1 100644
--- a/target/linux/generic-2.4/config-default
+++ b/target/linux/generic-2.4/config-default
@@ -198,6 +198,7 @@ CONFIG_IP6_NF_MATCH_RANDOM=m
 CONFIG_IP6_NF_TARGET_IMQ=m
 CONFIG_IP6_NF_TARGET_LOG=m
 CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_TARGET_REJECT=m
 # CONFIG_IPMI_DEVICE_INTERFACE is not set
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_IPMI_KCS is not set
diff --git a/target/linux/generic-2.4/patches/623-netfilter_ip6t_reject.patch b/target/linux/generic-2.4/patches/623-netfilter_ip6t_reject.patch
new file mode 100644
index 0000000000..2caae3ab01
--- /dev/null
+++ b/target/linux/generic-2.4/patches/623-netfilter_ip6t_reject.patch
@@ -0,0 +1,360 @@
+Index: linux-2.4.35.4/net/ipv6/netfilter/ip6t_REJECT.c
+===================================================================
+--- /dev/null
++++ linux-2.4.35.4/net/ipv6/netfilter/ip6t_REJECT.c
+@@ -0,0 +1,301 @@
++/*
++ * This is a module which is used for rejecting packets.
++ * 	Added support for customized reject packets (Jozsef Kadlecsik).
++ * Sun 12 Nov 2000
++ * 	Port to IPv6 / ip6tables (Harald Welte <laforge@gnumonks.org>)
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/icmpv6.h>
++#include <net/tcp.h>
++#include <net/ipv6.h>
++#include <net/ip6_fib.h>
++#include <net/ip6_route.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_REJECT.h>
++
++#if 1
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#if 0
++/* Send RST reply */
++static void send_reset(struct sk_buff *oldskb)
++{
++	struct sk_buff *nskb;
++	struct tcphdr *otcph, *tcph;
++	struct rtable *rt;
++	unsigned int otcplen;
++	int needs_ack;
++
++	/* IP header checks: fragment, too short. */
++	if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
++	    || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
++		return;
++
++	otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
++	otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
++
++	/* No RST for RST. */
++	if (otcph->rst)
++		return;
++
++	/* Check checksum. */
++	if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
++			 oldskb->nh.iph->daddr,
++			 csum_partial((char *)otcph, otcplen, 0)) != 0)
++		return;
++
++	/* 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) */
++	nskb = skb_copy(oldskb, GFP_ATOMIC);
++	if (!nskb)
++		return;
++
++	/* This packet will not be the same as the other: clear nf fields */
++	nf_conntrack_put(nskb->nfct);
++	nskb->nfct = NULL;
++	nskb->nfcache = 0;
++#ifdef CONFIG_NETFILTER_DEBUG
++	nskb->nf_debug = 0;
++#endif
++
++	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
++
++	nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
++	tcph->source = xchg(&tcph->dest, tcph->source);
++
++	/* Truncate to length (no data) */
++	tcph->doff = sizeof(struct tcphdr)/4;
++	skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
++	nskb->nh.iph->tot_len = htons(nskb->len);
++
++	if (tcph->ack) {
++		needs_ack = 0;
++		tcph->seq = otcph->ack_seq;
++		tcph->ack_seq = 0;
++	} else {
++		needs_ack = 1;
++		tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
++				      + otcplen - (otcph->doff<<2));
++		tcph->seq = 0;
++	}
++
++	/* Reset flags */
++	((u_int8_t *)tcph)[13] = 0;
++	tcph->rst = 1;
++	tcph->ack = needs_ack;
++
++	tcph->window = 0;
++	tcph->urg_ptr = 0;
++
++	/* Adjust TCP checksum */
++	tcph->check = 0;
++	tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
++				   nskb->nh.iph->saddr,
++				   nskb->nh.iph->daddr,
++				   csum_partial((char *)tcph,
++						sizeof(struct tcphdr), 0));
++
++	/* Adjust IP TTL, DF */
++	nskb->nh.iph->ttl = MAXTTL;
++	/* Set DF, id = 0 */
++	nskb->nh.iph->frag_off = htons(IP_DF);
++	nskb->nh.iph->id = 0;
++
++	/* Adjust IP checksum */
++	nskb->nh.iph->check = 0;
++	nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
++					   nskb->nh.iph->ihl);
++
++	/* Routing */
++	if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr,
++			    RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
++			    0) != 0)
++		goto free_nskb;
++
++	dst_release(nskb->dst);
++	nskb->dst = &rt->u.dst;
++
++	/* "Never happens" */
++	if (nskb->len > nskb->dst->pmtu)
++		goto free_nskb;
++
++	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
++		ip_finish_output);
++	return;
++
++ free_nskb:
++	kfree_skb(nskb);
++}
++#endif
++
++static unsigned int reject6_target(struct sk_buff **pskb,
++			   unsigned int hooknum,
++			   const struct net_device *in,
++			   const struct net_device *out,
++			   const void *targinfo,
++			   void *userinfo)
++{
++	const struct ip6t_reject_info *reject = targinfo;
++	struct sk_buff *skb2 = NULL;
++	struct rt6_info *rt6i;
++	struct net_device odev;
++
++	if (!out) {
++		skb2 = skb_clone(*pskb, GFP_ATOMIC);
++		if (skb2 == NULL) {
++			return NF_DROP;
++		}
++		dst_release(skb2->dst);
++		skb2->dst = NULL;
++
++		rt6i = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
++		if (rt6i && rt6i->rt6i_dev) {
++			skb2->dev = rt6i->rt6i_dev;
++			rt6i = rt6_lookup(&skb2->nh.ipv6h->daddr, &skb2->nh.ipv6h->saddr, 0, 0);
++		}
++		memcpy(&odev, skb2->dev, sizeof(odev)); /* XXX 'out' has 'const' qualifier... */
++	} else {
++		memcpy(&odev, out, sizeof(odev));
++	}
++
++	printk(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
++	/* WARNING: This code causes reentry within ip6tables.
++	   This means that the ip6tables jump stack is now crap.  We
++	   must return an absolute verdict. --RR */
++	DEBUGP("REJECTv6: calling icmpv6_send\n");
++    	switch (reject->with) {
++    	case IP6T_ICMP6_NO_ROUTE:
++    		icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, &odev);
++    		break;
++    	case IP6T_ICMP6_ADM_PROHIBITED:
++    		icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, &odev);
++    		break;
++    	case IP6T_ICMP6_NOT_NEIGHBOUR:
++    		icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, &odev);
++    		break;
++    	case IP6T_ICMP6_ADDR_UNREACH:
++    		icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, &odev);
++    		break;
++    	case IP6T_ICMP6_PORT_UNREACH:
++    		icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, &odev);
++    		break;
++#if 0
++    	case IPT_ICMP_ECHOREPLY: {
++		struct icmp6hdr *icmph  = (struct icmphdr *)
++			((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl);
++		unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
++
++		/* Not non-head frags, or truncated */
++		if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0)
++		    && datalen >= 4) {
++			/* Usually I don't like cut & pasting code,
++                           but dammit, my party is starting in 45
++                           mins! --RR */
++			struct icmp_bxm icmp_param;
++
++			icmp_param.icmph=*icmph;
++			icmp_param.icmph.type=ICMP_ECHOREPLY;
++			icmp_param.data_ptr=(icmph+1);
++			icmp_param.data_len=datalen;
++			icmp_reply(&icmp_param, *pskb);
++		}
++	}
++	break;
++	case IPT_TCP_RESET:
++		send_reset(*pskb);
++		break;
++#endif
++	default:
++		printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with);
++		break;
++	}
++
++	if (skb2) kfree_skb(skb2);
++
++	return NF_DROP;
++}
++
++static inline int find_ping_match(const struct ip6t_entry_match *m)
++{
++	const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data;
++
++	if (strcmp(m->u.kernel.match->name, "icmp6") == 0
++	    && icmpinfo->type == ICMPV6_ECHO_REQUEST
++	    && !(icmpinfo->invflags & IP6T_ICMP_INV))
++		return 1;
++
++	return 0;
++}
++
++static int check(const char *tablename,
++		 const struct ip6t_entry *e,
++		 void *targinfo,
++		 unsigned int targinfosize,
++		 unsigned int hook_mask)
++{
++ 	const struct ip6t_reject_info *rejinfo = targinfo;
++
++ 	if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
++  		DEBUGP("REJECTv6: targinfosize %u != 0\n", targinfosize);
++  		return 0;
++  	}
++
++	/* Only allow these for packet filtering. */
++	if (strcmp(tablename, "filter") != 0) {
++		DEBUGP("REJECTv6: bad table `%s'.\n", tablename);
++		return 0;
++	}
++	if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
++			   | (1 << NF_IP6_FORWARD)
++			   | (1 << NF_IP6_LOCAL_OUT))) != 0) {
++		DEBUGP("REJECTv6: bad hook mask %X\n", hook_mask);
++		return 0;
++	}
++
++	if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
++		/* Must specify that it's an ICMP ping packet. */
++		if (e->ipv6.proto != IPPROTO_ICMPV6
++		    || (e->ipv6.invflags & IP6T_INV_PROTO)) {
++			DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n");
++			return 0;
++		}
++		/* Must contain ICMP match. */
++		if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) {
++			DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\n");
++			return 0;
++		}
++	} else if (rejinfo->with == IP6T_TCP_RESET) {
++		/* Must specify that it's a TCP packet */
++		if (e->ipv6.proto != IPPROTO_TCP
++		    || (e->ipv6.invflags & IP6T_INV_PROTO)) {
++			DEBUGP("REJECTv6: TCP_RESET illegal for non-tcp\n");
++			return 0;
++		}
++	}
++
++	return 1;
++}
++
++static struct ip6t_target ip6t_reject_reg
++= { { NULL, NULL }, "REJECT", reject6_target, check, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++	if (ip6t_register_target(&ip6t_reject_reg))
++		return -EINVAL;
++	return 0;
++}
++
++static void __exit fini(void)
++{
++	ip6t_unregister_target(&ip6t_reject_reg);
++}
++
++module_init(init);
++module_exit(fini);
+Index: linux-2.4.35.4/include/linux/netfilter_ipv6/ip6t_REJECT.h
+===================================================================
+--- linux-2.4.35.4.orig/include/linux/netfilter_ipv6/ip6t_REJECT.h
++++ linux-2.4.35.4/include/linux/netfilter_ipv6/ip6t_REJECT.h
+@@ -2,15 +2,17 @@
+ #define _IP6T_REJECT_H
+ 
+ enum ip6t_reject_with {
+-	IP6T_ICMP_NET_UNREACHABLE,
+-	IP6T_ICMP_HOST_UNREACHABLE,
+-	IP6T_ICMP_PROT_UNREACHABLE,
+-	IP6T_ICMP_PORT_UNREACHABLE,
+-	IP6T_ICMP_ECHOREPLY
++	IP6T_ICMP6_NO_ROUTE,
++	IP6T_ICMP6_ADM_PROHIBITED,
++	IP6T_ICMP6_NOT_NEIGHBOUR,
++	IP6T_ICMP6_ADDR_UNREACH,
++	IP6T_ICMP6_PORT_UNREACH,
++	IP6T_ICMP6_ECHOREPLY,
++	IP6T_TCP_RESET
+ };
+ 
+ struct ip6t_reject_info {
+ 	enum ip6t_reject_with with;      /* reject type */
+ };
+ 
+-#endif /*_IPT_REJECT_H*/
++#endif /*_IP6T_REJECT_H*/
+Index: linux-2.4.35.4/net/ipv6/netfilter/Makefile
+===================================================================
+--- linux-2.4.35.4.orig/net/ipv6/netfilter/Makefile
++++ linux-2.4.35.4/net/ipv6/netfilter/Makefile
+@@ -34,5 +34,7 @@ obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.
+ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
+ obj-$(CONFIG_IP6_NF_MATCH_RANDOM) += ip6t_random.o
+ obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
++obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
++
+ 
+ include $(TOPDIR)/Rules.make
+Index: linux-2.4.35.4/net/ipv6/netfilter/Config.in
+===================================================================
+--- linux-2.4.35.4.orig/net/ipv6/netfilter/Config.in
++++ linux-2.4.35.4/net/ipv6/netfilter/Config.in
+@@ -61,6 +61,9 @@ if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ];
+   if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
+     dep_tristate '    LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_FILTER
+   fi
++  if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
++    dep_tristate '    REJECT target support' CONFIG_IP6_NF_TARGET_REJECT $CONFIG_IP6_NF_FILTER
++  fi
+ 
+ #  if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
+ #    dep_tristate '    REJECT target support' CONFIG_IP6_NF_TARGET_REJECT $CONFIG_IP6_NF_FILTER
-- 
GitLab