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