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