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