1*18373Skarels /* ip_icmp.c 6.9 85/03/18 */ 24785Swnj 317059Sbloom #include "param.h" 417059Sbloom #include "systm.h" 517059Sbloom #include "mbuf.h" 617059Sbloom #include "protosw.h" 717059Sbloom #include "socket.h" 817059Sbloom #include "time.h" 917059Sbloom #include "kernel.h" 108694Sroot 118694Sroot #include "../net/route.h" 12*18373Skarels #include "../net/if.h" 1310891Ssam 1417059Sbloom #include "in.h" 1517059Sbloom #include "in_systm.h" 16*18373Skarels #include "in_var.h" 1717059Sbloom #include "ip.h" 1817059Sbloom #include "ip_icmp.h" 1917059Sbloom #include "icmp_var.h" 204785Swnj 2115027Smckusick #ifdef ICMPPRINTFS 224785Swnj /* 234785Swnj * ICMP routines: error generation, receive packet processing, and 244785Swnj * routines to turnaround packets back to the originator, and 254785Swnj * host table maintenance routines. 264785Swnj */ 276608Ssam int icmpprintfs = 0; 2815027Smckusick #endif 294785Swnj 304785Swnj /* 316583Ssam * Generate an error packet of type error 326583Ssam * in response to bad packet ip. 334785Swnj */ 344785Swnj icmp_error(oip, type, code) 354785Swnj struct ip *oip; 3612764Ssam int type, code; 374785Swnj { 386583Ssam register unsigned oiplen = oip->ip_hl << 2; 396583Ssam register struct icmp *icp; 404785Swnj struct mbuf *m; 414785Swnj struct ip *nip; 424785Swnj 4315027Smckusick #ifdef ICMPPRINTFS 446590Ssam if (icmpprintfs) 456590Ssam printf("icmp_error(%x, %d, %d)\n", oip, type, code); 4615027Smckusick #endif 4711532Ssam icmpstat.icps_error++; 484785Swnj /* 494785Swnj * Make sure that the old IP packet had 8 bytes of data to return; 504785Swnj * if not, don't bother. Also don't EVER error if the old 514785Swnj * packet protocol was ICMP. 524785Swnj */ 5311532Ssam if (oip->ip_len < 8) { 5411532Ssam icmpstat.icps_oldshort++; 554785Swnj goto free; 5611532Ssam } 5711532Ssam if (oip->ip_p == IPPROTO_ICMP) { 5811532Ssam icmpstat.icps_oldicmp++; 5911532Ssam goto free; 6011532Ssam } 614785Swnj 624785Swnj /* 636583Ssam * First, formulate icmp message 644785Swnj */ 659640Ssam m = m_get(M_DONTWAIT, MT_HEADER); 6611532Ssam if (m == NULL) 674785Swnj goto free; 686583Ssam m->m_len = oiplen + 8 + ICMP_MINLEN; 696583Ssam m->m_off = MMAXOFF - m->m_len; 706583Ssam icp = mtod(m, struct icmp *); 7112764Ssam if ((u_int)type > ICMP_IREQREPLY) 7211532Ssam panic("icmp_error"); 7311532Ssam icmpstat.icps_outhist[type]++; 744785Swnj icp->icmp_type = type; 756583Ssam icp->icmp_void = 0; 764785Swnj if (type == ICMP_PARAMPROB) { 774785Swnj icp->icmp_pptr = code; 786583Ssam code = 0; 796583Ssam } 806583Ssam icp->icmp_code = code; 814801Swnj bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8); 826590Ssam nip = &icp->icmp_ip; 836590Ssam nip->ip_len += oiplen; 846590Ssam nip->ip_len = htons((u_short)nip->ip_len); 854785Swnj 864785Swnj /* 876583Ssam * Now, copy old ip header in front of icmp 886583Ssam * message. This allows us to reuse any source 896583Ssam * routing info present. 904785Swnj */ 916583Ssam m->m_off -= oiplen; 926583Ssam nip = mtod(m, struct ip *); 936583Ssam bcopy((caddr_t)oip, (caddr_t)nip, oiplen); 946583Ssam nip->ip_len = m->m_len + oiplen; 956583Ssam nip->ip_p = IPPROTO_ICMP; 966583Ssam /* icmp_send adds ip header to m_off and m_len, so we deduct here */ 976583Ssam m->m_off += oiplen; 984801Swnj icmp_reflect(nip); 994785Swnj 1006485Swnj free: 1014785Swnj m_freem(dtom(oip)); 1024785Swnj } 1034785Swnj 1046583Ssam static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; 1056583Ssam static struct sockaddr_in icmpsrc = { AF_INET }; 1066583Ssam static struct sockaddr_in icmpdst = { AF_INET }; 1076583Ssam 1084785Swnj /* 1094801Swnj * Process a received ICMP message. 1104785Swnj */ 1114785Swnj icmp_input(m) 1124785Swnj struct mbuf *m; 1134785Swnj { 1144801Swnj register struct icmp *icp; 1154801Swnj register struct ip *ip = mtod(m, struct ip *); 1169185Ssam int icmplen = ip->ip_len, hlen = ip->ip_hl << 2; 11716171Skarels register int i; 11816171Skarels int (*ctlfunc)(), code; 1195172Swnj extern u_char ip_protox[]; 120*18373Skarels extern struct in_addr in_makeaddr(); 1214785Swnj 1224785Swnj /* 1234785Swnj * Locate icmp structure in mbuf, and check 1244785Swnj * that not corrupted and of at least minimum length. 1254785Swnj */ 12615027Smckusick #ifdef ICMPPRINTFS 1276590Ssam if (icmpprintfs) 1286590Ssam printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen); 12915027Smckusick #endif 13015913Skarels if (icmplen < ICMP_MINLEN) { 13111532Ssam icmpstat.icps_tooshort++; 1326583Ssam goto free; 13311532Ssam } 13416171Skarels /* THIS LENGTH CHECK STILL MISSES ANY IP OPTIONS IN ICMP_IP */ 13516171Skarels i = MIN(icmplen, ICMP_ADVLENMIN + hlen); 13616171Skarels if ((m->m_off > MMAXOFF || m->m_len < i) && 13716171Skarels (m = m_pullup(m, i)) == 0) { 13815831Skarels icmpstat.icps_tooshort++; 13915831Skarels return; 14015831Skarels } 14116171Skarels ip = mtod(m, struct ip *); 1424785Swnj m->m_len -= hlen; 1434785Swnj m->m_off += hlen; 1446583Ssam icp = mtod(m, struct icmp *); 14516171Skarels if (in_cksum(m, icmplen)) { 14611532Ssam icmpstat.icps_checksum++; 1474801Swnj goto free; 1486583Ssam } 1494785Swnj 15015027Smckusick #ifdef ICMPPRINTFS 1514785Swnj /* 1524785Swnj * Message type specific processing. 1534785Swnj */ 1546590Ssam if (icmpprintfs) 1556590Ssam printf("icmp_input, type %d code %d\n", icp->icmp_type, 15615027Smckusick icp->icmp_code); 15715027Smckusick #endif 15811532Ssam if (icp->icmp_type > ICMP_IREQREPLY) 15911532Ssam goto free; 16011532Ssam icmpstat.icps_inhist[icp->icmp_type]++; 16115027Smckusick code = icp->icmp_code; 16211532Ssam switch (icp->icmp_type) { 1634785Swnj 1644785Swnj case ICMP_UNREACH: 16515027Smckusick if (code > 5) 16615027Smckusick goto badcode; 16715027Smckusick code += PRC_UNREACH_NET; 16815027Smckusick goto deliver; 16915027Smckusick 1704785Swnj case ICMP_TIMXCEED: 17115027Smckusick if (code > 1) 17215027Smckusick goto badcode; 17315027Smckusick code += PRC_TIMXCEED_INTRANS; 17415027Smckusick goto deliver; 17515027Smckusick 1764785Swnj case ICMP_PARAMPROB: 17715027Smckusick if (code) 17815027Smckusick goto badcode; 17915027Smckusick code = PRC_PARAMPROB; 18015027Smckusick goto deliver; 18115027Smckusick 1824785Swnj case ICMP_SOURCEQUENCH: 18315027Smckusick if (code) 18415027Smckusick goto badcode; 18515027Smckusick code = PRC_QUENCH; 18615027Smckusick deliver: 1874785Swnj /* 18815027Smckusick * Problem with datagram; advise higher level routines. 1894785Swnj */ 1908637Sroot icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len); 19111532Ssam if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 19211532Ssam icmpstat.icps_badlen++; 1934801Swnj goto free; 19411532Ssam } 19515027Smckusick #ifdef ICMPPRINTFS 1966590Ssam if (icmpprintfs) 1976590Ssam printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 19815027Smckusick #endif 1999030Sroot if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) 20015027Smckusick (*ctlfunc)(code, (caddr_t)icp); 2014785Swnj goto free; 2024785Swnj 20315027Smckusick badcode: 20415027Smckusick icmpstat.icps_badcode++; 20515027Smckusick goto free; 20615027Smckusick 2074785Swnj case ICMP_ECHO: 2084785Swnj icp->icmp_type = ICMP_ECHOREPLY; 2094785Swnj goto reflect; 2104785Swnj 2114785Swnj case ICMP_TSTAMP: 21211532Ssam if (icmplen < ICMP_TSLEN) { 21311532Ssam icmpstat.icps_badlen++; 2144801Swnj goto free; 21511532Ssam } 2164785Swnj icp->icmp_type = ICMP_TSTAMPREPLY; 2174923Swnj icp->icmp_rtime = iptime(); 2184785Swnj icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 2194785Swnj goto reflect; 2204785Swnj 2214785Swnj case ICMP_IREQ: 222*18373Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 223*18373Skarels if (in_netof(ip->ip_src) == 0) 224*18373Skarels ip->ip_src = in_makeaddr( 225*18373Skarels in_netof(satosin(&in_ifaddr->ia_addr)->sin_addr), 226*18373Skarels in_lnaof(ip->ip_src)); 227*18373Skarels icp->icmp_type = ICMP_IREQREPLY; 2284785Swnj goto reflect; 2294785Swnj 23011549Ssam case ICMP_REDIRECT: 23111532Ssam if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 23211532Ssam icmpstat.icps_badlen++; 2334801Swnj goto free; 23411532Ssam } 23511549Ssam /* 23611549Ssam * Short circuit routing redirects to force 23711549Ssam * immediate change in the kernel's routing 23811549Ssam * tables. The message is also handed to anyone 23911549Ssam * listening on a raw socket (e.g. the routing 24017046Skarels * daemon for use in updating its tables). 24111549Ssam */ 24215831Skarels icmpdst.sin_addr = icp->icmp_gwaddr; 24317046Skarels if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) { 24417046Skarels icmpsrc.sin_addr = 245*18373Skarels in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY); 24617046Skarels rtredirect((struct sockaddr *)&icmpsrc, 24717046Skarels (struct sockaddr *)&icmpdst, RTF_GATEWAY); 24817358Skarels ip_ctlinput(PRC_REDIRECT_NET, (caddr_t)icp); 24917046Skarels } else { 25017046Skarels icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 25117046Skarels rtredirect((struct sockaddr *)&icmpsrc, 25217046Skarels (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST); 25317358Skarels ip_ctlinput(PRC_REDIRECT_HOST, (caddr_t)icp); 25417046Skarels } 25515831Skarels /* FALL THROUGH */ 25615831Skarels 25715831Skarels case ICMP_ECHOREPLY: 25815831Skarels case ICMP_TSTAMPREPLY: 25915831Skarels case ICMP_IREQREPLY: 2606583Ssam icmpsrc.sin_addr = ip->ip_src; 2616583Ssam icmpdst.sin_addr = ip->ip_dst; 2626583Ssam raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc, 2636583Ssam (struct sockaddr *)&icmpdst); 26412165Ssam return; 2654785Swnj 2664785Swnj default: 2674785Swnj goto free; 2684785Swnj } 2694785Swnj reflect: 27011228Ssam ip->ip_len += hlen; /* since ip_input deducts this */ 27111532Ssam icmpstat.icps_reflect++; 2724785Swnj icmp_reflect(ip); 2739185Ssam return; 2744785Swnj free: 2754785Swnj m_freem(dtom(ip)); 2764785Swnj } 2774785Swnj 2784785Swnj /* 2794785Swnj * Reflect the ip packet back to the source 2806583Ssam * TODO: rearrange ip source routing options. 2814785Swnj */ 2824785Swnj icmp_reflect(ip) 2834785Swnj struct ip *ip; 2844785Swnj { 285*18373Skarels register struct in_addr t; 286*18373Skarels register struct in_ifaddr *ia; 2874785Swnj 2886583Ssam t = ip->ip_dst; 289*18373Skarels if (t.s_addr == INADDR_ANY) 290*18373Skarels t = IA_SIN(in_ifaddr)->sin_addr; 291*18373Skarels else for (ia = in_ifaddr; ia; ia = ia->ia_next) 292*18373Skarels if (t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr && 293*18373Skarels (ia->ia_ifp->if_flags & IFF_BROADCAST)) { 294*18373Skarels t = IA_SIN(ia)->sin_addr; 295*18373Skarels break; 296*18373Skarels } 2976583Ssam ip->ip_dst = ip->ip_src; 2986583Ssam ip->ip_src = t; 2994785Swnj icmp_send(ip); 3004785Swnj } 3014785Swnj 3024785Swnj /* 3036583Ssam * Send an icmp packet back to the ip level, 3046583Ssam * after supplying a checksum. 3054785Swnj */ 3064907Swnj icmp_send(ip) 3074785Swnj struct ip *ip; 3084785Swnj { 3099185Ssam register int hlen; 3106583Ssam register struct icmp *icp; 3119185Ssam register struct mbuf *m; 3126583Ssam 3139185Ssam m = dtom(ip); 3149185Ssam hlen = ip->ip_hl << 2; 3156583Ssam icp = mtod(m, struct icmp *); 3166583Ssam icp->icmp_cksum = 0; 3176583Ssam icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 3186583Ssam m->m_off -= hlen; 3196583Ssam m->m_len += hlen; 32015027Smckusick #ifdef ICMPPRINTFS 3216590Ssam if (icmpprintfs) 3226590Ssam printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 32315027Smckusick #endif 3248637Sroot (void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0); 3254785Swnj } 3264785Swnj 3274907Swnj n_time 3284923Swnj iptime() 3294801Swnj { 3304907Swnj int s = spl6(); 3314967Swnj u_long t; 3324801Swnj 3338171Sroot t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000; 3344907Swnj splx(s); 3354907Swnj return (htonl(t)); 3364801Swnj } 337