1 /* 2 * Copyright (c) 1982, 1986, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2005 5 * Andre Oppermann, Internet Business Solutions AG. All right reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 4. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 #include "opt_ipstealth.h" 35 #include "opt_mac.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/mbuf.h> 40 /* #include <sys/malloc.h> */ 41 #include <sys/domain.h> 42 #include <sys/protosw.h> 43 #include <sys/socket.h> 44 #include <sys/time.h> 45 #include <sys/kernel.h> 46 #include <sys/syslog.h> 47 #include <sys/sysctl.h> 48 49 #include <net/if.h> 50 #include <net/if_types.h> 51 #include <net/if_var.h> 52 #include <net/if_dl.h> 53 #include <net/route.h> 54 #include <net/netisr.h> 55 56 #include <netinet/in.h> 57 #include <netinet/in_systm.h> 58 #include <netinet/in_var.h> 59 #include <netinet/ip.h> 60 #include <netinet/in_pcb.h> 61 #include <netinet/ip_var.h> 62 #include <netinet/ip_options.h> 63 #include <netinet/ip_icmp.h> 64 #include <machine/in_cksum.h> 65 66 #include <sys/socketvar.h> 67 68 #include <security/mac/mac_framework.h> 69 70 static int ip_dosourceroute = 0; 71 SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 72 &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); 73 74 static int ip_acceptsourceroute = 0; 75 SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 76 CTLFLAG_RW, &ip_acceptsourceroute, 0, 77 "Enable accepting source routed IP packets"); 78 79 int ip_doopts = 1; /* 0 = ignore, 1 = process, 2 = reject */ 80 SYSCTL_INT(_net_inet_ip, OID_AUTO, process_options, CTLFLAG_RW, 81 &ip_doopts, 0, "Enable IP options processing ([LS]SRR, RR, TS)"); 82 83 static void save_rte(struct mbuf *m, u_char *, struct in_addr); 84 85 /* 86 * Do option processing on a datagram, 87 * possibly discarding it if bad options are encountered, 88 * or forwarding it if source-routed. 89 * The pass argument is used when operating in the IPSTEALTH 90 * mode to tell what options to process: 91 * [LS]SRR (pass 0) or the others (pass 1). 92 * The reason for as many as two passes is that when doing IPSTEALTH, 93 * non-routing options should be processed only if the packet is for us. 94 * Returns 1 if packet has been forwarded/freed, 95 * 0 if the packet should be processed further. 96 */ 97 int 98 ip_dooptions(struct mbuf *m, int pass) 99 { 100 struct ip *ip = mtod(m, struct ip *); 101 u_char *cp; 102 struct in_ifaddr *ia; 103 int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 104 struct in_addr *sin, dst; 105 n_time ntime; 106 struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 107 108 /* ignore or reject packets with IP options */ 109 if (ip_doopts == 0) 110 return 0; 111 else if (ip_doopts == 2) { 112 type = ICMP_UNREACH; 113 code = ICMP_UNREACH_FILTER_PROHIB; 114 goto bad; 115 } 116 117 dst = ip->ip_dst; 118 cp = (u_char *)(ip + 1); 119 cnt = (ip->ip_hl << 2) - sizeof (struct ip); 120 for (; cnt > 0; cnt -= optlen, cp += optlen) { 121 opt = cp[IPOPT_OPTVAL]; 122 if (opt == IPOPT_EOL) 123 break; 124 if (opt == IPOPT_NOP) 125 optlen = 1; 126 else { 127 if (cnt < IPOPT_OLEN + sizeof(*cp)) { 128 code = &cp[IPOPT_OLEN] - (u_char *)ip; 129 goto bad; 130 } 131 optlen = cp[IPOPT_OLEN]; 132 if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { 133 code = &cp[IPOPT_OLEN] - (u_char *)ip; 134 goto bad; 135 } 136 } 137 switch (opt) { 138 139 default: 140 break; 141 142 /* 143 * Source routing with record. 144 * Find interface with current destination address. 145 * If none on this machine then drop if strictly routed, 146 * or do nothing if loosely routed. 147 * Record interface address and bring up next address 148 * component. If strictly routed make sure next 149 * address is on directly accessible net. 150 */ 151 case IPOPT_LSRR: 152 case IPOPT_SSRR: 153 #ifdef IPSTEALTH 154 if (ipstealth && pass > 0) 155 break; 156 #endif 157 if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 158 code = &cp[IPOPT_OLEN] - (u_char *)ip; 159 goto bad; 160 } 161 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 162 code = &cp[IPOPT_OFFSET] - (u_char *)ip; 163 goto bad; 164 } 165 ipaddr.sin_addr = ip->ip_dst; 166 ia = (struct in_ifaddr *) 167 ifa_ifwithaddr((struct sockaddr *)&ipaddr); 168 if (ia == NULL) { 169 if (opt == IPOPT_SSRR) { 170 type = ICMP_UNREACH; 171 code = ICMP_UNREACH_SRCFAIL; 172 goto bad; 173 } 174 if (!ip_dosourceroute) 175 goto nosourcerouting; 176 /* 177 * Loose routing, and not at next destination 178 * yet; nothing to do except forward. 179 */ 180 break; 181 } 182 off--; /* 0 origin */ 183 if (off > optlen - (int)sizeof(struct in_addr)) { 184 /* 185 * End of source route. Should be for us. 186 */ 187 if (!ip_acceptsourceroute) 188 goto nosourcerouting; 189 save_rte(m, cp, ip->ip_src); 190 break; 191 } 192 #ifdef IPSTEALTH 193 if (ipstealth) 194 goto dropit; 195 #endif 196 if (!ip_dosourceroute) { 197 if (ipforwarding) { 198 char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 199 /* 200 * Acting as a router, so generate ICMP 201 */ 202 nosourcerouting: 203 strcpy(buf, inet_ntoa(ip->ip_dst)); 204 log(LOG_WARNING, 205 "attempted source route from %s to %s\n", 206 inet_ntoa(ip->ip_src), buf); 207 type = ICMP_UNREACH; 208 code = ICMP_UNREACH_SRCFAIL; 209 goto bad; 210 } else { 211 /* 212 * Not acting as a router, so silently drop. 213 */ 214 #ifdef IPSTEALTH 215 dropit: 216 #endif 217 ipstat.ips_cantforward++; 218 m_freem(m); 219 return (1); 220 } 221 } 222 223 /* 224 * locate outgoing interface 225 */ 226 (void)memcpy(&ipaddr.sin_addr, cp + off, 227 sizeof(ipaddr.sin_addr)); 228 229 if (opt == IPOPT_SSRR) { 230 #define INA struct in_ifaddr * 231 #define SA struct sockaddr * 232 if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == NULL) 233 ia = (INA)ifa_ifwithnet((SA)&ipaddr); 234 } else 235 ia = ip_rtaddr(ipaddr.sin_addr); 236 if (ia == NULL) { 237 type = ICMP_UNREACH; 238 code = ICMP_UNREACH_SRCFAIL; 239 goto bad; 240 } 241 ip->ip_dst = ipaddr.sin_addr; 242 (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 243 sizeof(struct in_addr)); 244 cp[IPOPT_OFFSET] += sizeof(struct in_addr); 245 /* 246 * Let ip_intr's mcast routing check handle mcast pkts 247 */ 248 forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 249 break; 250 251 case IPOPT_RR: 252 #ifdef IPSTEALTH 253 if (ipstealth && pass == 0) 254 break; 255 #endif 256 if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 257 code = &cp[IPOPT_OFFSET] - (u_char *)ip; 258 goto bad; 259 } 260 if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 261 code = &cp[IPOPT_OFFSET] - (u_char *)ip; 262 goto bad; 263 } 264 /* 265 * If no space remains, ignore. 266 */ 267 off--; /* 0 origin */ 268 if (off > optlen - (int)sizeof(struct in_addr)) 269 break; 270 (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 271 sizeof(ipaddr.sin_addr)); 272 /* 273 * locate outgoing interface; if we're the destination, 274 * use the incoming interface (should be same). 275 */ 276 if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == NULL && 277 (ia = ip_rtaddr(ipaddr.sin_addr)) == NULL) { 278 type = ICMP_UNREACH; 279 code = ICMP_UNREACH_HOST; 280 goto bad; 281 } 282 (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 283 sizeof(struct in_addr)); 284 cp[IPOPT_OFFSET] += sizeof(struct in_addr); 285 break; 286 287 case IPOPT_TS: 288 #ifdef IPSTEALTH 289 if (ipstealth && pass == 0) 290 break; 291 #endif 292 code = cp - (u_char *)ip; 293 if (optlen < 4 || optlen > 40) { 294 code = &cp[IPOPT_OLEN] - (u_char *)ip; 295 goto bad; 296 } 297 if ((off = cp[IPOPT_OFFSET]) < 5) { 298 code = &cp[IPOPT_OLEN] - (u_char *)ip; 299 goto bad; 300 } 301 if (off > optlen - (int)sizeof(int32_t)) { 302 cp[IPOPT_OFFSET + 1] += (1 << 4); 303 if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) { 304 code = &cp[IPOPT_OFFSET] - (u_char *)ip; 305 goto bad; 306 } 307 break; 308 } 309 off--; /* 0 origin */ 310 sin = (struct in_addr *)(cp + off); 311 switch (cp[IPOPT_OFFSET + 1] & 0x0f) { 312 313 case IPOPT_TS_TSONLY: 314 break; 315 316 case IPOPT_TS_TSANDADDR: 317 if (off + sizeof(n_time) + 318 sizeof(struct in_addr) > optlen) { 319 code = &cp[IPOPT_OFFSET] - (u_char *)ip; 320 goto bad; 321 } 322 ipaddr.sin_addr = dst; 323 ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 324 m->m_pkthdr.rcvif); 325 if (ia == NULL) 326 continue; 327 (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 328 sizeof(struct in_addr)); 329 cp[IPOPT_OFFSET] += sizeof(struct in_addr); 330 off += sizeof(struct in_addr); 331 break; 332 333 case IPOPT_TS_PRESPEC: 334 if (off + sizeof(n_time) + 335 sizeof(struct in_addr) > optlen) { 336 code = &cp[IPOPT_OFFSET] - (u_char *)ip; 337 goto bad; 338 } 339 (void)memcpy(&ipaddr.sin_addr, sin, 340 sizeof(struct in_addr)); 341 if (ifa_ifwithaddr((SA)&ipaddr) == NULL) 342 continue; 343 cp[IPOPT_OFFSET] += sizeof(struct in_addr); 344 off += sizeof(struct in_addr); 345 break; 346 347 default: 348 code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip; 349 goto bad; 350 } 351 ntime = iptime(); 352 (void)memcpy(cp + off, &ntime, sizeof(n_time)); 353 cp[IPOPT_OFFSET] += sizeof(n_time); 354 } 355 } 356 if (forward && ipforwarding) { 357 ip_forward(m, 1); 358 return (1); 359 } 360 return (0); 361 bad: 362 icmp_error(m, type, code, 0, 0); 363 ipstat.ips_badoptions++; 364 return (1); 365 } 366 367 /* 368 * Save incoming source route for use in replies, 369 * to be picked up later by ip_srcroute if the receiver is interested. 370 */ 371 static void 372 save_rte(m, option, dst) 373 struct mbuf *m; 374 u_char *option; 375 struct in_addr dst; 376 { 377 unsigned olen; 378 struct ipopt_tag *opts; 379 380 opts = (struct ipopt_tag *)m_tag_get(PACKET_TAG_IPOPTIONS, 381 sizeof(struct ipopt_tag), M_NOWAIT); 382 if (opts == NULL) 383 return; 384 385 olen = option[IPOPT_OLEN]; 386 if (olen > sizeof(opts->ip_srcrt) - (1 + sizeof(dst))) { 387 m_tag_free((struct m_tag *)opts); 388 return; 389 } 390 bcopy(option, opts->ip_srcrt.srcopt, olen); 391 opts->ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 392 opts->ip_srcrt.dst = dst; 393 m_tag_prepend(m, (struct m_tag *)opts); 394 } 395 396 /* 397 * Retrieve incoming source route for use in replies, 398 * in the same form used by setsockopt. 399 * The first hop is placed before the options, will be removed later. 400 */ 401 struct mbuf * 402 ip_srcroute(m0) 403 struct mbuf *m0; 404 { 405 register struct in_addr *p, *q; 406 register struct mbuf *m; 407 struct ipopt_tag *opts; 408 409 opts = (struct ipopt_tag *)m_tag_find(m0, PACKET_TAG_IPOPTIONS, NULL); 410 if (opts == NULL) 411 return (NULL); 412 413 if (opts->ip_nhops == 0) 414 return (NULL); 415 m = m_get(M_DONTWAIT, MT_DATA); 416 if (m == NULL) 417 return (NULL); 418 419 #define OPTSIZ (sizeof(opts->ip_srcrt.nop) + sizeof(opts->ip_srcrt.srcopt)) 420 421 /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 422 m->m_len = opts->ip_nhops * sizeof(struct in_addr) + 423 sizeof(struct in_addr) + OPTSIZ; 424 425 /* 426 * First save first hop for return route 427 */ 428 p = &(opts->ip_srcrt.route[opts->ip_nhops - 1]); 429 *(mtod(m, struct in_addr *)) = *p--; 430 431 /* 432 * Copy option fields and padding (nop) to mbuf. 433 */ 434 opts->ip_srcrt.nop = IPOPT_NOP; 435 opts->ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 436 (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 437 &(opts->ip_srcrt.nop), OPTSIZ); 438 q = (struct in_addr *)(mtod(m, caddr_t) + 439 sizeof(struct in_addr) + OPTSIZ); 440 #undef OPTSIZ 441 /* 442 * Record return path as an IP source route, 443 * reversing the path (pointers are now aligned). 444 */ 445 while (p >= opts->ip_srcrt.route) { 446 *q++ = *p--; 447 } 448 /* 449 * Last hop goes to final destination. 450 */ 451 *q = opts->ip_srcrt.dst; 452 m_tag_delete(m0, (struct m_tag *)opts); 453 return (m); 454 } 455 456 /* 457 * Strip out IP options, at higher 458 * level protocol in the kernel. 459 * Second argument is buffer to which options 460 * will be moved, and return value is their length. 461 * XXX should be deleted; last arg currently ignored. 462 */ 463 void 464 ip_stripoptions(m, mopt) 465 register struct mbuf *m; 466 struct mbuf *mopt; 467 { 468 register int i; 469 struct ip *ip = mtod(m, struct ip *); 470 register caddr_t opts; 471 int olen; 472 473 olen = (ip->ip_hl << 2) - sizeof (struct ip); 474 opts = (caddr_t)(ip + 1); 475 i = m->m_len - (sizeof (struct ip) + olen); 476 bcopy(opts + olen, opts, (unsigned)i); 477 m->m_len -= olen; 478 if (m->m_flags & M_PKTHDR) 479 m->m_pkthdr.len -= olen; 480 ip->ip_v = IPVERSION; 481 ip->ip_hl = sizeof(struct ip) >> 2; 482 } 483 484 /* 485 * Insert IP options into preformed packet. 486 * Adjust IP destination as required for IP source routing, 487 * as indicated by a non-zero in_addr at the start of the options. 488 * 489 * XXX This routine assumes that the packet has no options in place. 490 */ 491 struct mbuf * 492 ip_insertoptions(m, opt, phlen) 493 register struct mbuf *m; 494 struct mbuf *opt; 495 int *phlen; 496 { 497 register struct ipoption *p = mtod(opt, struct ipoption *); 498 struct mbuf *n; 499 register struct ip *ip = mtod(m, struct ip *); 500 unsigned optlen; 501 502 optlen = opt->m_len - sizeof(p->ipopt_dst); 503 if (optlen + ip->ip_len > IP_MAXPACKET) { 504 *phlen = 0; 505 return (m); /* XXX should fail */ 506 } 507 if (p->ipopt_dst.s_addr) 508 ip->ip_dst = p->ipopt_dst; 509 if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { 510 MGETHDR(n, M_DONTWAIT, MT_DATA); 511 if (n == NULL) { 512 *phlen = 0; 513 return (m); 514 } 515 M_MOVE_PKTHDR(n, m); 516 n->m_pkthdr.rcvif = NULL; 517 #ifdef MAC 518 mac_copy_mbuf(m, n); 519 #endif 520 n->m_pkthdr.len += optlen; 521 m->m_len -= sizeof(struct ip); 522 m->m_data += sizeof(struct ip); 523 n->m_next = m; 524 m = n; 525 m->m_len = optlen + sizeof(struct ip); 526 m->m_data += max_linkhdr; 527 bcopy(ip, mtod(m, void *), sizeof(struct ip)); 528 } else { 529 m->m_data -= optlen; 530 m->m_len += optlen; 531 m->m_pkthdr.len += optlen; 532 bcopy(ip, mtod(m, void *), sizeof(struct ip)); 533 } 534 ip = mtod(m, struct ip *); 535 bcopy(p->ipopt_list, ip + 1, optlen); 536 *phlen = sizeof(struct ip) + optlen; 537 ip->ip_v = IPVERSION; 538 ip->ip_hl = *phlen >> 2; 539 ip->ip_len += optlen; 540 return (m); 541 } 542 543 /* 544 * Copy options from ip to jp, 545 * omitting those not copied during fragmentation. 546 */ 547 int 548 ip_optcopy(ip, jp) 549 struct ip *ip, *jp; 550 { 551 register u_char *cp, *dp; 552 int opt, optlen, cnt; 553 554 cp = (u_char *)(ip + 1); 555 dp = (u_char *)(jp + 1); 556 cnt = (ip->ip_hl << 2) - sizeof (struct ip); 557 for (; cnt > 0; cnt -= optlen, cp += optlen) { 558 opt = cp[0]; 559 if (opt == IPOPT_EOL) 560 break; 561 if (opt == IPOPT_NOP) { 562 /* Preserve for IP mcast tunnel's LSRR alignment. */ 563 *dp++ = IPOPT_NOP; 564 optlen = 1; 565 continue; 566 } 567 568 KASSERT(cnt >= IPOPT_OLEN + sizeof(*cp), 569 ("ip_optcopy: malformed ipv4 option")); 570 optlen = cp[IPOPT_OLEN]; 571 KASSERT(optlen >= IPOPT_OLEN + sizeof(*cp) && optlen <= cnt, 572 ("ip_optcopy: malformed ipv4 option")); 573 574 /* bogus lengths should have been caught by ip_dooptions */ 575 if (optlen > cnt) 576 optlen = cnt; 577 if (IPOPT_COPIED(opt)) { 578 bcopy(cp, dp, optlen); 579 dp += optlen; 580 } 581 } 582 for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 583 *dp++ = IPOPT_EOL; 584 return (optlen); 585 } 586 587 /* 588 * Set up IP options in pcb for insertion in output packets. 589 * Store in mbuf with pointer in pcbopt, adding pseudo-option 590 * with destination address if source routed. 591 */ 592 int 593 ip_pcbopts(struct inpcb *inp, int optname, struct mbuf *m) 594 { 595 register int cnt, optlen; 596 register u_char *cp; 597 struct mbuf **pcbopt; 598 u_char opt; 599 600 INP_LOCK_ASSERT(inp); 601 602 pcbopt = &inp->inp_options; 603 604 /* turn off any old options */ 605 if (*pcbopt) 606 (void)m_free(*pcbopt); 607 *pcbopt = 0; 608 if (m == NULL || m->m_len == 0) { 609 /* 610 * Only turning off any previous options. 611 */ 612 if (m != NULL) 613 (void)m_free(m); 614 return (0); 615 } 616 617 if (m->m_len % sizeof(int32_t)) 618 goto bad; 619 /* 620 * IP first-hop destination address will be stored before 621 * actual options; move other options back 622 * and clear it when none present. 623 */ 624 if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) 625 goto bad; 626 cnt = m->m_len; 627 m->m_len += sizeof(struct in_addr); 628 cp = mtod(m, u_char *) + sizeof(struct in_addr); 629 bcopy(mtod(m, void *), cp, (unsigned)cnt); 630 bzero(mtod(m, void *), sizeof(struct in_addr)); 631 632 for (; cnt > 0; cnt -= optlen, cp += optlen) { 633 opt = cp[IPOPT_OPTVAL]; 634 if (opt == IPOPT_EOL) 635 break; 636 if (opt == IPOPT_NOP) 637 optlen = 1; 638 else { 639 if (cnt < IPOPT_OLEN + sizeof(*cp)) 640 goto bad; 641 optlen = cp[IPOPT_OLEN]; 642 if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) 643 goto bad; 644 } 645 switch (opt) { 646 647 default: 648 break; 649 650 case IPOPT_LSRR: 651 case IPOPT_SSRR: 652 /* 653 * user process specifies route as: 654 * ->A->B->C->D 655 * D must be our final destination (but we can't 656 * check that since we may not have connected yet). 657 * A is first hop destination, which doesn't appear in 658 * actual IP option, but is stored before the options. 659 */ 660 if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 661 goto bad; 662 m->m_len -= sizeof(struct in_addr); 663 cnt -= sizeof(struct in_addr); 664 optlen -= sizeof(struct in_addr); 665 cp[IPOPT_OLEN] = optlen; 666 /* 667 * Move first hop before start of options. 668 */ 669 bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 670 sizeof(struct in_addr)); 671 /* 672 * Then copy rest of options back 673 * to close up the deleted entry. 674 */ 675 bcopy((&cp[IPOPT_OFFSET+1] + sizeof(struct in_addr)), 676 &cp[IPOPT_OFFSET+1], 677 (unsigned)cnt - (IPOPT_MINOFF - 1)); 678 break; 679 } 680 } 681 if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) 682 goto bad; 683 *pcbopt = m; 684 return (0); 685 686 bad: 687 (void)m_free(m); 688 return (EINVAL); 689 } 690