[8.09] kernel: refresh patches
[openwrt/svn-archive/archive.git] / target / linux / generic-2.4 / patches / 623-netfilter_ip6t_reject.patch
1 --- /dev/null
2 +++ b/net/ipv6/netfilter/ip6t_REJECT.c
3 @@ -0,0 +1,301 @@
4 +/*
5 + * This is a module which is used for rejecting packets.
6 + * Added support for customized reject packets (Jozsef Kadlecsik).
7 + * Sun 12 Nov 2000
8 + * Port to IPv6 / ip6tables (Harald Welte <laforge@gnumonks.org>)
9 + */
10 +#include <linux/config.h>
11 +#include <linux/module.h>
12 +#include <linux/skbuff.h>
13 +#include <linux/icmpv6.h>
14 +#include <net/tcp.h>
15 +#include <net/ipv6.h>
16 +#include <net/ip6_fib.h>
17 +#include <net/ip6_route.h>
18 +#include <linux/netfilter_ipv6/ip6_tables.h>
19 +#include <linux/netfilter_ipv6/ip6t_REJECT.h>
20 +
21 +#if 1
22 +#define DEBUGP printk
23 +#else
24 +#define DEBUGP(format, args...)
25 +#endif
26 +
27 +#if 0
28 +/* Send RST reply */
29 +static void send_reset(struct sk_buff *oldskb)
30 +{
31 + struct sk_buff *nskb;
32 + struct tcphdr *otcph, *tcph;
33 + struct rtable *rt;
34 + unsigned int otcplen;
35 + int needs_ack;
36 +
37 + /* IP header checks: fragment, too short. */
38 + if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
39 + || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
40 + return;
41 +
42 + otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
43 + otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
44 +
45 + /* No RST for RST. */
46 + if (otcph->rst)
47 + return;
48 +
49 + /* Check checksum. */
50 + if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
51 + oldskb->nh.iph->daddr,
52 + csum_partial((char *)otcph, otcplen, 0)) != 0)
53 + return;
54 +
55 + /* Copy skb (even if skb is about to be dropped, we can't just
56 + clone it because there may be other things, such as tcpdump,
57 + interested in it) */
58 + nskb = skb_copy(oldskb, GFP_ATOMIC);
59 + if (!nskb)
60 + return;
61 +
62 + /* This packet will not be the same as the other: clear nf fields */
63 + nf_conntrack_put(nskb->nfct);
64 + nskb->nfct = NULL;
65 + nskb->nfcache = 0;
66 +#ifdef CONFIG_NETFILTER_DEBUG
67 + nskb->nf_debug = 0;
68 +#endif
69 +
70 + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
71 +
72 + nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
73 + tcph->source = xchg(&tcph->dest, tcph->source);
74 +
75 + /* Truncate to length (no data) */
76 + tcph->doff = sizeof(struct tcphdr)/4;
77 + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
78 + nskb->nh.iph->tot_len = htons(nskb->len);
79 +
80 + if (tcph->ack) {
81 + needs_ack = 0;
82 + tcph->seq = otcph->ack_seq;
83 + tcph->ack_seq = 0;
84 + } else {
85 + needs_ack = 1;
86 + tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
87 + + otcplen - (otcph->doff<<2));
88 + tcph->seq = 0;
89 + }
90 +
91 + /* Reset flags */
92 + ((u_int8_t *)tcph)[13] = 0;
93 + tcph->rst = 1;
94 + tcph->ack = needs_ack;
95 +
96 + tcph->window = 0;
97 + tcph->urg_ptr = 0;
98 +
99 + /* Adjust TCP checksum */
100 + tcph->check = 0;
101 + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
102 + nskb->nh.iph->saddr,
103 + nskb->nh.iph->daddr,
104 + csum_partial((char *)tcph,
105 + sizeof(struct tcphdr), 0));
106 +
107 + /* Adjust IP TTL, DF */
108 + nskb->nh.iph->ttl = MAXTTL;
109 + /* Set DF, id = 0 */
110 + nskb->nh.iph->frag_off = htons(IP_DF);
111 + nskb->nh.iph->id = 0;
112 +
113 + /* Adjust IP checksum */
114 + nskb->nh.iph->check = 0;
115 + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
116 + nskb->nh.iph->ihl);
117 +
118 + /* Routing */
119 + if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr,
120 + RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
121 + 0) != 0)
122 + goto free_nskb;
123 +
124 + dst_release(nskb->dst);
125 + nskb->dst = &rt->u.dst;
126 +
127 + /* "Never happens" */
128 + if (nskb->len > nskb->dst->pmtu)
129 + goto free_nskb;
130 +
131 + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
132 + ip_finish_output);
133 + return;
134 +
135 + free_nskb:
136 + kfree_skb(nskb);
137 +}
138 +#endif
139 +
140 +static unsigned int reject6_target(struct sk_buff **pskb,
141 + unsigned int hooknum,
142 + const struct net_device *in,
143 + const struct net_device *out,
144 + const void *targinfo,
145 + void *userinfo)
146 +{
147 + const struct ip6t_reject_info *reject = targinfo;
148 + struct sk_buff *skb2 = NULL;
149 + struct rt6_info *rt6i;
150 + struct net_device odev;
151 +
152 + if (!out) {
153 + skb2 = skb_clone(*pskb, GFP_ATOMIC);
154 + if (skb2 == NULL) {
155 + return NF_DROP;
156 + }
157 + dst_release(skb2->dst);
158 + skb2->dst = NULL;
159 +
160 + rt6i = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
161 + if (rt6i && rt6i->rt6i_dev) {
162 + skb2->dev = rt6i->rt6i_dev;
163 + rt6i = rt6_lookup(&skb2->nh.ipv6h->daddr, &skb2->nh.ipv6h->saddr, 0, 0);
164 + }
165 + memcpy(&odev, skb2->dev, sizeof(odev)); /* XXX 'out' has 'const' qualifier... */
166 + } else {
167 + memcpy(&odev, out, sizeof(odev));
168 + }
169 +
170 + printk(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
171 + /* WARNING: This code causes reentry within ip6tables.
172 + This means that the ip6tables jump stack is now crap. We
173 + must return an absolute verdict. --RR */
174 + DEBUGP("REJECTv6: calling icmpv6_send\n");
175 + switch (reject->with) {
176 + case IP6T_ICMP6_NO_ROUTE:
177 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, &odev);
178 + break;
179 + case IP6T_ICMP6_ADM_PROHIBITED:
180 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, &odev);
181 + break;
182 + case IP6T_ICMP6_NOT_NEIGHBOUR:
183 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, &odev);
184 + break;
185 + case IP6T_ICMP6_ADDR_UNREACH:
186 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, &odev);
187 + break;
188 + case IP6T_ICMP6_PORT_UNREACH:
189 + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, &odev);
190 + break;
191 +#if 0
192 + case IPT_ICMP_ECHOREPLY: {
193 + struct icmp6hdr *icmph = (struct icmphdr *)
194 + ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl);
195 + unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
196 +
197 + /* Not non-head frags, or truncated */
198 + if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0)
199 + && datalen >= 4) {
200 + /* Usually I don't like cut & pasting code,
201 + but dammit, my party is starting in 45
202 + mins! --RR */
203 + struct icmp_bxm icmp_param;
204 +
205 + icmp_param.icmph=*icmph;
206 + icmp_param.icmph.type=ICMP_ECHOREPLY;
207 + icmp_param.data_ptr=(icmph+1);
208 + icmp_param.data_len=datalen;
209 + icmp_reply(&icmp_param, *pskb);
210 + }
211 + }
212 + break;
213 + case IPT_TCP_RESET:
214 + send_reset(*pskb);
215 + break;
216 +#endif
217 + default:
218 + printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with);
219 + break;
220 + }
221 +
222 + if (skb2) kfree_skb(skb2);
223 +
224 + return NF_DROP;
225 +}
226 +
227 +static inline int find_ping_match(const struct ip6t_entry_match *m)
228 +{
229 + const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data;
230 +
231 + if (strcmp(m->u.kernel.match->name, "icmp6") == 0
232 + && icmpinfo->type == ICMPV6_ECHO_REQUEST
233 + && !(icmpinfo->invflags & IP6T_ICMP_INV))
234 + return 1;
235 +
236 + return 0;
237 +}
238 +
239 +static int check(const char *tablename,
240 + const struct ip6t_entry *e,
241 + void *targinfo,
242 + unsigned int targinfosize,
243 + unsigned int hook_mask)
244 +{
245 + const struct ip6t_reject_info *rejinfo = targinfo;
246 +
247 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
248 + DEBUGP("REJECTv6: targinfosize %u != 0\n", targinfosize);
249 + return 0;
250 + }
251 +
252 + /* Only allow these for packet filtering. */
253 + if (strcmp(tablename, "filter") != 0) {
254 + DEBUGP("REJECTv6: bad table `%s'.\n", tablename);
255 + return 0;
256 + }
257 + if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
258 + | (1 << NF_IP6_FORWARD)
259 + | (1 << NF_IP6_LOCAL_OUT))) != 0) {
260 + DEBUGP("REJECTv6: bad hook mask %X\n", hook_mask);
261 + return 0;
262 + }
263 +
264 + if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
265 + /* Must specify that it's an ICMP ping packet. */
266 + if (e->ipv6.proto != IPPROTO_ICMPV6
267 + || (e->ipv6.invflags & IP6T_INV_PROTO)) {
268 + DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n");
269 + return 0;
270 + }
271 + /* Must contain ICMP match. */
272 + if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) {
273 + DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\n");
274 + return 0;
275 + }
276 + } else if (rejinfo->with == IP6T_TCP_RESET) {
277 + /* Must specify that it's a TCP packet */
278 + if (e->ipv6.proto != IPPROTO_TCP
279 + || (e->ipv6.invflags & IP6T_INV_PROTO)) {
280 + DEBUGP("REJECTv6: TCP_RESET illegal for non-tcp\n");
281 + return 0;
282 + }
283 + }
284 +
285 + return 1;
286 +}
287 +
288 +static struct ip6t_target ip6t_reject_reg
289 += { { NULL, NULL }, "REJECT", reject6_target, check, NULL, THIS_MODULE };
290 +
291 +static int __init init(void)
292 +{
293 + if (ip6t_register_target(&ip6t_reject_reg))
294 + return -EINVAL;
295 + return 0;
296 +}
297 +
298 +static void __exit fini(void)
299 +{
300 + ip6t_unregister_target(&ip6t_reject_reg);
301 +}
302 +
303 +module_init(init);
304 +module_exit(fini);
305 --- a/include/linux/netfilter_ipv6/ip6t_REJECT.h
306 +++ b/include/linux/netfilter_ipv6/ip6t_REJECT.h
307 @@ -2,15 +2,17 @@
308 #define _IP6T_REJECT_H
309
310 enum ip6t_reject_with {
311 - IP6T_ICMP_NET_UNREACHABLE,
312 - IP6T_ICMP_HOST_UNREACHABLE,
313 - IP6T_ICMP_PROT_UNREACHABLE,
314 - IP6T_ICMP_PORT_UNREACHABLE,
315 - IP6T_ICMP_ECHOREPLY
316 + IP6T_ICMP6_NO_ROUTE,
317 + IP6T_ICMP6_ADM_PROHIBITED,
318 + IP6T_ICMP6_NOT_NEIGHBOUR,
319 + IP6T_ICMP6_ADDR_UNREACH,
320 + IP6T_ICMP6_PORT_UNREACH,
321 + IP6T_ICMP6_ECHOREPLY,
322 + IP6T_TCP_RESET
323 };
324
325 struct ip6t_reject_info {
326 enum ip6t_reject_with with; /* reject type */
327 };
328
329 -#endif /*_IPT_REJECT_H*/
330 +#endif /*_IP6T_REJECT_H*/
331 --- a/net/ipv6/netfilter/Makefile
332 +++ b/net/ipv6/netfilter/Makefile
333 @@ -34,5 +34,7 @@ obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.
334 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
335 obj-$(CONFIG_IP6_NF_MATCH_RANDOM) += ip6t_random.o
336 obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
337 +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
338 +
339
340 include $(TOPDIR)/Rules.make
341 --- a/net/ipv6/netfilter/Config.in
342 +++ b/net/ipv6/netfilter/Config.in
343 @@ -61,6 +61,9 @@ if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ];
344 if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
345 dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_FILTER
346 fi
347 + if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
348 + dep_tristate ' REJECT target support' CONFIG_IP6_NF_TARGET_REJECT $CONFIG_IP6_NF_FILTER
349 + fi
350
351 # if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
352 # dep_tristate ' REJECT target support' CONFIG_IP6_NF_TARGET_REJECT $CONFIG_IP6_NF_FILTER