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/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 40 void 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 49 if (opt->srr) 50 memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4); 51 52 if (!is_frag) { 53 if (opt->rr_needaddr) 54 ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, rt); 55 if (opt->ts_needaddr) 56 ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt); 57 if (opt->ts_needtime) { 58 struct timeval tv; 59 __be32 midtime; 60 do_gettimeofday(&tv); 61 midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); 62 memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4); 63 } 64 return; 65 } 66 if (opt->rr) { 67 memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]); 68 opt->rr = 0; 69 opt->rr_needaddr = 0; 70 } 71 if (opt->ts) { 72 memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]); 73 opt->ts = 0; 74 opt->ts_needaddr = opt->ts_needtime = 0; 75 } 76 } 77 78 /* 79 * Provided (sopt, skb) points to received options, 80 * build in dopt compiled option set appropriate for answering. 81 * i.e. invert SRR option, copy anothers, 82 * and grab room in RR/TS options. 83 * 84 * NOTE: dopt cannot point to skb. 85 */ 86 87 int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) 88 { 89 struct ip_options *sopt; 90 unsigned char *sptr, *dptr; 91 int soffset, doffset; 92 int optlen; 93 __be32 daddr; 94 95 memset(dopt, 0, sizeof(struct ip_options)); 96 97 sopt = &(IPCB(skb)->opt); 98 99 if (sopt->optlen == 0) { 100 dopt->optlen = 0; 101 return 0; 102 } 103 104 sptr = skb_network_header(skb); 105 dptr = dopt->__data; 106 107 daddr = skb->rtable->rt_spec_dst; 108 109 if (sopt->rr) { 110 optlen = sptr[sopt->rr+1]; 111 soffset = sptr[sopt->rr+2]; 112 dopt->rr = dopt->optlen + sizeof(struct iphdr); 113 memcpy(dptr, sptr+sopt->rr, optlen); 114 if (sopt->rr_needaddr && soffset <= optlen) { 115 if (soffset + 3 > optlen) 116 return -EINVAL; 117 dptr[2] = soffset + 4; 118 dopt->rr_needaddr = 1; 119 } 120 dptr += optlen; 121 dopt->optlen += optlen; 122 } 123 if (sopt->ts) { 124 optlen = sptr[sopt->ts+1]; 125 soffset = sptr[sopt->ts+2]; 126 dopt->ts = dopt->optlen + sizeof(struct iphdr); 127 memcpy(dptr, sptr+sopt->ts, optlen); 128 if (soffset <= optlen) { 129 if (sopt->ts_needaddr) { 130 if (soffset + 3 > optlen) 131 return -EINVAL; 132 dopt->ts_needaddr = 1; 133 soffset += 4; 134 } 135 if (sopt->ts_needtime) { 136 if (soffset + 3 > optlen) 137 return -EINVAL; 138 if ((dptr[3]&0xF) != IPOPT_TS_PRESPEC) { 139 dopt->ts_needtime = 1; 140 soffset += 4; 141 } else { 142 dopt->ts_needtime = 0; 143 144 if (soffset + 8 <= optlen) { 145 __be32 addr; 146 147 memcpy(&addr, sptr+soffset-1, 4); 148 if (inet_addr_type(dev_net(skb->dst->dev), addr) != RTN_LOCAL) { 149 dopt->ts_needtime = 1; 150 soffset += 8; 151 } 152 } 153 } 154 } 155 dptr[2] = soffset; 156 } 157 dptr += optlen; 158 dopt->optlen += optlen; 159 } 160 if (sopt->srr) { 161 unsigned char * start = sptr+sopt->srr; 162 __be32 faddr; 163 164 optlen = start[1]; 165 soffset = start[2]; 166 doffset = 0; 167 if (soffset > optlen) 168 soffset = optlen + 1; 169 soffset -= 4; 170 if (soffset > 3) { 171 memcpy(&faddr, &start[soffset-1], 4); 172 for (soffset-=4, doffset=4; soffset > 3; soffset-=4, doffset+=4) 173 memcpy(&dptr[doffset-1], &start[soffset-1], 4); 174 /* 175 * RFC1812 requires to fix illegal source routes. 176 */ 177 if (memcmp(&ip_hdr(skb)->saddr, 178 &start[soffset + 3], 4) == 0) 179 doffset -= 4; 180 } 181 if (doffset > 3) { 182 memcpy(&start[doffset-1], &daddr, 4); 183 dopt->faddr = faddr; 184 dptr[0] = start[0]; 185 dptr[1] = doffset+3; 186 dptr[2] = 4; 187 dptr += doffset+3; 188 dopt->srr = dopt->optlen + sizeof(struct iphdr); 189 dopt->optlen += doffset+3; 190 dopt->is_strictroute = sopt->is_strictroute; 191 } 192 } 193 if (sopt->cipso) { 194 optlen = sptr[sopt->cipso+1]; 195 dopt->cipso = dopt->optlen+sizeof(struct iphdr); 196 memcpy(dptr, sptr+sopt->cipso, optlen); 197 dptr += optlen; 198 dopt->optlen += optlen; 199 } 200 while (dopt->optlen & 3) { 201 *dptr++ = IPOPT_END; 202 dopt->optlen++; 203 } 204 return 0; 205 } 206 207 /* 208 * Options "fragmenting", just fill options not 209 * allowed in fragments with NOOPs. 210 * Simple and stupid 8), but the most efficient way. 211 */ 212 213 void ip_options_fragment(struct sk_buff * skb) 214 { 215 unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr); 216 struct ip_options * opt = &(IPCB(skb)->opt); 217 int l = opt->optlen; 218 int optlen; 219 220 while (l > 0) { 221 switch (*optptr) { 222 case IPOPT_END: 223 return; 224 case IPOPT_NOOP: 225 l--; 226 optptr++; 227 continue; 228 } 229 optlen = optptr[1]; 230 if (optlen<2 || optlen>l) 231 return; 232 if (!IPOPT_COPIED(*optptr)) 233 memset(optptr, IPOPT_NOOP, optlen); 234 l -= optlen; 235 optptr += optlen; 236 } 237 opt->ts = 0; 238 opt->rr = 0; 239 opt->rr_needaddr = 0; 240 opt->ts_needaddr = 0; 241 opt->ts_needtime = 0; 242 return; 243 } 244 245 /* 246 * Verify options and fill pointers in struct options. 247 * Caller should clear *opt, and set opt->data. 248 * If opt == NULL, then skb->data should point to IP header. 249 */ 250 251 int ip_options_compile(struct net *net, 252 struct ip_options * opt, struct sk_buff * skb) 253 { 254 int l; 255 unsigned char * iph; 256 unsigned char * optptr; 257 int optlen; 258 unsigned char * pp_ptr = NULL; 259 struct rtable *rt = NULL; 260 261 if (skb != NULL) { 262 rt = skb->rtable; 263 optptr = (unsigned char *)&(ip_hdr(skb)[1]); 264 } else 265 optptr = opt->__data; 266 iph = optptr - sizeof(struct iphdr); 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 __be32 *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 = (__be32*)&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 = (__be32*)&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 __be32 addr; 392 memcpy(&addr, &optptr[optptr[2]-1], 4); 393 if (inet_addr_type(net, addr) == RTN_UNICAST) 394 break; 395 if (skb) 396 timeptr = (__be32*)&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 __be32 midtime; 411 do_gettimeofday(&tv); 412 midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); 413 memcpy(timeptr, &midtime, sizeof(__be32)); 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_CIPSO: 438 if ((!skb && !capable(CAP_NET_RAW)) || opt->cipso) { 439 pp_ptr = optptr; 440 goto error; 441 } 442 opt->cipso = optptr - iph; 443 if (cipso_v4_validate(&optptr)) { 444 pp_ptr = optptr; 445 goto error; 446 } 447 break; 448 case IPOPT_SEC: 449 case IPOPT_SID: 450 default: 451 if (!skb && !capable(CAP_NET_RAW)) { 452 pp_ptr = optptr; 453 goto error; 454 } 455 break; 456 } 457 l -= optlen; 458 optptr += optlen; 459 } 460 461 eol: 462 if (!pp_ptr) 463 return 0; 464 465 error: 466 if (skb) { 467 icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((pp_ptr-iph)<<24)); 468 } 469 return -EINVAL; 470 } 471 472 473 /* 474 * Undo all the changes done by ip_options_compile(). 475 */ 476 477 void ip_options_undo(struct ip_options * opt) 478 { 479 if (opt->srr) { 480 unsigned char * optptr = opt->__data+opt->srr-sizeof(struct iphdr); 481 memmove(optptr+7, optptr+3, optptr[1]-7); 482 memcpy(optptr+3, &opt->faddr, 4); 483 } 484 if (opt->rr_needaddr) { 485 unsigned char * optptr = opt->__data+opt->rr-sizeof(struct iphdr); 486 optptr[2] -= 4; 487 memset(&optptr[optptr[2]-1], 0, 4); 488 } 489 if (opt->ts) { 490 unsigned char * optptr = opt->__data+opt->ts-sizeof(struct iphdr); 491 if (opt->ts_needtime) { 492 optptr[2] -= 4; 493 memset(&optptr[optptr[2]-1], 0, 4); 494 if ((optptr[3]&0xF) == IPOPT_TS_PRESPEC) 495 optptr[2] -= 4; 496 } 497 if (opt->ts_needaddr) { 498 optptr[2] -= 4; 499 memset(&optptr[optptr[2]-1], 0, 4); 500 } 501 } 502 } 503 504 static struct ip_options *ip_options_get_alloc(const int optlen) 505 { 506 return kzalloc(sizeof(struct ip_options) + ((optlen + 3) & ~3), 507 GFP_KERNEL); 508 } 509 510 static int ip_options_get_finish(struct net *net, struct ip_options **optp, 511 struct ip_options *opt, int optlen) 512 { 513 while (optlen & 3) 514 opt->__data[optlen++] = IPOPT_END; 515 opt->optlen = optlen; 516 if (optlen && ip_options_compile(net, opt, NULL)) { 517 kfree(opt); 518 return -EINVAL; 519 } 520 kfree(*optp); 521 *optp = opt; 522 return 0; 523 } 524 525 int ip_options_get_from_user(struct net *net, struct ip_options **optp, 526 unsigned char __user *data, int optlen) 527 { 528 struct ip_options *opt = ip_options_get_alloc(optlen); 529 530 if (!opt) 531 return -ENOMEM; 532 if (optlen && copy_from_user(opt->__data, data, optlen)) { 533 kfree(opt); 534 return -EFAULT; 535 } 536 return ip_options_get_finish(net, optp, opt, optlen); 537 } 538 539 int ip_options_get(struct net *net, struct ip_options **optp, 540 unsigned char *data, int optlen) 541 { 542 struct ip_options *opt = ip_options_get_alloc(optlen); 543 544 if (!opt) 545 return -ENOMEM; 546 if (optlen) 547 memcpy(opt->__data, data, optlen); 548 return ip_options_get_finish(net, optp, opt, optlen); 549 } 550 551 void ip_forward_options(struct sk_buff *skb) 552 { 553 struct ip_options * opt = &(IPCB(skb)->opt); 554 unsigned char * optptr; 555 struct rtable *rt = skb->rtable; 556 unsigned char *raw = skb_network_header(skb); 557 558 if (opt->rr_needaddr) { 559 optptr = (unsigned char *)raw + opt->rr; 560 ip_rt_get_source(&optptr[optptr[2]-5], rt); 561 opt->is_changed = 1; 562 } 563 if (opt->srr_is_hit) { 564 int srrptr, srrspace; 565 566 optptr = raw + opt->srr; 567 568 for ( srrptr=optptr[2], srrspace = optptr[1]; 569 srrptr <= srrspace; 570 srrptr += 4 571 ) { 572 if (srrptr + 3 > srrspace) 573 break; 574 if (memcmp(&rt->rt_dst, &optptr[srrptr-1], 4) == 0) 575 break; 576 } 577 if (srrptr + 3 <= srrspace) { 578 opt->is_changed = 1; 579 ip_rt_get_source(&optptr[srrptr-1], rt); 580 ip_hdr(skb)->daddr = rt->rt_dst; 581 optptr[2] = srrptr+4; 582 } else if (net_ratelimit()) 583 printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); 584 if (opt->ts_needaddr) { 585 optptr = raw + opt->ts; 586 ip_rt_get_source(&optptr[optptr[2]-9], rt); 587 opt->is_changed = 1; 588 } 589 } 590 if (opt->is_changed) { 591 opt->is_changed = 0; 592 ip_send_check(ip_hdr(skb)); 593 } 594 } 595 596 int ip_options_rcv_srr(struct sk_buff *skb) 597 { 598 struct ip_options *opt = &(IPCB(skb)->opt); 599 int srrspace, srrptr; 600 __be32 nexthop; 601 struct iphdr *iph = ip_hdr(skb); 602 unsigned char *optptr = skb_network_header(skb) + opt->srr; 603 struct rtable *rt = skb->rtable; 604 struct rtable *rt2; 605 int err; 606 607 if (!opt->srr) 608 return 0; 609 610 if (skb->pkt_type != PACKET_HOST) 611 return -EINVAL; 612 if (rt->rt_type == RTN_UNICAST) { 613 if (!opt->is_strictroute) 614 return 0; 615 icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl(16<<24)); 616 return -EINVAL; 617 } 618 if (rt->rt_type != RTN_LOCAL) 619 return -EINVAL; 620 621 for (srrptr=optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) { 622 if (srrptr + 3 > srrspace) { 623 icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24)); 624 return -EINVAL; 625 } 626 memcpy(&nexthop, &optptr[srrptr-1], 4); 627 628 rt = skb->rtable; 629 skb->rtable = NULL; 630 err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); 631 rt2 = skb->rtable; 632 if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { 633 ip_rt_put(rt2); 634 skb->rtable = rt; 635 return -EINVAL; 636 } 637 ip_rt_put(rt); 638 if (rt2->rt_type != RTN_LOCAL) 639 break; 640 /* Superfast 8) loopback forward */ 641 memcpy(&iph->daddr, &optptr[srrptr-1], 4); 642 opt->is_changed = 1; 643 } 644 if (srrptr <= srrspace) { 645 opt->srr_is_hit = 1; 646 opt->is_changed = 1; 647 } 648 return 0; 649 } 650