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