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 26 /* 27 * Write options to IP header, record destination address to 28 * source route option, address of outgoing interface 29 * (we should already know it, so that this function is allowed be 30 * called only after routing decision) and timestamp, 31 * if we originate this datagram. 32 * 33 * daddr is real destination address, next hop is recorded in IP header. 34 * saddr is address of outgoing interface. 35 */ 36 37 void ip_options_build(struct sk_buff * skb, struct ip_options * opt, 38 u32 daddr, struct rtable *rt, int is_frag) 39 { 40 unsigned char * iph = skb->nh.raw; 41 42 memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options)); 43 memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen); 44 opt = &(IPCB(skb)->opt); 45 opt->is_data = 0; 46 47 if (opt->srr) 48 memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4); 49 50 if (!is_frag) { 51 if (opt->rr_needaddr) 52 ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, rt); 53 if (opt->ts_needaddr) 54 ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt); 55 if (opt->ts_needtime) { 56 struct timeval tv; 57 __u32 midtime; 58 do_gettimeofday(&tv); 59 midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); 60 memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4); 61 } 62 return; 63 } 64 if (opt->rr) { 65 memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]); 66 opt->rr = 0; 67 opt->rr_needaddr = 0; 68 } 69 if (opt->ts) { 70 memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]); 71 opt->ts = 0; 72 opt->ts_needaddr = opt->ts_needtime = 0; 73 } 74 } 75 76 /* 77 * Provided (sopt, skb) points to received options, 78 * build in dopt compiled option set appropriate for answering. 79 * i.e. invert SRR option, copy anothers, 80 * and grab room in RR/TS options. 81 * 82 * NOTE: dopt cannot point to skb. 83 */ 84 85 int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) 86 { 87 struct ip_options *sopt; 88 unsigned char *sptr, *dptr; 89 int soffset, doffset; 90 int optlen; 91 u32 daddr; 92 93 memset(dopt, 0, sizeof(struct ip_options)); 94 95 dopt->is_data = 1; 96 97 sopt = &(IPCB(skb)->opt); 98 99 if (sopt->optlen == 0) { 100 dopt->optlen = 0; 101 return 0; 102 } 103 104 sptr = skb->nh.raw; 105 dptr = dopt->__data; 106 107 if (skb->dst) 108 daddr = ((struct rtable*)skb->dst)->rt_spec_dst; 109 else 110 daddr = skb->nh.iph->daddr; 111 112 if (sopt->rr) { 113 optlen = sptr[sopt->rr+1]; 114 soffset = sptr[sopt->rr+2]; 115 dopt->rr = dopt->optlen + sizeof(struct iphdr); 116 memcpy(dptr, sptr+sopt->rr, optlen); 117 if (sopt->rr_needaddr && soffset <= optlen) { 118 if (soffset + 3 > optlen) 119 return -EINVAL; 120 dptr[2] = soffset + 4; 121 dopt->rr_needaddr = 1; 122 } 123 dptr += optlen; 124 dopt->optlen += optlen; 125 } 126 if (sopt->ts) { 127 optlen = sptr[sopt->ts+1]; 128 soffset = sptr[sopt->ts+2]; 129 dopt->ts = dopt->optlen + sizeof(struct iphdr); 130 memcpy(dptr, sptr+sopt->ts, optlen); 131 if (soffset <= optlen) { 132 if (sopt->ts_needaddr) { 133 if (soffset + 3 > optlen) 134 return -EINVAL; 135 dopt->ts_needaddr = 1; 136 soffset += 4; 137 } 138 if (sopt->ts_needtime) { 139 if (soffset + 3 > optlen) 140 return -EINVAL; 141 if ((dptr[3]&0xF) != IPOPT_TS_PRESPEC) { 142 dopt->ts_needtime = 1; 143 soffset += 4; 144 } else { 145 dopt->ts_needtime = 0; 146 147 if (soffset + 8 <= optlen) { 148 __u32 addr; 149 150 memcpy(&addr, sptr+soffset-1, 4); 151 if (inet_addr_type(addr) != RTN_LOCAL) { 152 dopt->ts_needtime = 1; 153 soffset += 8; 154 } 155 } 156 } 157 } 158 dptr[2] = soffset; 159 } 160 dptr += optlen; 161 dopt->optlen += optlen; 162 } 163 if (sopt->srr) { 164 unsigned char * start = sptr+sopt->srr; 165 u32 faddr; 166 167 optlen = start[1]; 168 soffset = start[2]; 169 doffset = 0; 170 if (soffset > optlen) 171 soffset = optlen + 1; 172 soffset -= 4; 173 if (soffset > 3) { 174 memcpy(&faddr, &start[soffset-1], 4); 175 for (soffset-=4, doffset=4; soffset > 3; soffset-=4, doffset+=4) 176 memcpy(&dptr[doffset-1], &start[soffset-1], 4); 177 /* 178 * RFC1812 requires to fix illegal source routes. 179 */ 180 if (memcmp(&skb->nh.iph->saddr, &start[soffset+3], 4) == 0) 181 doffset -= 4; 182 } 183 if (doffset > 3) { 184 memcpy(&start[doffset-1], &daddr, 4); 185 dopt->faddr = faddr; 186 dptr[0] = start[0]; 187 dptr[1] = doffset+3; 188 dptr[2] = 4; 189 dptr += doffset+3; 190 dopt->srr = dopt->optlen + sizeof(struct iphdr); 191 dopt->optlen += doffset+3; 192 dopt->is_strictroute = sopt->is_strictroute; 193 } 194 } 195 while (dopt->optlen & 3) { 196 *dptr++ = IPOPT_END; 197 dopt->optlen++; 198 } 199 return 0; 200 } 201 202 /* 203 * Options "fragmenting", just fill options not 204 * allowed in fragments with NOOPs. 205 * Simple and stupid 8), but the most efficient way. 206 */ 207 208 void ip_options_fragment(struct sk_buff * skb) 209 { 210 unsigned char * optptr = skb->nh.raw; 211 struct ip_options * opt = &(IPCB(skb)->opt); 212 int l = opt->optlen; 213 int optlen; 214 215 while (l > 0) { 216 switch (*optptr) { 217 case IPOPT_END: 218 return; 219 case IPOPT_NOOP: 220 l--; 221 optptr++; 222 continue; 223 } 224 optlen = optptr[1]; 225 if (optlen<2 || optlen>l) 226 return; 227 if (!IPOPT_COPIED(*optptr)) 228 memset(optptr, IPOPT_NOOP, optlen); 229 l -= optlen; 230 optptr += optlen; 231 } 232 opt->ts = 0; 233 opt->rr = 0; 234 opt->rr_needaddr = 0; 235 opt->ts_needaddr = 0; 236 opt->ts_needtime = 0; 237 return; 238 } 239 240 /* 241 * Verify options and fill pointers in struct options. 242 * Caller should clear *opt, and set opt->data. 243 * If opt == NULL, then skb->data should point to IP header. 244 */ 245 246 int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) 247 { 248 int l; 249 unsigned char * iph; 250 unsigned char * optptr; 251 int optlen; 252 unsigned char * pp_ptr = NULL; 253 struct rtable *rt = skb ? (struct rtable*)skb->dst : NULL; 254 255 if (!opt) { 256 opt = &(IPCB(skb)->opt); 257 memset(opt, 0, sizeof(struct ip_options)); 258 iph = skb->nh.raw; 259 opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr); 260 optptr = iph + sizeof(struct iphdr); 261 opt->is_data = 0; 262 } else { 263 optptr = opt->is_data ? opt->__data : (unsigned char*)&(skb->nh.iph[1]); 264 iph = optptr - sizeof(struct iphdr); 265 } 266 267 for (l = opt->optlen; l > 0; ) { 268 switch (*optptr) { 269 case IPOPT_END: 270 for (optptr++, l--; l>0; optptr++, l--) { 271 if (*optptr != IPOPT_END) { 272 *optptr = IPOPT_END; 273 opt->is_changed = 1; 274 } 275 } 276 goto eol; 277 case IPOPT_NOOP: 278 l--; 279 optptr++; 280 continue; 281 } 282 optlen = optptr[1]; 283 if (optlen<2 || optlen>l) { 284 pp_ptr = optptr; 285 goto error; 286 } 287 switch (*optptr) { 288 case IPOPT_SSRR: 289 case IPOPT_LSRR: 290 if (optlen < 3) { 291 pp_ptr = optptr + 1; 292 goto error; 293 } 294 if (optptr[2] < 4) { 295 pp_ptr = optptr + 2; 296 goto error; 297 } 298 /* NB: cf RFC-1812 5.2.4.1 */ 299 if (opt->srr) { 300 pp_ptr = optptr; 301 goto error; 302 } 303 if (!skb) { 304 if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) { 305 pp_ptr = optptr + 1; 306 goto error; 307 } 308 memcpy(&opt->faddr, &optptr[3], 4); 309 if (optlen > 7) 310 memmove(&optptr[3], &optptr[7], optlen-7); 311 } 312 opt->is_strictroute = (optptr[0] == IPOPT_SSRR); 313 opt->srr = optptr - iph; 314 break; 315 case IPOPT_RR: 316 if (opt->rr) { 317 pp_ptr = optptr; 318 goto error; 319 } 320 if (optlen < 3) { 321 pp_ptr = optptr + 1; 322 goto error; 323 } 324 if (optptr[2] < 4) { 325 pp_ptr = optptr + 2; 326 goto error; 327 } 328 if (optptr[2] <= optlen) { 329 if (optptr[2]+3 > optlen) { 330 pp_ptr = optptr + 2; 331 goto error; 332 } 333 if (skb) { 334 memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4); 335 opt->is_changed = 1; 336 } 337 optptr[2] += 4; 338 opt->rr_needaddr = 1; 339 } 340 opt->rr = optptr - iph; 341 break; 342 case IPOPT_TIMESTAMP: 343 if (opt->ts) { 344 pp_ptr = optptr; 345 goto error; 346 } 347 if (optlen < 4) { 348 pp_ptr = optptr + 1; 349 goto error; 350 } 351 if (optptr[2] < 5) { 352 pp_ptr = optptr + 2; 353 goto error; 354 } 355 if (optptr[2] <= optlen) { 356 __u32 * timeptr = NULL; 357 if (optptr[2]+3 > optptr[1]) { 358 pp_ptr = optptr + 2; 359 goto error; 360 } 361 switch (optptr[3]&0xF) { 362 case IPOPT_TS_TSONLY: 363 opt->ts = optptr - iph; 364 if (skb) 365 timeptr = (__u32*)&optptr[optptr[2]-1]; 366 opt->ts_needtime = 1; 367 optptr[2] += 4; 368 break; 369 case IPOPT_TS_TSANDADDR: 370 if (optptr[2]+7 > optptr[1]) { 371 pp_ptr = optptr + 2; 372 goto error; 373 } 374 opt->ts = optptr - iph; 375 if (skb) { 376 memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4); 377 timeptr = (__u32*)&optptr[optptr[2]+3]; 378 } 379 opt->ts_needaddr = 1; 380 opt->ts_needtime = 1; 381 optptr[2] += 8; 382 break; 383 case IPOPT_TS_PRESPEC: 384 if (optptr[2]+7 > optptr[1]) { 385 pp_ptr = optptr + 2; 386 goto error; 387 } 388 opt->ts = optptr - iph; 389 { 390 u32 addr; 391 memcpy(&addr, &optptr[optptr[2]-1], 4); 392 if (inet_addr_type(addr) == RTN_UNICAST) 393 break; 394 if (skb) 395 timeptr = (__u32*)&optptr[optptr[2]+3]; 396 } 397 opt->ts_needtime = 1; 398 optptr[2] += 8; 399 break; 400 default: 401 if (!skb && !capable(CAP_NET_RAW)) { 402 pp_ptr = optptr + 3; 403 goto error; 404 } 405 break; 406 } 407 if (timeptr) { 408 struct timeval tv; 409 __u32 midtime; 410 do_gettimeofday(&tv); 411 midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); 412 memcpy(timeptr, &midtime, sizeof(__u32)); 413 opt->is_changed = 1; 414 } 415 } else { 416 unsigned overflow = optptr[3]>>4; 417 if (overflow == 15) { 418 pp_ptr = optptr + 3; 419 goto error; 420 } 421 opt->ts = optptr - iph; 422 if (skb) { 423 optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4); 424 opt->is_changed = 1; 425 } 426 } 427 break; 428 case IPOPT_RA: 429 if (optlen < 4) { 430 pp_ptr = optptr + 1; 431 goto error; 432 } 433 if (optptr[2] == 0 && optptr[3] == 0) 434 opt->router_alert = optptr - iph; 435 break; 436 case IPOPT_SEC: 437 case IPOPT_SID: 438 default: 439 if (!skb && !capable(CAP_NET_RAW)) { 440 pp_ptr = optptr; 441 goto error; 442 } 443 break; 444 } 445 l -= optlen; 446 optptr += optlen; 447 } 448 449 eol: 450 if (!pp_ptr) 451 return 0; 452 453 error: 454 if (skb) { 455 icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((pp_ptr-iph)<<24)); 456 } 457 return -EINVAL; 458 } 459 460 461 /* 462 * Undo all the changes done by ip_options_compile(). 463 */ 464 465 void ip_options_undo(struct ip_options * opt) 466 { 467 if (opt->srr) { 468 unsigned char * optptr = opt->__data+opt->srr-sizeof(struct iphdr); 469 memmove(optptr+7, optptr+3, optptr[1]-7); 470 memcpy(optptr+3, &opt->faddr, 4); 471 } 472 if (opt->rr_needaddr) { 473 unsigned char * optptr = opt->__data+opt->rr-sizeof(struct iphdr); 474 optptr[2] -= 4; 475 memset(&optptr[optptr[2]-1], 0, 4); 476 } 477 if (opt->ts) { 478 unsigned char * optptr = opt->__data+opt->ts-sizeof(struct iphdr); 479 if (opt->ts_needtime) { 480 optptr[2] -= 4; 481 memset(&optptr[optptr[2]-1], 0, 4); 482 if ((optptr[3]&0xF) == IPOPT_TS_PRESPEC) 483 optptr[2] -= 4; 484 } 485 if (opt->ts_needaddr) { 486 optptr[2] -= 4; 487 memset(&optptr[optptr[2]-1], 0, 4); 488 } 489 } 490 } 491 492 static struct ip_options *ip_options_get_alloc(const int optlen) 493 { 494 struct ip_options *opt = kmalloc(sizeof(*opt) + ((optlen + 3) & ~3), 495 GFP_KERNEL); 496 if (opt) 497 memset(opt, 0, sizeof(*opt)); 498 return opt; 499 } 500 501 static int ip_options_get_finish(struct ip_options **optp, 502 struct ip_options *opt, int optlen) 503 { 504 while (optlen & 3) 505 opt->__data[optlen++] = IPOPT_END; 506 opt->optlen = optlen; 507 opt->is_data = 1; 508 opt->is_setbyuser = 1; 509 if (optlen && ip_options_compile(opt, NULL)) { 510 kfree(opt); 511 return -EINVAL; 512 } 513 if (*optp) 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