123184Smckusick /* 229143Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 3*32787Sbostic * All rights reserved. 423184Smckusick * 5*32787Sbostic * Redistribution and use in source and binary forms are permitted 6*32787Sbostic * provided that this notice is preserved and that due credit is given 7*32787Sbostic * to the University of California at Berkeley. The name of the University 8*32787Sbostic * may not be used to endorse or promote products derived from this 9*32787Sbostic * software without specific prior written permission. This software 10*32787Sbostic * is provided ``as is'' without express or implied warranty. 11*32787Sbostic * 12*32787Sbostic * @(#)ip_input.c 7.8 (Berkeley) 12/07/87 1323184Smckusick */ 144571Swnj 1517060Sbloom #include "param.h" 1617060Sbloom #include "systm.h" 1717060Sbloom #include "mbuf.h" 1817060Sbloom #include "domain.h" 1917060Sbloom #include "protosw.h" 2017060Sbloom #include "socket.h" 2117060Sbloom #include "errno.h" 2217060Sbloom #include "time.h" 2317060Sbloom #include "kernel.h" 248695Sroot 258695Sroot #include "../net/if.h" 268695Sroot #include "../net/route.h" 2710892Ssam 2817060Sbloom #include "in.h" 2917060Sbloom #include "in_pcb.h" 3017060Sbloom #include "in_systm.h" 3118376Skarels #include "in_var.h" 3217060Sbloom #include "ip.h" 3317060Sbloom #include "ip_var.h" 3417060Sbloom #include "ip_icmp.h" 3517060Sbloom #include "tcp.h" 364495Swnj 374898Swnj u_char ip_protox[IPPROTO_MAX]; 386210Swnj int ipqmaxlen = IFQ_MAXLEN; 3918376Skarels struct in_ifaddr *in_ifaddr; /* first inet address */ 404898Swnj 414801Swnj /* 4224813Skarels * We need to save the IP options in case a protocol wants to respond 4324813Skarels * to an incoming packet over the same route if the packet got here 4424813Skarels * using IP source routing. This allows connection establishment and 4524813Skarels * maintenance when the remote end is on a network that is not known 4624813Skarels * to us. 4724813Skarels */ 4824813Skarels int ip_nhops = 0; 4924813Skarels static struct ip_srcrt { 5024813Skarels char nop; /* one NOP to align */ 5124813Skarels char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 5224813Skarels struct in_addr route[MAX_IPOPTLEN]; 5324813Skarels } ip_srcrt; 5424813Skarels 5524813Skarels /* 565172Swnj * IP initialization: fill in IP protocol switch table. 575161Swnj * All protocols not implemented in kernel go to raw IP protocol handler. 584801Swnj */ 594801Swnj ip_init() 604801Swnj { 614898Swnj register struct protosw *pr; 624898Swnj register int i; 634495Swnj 6424813Skarels pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 654898Swnj if (pr == 0) 664898Swnj panic("ip_init"); 674898Swnj for (i = 0; i < IPPROTO_MAX; i++) 689030Sroot ip_protox[i] = pr - inetsw; 699030Sroot for (pr = inetdomain.dom_protosw; 7017551Skarels pr < inetdomain.dom_protoswNPROTOSW; pr++) 7116990Skarels if (pr->pr_domain->dom_family == PF_INET && 724898Swnj pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 739030Sroot ip_protox[pr->pr_protocol] = pr - inetsw; 744801Swnj ipq.next = ipq.prev = &ipq; 758172Sroot ip_id = time.tv_sec & 0xffff; 766210Swnj ipintrq.ifq_maxlen = ipqmaxlen; 774801Swnj } 784801Swnj 794898Swnj u_char ipcksum = 1; 804640Swnj struct ip *ip_reass(); 816338Ssam struct sockaddr_in ipaddr = { AF_INET }; 8224813Skarels struct route ipforward_rt; 834640Swnj 844640Swnj /* 854640Swnj * Ip input routine. Checksum and byte swap header. If fragmented 864640Swnj * try to reassamble. If complete and fragment queue exists, discard. 874640Swnj * Process options. Pass to next level. 884640Swnj */ 895084Swnj ipintr() 904495Swnj { 914923Swnj register struct ip *ip; 925084Swnj register struct mbuf *m; 938597Sroot struct mbuf *m0; 944640Swnj register int i; 954495Swnj register struct ipq *fp; 9618376Skarels register struct in_ifaddr *ia; 9724813Skarels struct ifnet *ifp; 985084Swnj int hlen, s; 994495Swnj 1005084Swnj next: 1014640Swnj /* 1025084Swnj * Get next datagram off input queue and get IP header 1035084Swnj * in first mbuf. 1044640Swnj */ 1055084Swnj s = splimp(); 10624813Skarels IF_DEQUEUEIF(&ipintrq, m, ifp); 1075084Swnj splx(s); 1085218Swnj if (m == 0) 1095084Swnj return; 11026001Skarels /* 11126001Skarels * If no IP addresses have been set yet but the interfaces 11226001Skarels * are receiving, can't do anything with incoming packets yet. 11326001Skarels */ 11426001Skarels if (in_ifaddr == NULL) 11526001Skarels goto bad; 11625920Skarels ipstat.ips_total++; 1175306Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && 11811232Ssam (m = m_pullup(m, sizeof (struct ip))) == 0) { 11911232Ssam ipstat.ips_toosmall++; 12011232Ssam goto next; 12111232Ssam } 1224640Swnj ip = mtod(m, struct ip *); 12318376Skarels hlen = ip->ip_hl << 2; 12424813Skarels if (hlen < sizeof(struct ip)) { /* minimum header length */ 12518376Skarels ipstat.ips_badhlen++; 12621117Skarels goto bad; 12718376Skarels } 12818376Skarels if (hlen > m->m_len) { 12911232Ssam if ((m = m_pullup(m, hlen)) == 0) { 13011232Ssam ipstat.ips_badhlen++; 13111232Ssam goto next; 13211232Ssam } 1335161Swnj ip = mtod(m, struct ip *); 1345161Swnj } 1354951Swnj if (ipcksum) 1365217Swnj if (ip->ip_sum = in_cksum(m, hlen)) { 1374951Swnj ipstat.ips_badsum++; 1384951Swnj goto bad; 1394495Swnj } 1404951Swnj 1414951Swnj /* 1424951Swnj * Convert fields to host representation. 1434951Swnj */ 1444907Swnj ip->ip_len = ntohs((u_short)ip->ip_len); 14511232Ssam if (ip->ip_len < hlen) { 14611232Ssam ipstat.ips_badlen++; 14711232Ssam goto bad; 14811232Ssam } 1494640Swnj ip->ip_id = ntohs(ip->ip_id); 1504951Swnj ip->ip_off = ntohs((u_short)ip->ip_off); 1514495Swnj 1524543Swnj /* 1534640Swnj * Check that the amount of data in the buffers 1544640Swnj * is as at least much as the IP header would have us expect. 1554640Swnj * Trim mbufs if longer than we expect. 1564640Swnj * Drop packet if shorter than we expect. 1574543Swnj */ 15824813Skarels i = -(u_short)ip->ip_len; 1595161Swnj m0 = m; 1606475Sroot for (;;) { 1614495Swnj i += m->m_len; 1626475Sroot if (m->m_next == 0) 1636475Sroot break; 1646475Sroot m = m->m_next; 1656088Sroot } 1666475Sroot if (i != 0) { 1676475Sroot if (i < 0) { 1685161Swnj ipstat.ips_tooshort++; 16917358Skarels m = m0; 1704951Swnj goto bad; 1715161Swnj } 1726475Sroot if (i <= m->m_len) 1736475Sroot m->m_len -= i; 1746475Sroot else 1756475Sroot m_adj(m0, -i); 1764495Swnj } 1776475Sroot m = m0; 1784495Swnj 1794640Swnj /* 1804640Swnj * Process options and, if not destined for us, 1816583Ssam * ship it on. ip_dooptions returns 1 when an 1826583Ssam * error was detected (causing an icmp message 18321117Skarels * to be sent and the original packet to be freed). 1844640Swnj */ 18524813Skarels ip_nhops = 0; /* for source routed packets */ 18626031Skarels if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp)) 1876583Ssam goto next; 1886210Swnj 1896338Ssam /* 19018376Skarels * Check our list of addresses, to see if the packet is for us. 1916338Ssam */ 19218376Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) { 19318376Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 1946338Ssam 19518376Skarels if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) 19624813Skarels goto ours; 19725195Skarels if ( 19825195Skarels #ifdef DIRECTED_BROADCAST 19925195Skarels ia->ia_ifp == ifp && 20025195Skarels #endif 20125195Skarels (ia->ia_ifp->if_flags & IFF_BROADCAST)) { 20226247Skarels u_long t; 20325195Skarels 20425195Skarels if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 20525195Skarels ip->ip_dst.s_addr) 20625195Skarels goto ours; 20725195Skarels if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) 20825195Skarels goto ours; 20925195Skarels /* 21025195Skarels * Look for all-0's host part (old broadcast addr), 21125195Skarels * either for subnet or net. 21225195Skarels */ 21326247Skarels t = ntohl(ip->ip_dst.s_addr); 21426247Skarels if (t == ia->ia_subnet) 21525195Skarels goto ours; 21626247Skarels if (t == ia->ia_net) 21725195Skarels goto ours; 21825195Skarels } 2196338Ssam } 22024813Skarels if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 22124813Skarels goto ours; 22224813Skarels if (ip->ip_dst.s_addr == INADDR_ANY) 22324813Skarels goto ours; 2244495Swnj 2254640Swnj /* 22624813Skarels * Not for us; forward if possible and desirable. 22724813Skarels */ 22824813Skarels ip_forward(ip, ifp); 22924813Skarels goto next; 23024813Skarels 23124813Skarels ours: 23224813Skarels /* 2334640Swnj * Look for queue of fragments 2344640Swnj * of this datagram. 2354640Swnj */ 2364640Swnj for (fp = ipq.next; fp != &ipq; fp = fp->next) 2374640Swnj if (ip->ip_id == fp->ipq_id && 2384640Swnj ip->ip_src.s_addr == fp->ipq_src.s_addr && 2394640Swnj ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 2404640Swnj ip->ip_p == fp->ipq_p) 2414640Swnj goto found; 2424640Swnj fp = 0; 2434640Swnj found: 2444495Swnj 2454640Swnj /* 2464640Swnj * Adjust ip_len to not reflect header, 2474640Swnj * set ip_mff if more fragments are expected, 2484640Swnj * convert offset of this to bytes. 2494640Swnj */ 2504640Swnj ip->ip_len -= hlen; 2514898Swnj ((struct ipasfrag *)ip)->ipf_mff = 0; 2524640Swnj if (ip->ip_off & IP_MF) 2534898Swnj ((struct ipasfrag *)ip)->ipf_mff = 1; 2544640Swnj ip->ip_off <<= 3; 2554495Swnj 2564640Swnj /* 2574640Swnj * If datagram marked as having more fragments 2584640Swnj * or if this is not the first fragment, 2594640Swnj * attempt reassembly; if it succeeds, proceed. 2604640Swnj */ 2614898Swnj if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { 26224813Skarels ipstat.ips_fragments++; 2634898Swnj ip = ip_reass((struct ipasfrag *)ip, fp); 2644640Swnj if (ip == 0) 2655084Swnj goto next; 2664640Swnj m = dtom(ip); 2674640Swnj } else 2684640Swnj if (fp) 26910735Ssam ip_freef(fp); 2704951Swnj 2714951Swnj /* 2724951Swnj * Switch out to protocol's input routine. 2734951Swnj */ 27424813Skarels (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp); 2755084Swnj goto next; 2764951Swnj bad: 2774951Swnj m_freem(m); 2785084Swnj goto next; 2794640Swnj } 2804495Swnj 2814640Swnj /* 2824640Swnj * Take incoming datagram fragment and try to 2834951Swnj * reassemble it into whole datagram. If a chain for 2844640Swnj * reassembly of this datagram already exists, then it 2854640Swnj * is given as fp; otherwise have to make a chain. 2864640Swnj */ 2874640Swnj struct ip * 2884640Swnj ip_reass(ip, fp) 2894898Swnj register struct ipasfrag *ip; 2904640Swnj register struct ipq *fp; 2914640Swnj { 2924640Swnj register struct mbuf *m = dtom(ip); 2934898Swnj register struct ipasfrag *q; 2944640Swnj struct mbuf *t; 2954640Swnj int hlen = ip->ip_hl << 2; 2964640Swnj int i, next; 2974543Swnj 2984640Swnj /* 2994640Swnj * Presence of header sizes in mbufs 3004640Swnj * would confuse code below. 3014640Swnj */ 3024640Swnj m->m_off += hlen; 3034640Swnj m->m_len -= hlen; 3044495Swnj 3054640Swnj /* 3064640Swnj * If first fragment to arrive, create a reassembly queue. 3074640Swnj */ 3084640Swnj if (fp == 0) { 30931201Skarels if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 3104640Swnj goto dropfrag; 3114640Swnj fp = mtod(t, struct ipq *); 3124640Swnj insque(fp, &ipq); 3134640Swnj fp->ipq_ttl = IPFRAGTTL; 3144640Swnj fp->ipq_p = ip->ip_p; 3154640Swnj fp->ipq_id = ip->ip_id; 3164898Swnj fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; 3174898Swnj fp->ipq_src = ((struct ip *)ip)->ip_src; 3184898Swnj fp->ipq_dst = ((struct ip *)ip)->ip_dst; 3195161Swnj q = (struct ipasfrag *)fp; 3205161Swnj goto insert; 3214640Swnj } 3224495Swnj 3234640Swnj /* 3244640Swnj * Find a segment which begins after this one does. 3254640Swnj */ 3264898Swnj for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 3274640Swnj if (q->ip_off > ip->ip_off) 3284640Swnj break; 3294495Swnj 3304640Swnj /* 3314640Swnj * If there is a preceding segment, it may provide some of 3324640Swnj * our data already. If so, drop the data from the incoming 3334640Swnj * segment. If it provides all of our data, drop us. 3344640Swnj */ 3354898Swnj if (q->ipf_prev != (struct ipasfrag *)fp) { 3364898Swnj i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; 3374640Swnj if (i > 0) { 3384640Swnj if (i >= ip->ip_len) 3394640Swnj goto dropfrag; 3404640Swnj m_adj(dtom(ip), i); 3414640Swnj ip->ip_off += i; 3424640Swnj ip->ip_len -= i; 3434640Swnj } 3444640Swnj } 3454543Swnj 3464640Swnj /* 3474640Swnj * While we overlap succeeding segments trim them or, 3484640Swnj * if they are completely covered, dequeue them. 3494640Swnj */ 3504898Swnj while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 3514640Swnj i = (ip->ip_off + ip->ip_len) - q->ip_off; 3524640Swnj if (i < q->ip_len) { 3534640Swnj q->ip_len -= i; 3546256Sroot q->ip_off += i; 3554640Swnj m_adj(dtom(q), i); 3564640Swnj break; 3574495Swnj } 3584898Swnj q = q->ipf_next; 3594898Swnj m_freem(dtom(q->ipf_prev)); 3604898Swnj ip_deq(q->ipf_prev); 3614543Swnj } 3624495Swnj 3635161Swnj insert: 3644640Swnj /* 3654640Swnj * Stick new segment in its place; 3664640Swnj * check for complete reassembly. 3674640Swnj */ 3684898Swnj ip_enq(ip, q->ipf_prev); 3694640Swnj next = 0; 3704898Swnj for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { 3714640Swnj if (q->ip_off != next) 3724640Swnj return (0); 3734640Swnj next += q->ip_len; 3744640Swnj } 3754898Swnj if (q->ipf_prev->ipf_mff) 3764640Swnj return (0); 3774495Swnj 3784640Swnj /* 3794640Swnj * Reassembly is complete; concatenate fragments. 3804640Swnj */ 3814640Swnj q = fp->ipq_next; 3824640Swnj m = dtom(q); 3834640Swnj t = m->m_next; 3844640Swnj m->m_next = 0; 3854640Swnj m_cat(m, t); 3866298Swnj q = q->ipf_next; 3876298Swnj while (q != (struct ipasfrag *)fp) { 3886298Swnj t = dtom(q); 3896298Swnj q = q->ipf_next; 3906298Swnj m_cat(m, t); 3916298Swnj } 3924495Swnj 3934640Swnj /* 3944640Swnj * Create header for new ip packet by 3954640Swnj * modifying header of first packet; 3964640Swnj * dequeue and discard fragment reassembly header. 3974640Swnj * Make header visible. 3984640Swnj */ 3994640Swnj ip = fp->ipq_next; 4004640Swnj ip->ip_len = next; 4014898Swnj ((struct ip *)ip)->ip_src = fp->ipq_src; 4024898Swnj ((struct ip *)ip)->ip_dst = fp->ipq_dst; 4034640Swnj remque(fp); 4044907Swnj (void) m_free(dtom(fp)); 4054640Swnj m = dtom(ip); 40624813Skarels m->m_len += (ip->ip_hl << 2); 40724813Skarels m->m_off -= (ip->ip_hl << 2); 4084898Swnj return ((struct ip *)ip); 4094495Swnj 4104640Swnj dropfrag: 41124813Skarels ipstat.ips_fragdropped++; 4124640Swnj m_freem(m); 4134640Swnj return (0); 4144495Swnj } 4154495Swnj 4164640Swnj /* 4174640Swnj * Free a fragment reassembly header and all 4184640Swnj * associated datagrams. 4194640Swnj */ 4204640Swnj ip_freef(fp) 4214640Swnj struct ipq *fp; 4224495Swnj { 42310735Ssam register struct ipasfrag *q, *p; 4244495Swnj 42510735Ssam for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { 42610735Ssam p = q->ipf_next; 42710735Ssam ip_deq(q); 4284640Swnj m_freem(dtom(q)); 42910735Ssam } 43010735Ssam remque(fp); 43110735Ssam (void) m_free(dtom(fp)); 4324495Swnj } 4334495Swnj 4344640Swnj /* 4354640Swnj * Put an ip fragment on a reassembly chain. 4364640Swnj * Like insque, but pointers in middle of structure. 4374640Swnj */ 4384640Swnj ip_enq(p, prev) 4394898Swnj register struct ipasfrag *p, *prev; 4404495Swnj { 4414951Swnj 4424898Swnj p->ipf_prev = prev; 4434898Swnj p->ipf_next = prev->ipf_next; 4444898Swnj prev->ipf_next->ipf_prev = p; 4454898Swnj prev->ipf_next = p; 4464495Swnj } 4474495Swnj 4484640Swnj /* 4494640Swnj * To ip_enq as remque is to insque. 4504640Swnj */ 4514640Swnj ip_deq(p) 4524898Swnj register struct ipasfrag *p; 4534640Swnj { 4544951Swnj 4554898Swnj p->ipf_prev->ipf_next = p->ipf_next; 4564898Swnj p->ipf_next->ipf_prev = p->ipf_prev; 4574495Swnj } 4584495Swnj 4594640Swnj /* 4604640Swnj * IP timer processing; 4614640Swnj * if a timer expires on a reassembly 4624640Swnj * queue, discard it. 4634640Swnj */ 4644801Swnj ip_slowtimo() 4654495Swnj { 4664495Swnj register struct ipq *fp; 4674640Swnj int s = splnet(); 4684951Swnj 4695243Sroot fp = ipq.next; 4705243Sroot if (fp == 0) { 4715243Sroot splx(s); 4725243Sroot return; 4735243Sroot } 47410735Ssam while (fp != &ipq) { 47510735Ssam --fp->ipq_ttl; 47610735Ssam fp = fp->next; 47724813Skarels if (fp->prev->ipq_ttl == 0) { 47824813Skarels ipstat.ips_fragtimeout++; 47910735Ssam ip_freef(fp->prev); 48024813Skarels } 48110735Ssam } 4824640Swnj splx(s); 4834495Swnj } 4844495Swnj 4854951Swnj /* 4864951Swnj * Drain off all datagram fragments. 4874951Swnj */ 4884801Swnj ip_drain() 4894801Swnj { 4904801Swnj 49124813Skarels while (ipq.next != &ipq) { 49224813Skarels ipstat.ips_fragdropped++; 49310735Ssam ip_freef(ipq.next); 49424813Skarels } 4954801Swnj } 4964923Swnj 49730925Skarels extern struct in_ifaddr *ifptoia(); 49824813Skarels struct in_ifaddr *ip_rtaddr(); 49924813Skarels 5004640Swnj /* 5014640Swnj * Do option processing on a datagram, 5024640Swnj * possibly discarding it if bad options 5034640Swnj * are encountered. 5044640Swnj */ 50526031Skarels ip_dooptions(ip, ifp) 50626031Skarels register struct ip *ip; 50726031Skarels struct ifnet *ifp; 5084495Swnj { 5094640Swnj register u_char *cp; 51024813Skarels int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB; 51124813Skarels register struct ip_timestamp *ipt; 51224813Skarels register struct in_ifaddr *ia; 5134923Swnj struct in_addr *sin; 51424813Skarels n_time ntime; 5154495Swnj 5164640Swnj cp = (u_char *)(ip + 1); 5174640Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 5184640Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 51924813Skarels opt = cp[IPOPT_OPTVAL]; 5204640Swnj if (opt == IPOPT_EOL) 5214640Swnj break; 5224640Swnj if (opt == IPOPT_NOP) 5234640Swnj optlen = 1; 52416392Ssam else { 52524813Skarels optlen = cp[IPOPT_OLEN]; 52624813Skarels if (optlen <= 0 || optlen > cnt) { 52724813Skarels code = &cp[IPOPT_OLEN] - (u_char *)ip; 52817551Skarels goto bad; 52924813Skarels } 53016392Ssam } 5314640Swnj switch (opt) { 5324495Swnj 5334640Swnj default: 5344640Swnj break; 5354495Swnj 5364951Swnj /* 5374951Swnj * Source routing with record. 5384951Swnj * Find interface with current destination address. 5394951Swnj * If none on this machine then drop if strictly routed, 5404951Swnj * or do nothing if loosely routed. 5414951Swnj * Record interface address and bring up next address 5424951Swnj * component. If strictly routed make sure next 5434951Swnj * address on directly accessible net. 5444951Swnj */ 5454640Swnj case IPOPT_LSRR: 5467508Sroot case IPOPT_SSRR: 54724813Skarels if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 54824813Skarels code = &cp[IPOPT_OFFSET] - (u_char *)ip; 54924813Skarels goto bad; 55024813Skarels } 55124813Skarels ipaddr.sin_addr = ip->ip_dst; 55224813Skarels ia = (struct in_ifaddr *) 55324813Skarels ifa_ifwithaddr((struct sockaddr *)&ipaddr); 55424813Skarels if (ia == 0) { 55524813Skarels if (opt == IPOPT_SSRR) { 55624813Skarels type = ICMP_UNREACH; 55724813Skarels code = ICMP_UNREACH_SRCFAIL; 5584951Swnj goto bad; 55924813Skarels } 56024813Skarels /* 56124813Skarels * Loose routing, and not at next destination 56224813Skarels * yet; nothing to do except forward. 56324813Skarels */ 5644951Swnj break; 5654640Swnj } 56624813Skarels off--; /* 0 origin */ 56724813Skarels if (off > optlen - sizeof(struct in_addr)) { 56824813Skarels /* 56924813Skarels * End of source route. Should be for us. 57024813Skarels */ 57124813Skarels save_rte(cp, ip->ip_src); 5724951Swnj break; 57324813Skarels } 57424813Skarels /* 57524813Skarels * locate outgoing interface 57624813Skarels */ 57726384Skarels bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, 57824813Skarels sizeof(ipaddr.sin_addr)); 57924813Skarels if ((opt == IPOPT_SSRR && 58024813Skarels in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) || 58124813Skarels (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 58224813Skarels type = ICMP_UNREACH; 58324813Skarels code = ICMP_UNREACH_SRCFAIL; 5844951Swnj goto bad; 58524813Skarels } 58624813Skarels ip->ip_dst = ipaddr.sin_addr; 58726384Skarels bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), 58826384Skarels (caddr_t)(cp + off), sizeof(struct in_addr)); 58924813Skarels cp[IPOPT_OFFSET] += sizeof(struct in_addr); 5904640Swnj break; 5914495Swnj 59224813Skarels case IPOPT_RR: 59324813Skarels if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 59424813Skarels code = &cp[IPOPT_OFFSET] - (u_char *)ip; 59524813Skarels goto bad; 59624813Skarels } 59724813Skarels /* 59824813Skarels * If no space remains, ignore. 59924813Skarels */ 60024813Skarels off--; /* 0 origin */ 60124813Skarels if (off > optlen - sizeof(struct in_addr)) 60224813Skarels break; 60331393Skarels bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, 60424813Skarels sizeof(ipaddr.sin_addr)); 60524813Skarels /* 60624813Skarels * locate outgoing interface 60724813Skarels */ 60824813Skarels if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 60924813Skarels type = ICMP_UNREACH; 61032113Skarels code = ICMP_UNREACH_HOST; 61124813Skarels goto bad; 61224813Skarels } 61326384Skarels bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), 61426384Skarels (caddr_t)(cp + off), sizeof(struct in_addr)); 61524813Skarels cp[IPOPT_OFFSET] += sizeof(struct in_addr); 61624813Skarels break; 61724813Skarels 6184640Swnj case IPOPT_TS: 6196583Ssam code = cp - (u_char *)ip; 6204801Swnj ipt = (struct ip_timestamp *)cp; 6214801Swnj if (ipt->ipt_len < 5) 6224640Swnj goto bad; 6234801Swnj if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { 6244801Swnj if (++ipt->ipt_oflw == 0) 6254640Swnj goto bad; 6264495Swnj break; 6274640Swnj } 62830925Skarels sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 6294801Swnj switch (ipt->ipt_flg) { 6304495Swnj 6314640Swnj case IPOPT_TS_TSONLY: 6324640Swnj break; 6334640Swnj 6344640Swnj case IPOPT_TS_TSANDADDR: 63524813Skarels if (ipt->ipt_ptr + sizeof(n_time) + 63624813Skarels sizeof(struct in_addr) > ipt->ipt_len) 6374640Swnj goto bad; 63830925Skarels ia = ifptoia(ifp); 63930925Skarels bcopy((caddr_t)&IA_SIN(ia)->sin_addr, 64024813Skarels (caddr_t)sin, sizeof(struct in_addr)); 64130925Skarels ipt->ipt_ptr += sizeof(struct in_addr); 6424640Swnj break; 6434640Swnj 6444640Swnj case IPOPT_TS_PRESPEC: 64530925Skarels if (ipt->ipt_ptr + sizeof(n_time) + 64630925Skarels sizeof(struct in_addr) > ipt->ipt_len) 64730925Skarels goto bad; 64824813Skarels bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, 64924813Skarels sizeof(struct in_addr)); 65018376Skarels if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0) 6514951Swnj continue; 65224813Skarels ipt->ipt_ptr += sizeof(struct in_addr); 6534640Swnj break; 6544640Swnj 6554495Swnj default: 6564640Swnj goto bad; 6574495Swnj } 65824813Skarels ntime = iptime(); 65930925Skarels bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, 66030925Skarels sizeof(n_time)); 66124813Skarels ipt->ipt_ptr += sizeof(n_time); 6624640Swnj } 6634495Swnj } 6646583Ssam return (0); 6654640Swnj bad: 66626031Skarels icmp_error(ip, type, code, ifp); 6676583Ssam return (1); 6684495Swnj } 6694495Swnj 6704640Swnj /* 67124813Skarels * Given address of next destination (final or next hop), 67224813Skarels * return internet address info of interface to be used to get there. 67324813Skarels */ 67424813Skarels struct in_ifaddr * 67524813Skarels ip_rtaddr(dst) 67624813Skarels struct in_addr dst; 67724813Skarels { 67824813Skarels register struct sockaddr_in *sin; 67924813Skarels register struct in_ifaddr *ia; 68024813Skarels 68124813Skarels sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 68224813Skarels 68324813Skarels if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 68424813Skarels if (ipforward_rt.ro_rt) { 68524813Skarels RTFREE(ipforward_rt.ro_rt); 68624813Skarels ipforward_rt.ro_rt = 0; 68724813Skarels } 68824813Skarels sin->sin_family = AF_INET; 68924813Skarels sin->sin_addr = dst; 69024813Skarels 69124813Skarels rtalloc(&ipforward_rt); 69224813Skarels } 69324813Skarels if (ipforward_rt.ro_rt == 0) 69424813Skarels return ((struct in_ifaddr *)0); 69524813Skarels /* 69624813Skarels * Find address associated with outgoing interface. 69724813Skarels */ 69824813Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 69924813Skarels if (ia->ia_ifp == ipforward_rt.ro_rt->rt_ifp) 70024813Skarels break; 70124813Skarels return (ia); 70224813Skarels } 70324813Skarels 70424813Skarels /* 70524813Skarels * Save incoming source route for use in replies, 70624813Skarels * to be picked up later by ip_srcroute if the receiver is interested. 70724813Skarels */ 70824813Skarels save_rte(option, dst) 70926384Skarels u_char *option; 71024813Skarels struct in_addr dst; 71124813Skarels { 71226384Skarels unsigned olen; 71324813Skarels extern ipprintfs; 71424813Skarels 71524813Skarels olen = option[IPOPT_OLEN]; 71624813Skarels if (olen > sizeof(ip_srcrt) - 1) { 71724813Skarels if (ipprintfs) 71824813Skarels printf("save_rte: olen %d\n", olen); 71924813Skarels return; 72024813Skarels } 72126384Skarels bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen); 72224813Skarels ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 72324813Skarels ip_srcrt.route[ip_nhops++] = dst; 72424813Skarels } 72524813Skarels 72624813Skarels /* 72724813Skarels * Retrieve incoming source route for use in replies, 72824813Skarels * in the same form used by setsockopt. 72924813Skarels * The first hop is placed before the options, will be removed later. 73024813Skarels */ 73124813Skarels struct mbuf * 73224813Skarels ip_srcroute() 73324813Skarels { 73424813Skarels register struct in_addr *p, *q; 73524813Skarels register struct mbuf *m; 73624813Skarels 73724813Skarels if (ip_nhops == 0) 73824813Skarels return ((struct mbuf *)0); 73931201Skarels m = m_get(M_DONTWAIT, MT_SOOPTS); 74031201Skarels if (m == 0) 74131201Skarels return ((struct mbuf *)0); 74224813Skarels m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1; 74324813Skarels 74424813Skarels /* 74524813Skarels * First save first hop for return route 74624813Skarels */ 74724813Skarels p = &ip_srcrt.route[ip_nhops - 1]; 74824813Skarels *(mtod(m, struct in_addr *)) = *p--; 74924813Skarels 75024813Skarels /* 75124813Skarels * Copy option fields and padding (nop) to mbuf. 75224813Skarels */ 75324813Skarels ip_srcrt.nop = IPOPT_NOP; 75424813Skarels bcopy((caddr_t)&ip_srcrt, mtod(m, caddr_t) + sizeof(struct in_addr), 75524813Skarels IPOPT_OFFSET + 1 + 1); 75624813Skarels q = (struct in_addr *)(mtod(m, caddr_t) + 75724813Skarels sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1); 75824813Skarels /* 75924813Skarels * Record return path as an IP source route, 76024813Skarels * reversing the path (pointers are now aligned). 76124813Skarels */ 76224813Skarels while (p >= ip_srcrt.route) 76324813Skarels *q++ = *p--; 76424813Skarels return (m); 76524813Skarels } 76624813Skarels 76724813Skarels /* 7684951Swnj * Strip out IP options, at higher 7694951Swnj * level protocol in the kernel. 7704951Swnj * Second argument is buffer to which options 7714951Swnj * will be moved, and return value is their length. 7724640Swnj */ 7735217Swnj ip_stripoptions(ip, mopt) 7744640Swnj struct ip *ip; 7755217Swnj struct mbuf *mopt; 7764495Swnj { 7774640Swnj register int i; 7784640Swnj register struct mbuf *m; 77924813Skarels register caddr_t opts; 7804640Swnj int olen; 7814640Swnj 7824640Swnj olen = (ip->ip_hl<<2) - sizeof (struct ip); 7834951Swnj m = dtom(ip); 78424813Skarels opts = (caddr_t)(ip + 1); 7855217Swnj if (mopt) { 7865217Swnj mopt->m_len = olen; 7875217Swnj mopt->m_off = MMINOFF; 78824813Skarels bcopy(opts, mtod(mopt, caddr_t), (unsigned)olen); 7895217Swnj } 7904640Swnj i = m->m_len - (sizeof (struct ip) + olen); 79124813Skarels bcopy(opts + olen, opts, (unsigned)i); 7925243Sroot m->m_len -= olen; 79324813Skarels ip->ip_hl = sizeof(struct ip) >> 2; 7944495Swnj } 7956583Ssam 79614670Ssam u_char inetctlerrmap[PRC_NCMDS] = { 79724813Skarels 0, 0, 0, 0, 79814670Ssam 0, 0, EHOSTDOWN, EHOSTUNREACH, 79914670Ssam ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 80024813Skarels EMSGSIZE, EHOSTUNREACH, 0, 0, 80124813Skarels 0, 0, 0, 0, 80224813Skarels ENOPROTOOPT 8036583Ssam }; 8046583Ssam 80524813Skarels #ifndef IPFORWARDING 80624813Skarels #define IPFORWARDING 1 80724813Skarels #endif 80824813Skarels #ifndef IPSENDREDIRECTS 80924813Skarels #define IPSENDREDIRECTS 1 81024813Skarels #endif 8116583Ssam int ipprintfs = 0; 81224813Skarels int ipforwarding = IPFORWARDING; 81324813Skarels extern int in_interfaces; 81424813Skarels int ipsendredirects = IPSENDREDIRECTS; 81524813Skarels 8166583Ssam /* 8176583Ssam * Forward a packet. If some error occurs return the sender 81818376Skarels * an icmp packet. Note we can't always generate a meaningful 81924813Skarels * icmp message because icmp doesn't have a large enough repertoire 8206583Ssam * of codes and types. 82126308Skarels * 82226308Skarels * If not forwarding (possibly because we have only a single external 82326308Skarels * network), just drop the packet. This could be confusing if ipforwarding 82426308Skarels * was zero but some routing protocol was advancing us as a gateway 82526308Skarels * to somewhere. However, we must let the routing protocol deal with that. 8266583Ssam */ 82724813Skarels ip_forward(ip, ifp) 8286583Ssam register struct ip *ip; 82924813Skarels struct ifnet *ifp; 8306583Ssam { 83124813Skarels register int error, type = 0, code; 83224813Skarels register struct sockaddr_in *sin; 83318376Skarels struct mbuf *mcopy; 83424813Skarels struct in_addr dest; 8356583Ssam 83624813Skarels dest.s_addr = 0; 8376583Ssam if (ipprintfs) 8386583Ssam printf("forward: src %x dst %x ttl %x\n", ip->ip_src, 8396583Ssam ip->ip_dst, ip->ip_ttl); 84018376Skarels ip->ip_id = htons(ip->ip_id); 84124813Skarels if (ipforwarding == 0 || in_interfaces <= 1) { 84226308Skarels ipstat.ips_cantforward++; 84326985Skarels #ifdef GATEWAY 84426985Skarels type = ICMP_UNREACH, code = ICMP_UNREACH_NET; 84526985Skarels goto sendicmp; 84626985Skarels #else 84726308Skarels m_freem(dtom(ip)); 84826308Skarels return; 84926985Skarels #endif 8506583Ssam } 85132572Skarels if (in_canforward(ip->ip_dst) == 0) { 85232572Skarels m_freem(dtom(ip)); 85332572Skarels return; 85432572Skarels } 85531393Skarels if (ip->ip_ttl <= IPTTLDEC) { 8566583Ssam type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS; 8576583Ssam goto sendicmp; 8586583Ssam } 8596583Ssam ip->ip_ttl -= IPTTLDEC; 8606609Ssam 8616609Ssam /* 8626609Ssam * Save at most 64 bytes of the packet in case 8636609Ssam * we need to generate an ICMP message to the src. 8646609Ssam */ 86528944Skarels mcopy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64)); 8666583Ssam 86724813Skarels sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 86824813Skarels if (ipforward_rt.ro_rt == 0 || 86924813Skarels ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 87024813Skarels if (ipforward_rt.ro_rt) { 87124813Skarels RTFREE(ipforward_rt.ro_rt); 87224813Skarels ipforward_rt.ro_rt = 0; 87324813Skarels } 87424813Skarels sin->sin_family = AF_INET; 87524813Skarels sin->sin_addr = ip->ip_dst; 87624813Skarels 87724813Skarels rtalloc(&ipforward_rt); 87824813Skarels } 87924813Skarels /* 88024813Skarels * If forwarding packet using same interface that it came in on, 88124813Skarels * perhaps should send a redirect to sender to shortcut a hop. 88224813Skarels * Only send redirect if source is sending directly to us, 88324813Skarels * and if packet was not source routed (or has any options). 88430447Skarels * Also, don't send redirect if forwarding using a default route 88530447Skarels * or a route modfied by a redirect. 88624813Skarels */ 88730447Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 88824813Skarels if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp && 88932572Skarels (ipforward_rt.ro_rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 89030447Skarels satosin(&ipforward_rt.ro_rt->rt_dst)->sin_addr.s_addr != 0 && 89124813Skarels ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) { 89224813Skarels struct in_ifaddr *ia; 89324813Skarels u_long src = ntohl(ip->ip_src.s_addr); 89424813Skarels u_long dst = ntohl(ip->ip_dst.s_addr); 89524813Skarels 89624813Skarels if ((ia = ifptoia(ifp)) && 89724813Skarels (src & ia->ia_subnetmask) == ia->ia_subnet) { 89824813Skarels if (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) 89924813Skarels dest = satosin(&ipforward_rt.ro_rt->rt_gateway)->sin_addr; 90024813Skarels else 90124813Skarels dest = ip->ip_dst; 90224813Skarels /* 90324813Skarels * If the destination is reached by a route to host, 90427145Skarels * is on a subnet of a local net, or is directly 90527145Skarels * on the attached net (!), use host redirect. 90624813Skarels * (We may be the correct first hop for other subnets.) 90724813Skarels */ 90824813Skarels type = ICMP_REDIRECT; 90924813Skarels code = ICMP_REDIRECT_NET; 91024813Skarels if ((ipforward_rt.ro_rt->rt_flags & RTF_HOST) || 91124813Skarels (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) == 0) 91224813Skarels code = ICMP_REDIRECT_HOST; 91324813Skarels else for (ia = in_ifaddr; ia = ia->ia_next; ) 91424813Skarels if ((dst & ia->ia_netmask) == ia->ia_net) { 91527145Skarels if (ia->ia_subnetmask != ia->ia_netmask) 91627145Skarels code = ICMP_REDIRECT_HOST; 91724813Skarels break; 91824813Skarels } 91924813Skarels if (ipprintfs) 92024813Skarels printf("redirect (%d) to %x\n", code, dest); 92124813Skarels } 92224813Skarels } 92324813Skarels 92424813Skarels error = ip_output(dtom(ip), (struct mbuf *)0, &ipforward_rt, 92518376Skarels IP_FORWARDING); 92624813Skarels if (error) 92724813Skarels ipstat.ips_cantforward++; 92824813Skarels else if (type) 92924813Skarels ipstat.ips_redirectsent++; 93024813Skarels else { 9316609Ssam if (mcopy) 9326609Ssam m_freem(mcopy); 93321117Skarels ipstat.ips_forward++; 9346583Ssam return; 9356609Ssam } 93611540Ssam if (mcopy == NULL) 93711540Ssam return; 9386609Ssam ip = mtod(mcopy, struct ip *); 93924813Skarels type = ICMP_UNREACH; 9406609Ssam switch (error) { 9416609Ssam 94224813Skarels case 0: /* forwarded, but need redirect */ 94324813Skarels type = ICMP_REDIRECT; 94424813Skarels /* code set above */ 94524813Skarels break; 94624813Skarels 9476609Ssam case ENETUNREACH: 9486609Ssam case ENETDOWN: 94932572Skarels if (in_localaddr(ip->ip_dst)) 95032572Skarels code = ICMP_UNREACH_HOST; 95132572Skarels else 95232572Skarels code = ICMP_UNREACH_NET; 9536609Ssam break; 9546609Ssam 9556609Ssam case EMSGSIZE: 9566583Ssam code = ICMP_UNREACH_NEEDFRAG; 9576609Ssam break; 9586609Ssam 9596609Ssam case EPERM: 9606609Ssam code = ICMP_UNREACH_PORT; 9616609Ssam break; 9626609Ssam 9636609Ssam case ENOBUFS: 9646609Ssam type = ICMP_SOURCEQUENCH; 9656609Ssam break; 9666609Ssam 9676609Ssam case EHOSTDOWN: 9686609Ssam case EHOSTUNREACH: 9696609Ssam code = ICMP_UNREACH_HOST; 9706609Ssam break; 9716609Ssam } 9726583Ssam sendicmp: 97326031Skarels icmp_error(ip, type, code, ifp, dest); 9746583Ssam } 975