ip_icmp.c revision 12881
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1988, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 3412881Sbde * $Id: ip_icmp.c,v 1.16 1995/12/14 09:53:40 phk Exp $ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes#include <sys/param.h> 381541Srgrimes#include <sys/systm.h> 391541Srgrimes#include <sys/malloc.h> 401541Srgrimes#include <sys/mbuf.h> 411541Srgrimes#include <sys/protosw.h> 421541Srgrimes#include <sys/socket.h> 431541Srgrimes#include <sys/time.h> 441541Srgrimes#include <sys/kernel.h> 453444Sphk#include <sys/socket.h> 467090Sbde#include <sys/sysctl.h> 471541Srgrimes 481541Srgrimes#include <net/if.h> 491541Srgrimes#include <net/route.h> 501541Srgrimes 511541Srgrimes#include <netinet/in.h> 521541Srgrimes#include <netinet/in_systm.h> 531541Srgrimes#include <netinet/in_var.h> 541541Srgrimes#include <netinet/ip.h> 551541Srgrimes#include <netinet/ip_icmp.h> 567090Sbde#include <netinet/ip_var.h> 571541Srgrimes#include <netinet/icmp_var.h> 581541Srgrimes 591541Srgrimes/* 601541Srgrimes * ICMP routines: error generation, receive packet processing, and 611541Srgrimes * routines to turnaround packets back to the originator, and 621541Srgrimes * host table maintenance routines. 631541Srgrimes */ 641541Srgrimes 6512820Sphkstatic struct icmpstat icmpstat; 6612296SphkSYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD, 6712296Sphk &icmpstat, icmpstat, ""); 6812296Sphk 6912296Sphkstatic int icmpmaskrepl = 0; 7012296SphkSYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW, 7112296Sphk &icmpmaskrepl, 0, ""); 7212296Sphk 731541Srgrimes#ifdef ICMPPRINTFS 741541Srgrimesint icmpprintfs = 0; 751541Srgrimes#endif 761541Srgrimes 7712296Sphkstatic void icmp_reflect __P((struct mbuf *)); 7812296Sphkstatic void icmp_send __P((struct mbuf *, struct mbuf *)); 7912820Sphkstatic int ip_next_mtu __P((int, int)); 8012296Sphk 811541Srgrimesextern struct protosw inetsw[]; 821541Srgrimes 831541Srgrimes/* 841541Srgrimes * Generate an error packet of type error 851541Srgrimes * in response to bad packet ip. 861541Srgrimes */ 871541Srgrimesvoid 881541Srgrimesicmp_error(n, type, code, dest, destifp) 891541Srgrimes struct mbuf *n; 901541Srgrimes int type, code; 911541Srgrimes n_long dest; 921541Srgrimes struct ifnet *destifp; 931541Srgrimes{ 941541Srgrimes register struct ip *oip = mtod(n, struct ip *), *nip; 951541Srgrimes register unsigned oiplen = oip->ip_hl << 2; 961541Srgrimes register struct icmp *icp; 971541Srgrimes register struct mbuf *m; 981541Srgrimes unsigned icmplen; 991541Srgrimes 1001541Srgrimes#ifdef ICMPPRINTFS 1011541Srgrimes if (icmpprintfs) 1023311Sphk printf("icmp_error(%p, %x, %d)\n", oip, type, code); 1031541Srgrimes#endif 1041541Srgrimes if (type != ICMP_REDIRECT) 1051541Srgrimes icmpstat.icps_error++; 1061541Srgrimes /* 1071541Srgrimes * Don't send error if not the first fragment of message. 1081541Srgrimes * Don't error if the old packet protocol was ICMP 1091541Srgrimes * error message, only known informational types. 1101541Srgrimes */ 1111541Srgrimes if (oip->ip_off &~ (IP_MF|IP_DF)) 1121541Srgrimes goto freeit; 1131541Srgrimes if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 1141541Srgrimes n->m_len >= oiplen + ICMP_MINLEN && 1151541Srgrimes !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { 1161541Srgrimes icmpstat.icps_oldicmp++; 1171541Srgrimes goto freeit; 1181541Srgrimes } 1191541Srgrimes /* Don't send error in response to a multicast or broadcast packet */ 1201541Srgrimes if (n->m_flags & (M_BCAST|M_MCAST)) 1211541Srgrimes goto freeit; 1221541Srgrimes /* 1231541Srgrimes * First, formulate icmp message 1241541Srgrimes */ 1251541Srgrimes m = m_gethdr(M_DONTWAIT, MT_HEADER); 1261541Srgrimes if (m == NULL) 1271541Srgrimes goto freeit; 1281541Srgrimes icmplen = oiplen + min(8, oip->ip_len); 1291541Srgrimes m->m_len = icmplen + ICMP_MINLEN; 1301541Srgrimes MH_ALIGN(m, m->m_len); 1311541Srgrimes icp = mtod(m, struct icmp *); 1321541Srgrimes if ((u_int)type > ICMP_MAXTYPE) 1331541Srgrimes panic("icmp_error"); 1341541Srgrimes icmpstat.icps_outhist[type]++; 1351541Srgrimes icp->icmp_type = type; 1361541Srgrimes if (type == ICMP_REDIRECT) 1371541Srgrimes icp->icmp_gwaddr.s_addr = dest; 1381541Srgrimes else { 1391541Srgrimes icp->icmp_void = 0; 1408876Srgrimes /* 1411541Srgrimes * The following assignments assume an overlay with the 1421541Srgrimes * zeroed icmp_void field. 1431541Srgrimes */ 1441541Srgrimes if (type == ICMP_PARAMPROB) { 1451541Srgrimes icp->icmp_pptr = code; 1461541Srgrimes code = 0; 1471541Srgrimes } else if (type == ICMP_UNREACH && 1481541Srgrimes code == ICMP_UNREACH_NEEDFRAG && destifp) { 1491541Srgrimes icp->icmp_nextmtu = htons(destifp->if_mtu); 1501541Srgrimes } 1511541Srgrimes } 1521541Srgrimes 1531541Srgrimes icp->icmp_code = code; 1541541Srgrimes bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); 1551541Srgrimes nip = &icp->icmp_ip; 1561541Srgrimes nip->ip_len = htons((u_short)(nip->ip_len + oiplen)); 1571541Srgrimes 1581541Srgrimes /* 1591541Srgrimes * Now, copy old ip header (without options) 1601541Srgrimes * in front of icmp message. 1611541Srgrimes */ 1621541Srgrimes if (m->m_data - sizeof(struct ip) < m->m_pktdat) 1631541Srgrimes panic("icmp len"); 1641541Srgrimes m->m_data -= sizeof(struct ip); 1651541Srgrimes m->m_len += sizeof(struct ip); 1661541Srgrimes m->m_pkthdr.len = m->m_len; 1671541Srgrimes m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 1681541Srgrimes nip = mtod(m, struct ip *); 1691541Srgrimes bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); 1701541Srgrimes nip->ip_len = m->m_len; 1711541Srgrimes nip->ip_hl = sizeof(struct ip) >> 2; 1721541Srgrimes nip->ip_p = IPPROTO_ICMP; 1731541Srgrimes nip->ip_tos = 0; 1741541Srgrimes icmp_reflect(m); 1751541Srgrimes 1761541Srgrimesfreeit: 1771541Srgrimes m_freem(n); 1781541Srgrimes} 1791541Srgrimes 1801541Srgrimesstatic struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 1811541Srgrimesstatic struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 1821541Srgrimesstatic struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 1831541Srgrimes 1841541Srgrimes/* 1851541Srgrimes * Process a received ICMP message. 1861541Srgrimes */ 1871541Srgrimesvoid 1881541Srgrimesicmp_input(m, hlen) 1891541Srgrimes register struct mbuf *m; 1901541Srgrimes int hlen; 1911541Srgrimes{ 1921541Srgrimes register struct icmp *icp; 1931541Srgrimes register struct ip *ip = mtod(m, struct ip *); 1941541Srgrimes int icmplen = ip->ip_len; 1951541Srgrimes register int i; 1961541Srgrimes struct in_ifaddr *ia; 19712881Sbde void (*ctlfunc) __P((int, struct sockaddr *, void *)); 1981541Srgrimes int code; 1991541Srgrimes 2001541Srgrimes /* 2011541Srgrimes * Locate icmp structure in mbuf, and check 2021541Srgrimes * that not corrupted and of at least minimum length. 2031541Srgrimes */ 2041541Srgrimes#ifdef ICMPPRINTFS 20510421Swollman if (icmpprintfs) { 20610421Swollman char buf[4 * sizeof "123"]; 20710421Swollman strcpy(buf, inet_ntoa(ip->ip_src)); 20810421Swollman printf("icmp_input from %s to %s, len %d\n", 20910421Swollman buf, inet_ntoa(ip->ip_dst), icmplen); 21010421Swollman } 2111541Srgrimes#endif 2121541Srgrimes if (icmplen < ICMP_MINLEN) { 2131541Srgrimes icmpstat.icps_tooshort++; 2141541Srgrimes goto freeit; 2151541Srgrimes } 2161541Srgrimes i = hlen + min(icmplen, ICMP_ADVLENMIN); 2171541Srgrimes if (m->m_len < i && (m = m_pullup(m, i)) == 0) { 2181541Srgrimes icmpstat.icps_tooshort++; 2191541Srgrimes return; 2201541Srgrimes } 2211541Srgrimes ip = mtod(m, struct ip *); 2221541Srgrimes m->m_len -= hlen; 2231541Srgrimes m->m_data += hlen; 2241541Srgrimes icp = mtod(m, struct icmp *); 2251541Srgrimes if (in_cksum(m, icmplen)) { 2261541Srgrimes icmpstat.icps_checksum++; 2271541Srgrimes goto freeit; 2281541Srgrimes } 2291541Srgrimes m->m_len += hlen; 2301541Srgrimes m->m_data -= hlen; 2311541Srgrimes 2321541Srgrimes#ifdef ICMPPRINTFS 2331541Srgrimes if (icmpprintfs) 2341541Srgrimes printf("icmp_input, type %d code %d\n", icp->icmp_type, 2351541Srgrimes icp->icmp_code); 2361541Srgrimes#endif 2379472Swollman 2389472Swollman /* 2399472Swollman * Message type specific processing. 2409472Swollman */ 2411541Srgrimes if (icp->icmp_type > ICMP_MAXTYPE) 2421541Srgrimes goto raw; 2431541Srgrimes icmpstat.icps_inhist[icp->icmp_type]++; 2441541Srgrimes code = icp->icmp_code; 2451541Srgrimes switch (icp->icmp_type) { 2461541Srgrimes 2471541Srgrimes case ICMP_UNREACH: 2481541Srgrimes switch (code) { 2491541Srgrimes case ICMP_UNREACH_NET: 2501541Srgrimes case ICMP_UNREACH_HOST: 2511541Srgrimes case ICMP_UNREACH_PROTOCOL: 2521541Srgrimes case ICMP_UNREACH_PORT: 2531541Srgrimes case ICMP_UNREACH_SRCFAIL: 2541541Srgrimes code += PRC_UNREACH_NET; 2551541Srgrimes break; 2561541Srgrimes 2571541Srgrimes case ICMP_UNREACH_NEEDFRAG: 2581541Srgrimes code = PRC_MSGSIZE; 2591541Srgrimes break; 2608876Srgrimes 2611541Srgrimes case ICMP_UNREACH_NET_UNKNOWN: 2621541Srgrimes case ICMP_UNREACH_NET_PROHIB: 2631541Srgrimes case ICMP_UNREACH_TOSNET: 2641541Srgrimes code = PRC_UNREACH_NET; 2651541Srgrimes break; 2661541Srgrimes 2671541Srgrimes case ICMP_UNREACH_HOST_UNKNOWN: 2681541Srgrimes case ICMP_UNREACH_ISOLATED: 2691541Srgrimes case ICMP_UNREACH_HOST_PROHIB: 2701541Srgrimes case ICMP_UNREACH_TOSHOST: 2711541Srgrimes code = PRC_UNREACH_HOST; 2721541Srgrimes break; 2731541Srgrimes 2741541Srgrimes default: 2751541Srgrimes goto badcode; 2761541Srgrimes } 2771541Srgrimes goto deliver; 2781541Srgrimes 2791541Srgrimes case ICMP_TIMXCEED: 2801541Srgrimes if (code > 1) 2811541Srgrimes goto badcode; 2821541Srgrimes code += PRC_TIMXCEED_INTRANS; 2831541Srgrimes goto deliver; 2841541Srgrimes 2851541Srgrimes case ICMP_PARAMPROB: 2861541Srgrimes if (code > 1) 2871541Srgrimes goto badcode; 2881541Srgrimes code = PRC_PARAMPROB; 2891541Srgrimes goto deliver; 2901541Srgrimes 2911541Srgrimes case ICMP_SOURCEQUENCH: 2921541Srgrimes if (code) 2931541Srgrimes goto badcode; 2941541Srgrimes code = PRC_QUENCH; 2951541Srgrimes deliver: 2961541Srgrimes /* 2971541Srgrimes * Problem with datagram; advise higher level routines. 2981541Srgrimes */ 2991541Srgrimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 3001541Srgrimes icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 3011541Srgrimes icmpstat.icps_badlen++; 3021541Srgrimes goto freeit; 3031541Srgrimes } 3041541Srgrimes NTOHS(icp->icmp_ip.ip_len); 3059472Swollman /* Discard ICMP's in response to multicast packets */ 3069472Swollman if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr))) 3079472Swollman goto badcode; 3081541Srgrimes#ifdef ICMPPRINTFS 3091541Srgrimes if (icmpprintfs) 3101541Srgrimes printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 3111541Srgrimes#endif 3121541Srgrimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 31312635Swollman#if 1 31410881Swollman /* 31510881Swollman * MTU discovery: 31610881Swollman * If we got a needfrag and there is a host route to the 31710881Swollman * original destination, and the MTU is not locked, then 31810881Swollman * set the MTU in the route to the suggested new value 31910881Swollman * (if given) and then notify as usual. The ULPs will 32010881Swollman * notice that the MTU has changed and adapt accordingly. 32110881Swollman * If no new MTU was suggested, then we guess a new one 32210881Swollman * less than the current value. If the new MTU is 32310881Swollman * unreasonably small (arbitrarily set at 296), then 32410881Swollman * we reset the MTU to the interface value and enable the 32510881Swollman * lock bit, indicating that we are no longer doing MTU 32610881Swollman * discovery. 32710881Swollman */ 32810881Swollman if (code == PRC_MSGSIZE) { 32910881Swollman struct rtentry *rt; 33010881Swollman int mtu; 33110881Swollman 33210881Swollman rt = rtalloc1((struct sockaddr *)&icmpsrc, 0, 33310881Swollman RTF_CLONING | RTF_PRCLONING); 33410881Swollman if (rt && (rt->rt_flags & RTF_HOST) 33510881Swollman && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { 33610881Swollman mtu = ntohs(icp->icmp_nextmtu); 33710881Swollman if (!mtu) 33810881Swollman mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu, 33910881Swollman 1); 34012676Swollman#ifdef DEBUG_MTUDISC 34112676Swollman printf("MTU for %s reduced to %d\n", 34212676Swollman inet_ntoa(icmpsrc.sin_addr), mtu); 34312676Swollman#endif 34412676Swollman if (mtu < 296) { 34512635Swollman /* rt->rt_rmx.rmx_mtu = 34612635Swollman rt->rt_ifp->if_mtu; */ 34710881Swollman rt->rt_rmx.rmx_locks |= RTV_MTU; 34810881Swollman } else if (rt->rt_rmx.rmx_mtu > mtu) { 34910881Swollman rt->rt_rmx.rmx_mtu = mtu; 35010881Swollman } 35110881Swollman } 35210881Swollman if (rt) 35310881Swollman RTFREE(rt); 35410881Swollman } 35510881Swollman 35612635Swollman#endif 3573311Sphk ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput; 3583311Sphk if (ctlfunc) 3591541Srgrimes (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, 36012881Sbde (void *)&icp->icmp_ip); 3611541Srgrimes break; 3621541Srgrimes 3631541Srgrimes badcode: 3641541Srgrimes icmpstat.icps_badcode++; 3651541Srgrimes break; 3661541Srgrimes 3671541Srgrimes case ICMP_ECHO: 3681541Srgrimes icp->icmp_type = ICMP_ECHOREPLY; 3691541Srgrimes goto reflect; 3701541Srgrimes 3711541Srgrimes case ICMP_TSTAMP: 3721541Srgrimes if (icmplen < ICMP_TSLEN) { 3731541Srgrimes icmpstat.icps_badlen++; 3741541Srgrimes break; 3751541Srgrimes } 3761541Srgrimes icp->icmp_type = ICMP_TSTAMPREPLY; 3771541Srgrimes icp->icmp_rtime = iptime(); 3781541Srgrimes icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 3791541Srgrimes goto reflect; 3808876Srgrimes 3811541Srgrimes case ICMP_MASKREQ: 3821541Srgrimes#define satosin(sa) ((struct sockaddr_in *)(sa)) 3831541Srgrimes if (icmpmaskrepl == 0) 3841541Srgrimes break; 3851541Srgrimes /* 3861541Srgrimes * We are not able to respond with all ones broadcast 3871541Srgrimes * unless we receive it over a point-to-point interface. 3881541Srgrimes */ 3891541Srgrimes if (icmplen < ICMP_MASKLEN) 3901541Srgrimes break; 3911541Srgrimes switch (ip->ip_dst.s_addr) { 3921541Srgrimes 3931541Srgrimes case INADDR_BROADCAST: 3941541Srgrimes case INADDR_ANY: 3951541Srgrimes icmpdst.sin_addr = ip->ip_src; 3961541Srgrimes break; 3971541Srgrimes 3981541Srgrimes default: 3991541Srgrimes icmpdst.sin_addr = ip->ip_dst; 4001541Srgrimes } 4011541Srgrimes ia = (struct in_ifaddr *)ifaof_ifpforaddr( 4021541Srgrimes (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); 4031541Srgrimes if (ia == 0) 4041541Srgrimes break; 4051541Srgrimes icp->icmp_type = ICMP_MASKREPLY; 4061541Srgrimes icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 4071541Srgrimes if (ip->ip_src.s_addr == 0) { 4081541Srgrimes if (ia->ia_ifp->if_flags & IFF_BROADCAST) 4091541Srgrimes ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; 4101541Srgrimes else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 4111541Srgrimes ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; 4121541Srgrimes } 4131541Srgrimesreflect: 4141541Srgrimes ip->ip_len += hlen; /* since ip_input deducts this */ 4151541Srgrimes icmpstat.icps_reflect++; 4161541Srgrimes icmpstat.icps_outhist[icp->icmp_type]++; 4171541Srgrimes icmp_reflect(m); 4181541Srgrimes return; 4191541Srgrimes 4201541Srgrimes case ICMP_REDIRECT: 4211541Srgrimes if (code > 3) 4221541Srgrimes goto badcode; 4231541Srgrimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 4241541Srgrimes icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 4251541Srgrimes icmpstat.icps_badlen++; 4261541Srgrimes break; 4271541Srgrimes } 4281541Srgrimes /* 4291541Srgrimes * Short circuit routing redirects to force 4301541Srgrimes * immediate change in the kernel's routing 4311541Srgrimes * tables. The message is also handed to anyone 4321541Srgrimes * listening on a raw socket (e.g. the routing 4331541Srgrimes * daemon for use in updating its tables). 4341541Srgrimes */ 4351541Srgrimes icmpgw.sin_addr = ip->ip_src; 4361541Srgrimes icmpdst.sin_addr = icp->icmp_gwaddr; 4371541Srgrimes#ifdef ICMPPRINTFS 43810421Swollman if (icmpprintfs) { 43910421Swollman char buf[4 * sizeof "123"]; 44010421Swollman strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst)); 44110421Swollman 44210421Swollman printf("redirect dst %s to %s\n", 44310421Swollman buf, inet_ntoa(icp->icmp_gwaddr)); 44410421Swollman } 4451541Srgrimes#endif 4461541Srgrimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 4471541Srgrimes rtredirect((struct sockaddr *)&icmpsrc, 4481541Srgrimes (struct sockaddr *)&icmpdst, 4491541Srgrimes (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 4501541Srgrimes (struct sockaddr *)&icmpgw, (struct rtentry **)0); 4511541Srgrimes pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); 4521541Srgrimes break; 4531541Srgrimes 4541541Srgrimes /* 4551541Srgrimes * No kernel processing for the following; 4561541Srgrimes * just fall through to send to raw listener. 4571541Srgrimes */ 4581541Srgrimes case ICMP_ECHOREPLY: 4591541Srgrimes case ICMP_ROUTERADVERT: 4601541Srgrimes case ICMP_ROUTERSOLICIT: 4611541Srgrimes case ICMP_TSTAMPREPLY: 4621541Srgrimes case ICMP_IREQREPLY: 4631541Srgrimes case ICMP_MASKREPLY: 4641541Srgrimes default: 4651541Srgrimes break; 4661541Srgrimes } 4671541Srgrimes 4681541Srgrimesraw: 4691541Srgrimes rip_input(m); 4701541Srgrimes return; 4711541Srgrimes 4721541Srgrimesfreeit: 4731541Srgrimes m_freem(m); 4741541Srgrimes} 4751541Srgrimes 4761541Srgrimes/* 4771541Srgrimes * Reflect the ip packet back to the source 4781541Srgrimes */ 47912296Sphkstatic void 4801541Srgrimesicmp_reflect(m) 4811541Srgrimes struct mbuf *m; 4821541Srgrimes{ 4831541Srgrimes register struct ip *ip = mtod(m, struct ip *); 4841541Srgrimes register struct in_ifaddr *ia; 4851541Srgrimes struct in_addr t; 4867090Sbde struct mbuf *opts = 0; 4871541Srgrimes int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 4881541Srgrimes 4891541Srgrimes if (!in_canforward(ip->ip_src) && 4901541Srgrimes ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) != 4911541Srgrimes (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { 4921541Srgrimes m_freem(m); /* Bad return address */ 4931541Srgrimes goto done; /* Ip_output() will check for broadcast */ 4941541Srgrimes } 4951541Srgrimes t = ip->ip_dst; 4961541Srgrimes ip->ip_dst = ip->ip_src; 4971541Srgrimes /* 4981541Srgrimes * If the incoming packet was addressed directly to us, 4991541Srgrimes * use dst as the src for the reply. Otherwise (broadcast 5001541Srgrimes * or anonymous), use the address which corresponds 5011541Srgrimes * to the incoming interface. 5021541Srgrimes */ 5031541Srgrimes for (ia = in_ifaddr; ia; ia = ia->ia_next) { 5041541Srgrimes if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) 5051541Srgrimes break; 5061541Srgrimes if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 5071541Srgrimes t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) 5081541Srgrimes break; 5091541Srgrimes } 5101541Srgrimes icmpdst.sin_addr = t; 5111541Srgrimes if (ia == (struct in_ifaddr *)0) 5121541Srgrimes ia = (struct in_ifaddr *)ifaof_ifpforaddr( 5131541Srgrimes (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); 5141541Srgrimes /* 5151541Srgrimes * The following happens if the packet was not addressed to us, 5161541Srgrimes * and was received on an interface with no IP address. 5171541Srgrimes */ 5181541Srgrimes if (ia == (struct in_ifaddr *)0) 5191541Srgrimes ia = in_ifaddr; 5201541Srgrimes t = IA_SIN(ia)->sin_addr; 5211541Srgrimes ip->ip_src = t; 5221541Srgrimes ip->ip_ttl = MAXTTL; 5231541Srgrimes 5241541Srgrimes if (optlen > 0) { 5251541Srgrimes register u_char *cp; 5261541Srgrimes int opt, cnt; 5271541Srgrimes u_int len; 5281541Srgrimes 5291541Srgrimes /* 5301541Srgrimes * Retrieve any source routing from the incoming packet; 5311541Srgrimes * add on any record-route or timestamp options. 5321541Srgrimes */ 5331541Srgrimes cp = (u_char *) (ip + 1); 5341541Srgrimes if ((opts = ip_srcroute()) == 0 && 5351541Srgrimes (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 5361541Srgrimes opts->m_len = sizeof(struct in_addr); 5371541Srgrimes mtod(opts, struct in_addr *)->s_addr = 0; 5381541Srgrimes } 5391541Srgrimes if (opts) { 5401541Srgrimes#ifdef ICMPPRINTFS 5411541Srgrimes if (icmpprintfs) 5421541Srgrimes printf("icmp_reflect optlen %d rt %d => ", 5431541Srgrimes optlen, opts->m_len); 5441541Srgrimes#endif 5451541Srgrimes for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 5461541Srgrimes opt = cp[IPOPT_OPTVAL]; 5471541Srgrimes if (opt == IPOPT_EOL) 5481541Srgrimes break; 5491541Srgrimes if (opt == IPOPT_NOP) 5501541Srgrimes len = 1; 5511541Srgrimes else { 5521541Srgrimes len = cp[IPOPT_OLEN]; 5531541Srgrimes if (len <= 0 || len > cnt) 5541541Srgrimes break; 5551541Srgrimes } 5561541Srgrimes /* 5571541Srgrimes * Should check for overflow, but it "can't happen" 5581541Srgrimes */ 5598876Srgrimes if (opt == IPOPT_RR || opt == IPOPT_TS || 5601541Srgrimes opt == IPOPT_SECURITY) { 5611541Srgrimes bcopy((caddr_t)cp, 5621541Srgrimes mtod(opts, caddr_t) + opts->m_len, len); 5631541Srgrimes opts->m_len += len; 5641541Srgrimes } 5651541Srgrimes } 5661541Srgrimes /* Terminate & pad, if necessary */ 5673311Sphk cnt = opts->m_len % 4; 5683311Sphk if (cnt) { 5691541Srgrimes for (; cnt < 4; cnt++) { 5701541Srgrimes *(mtod(opts, caddr_t) + opts->m_len) = 5711541Srgrimes IPOPT_EOL; 5721541Srgrimes opts->m_len++; 5731541Srgrimes } 5741541Srgrimes } 5751541Srgrimes#ifdef ICMPPRINTFS 5761541Srgrimes if (icmpprintfs) 5771541Srgrimes printf("%d\n", opts->m_len); 5781541Srgrimes#endif 5791541Srgrimes } 5801541Srgrimes /* 5811541Srgrimes * Now strip out original options by copying rest of first 5821541Srgrimes * mbuf's data back, and adjust the IP length. 5831541Srgrimes */ 5841541Srgrimes ip->ip_len -= optlen; 5851541Srgrimes ip->ip_hl = sizeof(struct ip) >> 2; 5861541Srgrimes m->m_len -= optlen; 5871541Srgrimes if (m->m_flags & M_PKTHDR) 5881541Srgrimes m->m_pkthdr.len -= optlen; 5891541Srgrimes optlen += sizeof(struct ip); 5901541Srgrimes bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 5911541Srgrimes (unsigned)(m->m_len - sizeof(struct ip))); 5921541Srgrimes } 5931541Srgrimes m->m_flags &= ~(M_BCAST|M_MCAST); 5941541Srgrimes icmp_send(m, opts); 5951541Srgrimesdone: 5961541Srgrimes if (opts) 5971541Srgrimes (void)m_free(opts); 5981541Srgrimes} 5991541Srgrimes 6001541Srgrimes/* 6011541Srgrimes * Send an icmp packet back to the ip level, 6021541Srgrimes * after supplying a checksum. 6031541Srgrimes */ 60412296Sphkstatic void 6051541Srgrimesicmp_send(m, opts) 6061541Srgrimes register struct mbuf *m; 6071541Srgrimes struct mbuf *opts; 6081541Srgrimes{ 6091541Srgrimes register struct ip *ip = mtod(m, struct ip *); 6101541Srgrimes register int hlen; 6111541Srgrimes register struct icmp *icp; 6121541Srgrimes 6131541Srgrimes hlen = ip->ip_hl << 2; 6141541Srgrimes m->m_data += hlen; 6151541Srgrimes m->m_len -= hlen; 6161541Srgrimes icp = mtod(m, struct icmp *); 6171541Srgrimes icp->icmp_cksum = 0; 6181541Srgrimes icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 6191541Srgrimes m->m_data -= hlen; 6201541Srgrimes m->m_len += hlen; 6211541Srgrimes#ifdef ICMPPRINTFS 62210421Swollman if (icmpprintfs) { 62310421Swollman char buf[4 * sizeof "123"]; 62410421Swollman strcpy(buf, inet_ntoa(ip->ip_dst)); 62510421Swollman printf("icmp_send dst %s src %s\n", 62610421Swollman buf, inet_ntoa(ip->ip_src)); 62710421Swollman } 6281541Srgrimes#endif 6291541Srgrimes (void) ip_output(m, opts, NULL, 0, NULL); 6301541Srgrimes} 6311541Srgrimes 6321541Srgrimesn_time 6331541Srgrimesiptime() 6341541Srgrimes{ 6351541Srgrimes struct timeval atv; 6361541Srgrimes u_long t; 6371541Srgrimes 6381541Srgrimes microtime(&atv); 6391541Srgrimes t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 6401541Srgrimes return (htonl(t)); 6411541Srgrimes} 6421541Srgrimes 64312635Swollman#if 1 64410881Swollman/* 64510881Swollman * Return the next larger or smaller MTU plateau (table from RFC 1191) 64610881Swollman * given current value MTU. If DIR is less than zero, a larger plateau 64710881Swollman * is returned; otherwise, a smaller value is returned. 64810881Swollman */ 64912820Sphkstatic int 65010881Swollmanip_next_mtu(mtu, dir) 65110881Swollman int mtu; 65210881Swollman int dir; 65310881Swollman{ 65410881Swollman static int mtutab[] = { 65510881Swollman 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296, 65610881Swollman 68, 0 65710881Swollman }; 65810881Swollman int i; 65910881Swollman 66010881Swollman for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) { 66110881Swollman if (mtu >= mtutab[i]) 66210881Swollman break; 66310881Swollman } 66410881Swollman 66510881Swollman if (dir < 0) { 66610881Swollman if (i == 0) { 66710881Swollman return 0; 66810881Swollman } else { 66910881Swollman return mtutab[i - 1]; 67010881Swollman } 67110881Swollman } else { 67210881Swollman if (mtutab[i] == 0) { 67310881Swollman return 0; 67410881Swollman } else if(mtu > mtutab[i]) { 67510881Swollman return mtutab[i]; 67610881Swollman } else { 67710881Swollman return mtutab[i + 1]; 67810881Swollman } 67910881Swollman } 68010881Swollman} 68112635Swollman#endif 682