|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that the above copyright notice and this paragraph are ! 7: * duplicated in all such forms and that any documentation, ! 8: * advertising materials, and other materials related to such ! 9: * distribution and use acknowledge that the software was developed ! 10: * by the University of California, Berkeley. The name of the ! 11: * University may not be used to endorse or promote products derived ! 12: * from this software without specific prior written permission. ! 13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 16: * ! 17: * @(#)ip_input.c 7.10 (Berkeley) 6/29/88 ! 18: */ ! 19: ! 20: #include "param.h" ! 21: #include "systm.h" ! 22: #include "mbuf.h" ! 23: #include "domain.h" ! 24: #include "protosw.h" ! 25: #include "socket.h" ! 26: #include "errno.h" ! 27: #include "time.h" ! 28: #include "kernel.h" ! 29: ! 30: #include "../net/if.h" ! 31: #include "../net/route.h" ! 32: ! 33: #include "in.h" ! 34: #include "in_pcb.h" ! 35: #include "in_systm.h" ! 36: #include "in_var.h" ! 37: #include "ip.h" ! 38: #include "ip_var.h" ! 39: #include "ip_icmp.h" ! 40: #include "tcp.h" ! 41: ! 42: u_char ip_protox[IPPROTO_MAX]; ! 43: int ipqmaxlen = IFQ_MAXLEN; ! 44: struct in_ifaddr *in_ifaddr; /* first inet address */ ! 45: ! 46: /* ! 47: * We need to save the IP options in case a protocol wants to respond ! 48: * to an incoming packet over the same route if the packet got here ! 49: * using IP source routing. This allows connection establishment and ! 50: * maintenance when the remote end is on a network that is not known ! 51: * to us. ! 52: */ ! 53: int ip_nhops = 0; ! 54: static struct ip_srcrt { ! 55: char nop; /* one NOP to align */ ! 56: char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ ! 57: struct in_addr route[MAX_IPOPTLEN]; ! 58: } ip_srcrt; ! 59: ! 60: /* ! 61: * IP initialization: fill in IP protocol switch table. ! 62: * All protocols not implemented in kernel go to raw IP protocol handler. ! 63: */ ! 64: ip_init() ! 65: { ! 66: register struct protosw *pr; ! 67: register int i; ! 68: ! 69: pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); ! 70: if (pr == 0) ! 71: panic("ip_init"); ! 72: for (i = 0; i < IPPROTO_MAX; i++) ! 73: ip_protox[i] = pr - inetsw; ! 74: for (pr = inetdomain.dom_protosw; ! 75: pr < inetdomain.dom_protoswNPROTOSW; pr++) ! 76: if (pr->pr_domain->dom_family == PF_INET && ! 77: pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) ! 78: ip_protox[pr->pr_protocol] = pr - inetsw; ! 79: ipq.next = ipq.prev = &ipq; ! 80: ip_id = time.tv_sec & 0xffff; ! 81: ipintrq.ifq_maxlen = ipqmaxlen; ! 82: } ! 83: ! 84: u_char ipcksum = 1; ! 85: struct ip *ip_reass(); ! 86: struct sockaddr_in ipaddr = { AF_INET }; ! 87: struct route ipforward_rt; ! 88: ! 89: /* ! 90: * Ip input routine. Checksum and byte swap header. If fragmented ! 91: * try to reassamble. If complete and fragment queue exists, discard. ! 92: * Process options. Pass to next level. ! 93: */ ! 94: ipintr() ! 95: { ! 96: register struct ip *ip; ! 97: register struct mbuf *m; ! 98: struct mbuf *m0; ! 99: register int i; ! 100: register struct ipq *fp; ! 101: register struct in_ifaddr *ia; ! 102: struct ifnet *ifp; ! 103: int hlen, s; ! 104: ! 105: next: ! 106: /* ! 107: * Get next datagram off input queue and get IP header ! 108: * in first mbuf. ! 109: */ ! 110: s = splimp(); ! 111: IF_DEQUEUEIF(&ipintrq, m, ifp); ! 112: splx(s); ! 113: if (m == 0) ! 114: return; ! 115: /* ! 116: * If no IP addresses have been set yet but the interfaces ! 117: * are receiving, can't do anything with incoming packets yet. ! 118: */ ! 119: if (in_ifaddr == NULL) ! 120: goto bad; ! 121: ipstat.ips_total++; ! 122: if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && ! 123: (m = m_pullup(m, sizeof (struct ip))) == 0) { ! 124: ipstat.ips_toosmall++; ! 125: goto next; ! 126: } ! 127: ip = mtod(m, struct ip *); ! 128: hlen = ip->ip_hl << 2; ! 129: if (hlen < sizeof(struct ip)) { /* minimum header length */ ! 130: ipstat.ips_badhlen++; ! 131: goto bad; ! 132: } ! 133: if (hlen > m->m_len) { ! 134: if ((m = m_pullup(m, hlen)) == 0) { ! 135: ipstat.ips_badhlen++; ! 136: goto next; ! 137: } ! 138: ip = mtod(m, struct ip *); ! 139: } ! 140: if (ipcksum) ! 141: if (ip->ip_sum = in_cksum(m, hlen)) { ! 142: ipstat.ips_badsum++; ! 143: goto bad; ! 144: } ! 145: ! 146: /* ! 147: * Convert fields to host representation. ! 148: */ ! 149: ip->ip_len = ntohs((u_short)ip->ip_len); ! 150: if (ip->ip_len < hlen) { ! 151: ipstat.ips_badlen++; ! 152: goto bad; ! 153: } ! 154: ip->ip_id = ntohs(ip->ip_id); ! 155: ip->ip_off = ntohs((u_short)ip->ip_off); ! 156: ! 157: /* ! 158: * Check that the amount of data in the buffers ! 159: * is as at least much as the IP header would have us expect. ! 160: * Trim mbufs if longer than we expect. ! 161: * Drop packet if shorter than we expect. ! 162: */ ! 163: i = -(u_short)ip->ip_len; ! 164: m0 = m; ! 165: for (;;) { ! 166: i += m->m_len; ! 167: if (m->m_next == 0) ! 168: break; ! 169: m = m->m_next; ! 170: } ! 171: if (i != 0) { ! 172: if (i < 0) { ! 173: ipstat.ips_tooshort++; ! 174: m = m0; ! 175: goto bad; ! 176: } ! 177: if (i <= m->m_len) ! 178: m->m_len -= i; ! 179: else ! 180: m_adj(m0, -i); ! 181: } ! 182: m = m0; ! 183: ! 184: /* ! 185: * Process options and, if not destined for us, ! 186: * ship it on. ip_dooptions returns 1 when an ! 187: * error was detected (causing an icmp message ! 188: * to be sent and the original packet to be freed). ! 189: */ ! 190: ip_nhops = 0; /* for source routed packets */ ! 191: if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp)) ! 192: goto next; ! 193: ! 194: /* ! 195: * Check our list of addresses, to see if the packet is for us. ! 196: */ ! 197: for (ia = in_ifaddr; ia; ia = ia->ia_next) { ! 198: #define satosin(sa) ((struct sockaddr_in *)(sa)) ! 199: ! 200: if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) ! 201: goto ours; ! 202: if ( ! 203: #ifdef DIRECTED_BROADCAST ! 204: ia->ia_ifp == ifp && ! 205: #endif ! 206: (ia->ia_ifp->if_flags & IFF_BROADCAST)) { ! 207: u_long t; ! 208: ! 209: if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == ! 210: ip->ip_dst.s_addr) ! 211: goto ours; ! 212: if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) ! 213: goto ours; ! 214: /* ! 215: * Look for all-0's host part (old broadcast addr), ! 216: * either for subnet or net. ! 217: */ ! 218: t = ntohl(ip->ip_dst.s_addr); ! 219: if (t == ia->ia_subnet) ! 220: goto ours; ! 221: if (t == ia->ia_net) ! 222: goto ours; ! 223: } ! 224: } ! 225: if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) ! 226: goto ours; ! 227: if (ip->ip_dst.s_addr == INADDR_ANY) ! 228: goto ours; ! 229: ! 230: /* ! 231: * Not for us; forward if possible and desirable. ! 232: */ ! 233: ip_forward(ip, ifp); ! 234: goto next; ! 235: ! 236: ours: ! 237: /* ! 238: * If offset or IP_MF are set, must reassemble. ! 239: * Otherwise, nothing need be done. ! 240: * (We could look in the reassembly queue to see ! 241: * if the packet was previously fragmented, ! 242: * but it's not worth the time; just let them time out.) ! 243: */ ! 244: if (ip->ip_off &~ IP_DF) { ! 245: /* ! 246: * Look for queue of fragments ! 247: * of this datagram. ! 248: */ ! 249: for (fp = ipq.next; fp != &ipq; fp = fp->next) ! 250: if (ip->ip_id == fp->ipq_id && ! 251: ip->ip_src.s_addr == fp->ipq_src.s_addr && ! 252: ip->ip_dst.s_addr == fp->ipq_dst.s_addr && ! 253: ip->ip_p == fp->ipq_p) ! 254: goto found; ! 255: fp = 0; ! 256: found: ! 257: ! 258: /* ! 259: * Adjust ip_len to not reflect header, ! 260: * set ip_mff if more fragments are expected, ! 261: * convert offset of this to bytes. ! 262: */ ! 263: ip->ip_len -= hlen; ! 264: ((struct ipasfrag *)ip)->ipf_mff = 0; ! 265: if (ip->ip_off & IP_MF) ! 266: ((struct ipasfrag *)ip)->ipf_mff = 1; ! 267: ip->ip_off <<= 3; ! 268: ! 269: /* ! 270: * If datagram marked as having more fragments ! 271: * or if this is not the first fragment, ! 272: * attempt reassembly; if it succeeds, proceed. ! 273: */ ! 274: if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { ! 275: ipstat.ips_fragments++; ! 276: ip = ip_reass((struct ipasfrag *)ip, fp); ! 277: if (ip == 0) ! 278: goto next; ! 279: m = dtom(ip); ! 280: } else ! 281: if (fp) ! 282: ip_freef(fp); ! 283: } else ! 284: ip->ip_len -= hlen; ! 285: ! 286: /* ! 287: * Switch out to protocol's input routine. ! 288: */ ! 289: (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp); ! 290: goto next; ! 291: bad: ! 292: m_freem(m); ! 293: goto next; ! 294: } ! 295: ! 296: /* ! 297: * Take incoming datagram fragment and try to ! 298: * reassemble it into whole datagram. If a chain for ! 299: * reassembly of this datagram already exists, then it ! 300: * is given as fp; otherwise have to make a chain. ! 301: */ ! 302: struct ip * ! 303: ip_reass(ip, fp) ! 304: register struct ipasfrag *ip; ! 305: register struct ipq *fp; ! 306: { ! 307: register struct mbuf *m = dtom(ip); ! 308: register struct ipasfrag *q; ! 309: struct mbuf *t; ! 310: int hlen = ip->ip_hl << 2; ! 311: int i, next; ! 312: ! 313: /* ! 314: * Presence of header sizes in mbufs ! 315: * would confuse code below. ! 316: */ ! 317: m->m_off += hlen; ! 318: m->m_len -= hlen; ! 319: ! 320: /* ! 321: * If first fragment to arrive, create a reassembly queue. ! 322: */ ! 323: if (fp == 0) { ! 324: if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) ! 325: goto dropfrag; ! 326: fp = mtod(t, struct ipq *); ! 327: insque(fp, &ipq); ! 328: fp->ipq_ttl = IPFRAGTTL; ! 329: fp->ipq_p = ip->ip_p; ! 330: fp->ipq_id = ip->ip_id; ! 331: fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; ! 332: fp->ipq_src = ((struct ip *)ip)->ip_src; ! 333: fp->ipq_dst = ((struct ip *)ip)->ip_dst; ! 334: q = (struct ipasfrag *)fp; ! 335: goto insert; ! 336: } ! 337: ! 338: /* ! 339: * Find a segment which begins after this one does. ! 340: */ ! 341: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) ! 342: if (q->ip_off > ip->ip_off) ! 343: break; ! 344: ! 345: /* ! 346: * If there is a preceding segment, it may provide some of ! 347: * our data already. If so, drop the data from the incoming ! 348: * segment. If it provides all of our data, drop us. ! 349: */ ! 350: if (q->ipf_prev != (struct ipasfrag *)fp) { ! 351: i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; ! 352: if (i > 0) { ! 353: if (i >= ip->ip_len) ! 354: goto dropfrag; ! 355: m_adj(dtom(ip), i); ! 356: ip->ip_off += i; ! 357: ip->ip_len -= i; ! 358: } ! 359: } ! 360: ! 361: /* ! 362: * While we overlap succeeding segments trim them or, ! 363: * if they are completely covered, dequeue them. ! 364: */ ! 365: while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { ! 366: i = (ip->ip_off + ip->ip_len) - q->ip_off; ! 367: if (i < q->ip_len) { ! 368: q->ip_len -= i; ! 369: q->ip_off += i; ! 370: m_adj(dtom(q), i); ! 371: break; ! 372: } ! 373: q = q->ipf_next; ! 374: m_freem(dtom(q->ipf_prev)); ! 375: ip_deq(q->ipf_prev); ! 376: } ! 377: ! 378: insert: ! 379: /* ! 380: * Stick new segment in its place; ! 381: * check for complete reassembly. ! 382: */ ! 383: ip_enq(ip, q->ipf_prev); ! 384: next = 0; ! 385: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { ! 386: if (q->ip_off != next) ! 387: return (0); ! 388: next += q->ip_len; ! 389: } ! 390: if (q->ipf_prev->ipf_mff) ! 391: return (0); ! 392: ! 393: /* ! 394: * Reassembly is complete; concatenate fragments. ! 395: */ ! 396: q = fp->ipq_next; ! 397: m = dtom(q); ! 398: t = m->m_next; ! 399: m->m_next = 0; ! 400: m_cat(m, t); ! 401: q = q->ipf_next; ! 402: while (q != (struct ipasfrag *)fp) { ! 403: t = dtom(q); ! 404: q = q->ipf_next; ! 405: m_cat(m, t); ! 406: } ! 407: ! 408: /* ! 409: * Create header for new ip packet by ! 410: * modifying header of first packet; ! 411: * dequeue and discard fragment reassembly header. ! 412: * Make header visible. ! 413: */ ! 414: ip = fp->ipq_next; ! 415: ip->ip_len = next; ! 416: ((struct ip *)ip)->ip_src = fp->ipq_src; ! 417: ((struct ip *)ip)->ip_dst = fp->ipq_dst; ! 418: remque(fp); ! 419: (void) m_free(dtom(fp)); ! 420: m = dtom(ip); ! 421: m->m_len += (ip->ip_hl << 2); ! 422: m->m_off -= (ip->ip_hl << 2); ! 423: return ((struct ip *)ip); ! 424: ! 425: dropfrag: ! 426: ipstat.ips_fragdropped++; ! 427: m_freem(m); ! 428: return (0); ! 429: } ! 430: ! 431: /* ! 432: * Free a fragment reassembly header and all ! 433: * associated datagrams. ! 434: */ ! 435: ip_freef(fp) ! 436: struct ipq *fp; ! 437: { ! 438: register struct ipasfrag *q, *p; ! 439: ! 440: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { ! 441: p = q->ipf_next; ! 442: ip_deq(q); ! 443: m_freem(dtom(q)); ! 444: } ! 445: remque(fp); ! 446: (void) m_free(dtom(fp)); ! 447: } ! 448: ! 449: /* ! 450: * Put an ip fragment on a reassembly chain. ! 451: * Like insque, but pointers in middle of structure. ! 452: */ ! 453: ip_enq(p, prev) ! 454: register struct ipasfrag *p, *prev; ! 455: { ! 456: ! 457: p->ipf_prev = prev; ! 458: p->ipf_next = prev->ipf_next; ! 459: prev->ipf_next->ipf_prev = p; ! 460: prev->ipf_next = p; ! 461: } ! 462: ! 463: /* ! 464: * To ip_enq as remque is to insque. ! 465: */ ! 466: ip_deq(p) ! 467: register struct ipasfrag *p; ! 468: { ! 469: ! 470: p->ipf_prev->ipf_next = p->ipf_next; ! 471: p->ipf_next->ipf_prev = p->ipf_prev; ! 472: } ! 473: ! 474: /* ! 475: * IP timer processing; ! 476: * if a timer expires on a reassembly ! 477: * queue, discard it. ! 478: */ ! 479: ip_slowtimo() ! 480: { ! 481: register struct ipq *fp; ! 482: int s = splnet(); ! 483: ! 484: fp = ipq.next; ! 485: if (fp == 0) { ! 486: splx(s); ! 487: return; ! 488: } ! 489: while (fp != &ipq) { ! 490: --fp->ipq_ttl; ! 491: fp = fp->next; ! 492: if (fp->prev->ipq_ttl == 0) { ! 493: ipstat.ips_fragtimeout++; ! 494: ip_freef(fp->prev); ! 495: } ! 496: } ! 497: splx(s); ! 498: } ! 499: ! 500: /* ! 501: * Drain off all datagram fragments. ! 502: */ ! 503: ip_drain() ! 504: { ! 505: ! 506: while (ipq.next != &ipq) { ! 507: ipstat.ips_fragdropped++; ! 508: ip_freef(ipq.next); ! 509: } ! 510: } ! 511: ! 512: extern struct in_ifaddr *ifptoia(); ! 513: struct in_ifaddr *ip_rtaddr(); ! 514: ! 515: /* ! 516: * Do option processing on a datagram, ! 517: * possibly discarding it if bad options ! 518: * are encountered. ! 519: */ ! 520: ip_dooptions(ip, ifp) ! 521: register struct ip *ip; ! 522: struct ifnet *ifp; ! 523: { ! 524: register u_char *cp; ! 525: int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB; ! 526: register struct ip_timestamp *ipt; ! 527: register struct in_ifaddr *ia; ! 528: struct in_addr *sin; ! 529: n_time ntime; ! 530: ! 531: cp = (u_char *)(ip + 1); ! 532: cnt = (ip->ip_hl << 2) - sizeof (struct ip); ! 533: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 534: opt = cp[IPOPT_OPTVAL]; ! 535: if (opt == IPOPT_EOL) ! 536: break; ! 537: if (opt == IPOPT_NOP) ! 538: optlen = 1; ! 539: else { ! 540: optlen = cp[IPOPT_OLEN]; ! 541: if (optlen <= 0 || optlen > cnt) { ! 542: code = &cp[IPOPT_OLEN] - (u_char *)ip; ! 543: goto bad; ! 544: } ! 545: } ! 546: switch (opt) { ! 547: ! 548: default: ! 549: break; ! 550: ! 551: /* ! 552: * Source routing with record. ! 553: * Find interface with current destination address. ! 554: * If none on this machine then drop if strictly routed, ! 555: * or do nothing if loosely routed. ! 556: * Record interface address and bring up next address ! 557: * component. If strictly routed make sure next ! 558: * address on directly accessible net. ! 559: */ ! 560: case IPOPT_LSRR: ! 561: case IPOPT_SSRR: ! 562: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { ! 563: code = &cp[IPOPT_OFFSET] - (u_char *)ip; ! 564: goto bad; ! 565: } ! 566: ipaddr.sin_addr = ip->ip_dst; ! 567: ia = (struct in_ifaddr *) ! 568: ifa_ifwithaddr((struct sockaddr *)&ipaddr); ! 569: if (ia == 0) { ! 570: if (opt == IPOPT_SSRR) { ! 571: type = ICMP_UNREACH; ! 572: code = ICMP_UNREACH_SRCFAIL; ! 573: goto bad; ! 574: } ! 575: /* ! 576: * Loose routing, and not at next destination ! 577: * yet; nothing to do except forward. ! 578: */ ! 579: break; ! 580: } ! 581: off--; /* 0 origin */ ! 582: if (off > optlen - sizeof(struct in_addr)) { ! 583: /* ! 584: * End of source route. Should be for us. ! 585: */ ! 586: save_rte(cp, ip->ip_src); ! 587: break; ! 588: } ! 589: /* ! 590: * locate outgoing interface ! 591: */ ! 592: bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, ! 593: sizeof(ipaddr.sin_addr)); ! 594: if ((opt == IPOPT_SSRR && ! 595: in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) || ! 596: (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { ! 597: type = ICMP_UNREACH; ! 598: code = ICMP_UNREACH_SRCFAIL; ! 599: goto bad; ! 600: } ! 601: ip->ip_dst = ipaddr.sin_addr; ! 602: bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), ! 603: (caddr_t)(cp + off), sizeof(struct in_addr)); ! 604: cp[IPOPT_OFFSET] += sizeof(struct in_addr); ! 605: break; ! 606: ! 607: case IPOPT_RR: ! 608: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { ! 609: code = &cp[IPOPT_OFFSET] - (u_char *)ip; ! 610: goto bad; ! 611: } ! 612: /* ! 613: * If no space remains, ignore. ! 614: */ ! 615: off--; /* 0 origin */ ! 616: if (off > optlen - sizeof(struct in_addr)) ! 617: break; ! 618: bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, ! 619: sizeof(ipaddr.sin_addr)); ! 620: /* ! 621: * locate outgoing interface ! 622: */ ! 623: if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { ! 624: type = ICMP_UNREACH; ! 625: code = ICMP_UNREACH_HOST; ! 626: goto bad; ! 627: } ! 628: bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), ! 629: (caddr_t)(cp + off), sizeof(struct in_addr)); ! 630: cp[IPOPT_OFFSET] += sizeof(struct in_addr); ! 631: break; ! 632: ! 633: case IPOPT_TS: ! 634: code = cp - (u_char *)ip; ! 635: ipt = (struct ip_timestamp *)cp; ! 636: if (ipt->ipt_len < 5) ! 637: goto bad; ! 638: if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { ! 639: if (++ipt->ipt_oflw == 0) ! 640: goto bad; ! 641: break; ! 642: } ! 643: sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); ! 644: switch (ipt->ipt_flg) { ! 645: ! 646: case IPOPT_TS_TSONLY: ! 647: break; ! 648: ! 649: case IPOPT_TS_TSANDADDR: ! 650: if (ipt->ipt_ptr + sizeof(n_time) + ! 651: sizeof(struct in_addr) > ipt->ipt_len) ! 652: goto bad; ! 653: ia = ifptoia(ifp); ! 654: bcopy((caddr_t)&IA_SIN(ia)->sin_addr, ! 655: (caddr_t)sin, sizeof(struct in_addr)); ! 656: ipt->ipt_ptr += sizeof(struct in_addr); ! 657: break; ! 658: ! 659: case IPOPT_TS_PRESPEC: ! 660: if (ipt->ipt_ptr + sizeof(n_time) + ! 661: sizeof(struct in_addr) > ipt->ipt_len) ! 662: goto bad; ! 663: bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, ! 664: sizeof(struct in_addr)); ! 665: if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0) ! 666: continue; ! 667: ipt->ipt_ptr += sizeof(struct in_addr); ! 668: break; ! 669: ! 670: default: ! 671: goto bad; ! 672: } ! 673: ntime = iptime(); ! 674: bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, ! 675: sizeof(n_time)); ! 676: ipt->ipt_ptr += sizeof(n_time); ! 677: } ! 678: } ! 679: return (0); ! 680: bad: ! 681: icmp_error(ip, type, code, ifp); ! 682: return (1); ! 683: } ! 684: ! 685: /* ! 686: * Given address of next destination (final or next hop), ! 687: * return internet address info of interface to be used to get there. ! 688: */ ! 689: struct in_ifaddr * ! 690: ip_rtaddr(dst) ! 691: struct in_addr dst; ! 692: { ! 693: register struct sockaddr_in *sin; ! 694: register struct in_ifaddr *ia; ! 695: ! 696: sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; ! 697: ! 698: if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { ! 699: if (ipforward_rt.ro_rt) { ! 700: RTFREE(ipforward_rt.ro_rt); ! 701: ipforward_rt.ro_rt = 0; ! 702: } ! 703: sin->sin_family = AF_INET; ! 704: sin->sin_addr = dst; ! 705: ! 706: rtalloc(&ipforward_rt); ! 707: } ! 708: if (ipforward_rt.ro_rt == 0) ! 709: return ((struct in_ifaddr *)0); ! 710: /* ! 711: * Find address associated with outgoing interface. ! 712: */ ! 713: for (ia = in_ifaddr; ia; ia = ia->ia_next) ! 714: if (ia->ia_ifp == ipforward_rt.ro_rt->rt_ifp) ! 715: break; ! 716: return (ia); ! 717: } ! 718: ! 719: /* ! 720: * Save incoming source route for use in replies, ! 721: * to be picked up later by ip_srcroute if the receiver is interested. ! 722: */ ! 723: save_rte(option, dst) ! 724: u_char *option; ! 725: struct in_addr dst; ! 726: { ! 727: unsigned olen; ! 728: extern ipprintfs; ! 729: ! 730: olen = option[IPOPT_OLEN]; ! 731: if (olen > sizeof(ip_srcrt) - 1) { ! 732: if (ipprintfs) ! 733: printf("save_rte: olen %d\n", olen); ! 734: return; ! 735: } ! 736: bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen); ! 737: ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); ! 738: ip_srcrt.route[ip_nhops++] = dst; ! 739: } ! 740: ! 741: /* ! 742: * Retrieve incoming source route for use in replies, ! 743: * in the same form used by setsockopt. ! 744: * The first hop is placed before the options, will be removed later. ! 745: */ ! 746: struct mbuf * ! 747: ip_srcroute() ! 748: { ! 749: register struct in_addr *p, *q; ! 750: register struct mbuf *m; ! 751: ! 752: if (ip_nhops == 0) ! 753: return ((struct mbuf *)0); ! 754: m = m_get(M_DONTWAIT, MT_SOOPTS); ! 755: if (m == 0) ! 756: return ((struct mbuf *)0); ! 757: m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1; ! 758: ! 759: /* ! 760: * First save first hop for return route ! 761: */ ! 762: p = &ip_srcrt.route[ip_nhops - 1]; ! 763: *(mtod(m, struct in_addr *)) = *p--; ! 764: ! 765: /* ! 766: * Copy option fields and padding (nop) to mbuf. ! 767: */ ! 768: ip_srcrt.nop = IPOPT_NOP; ! 769: bcopy((caddr_t)&ip_srcrt, mtod(m, caddr_t) + sizeof(struct in_addr), ! 770: IPOPT_OFFSET + 1 + 1); ! 771: q = (struct in_addr *)(mtod(m, caddr_t) + ! 772: sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1); ! 773: /* ! 774: * Record return path as an IP source route, ! 775: * reversing the path (pointers are now aligned). ! 776: */ ! 777: while (p >= ip_srcrt.route) ! 778: *q++ = *p--; ! 779: return (m); ! 780: } ! 781: ! 782: /* ! 783: * Strip out IP options, at higher ! 784: * level protocol in the kernel. ! 785: * Second argument is buffer to which options ! 786: * will be moved, and return value is their length. ! 787: */ ! 788: ip_stripoptions(ip, mopt) ! 789: struct ip *ip; ! 790: struct mbuf *mopt; ! 791: { ! 792: register int i; ! 793: register struct mbuf *m; ! 794: register caddr_t opts; ! 795: int olen; ! 796: ! 797: olen = (ip->ip_hl<<2) - sizeof (struct ip); ! 798: m = dtom(ip); ! 799: opts = (caddr_t)(ip + 1); ! 800: if (mopt) { ! 801: mopt->m_len = olen; ! 802: mopt->m_off = MMINOFF; ! 803: bcopy(opts, mtod(mopt, caddr_t), (unsigned)olen); ! 804: } ! 805: i = m->m_len - (sizeof (struct ip) + olen); ! 806: bcopy(opts + olen, opts, (unsigned)i); ! 807: m->m_len -= olen; ! 808: ip->ip_hl = sizeof(struct ip) >> 2; ! 809: } ! 810: ! 811: u_char inetctlerrmap[PRC_NCMDS] = { ! 812: 0, 0, 0, 0, ! 813: 0, 0, EHOSTDOWN, EHOSTUNREACH, ! 814: ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, ! 815: EMSGSIZE, EHOSTUNREACH, 0, 0, ! 816: 0, 0, 0, 0, ! 817: ENOPROTOOPT ! 818: }; ! 819: ! 820: #ifndef IPFORWARDING ! 821: #define IPFORWARDING 1 ! 822: #endif ! 823: #ifndef IPSENDREDIRECTS ! 824: #define IPSENDREDIRECTS 1 ! 825: #endif ! 826: int ipprintfs = 0; ! 827: int ipforwarding = IPFORWARDING; ! 828: extern int in_interfaces; ! 829: int ipsendredirects = IPSENDREDIRECTS; ! 830: ! 831: /* ! 832: * Forward a packet. If some error occurs return the sender ! 833: * an icmp packet. Note we can't always generate a meaningful ! 834: * icmp message because icmp doesn't have a large enough repertoire ! 835: * of codes and types. ! 836: * ! 837: * If not forwarding (possibly because we have only a single external ! 838: * network), just drop the packet. This could be confusing if ipforwarding ! 839: * was zero but some routing protocol was advancing us as a gateway ! 840: * to somewhere. However, we must let the routing protocol deal with that. ! 841: */ ! 842: ip_forward(ip, ifp) ! 843: register struct ip *ip; ! 844: struct ifnet *ifp; ! 845: { ! 846: register int error, type = 0, code; ! 847: register struct sockaddr_in *sin; ! 848: struct mbuf *mcopy; ! 849: struct in_addr dest; ! 850: ! 851: dest.s_addr = 0; ! 852: if (ipprintfs) ! 853: printf("forward: src %x dst %x ttl %x\n", ip->ip_src, ! 854: ip->ip_dst, ip->ip_ttl); ! 855: ip->ip_id = htons(ip->ip_id); ! 856: if (ipforwarding == 0 || in_interfaces <= 1) { ! 857: ipstat.ips_cantforward++; ! 858: #ifdef GATEWAY ! 859: type = ICMP_UNREACH, code = ICMP_UNREACH_NET; ! 860: goto sendicmp; ! 861: #else ! 862: m_freem(dtom(ip)); ! 863: return; ! 864: #endif ! 865: } ! 866: if (in_canforward(ip->ip_dst) == 0) { ! 867: m_freem(dtom(ip)); ! 868: return; ! 869: } ! 870: if (ip->ip_ttl <= IPTTLDEC) { ! 871: type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS; ! 872: goto sendicmp; ! 873: } ! 874: ip->ip_ttl -= IPTTLDEC; ! 875: ! 876: /* ! 877: * Save at most 64 bytes of the packet in case ! 878: * we need to generate an ICMP message to the src. ! 879: */ ! 880: mcopy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64)); ! 881: ! 882: sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; ! 883: if (ipforward_rt.ro_rt == 0 || ! 884: ip->ip_dst.s_addr != sin->sin_addr.s_addr) { ! 885: if (ipforward_rt.ro_rt) { ! 886: RTFREE(ipforward_rt.ro_rt); ! 887: ipforward_rt.ro_rt = 0; ! 888: } ! 889: sin->sin_family = AF_INET; ! 890: sin->sin_addr = ip->ip_dst; ! 891: ! 892: rtalloc(&ipforward_rt); ! 893: } ! 894: /* ! 895: * If forwarding packet using same interface that it came in on, ! 896: * perhaps should send a redirect to sender to shortcut a hop. ! 897: * Only send redirect if source is sending directly to us, ! 898: * and if packet was not source routed (or has any options). ! 899: * Also, don't send redirect if forwarding using a default route ! 900: * or a route modfied by a redirect. ! 901: */ ! 902: #define satosin(sa) ((struct sockaddr_in *)(sa)) ! 903: if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp && ! 904: (ipforward_rt.ro_rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && ! 905: satosin(&ipforward_rt.ro_rt->rt_dst)->sin_addr.s_addr != 0 && ! 906: ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) { ! 907: struct in_ifaddr *ia; ! 908: u_long src = ntohl(ip->ip_src.s_addr); ! 909: u_long dst = ntohl(ip->ip_dst.s_addr); ! 910: ! 911: if ((ia = ifptoia(ifp)) && ! 912: (src & ia->ia_subnetmask) == ia->ia_subnet) { ! 913: if (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) ! 914: dest = satosin(&ipforward_rt.ro_rt->rt_gateway)->sin_addr; ! 915: else ! 916: dest = ip->ip_dst; ! 917: /* ! 918: * If the destination is reached by a route to host, ! 919: * is on a subnet of a local net, or is directly ! 920: * on the attached net (!), use host redirect. ! 921: * (We may be the correct first hop for other subnets.) ! 922: */ ! 923: type = ICMP_REDIRECT; ! 924: code = ICMP_REDIRECT_NET; ! 925: if ((ipforward_rt.ro_rt->rt_flags & RTF_HOST) || ! 926: (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) == 0) ! 927: code = ICMP_REDIRECT_HOST; ! 928: else for (ia = in_ifaddr; ia = ia->ia_next; ) ! 929: if ((dst & ia->ia_netmask) == ia->ia_net) { ! 930: if (ia->ia_subnetmask != ia->ia_netmask) ! 931: code = ICMP_REDIRECT_HOST; ! 932: break; ! 933: } ! 934: if (ipprintfs) ! 935: printf("redirect (%d) to %x\n", code, dest); ! 936: } ! 937: } ! 938: ! 939: error = ip_output(dtom(ip), (struct mbuf *)0, &ipforward_rt, ! 940: IP_FORWARDING); ! 941: if (error) ! 942: ipstat.ips_cantforward++; ! 943: else if (type) ! 944: ipstat.ips_redirectsent++; ! 945: else { ! 946: if (mcopy) ! 947: m_freem(mcopy); ! 948: ipstat.ips_forward++; ! 949: return; ! 950: } ! 951: if (mcopy == NULL) ! 952: return; ! 953: ip = mtod(mcopy, struct ip *); ! 954: type = ICMP_UNREACH; ! 955: switch (error) { ! 956: ! 957: case 0: /* forwarded, but need redirect */ ! 958: type = ICMP_REDIRECT; ! 959: /* code set above */ ! 960: break; ! 961: ! 962: case ENETUNREACH: ! 963: case ENETDOWN: ! 964: if (in_localaddr(ip->ip_dst)) ! 965: code = ICMP_UNREACH_HOST; ! 966: else ! 967: code = ICMP_UNREACH_NET; ! 968: break; ! 969: ! 970: case EMSGSIZE: ! 971: code = ICMP_UNREACH_NEEDFRAG; ! 972: break; ! 973: ! 974: case EPERM: ! 975: code = ICMP_UNREACH_PORT; ! 976: break; ! 977: ! 978: case ENOBUFS: ! 979: type = ICMP_SOURCEQUENCH; ! 980: break; ! 981: ! 982: case EHOSTDOWN: ! 983: case EHOSTUNREACH: ! 984: code = ICMP_UNREACH_HOST; ! 985: break; ! 986: } ! 987: sendicmp: ! 988: icmp_error(ip, type, code, ifp, dest); ! 989: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.