1/*
2 * INET		An implementation of the TCP/IP protocol suite for the LINUX
3 *		operating system.  INET is implemented using the  BSD Socket
4 *		interface as the means of communication with the user level.
5 *
6 *		The options processing module for ip.c
7 *
8 * Version:	$Id: ip_options.c,v 1.1.1.1 2007/08/03 18:53:51 Exp $
9 *
10 * Authors:	A.N.Kuznetsov
11 *
12 */
13
14#include <linux/capability.h>
15#include <linux/module.h>
16#include <linux/types.h>
17#include <asm/uaccess.h>
18#include <linux/skbuff.h>
19#include <linux/ip.h>
20#include <linux/icmp.h>
21#include <linux/netdevice.h>
22#include <linux/rtnetlink.h>
23#include <net/sock.h>
24#include <net/ip.h>
25#include <net/icmp.h>
26#include <net/route.h>
27#include <net/cipso_ipv4.h>
28
29/*
30 * Write options to IP header, record destination address to
31 * source route option, address of outgoing interface
32 * (we should already know it, so that this  function is allowed be
33 * called only after routing decision) and timestamp,
34 * if we originate this datagram.
35 *
36 * daddr is real destination address, next hop is recorded in IP header.
37 * saddr is address of outgoing interface.
38 */
39
40void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
41			    __be32 daddr, struct rtable *rt, int is_frag)
42{
43	unsigned char *iph = skb_network_header(skb);
44
45	memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options));
46	memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen);
47	opt = &(IPCB(skb)->opt);
48	opt->is_data = 0;
49
50	if (opt->srr)
51		memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4);
52
53	if (!is_frag) {
54		if (opt->rr_needaddr)
55			ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, rt);
56		if (opt->ts_needaddr)
57			ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt);
58		if (opt->ts_needtime) {
59			struct timeval tv;
60			__be32 midtime;
61			do_gettimeofday(&tv);
62			midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
63			memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);
64		}
65		return;
66	}
67	if (opt->rr) {
68		memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]);
69		opt->rr = 0;
70		opt->rr_needaddr = 0;
71	}
72	if (opt->ts) {
73		memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]);
74		opt->ts = 0;
75		opt->ts_needaddr = opt->ts_needtime = 0;
76	}
77}
78
79/*
80 * Provided (sopt, skb) points to received options,
81 * build in dopt compiled option set appropriate for answering.
82 * i.e. invert SRR option, copy anothers,
83 * and grab room in RR/TS options.
84 *
85 * NOTE: dopt cannot point to skb.
86 */
87
88int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
89{
90	struct ip_options *sopt;
91	unsigned char *sptr, *dptr;
92	int soffset, doffset;
93	int	optlen;
94	__be32	daddr;
95
96	memset(dopt, 0, sizeof(struct ip_options));
97
98	dopt->is_data = 1;
99
100	sopt = &(IPCB(skb)->opt);
101
102	if (sopt->optlen == 0) {
103		dopt->optlen = 0;
104		return 0;
105	}
106
107	sptr = skb_network_header(skb);
108	dptr = dopt->__data;
109
110	if (skb->dst)
111		daddr = ((struct rtable*)skb->dst)->rt_spec_dst;
112	else
113		daddr = ip_hdr(skb)->daddr;
114
115	if (sopt->rr) {
116		optlen  = sptr[sopt->rr+1];
117		soffset = sptr[sopt->rr+2];
118		dopt->rr = dopt->optlen + sizeof(struct iphdr);
119		memcpy(dptr, sptr+sopt->rr, optlen);
120		if (sopt->rr_needaddr && soffset <= optlen) {
121			if (soffset + 3 > optlen)
122				return -EINVAL;
123			dptr[2] = soffset + 4;
124			dopt->rr_needaddr = 1;
125		}
126		dptr += optlen;
127		dopt->optlen += optlen;
128	}
129	if (sopt->ts) {
130		optlen = sptr[sopt->ts+1];
131		soffset = sptr[sopt->ts+2];
132		dopt->ts = dopt->optlen + sizeof(struct iphdr);
133		memcpy(dptr, sptr+sopt->ts, optlen);
134		if (soffset <= optlen) {
135			if (sopt->ts_needaddr) {
136				if (soffset + 3 > optlen)
137					return -EINVAL;
138				dopt->ts_needaddr = 1;
139				soffset += 4;
140			}
141			if (sopt->ts_needtime) {
142				if (soffset + 3 > optlen)
143					return -EINVAL;
144				if ((dptr[3]&0xF) != IPOPT_TS_PRESPEC) {
145					dopt->ts_needtime = 1;
146					soffset += 4;
147				} else {
148					dopt->ts_needtime = 0;
149
150					if (soffset + 8 <= optlen) {
151						__be32 addr;
152
153						memcpy(&addr, sptr+soffset-1, 4);
154						if (inet_addr_type(addr) != RTN_LOCAL) {
155							dopt->ts_needtime = 1;
156							soffset += 8;
157						}
158					}
159				}
160			}
161			dptr[2] = soffset;
162		}
163		dptr += optlen;
164		dopt->optlen += optlen;
165	}
166	if (sopt->srr) {
167		unsigned char * start = sptr+sopt->srr;
168		__be32 faddr;
169
170		optlen  = start[1];
171		soffset = start[2];
172		doffset = 0;
173		if (soffset > optlen)
174			soffset = optlen + 1;
175		soffset -= 4;
176		if (soffset > 3) {
177			memcpy(&faddr, &start[soffset-1], 4);
178			for (soffset-=4, doffset=4; soffset > 3; soffset-=4, doffset+=4)
179				memcpy(&dptr[doffset-1], &start[soffset-1], 4);
180			/*
181			 * RFC1812 requires to fix illegal source routes.
182			 */
183			if (memcmp(&ip_hdr(skb)->saddr,
184				   &start[soffset + 3], 4) == 0)
185				doffset -= 4;
186		}
187		if (doffset > 3) {
188			memcpy(&start[doffset-1], &daddr, 4);
189			dopt->faddr = faddr;
190			dptr[0] = start[0];
191			dptr[1] = doffset+3;
192			dptr[2] = 4;
193			dptr += doffset+3;
194			dopt->srr = dopt->optlen + sizeof(struct iphdr);
195			dopt->optlen += doffset+3;
196			dopt->is_strictroute = sopt->is_strictroute;
197		}
198	}
199	if (sopt->cipso) {
200		optlen  = sptr[sopt->cipso+1];
201		dopt->cipso = dopt->optlen+sizeof(struct iphdr);
202		memcpy(dptr, sptr+sopt->cipso, optlen);
203		dptr += optlen;
204		dopt->optlen += optlen;
205	}
206	while (dopt->optlen & 3) {
207		*dptr++ = IPOPT_END;
208		dopt->optlen++;
209	}
210	return 0;
211}
212
213/*
214 *	Options "fragmenting", just fill options not
215 *	allowed in fragments with NOOPs.
216 *	Simple and stupid 8), but the most efficient way.
217 */
218
219void ip_options_fragment(struct sk_buff * skb)
220{
221	unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr);
222	struct ip_options * opt = &(IPCB(skb)->opt);
223	int  l = opt->optlen;
224	int  optlen;
225
226	while (l > 0) {
227		switch (*optptr) {
228		case IPOPT_END:
229			return;
230		case IPOPT_NOOP:
231			l--;
232			optptr++;
233			continue;
234		}
235		optlen = optptr[1];
236		if (optlen<2 || optlen>l)
237		  return;
238		if (!IPOPT_COPIED(*optptr))
239			memset(optptr, IPOPT_NOOP, optlen);
240		l -= optlen;
241		optptr += optlen;
242	}
243	opt->ts = 0;
244	opt->rr = 0;
245	opt->rr_needaddr = 0;
246	opt->ts_needaddr = 0;
247	opt->ts_needtime = 0;
248	return;
249}
250
251/*
252 * Verify options and fill pointers in struct options.
253 * Caller should clear *opt, and set opt->data.
254 * If opt == NULL, then skb->data should point to IP header.
255 */
256
257int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
258{
259	int l;
260	unsigned char * iph;
261	unsigned char * optptr;
262	int optlen;
263	unsigned char * pp_ptr = NULL;
264	struct rtable *rt = skb ? (struct rtable*)skb->dst : NULL;
265
266	if (!opt) {
267		opt = &(IPCB(skb)->opt);
268		iph = skb_network_header(skb);
269		opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr);
270		optptr = iph + sizeof(struct iphdr);
271		opt->is_data = 0;
272	} else {
273		optptr = opt->is_data ? opt->__data :
274					(unsigned char *)&(ip_hdr(skb)[1]);
275		iph = optptr - sizeof(struct iphdr);
276	}
277
278	for (l = opt->optlen; l > 0; ) {
279		switch (*optptr) {
280		      case IPOPT_END:
281			for (optptr++, l--; l>0; optptr++, l--) {
282				if (*optptr != IPOPT_END) {
283					*optptr = IPOPT_END;
284					opt->is_changed = 1;
285				}
286			}
287			goto eol;
288		      case IPOPT_NOOP:
289			l--;
290			optptr++;
291			continue;
292		}
293		optlen = optptr[1];
294		if (optlen<2 || optlen>l) {
295			pp_ptr = optptr;
296			goto error;
297		}
298		switch (*optptr) {
299		      case IPOPT_SSRR:
300		      case IPOPT_LSRR:
301			if (optlen < 3) {
302				pp_ptr = optptr + 1;
303				goto error;
304			}
305			if (optptr[2] < 4) {
306				pp_ptr = optptr + 2;
307				goto error;
308			}
309			/* NB: cf RFC-1812 5.2.4.1 */
310			if (opt->srr) {
311				pp_ptr = optptr;
312				goto error;
313			}
314			if (!skb) {
315				if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) {
316					pp_ptr = optptr + 1;
317					goto error;
318				}
319				memcpy(&opt->faddr, &optptr[3], 4);
320				if (optlen > 7)
321					memmove(&optptr[3], &optptr[7], optlen-7);
322			}
323			opt->is_strictroute = (optptr[0] == IPOPT_SSRR);
324			opt->srr = optptr - iph;
325			break;
326		      case IPOPT_RR:
327			if (opt->rr) {
328				pp_ptr = optptr;
329				goto error;
330			}
331			if (optlen < 3) {
332				pp_ptr = optptr + 1;
333				goto error;
334			}
335			if (optptr[2] < 4) {
336				pp_ptr = optptr + 2;
337				goto error;
338			}
339			if (optptr[2] <= optlen) {
340				if (optptr[2]+3 > optlen) {
341					pp_ptr = optptr + 2;
342					goto error;
343				}
344				if (skb) {
345					memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
346					opt->is_changed = 1;
347				}
348				optptr[2] += 4;
349				opt->rr_needaddr = 1;
350			}
351			opt->rr = optptr - iph;
352			break;
353		      case IPOPT_TIMESTAMP:
354			if (opt->ts) {
355				pp_ptr = optptr;
356				goto error;
357			}
358			if (optlen < 4) {
359				pp_ptr = optptr + 1;
360				goto error;
361			}
362			if (optptr[2] < 5) {
363				pp_ptr = optptr + 2;
364				goto error;
365			}
366			if (optptr[2] <= optlen) {
367				__be32 *timeptr = NULL;
368				if (optptr[2]+3 > optptr[1]) {
369					pp_ptr = optptr + 2;
370					goto error;
371				}
372				switch (optptr[3]&0xF) {
373				      case IPOPT_TS_TSONLY:
374					opt->ts = optptr - iph;
375					if (skb)
376						timeptr = (__be32*)&optptr[optptr[2]-1];
377					opt->ts_needtime = 1;
378					optptr[2] += 4;
379					break;
380				      case IPOPT_TS_TSANDADDR:
381					if (optptr[2]+7 > optptr[1]) {
382						pp_ptr = optptr + 2;
383						goto error;
384					}
385					opt->ts = optptr - iph;
386					if (skb) {
387						memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
388						timeptr = (__be32*)&optptr[optptr[2]+3];
389					}
390					opt->ts_needaddr = 1;
391					opt->ts_needtime = 1;
392					optptr[2] += 8;
393					break;
394				      case IPOPT_TS_PRESPEC:
395					if (optptr[2]+7 > optptr[1]) {
396						pp_ptr = optptr + 2;
397						goto error;
398					}
399					opt->ts = optptr - iph;
400					{
401						__be32 addr;
402						memcpy(&addr, &optptr[optptr[2]-1], 4);
403						if (inet_addr_type(addr) == RTN_UNICAST)
404							break;
405						if (skb)
406							timeptr = (__be32*)&optptr[optptr[2]+3];
407					}
408					opt->ts_needtime = 1;
409					optptr[2] += 8;
410					break;
411				      default:
412					if (!skb && !capable(CAP_NET_RAW)) {
413						pp_ptr = optptr + 3;
414						goto error;
415					}
416					break;
417				}
418				if (timeptr) {
419					struct timeval tv;
420					__be32  midtime;
421					do_gettimeofday(&tv);
422					midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
423					memcpy(timeptr, &midtime, sizeof(__be32));
424					opt->is_changed = 1;
425				}
426			} else {
427				unsigned overflow = optptr[3]>>4;
428				if (overflow == 15) {
429					pp_ptr = optptr + 3;
430					goto error;
431				}
432				opt->ts = optptr - iph;
433				if (skb) {
434					optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4);
435					opt->is_changed = 1;
436				}
437			}
438			break;
439		      case IPOPT_RA:
440			if (optlen < 4) {
441				pp_ptr = optptr + 1;
442				goto error;
443			}
444			if (optptr[2] == 0 && optptr[3] == 0)
445				opt->router_alert = optptr - iph;
446			break;
447		      case IPOPT_CIPSO:
448			if ((!skb && !capable(CAP_NET_RAW)) || opt->cipso) {
449				pp_ptr = optptr;
450				goto error;
451			}
452			opt->cipso = optptr - iph;
453			if (cipso_v4_validate(&optptr)) {
454				pp_ptr = optptr;
455				goto error;
456			}
457			break;
458		      case IPOPT_SEC:
459		      case IPOPT_SID:
460		      default:
461			if (!skb && !capable(CAP_NET_RAW)) {
462				pp_ptr = optptr;
463				goto error;
464			}
465			break;
466		}
467		l -= optlen;
468		optptr += optlen;
469	}
470
471eol:
472	if (!pp_ptr)
473		return 0;
474
475error:
476	if (skb) {
477		icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((pp_ptr-iph)<<24));
478	}
479	return -EINVAL;
480}
481
482
483/*
484 *	Undo all the changes done by ip_options_compile().
485 */
486
487void ip_options_undo(struct ip_options * opt)
488{
489	if (opt->srr) {
490		unsigned  char * optptr = opt->__data+opt->srr-sizeof(struct  iphdr);
491		memmove(optptr+7, optptr+3, optptr[1]-7);
492		memcpy(optptr+3, &opt->faddr, 4);
493	}
494	if (opt->rr_needaddr) {
495		unsigned  char * optptr = opt->__data+opt->rr-sizeof(struct  iphdr);
496		optptr[2] -= 4;
497		memset(&optptr[optptr[2]-1], 0, 4);
498	}
499	if (opt->ts) {
500		unsigned  char * optptr = opt->__data+opt->ts-sizeof(struct  iphdr);
501		if (opt->ts_needtime) {
502			optptr[2] -= 4;
503			memset(&optptr[optptr[2]-1], 0, 4);
504			if ((optptr[3]&0xF) == IPOPT_TS_PRESPEC)
505				optptr[2] -= 4;
506		}
507		if (opt->ts_needaddr) {
508			optptr[2] -= 4;
509			memset(&optptr[optptr[2]-1], 0, 4);
510		}
511	}
512}
513
514static struct ip_options *ip_options_get_alloc(const int optlen)
515{
516	struct ip_options *opt = kmalloc(sizeof(*opt) + ((optlen + 3) & ~3),
517					 GFP_KERNEL);
518	if (opt)
519		memset(opt, 0, sizeof(*opt));
520	return opt;
521}
522
523static int ip_options_get_finish(struct ip_options **optp,
524				 struct ip_options *opt, int optlen)
525{
526	while (optlen & 3)
527		opt->__data[optlen++] = IPOPT_END;
528	opt->optlen = optlen;
529	opt->is_data = 1;
530	if (optlen && ip_options_compile(opt, NULL)) {
531		kfree(opt);
532		return -EINVAL;
533	}
534	kfree(*optp);
535	*optp = opt;
536	return 0;
537}
538
539int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *data, int optlen)
540{
541	struct ip_options *opt = ip_options_get_alloc(optlen);
542
543	if (!opt)
544		return -ENOMEM;
545	if (optlen && copy_from_user(opt->__data, data, optlen)) {
546		kfree(opt);
547		return -EFAULT;
548	}
549	return ip_options_get_finish(optp, opt, optlen);
550}
551
552int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen)
553{
554	struct ip_options *opt = ip_options_get_alloc(optlen);
555
556	if (!opt)
557		return -ENOMEM;
558	if (optlen)
559		memcpy(opt->__data, data, optlen);
560	return ip_options_get_finish(optp, opt, optlen);
561}
562
563void ip_forward_options(struct sk_buff *skb)
564{
565	struct   ip_options * opt	= &(IPCB(skb)->opt);
566	unsigned char * optptr;
567	struct rtable *rt = (struct rtable*)skb->dst;
568	unsigned char *raw = skb_network_header(skb);
569
570	if (opt->rr_needaddr) {
571		optptr = (unsigned char *)raw + opt->rr;
572		ip_rt_get_source(&optptr[optptr[2]-5], rt);
573		opt->is_changed = 1;
574	}
575	if (opt->srr_is_hit) {
576		int srrptr, srrspace;
577
578		optptr = raw + opt->srr;
579
580		for ( srrptr=optptr[2], srrspace = optptr[1];
581		     srrptr <= srrspace;
582		     srrptr += 4
583		     ) {
584			if (srrptr + 3 > srrspace)
585				break;
586			if (memcmp(&rt->rt_dst, &optptr[srrptr-1], 4) == 0)
587				break;
588		}
589		if (srrptr + 3 <= srrspace) {
590			opt->is_changed = 1;
591			ip_rt_get_source(&optptr[srrptr-1], rt);
592			ip_hdr(skb)->daddr = rt->rt_dst;
593			optptr[2] = srrptr+4;
594		} else if (net_ratelimit())
595			printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n");
596		if (opt->ts_needaddr) {
597			optptr = raw + opt->ts;
598			ip_rt_get_source(&optptr[optptr[2]-9], rt);
599			opt->is_changed = 1;
600		}
601	}
602	if (opt->is_changed) {
603		opt->is_changed = 0;
604		ip_send_check(ip_hdr(skb));
605	}
606}
607
608int ip_options_rcv_srr(struct sk_buff *skb)
609{
610	struct ip_options *opt = &(IPCB(skb)->opt);
611	int srrspace, srrptr;
612	__be32 nexthop;
613	struct iphdr *iph = ip_hdr(skb);
614	unsigned char *optptr = skb_network_header(skb) + opt->srr;
615	struct rtable *rt = (struct rtable*)skb->dst;
616	struct rtable *rt2;
617	int err;
618
619	if (!opt->srr)
620		return 0;
621
622	if (skb->pkt_type != PACKET_HOST)
623		return -EINVAL;
624	if (rt->rt_type == RTN_UNICAST) {
625		if (!opt->is_strictroute)
626			return 0;
627		icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl(16<<24));
628		return -EINVAL;
629	}
630	if (rt->rt_type != RTN_LOCAL)
631		return -EINVAL;
632
633	for (srrptr=optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) {
634		if (srrptr + 3 > srrspace) {
635			icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24));
636			return -EINVAL;
637		}
638		memcpy(&nexthop, &optptr[srrptr-1], 4);
639
640		rt = (struct rtable*)skb->dst;
641		skb->dst = NULL;
642		err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev);
643		rt2 = (struct rtable*)skb->dst;
644		if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
645			ip_rt_put(rt2);
646			skb->dst = &rt->u.dst;
647			return -EINVAL;
648		}
649		ip_rt_put(rt);
650		if (rt2->rt_type != RTN_LOCAL)
651			break;
652		/* Superfast 8) loopback forward */
653		memcpy(&iph->daddr, &optptr[srrptr-1], 4);
654		opt->is_changed = 1;
655	}
656	if (srrptr <= srrspace) {
657		opt->srr_is_hit = 1;
658		opt->is_changed = 1;
659	}
660	return 0;
661}
662