1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 376a800098SYoshinobu Inoue #include "opt_ipsec.h" 380070e096SRobert Watson #include "opt_mac.h" 396a800098SYoshinobu Inoue 40df8bae1dSRodney W. Grimes #include <sys/param.h> 41df8bae1dSRodney W. Grimes #include <sys/systm.h> 420070e096SRobert Watson #include <sys/mac.h> 43df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 44df8bae1dSRodney W. Grimes #include <sys/protosw.h> 45df8bae1dSRodney W. Grimes #include <sys/socket.h> 46df8bae1dSRodney W. Grimes #include <sys/time.h> 47df8bae1dSRodney W. Grimes #include <sys/kernel.h> 48b5e8ce9fSBruce Evans #include <sys/sysctl.h> 49df8bae1dSRodney W. Grimes 50df8bae1dSRodney W. Grimes #include <net/if.h> 519494d596SBrooks Davis #include <net/if_types.h> 52df8bae1dSRodney W. Grimes #include <net/route.h> 53df8bae1dSRodney W. Grimes 545e2d0696SGarrett Wollman #define _IP_VHL 55df8bae1dSRodney W. Grimes #include <netinet/in.h> 56df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 57df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 58df8bae1dSRodney W. Grimes #include <netinet/ip.h> 59df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 60b5e8ce9fSBruce Evans #include <netinet/ip_var.h> 61df8bae1dSRodney W. Grimes #include <netinet/icmp_var.h> 62df8bae1dSRodney W. Grimes 636a800098SYoshinobu Inoue #ifdef IPSEC 646a800098SYoshinobu Inoue #include <netinet6/ipsec.h> 656a800098SYoshinobu Inoue #include <netkey/key.h> 666a800098SYoshinobu Inoue #endif 676a800098SYoshinobu Inoue 68b9234fafSSam Leffler #ifdef FAST_IPSEC 69b9234fafSSam Leffler #include <netipsec/ipsec.h> 70b9234fafSSam Leffler #include <netipsec/key.h> 71b9234fafSSam Leffler #define IPSEC 72b9234fafSSam Leffler #endif 73b9234fafSSam Leffler 7472a52a35SJonathan Lemon #include <machine/in_cksum.h> 7572a52a35SJonathan Lemon 76df8bae1dSRodney W. Grimes /* 77df8bae1dSRodney W. Grimes * ICMP routines: error generation, receive packet processing, and 78df8bae1dSRodney W. Grimes * routines to turnaround packets back to the originator, and 79df8bae1dSRodney W. Grimes * host table maintenance routines. 80df8bae1dSRodney W. Grimes */ 81df8bae1dSRodney W. Grimes 82f708ef1bSPoul-Henning Kamp static struct icmpstat icmpstat; 83c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RW, 840312fbe9SPoul-Henning Kamp &icmpstat, icmpstat, ""); 850312fbe9SPoul-Henning Kamp 860312fbe9SPoul-Henning Kamp static int icmpmaskrepl = 0; 870312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW, 880312fbe9SPoul-Henning Kamp &icmpmaskrepl, 0, ""); 890312fbe9SPoul-Henning Kamp 9018d3153eSDag-Erling Smørgrav static int drop_redirect = 0; 9118d3153eSDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_RW, 9218d3153eSDag-Erling Smørgrav &drop_redirect, 0, ""); 9318d3153eSDag-Erling Smørgrav 946c3b5f69SDag-Erling Smørgrav static int log_redirect = 0; 956c3b5f69SDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW, 966c3b5f69SDag-Erling Smørgrav &log_redirect, 0, ""); 976c3b5f69SDag-Erling Smørgrav 98173c0f9fSWarner Losh static int icmplim = 200; 9951508de1SMatthew Dillon SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW, 10051508de1SMatthew Dillon &icmplim, 0, ""); 1015fce7fc4SMatthew Dillon 1024f14ee00SDan Moschuk static int icmplim_output = 1; 1034f14ee00SDan Moschuk SYSCTL_INT(_net_inet_icmp, OID_AUTO, icmplim_output, CTLFLAG_RW, 1044f14ee00SDan Moschuk &icmplim_output, 0, ""); 10551508de1SMatthew Dillon 1065fce7fc4SMatthew Dillon /* 1075fce7fc4SMatthew Dillon * ICMP broadcast echo sysctl 1085fce7fc4SMatthew Dillon */ 1095fce7fc4SMatthew Dillon 11061a4defdSJoseph Koshy static int icmpbmcastecho = 0; 11118d3153eSDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, 11218d3153eSDag-Erling Smørgrav &icmpbmcastecho, 0, ""); 1137022ea0aSGarrett Wollman 11451508de1SMatthew Dillon 115df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 116df8bae1dSRodney W. Grimes int icmpprintfs = 0; 117df8bae1dSRodney W. Grimes #endif 118df8bae1dSRodney W. Grimes 1194d77a549SAlfred Perlstein static void icmp_reflect(struct mbuf *); 1204d77a549SAlfred Perlstein static void icmp_send(struct mbuf *, struct mbuf *, struct route *); 1214d77a549SAlfred Perlstein static int ip_next_mtu(int, int); 1220312fbe9SPoul-Henning Kamp 123df8bae1dSRodney W. Grimes extern struct protosw inetsw[]; 124df8bae1dSRodney W. Grimes 125df8bae1dSRodney W. Grimes /* 126df8bae1dSRodney W. Grimes * Generate an error packet of type error 127df8bae1dSRodney W. Grimes * in response to bad packet ip. 128df8bae1dSRodney W. Grimes */ 129df8bae1dSRodney W. Grimes void 130df8bae1dSRodney W. Grimes icmp_error(n, type, code, dest, destifp) 131df8bae1dSRodney W. Grimes struct mbuf *n; 132df8bae1dSRodney W. Grimes int type, code; 133df8bae1dSRodney W. Grimes n_long dest; 134df8bae1dSRodney W. Grimes struct ifnet *destifp; 135df8bae1dSRodney W. Grimes { 136df8bae1dSRodney W. Grimes register struct ip *oip = mtod(n, struct ip *), *nip; 1375e2d0696SGarrett Wollman register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2; 138df8bae1dSRodney W. Grimes register struct icmp *icp; 139df8bae1dSRodney W. Grimes register struct mbuf *m; 140df8bae1dSRodney W. Grimes unsigned icmplen; 141df8bae1dSRodney W. Grimes 142df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 143df8bae1dSRodney W. Grimes if (icmpprintfs) 144623ae52eSPoul-Henning Kamp printf("icmp_error(%p, %x, %d)\n", oip, type, code); 145df8bae1dSRodney W. Grimes #endif 146df8bae1dSRodney W. Grimes if (type != ICMP_REDIRECT) 147df8bae1dSRodney W. Grimes icmpstat.icps_error++; 148df8bae1dSRodney W. Grimes /* 149df8bae1dSRodney W. Grimes * Don't send error if not the first fragment of message. 150df8bae1dSRodney W. Grimes * Don't error if the old packet protocol was ICMP 151df8bae1dSRodney W. Grimes * error message, only known informational types. 152df8bae1dSRodney W. Grimes */ 153df8bae1dSRodney W. Grimes if (oip->ip_off &~ (IP_MF|IP_DF)) 154df8bae1dSRodney W. Grimes goto freeit; 155df8bae1dSRodney W. Grimes if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 156df8bae1dSRodney W. Grimes n->m_len >= oiplen + ICMP_MINLEN && 157df8bae1dSRodney W. Grimes !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { 158df8bae1dSRodney W. Grimes icmpstat.icps_oldicmp++; 159df8bae1dSRodney W. Grimes goto freeit; 160df8bae1dSRodney W. Grimes } 161df8bae1dSRodney W. Grimes /* Don't send error in response to a multicast or broadcast packet */ 162df8bae1dSRodney W. Grimes if (n->m_flags & (M_BCAST|M_MCAST)) 163df8bae1dSRodney W. Grimes goto freeit; 164df8bae1dSRodney W. Grimes /* 165df8bae1dSRodney W. Grimes * First, formulate icmp message 166df8bae1dSRodney W. Grimes */ 167df8bae1dSRodney W. Grimes m = m_gethdr(M_DONTWAIT, MT_HEADER); 168df8bae1dSRodney W. Grimes if (m == NULL) 169df8bae1dSRodney W. Grimes goto freeit; 1700070e096SRobert Watson #ifdef MAC 1710070e096SRobert Watson mac_create_mbuf_netlayer(n, m); 1720070e096SRobert Watson #endif 1731d027522SRuslan Ermilov icmplen = min(oiplen + 8, oip->ip_len); 174bfef7ed4SIan Dowse if (icmplen < sizeof(struct ip)) 175bfef7ed4SIan Dowse panic("icmp_error: bad length"); 176df8bae1dSRodney W. Grimes m->m_len = icmplen + ICMP_MINLEN; 177df8bae1dSRodney W. Grimes MH_ALIGN(m, m->m_len); 178df8bae1dSRodney W. Grimes icp = mtod(m, struct icmp *); 179df8bae1dSRodney W. Grimes if ((u_int)type > ICMP_MAXTYPE) 180df8bae1dSRodney W. Grimes panic("icmp_error"); 181df8bae1dSRodney W. Grimes icmpstat.icps_outhist[type]++; 182df8bae1dSRodney W. Grimes icp->icmp_type = type; 183df8bae1dSRodney W. Grimes if (type == ICMP_REDIRECT) 184df8bae1dSRodney W. Grimes icp->icmp_gwaddr.s_addr = dest; 185df8bae1dSRodney W. Grimes else { 186df8bae1dSRodney W. Grimes icp->icmp_void = 0; 187df8bae1dSRodney W. Grimes /* 188df8bae1dSRodney W. Grimes * The following assignments assume an overlay with the 189df8bae1dSRodney W. Grimes * zeroed icmp_void field. 190df8bae1dSRodney W. Grimes */ 191df8bae1dSRodney W. Grimes if (type == ICMP_PARAMPROB) { 192df8bae1dSRodney W. Grimes icp->icmp_pptr = code; 193df8bae1dSRodney W. Grimes code = 0; 194df8bae1dSRodney W. Grimes } else if (type == ICMP_UNREACH && 195df8bae1dSRodney W. Grimes code == ICMP_UNREACH_NEEDFRAG && destifp) { 196df8bae1dSRodney W. Grimes icp->icmp_nextmtu = htons(destifp->if_mtu); 197df8bae1dSRodney W. Grimes } 198df8bae1dSRodney W. Grimes } 199df8bae1dSRodney W. Grimes 200df8bae1dSRodney W. Grimes icp->icmp_code = code; 201bfef7ed4SIan Dowse m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip); 202df8bae1dSRodney W. Grimes nip = &icp->icmp_ip; 20304287599SRuslan Ermilov 20404287599SRuslan Ermilov /* 20504287599SRuslan Ermilov * Convert fields to network representation. 20604287599SRuslan Ermilov */ 207fd8e4ebcSMike Barcroft nip->ip_len = htons(nip->ip_len); 208fd8e4ebcSMike Barcroft nip->ip_off = htons(nip->ip_off); 209df8bae1dSRodney W. Grimes 210df8bae1dSRodney W. Grimes /* 211df8bae1dSRodney W. Grimes * Now, copy old ip header (without options) 212df8bae1dSRodney W. Grimes * in front of icmp message. 213df8bae1dSRodney W. Grimes */ 214df8bae1dSRodney W. Grimes if (m->m_data - sizeof(struct ip) < m->m_pktdat) 215df8bae1dSRodney W. Grimes panic("icmp len"); 216df8bae1dSRodney W. Grimes m->m_data -= sizeof(struct ip); 217df8bae1dSRodney W. Grimes m->m_len += sizeof(struct ip); 218df8bae1dSRodney W. Grimes m->m_pkthdr.len = m->m_len; 219df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 220df8bae1dSRodney W. Grimes nip = mtod(m, struct ip *); 221df8bae1dSRodney W. Grimes bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); 222df8bae1dSRodney W. Grimes nip->ip_len = m->m_len; 2235e2d0696SGarrett Wollman nip->ip_vhl = IP_VHL_BORING; 224df8bae1dSRodney W. Grimes nip->ip_p = IPPROTO_ICMP; 225df8bae1dSRodney W. Grimes nip->ip_tos = 0; 226df8bae1dSRodney W. Grimes icmp_reflect(m); 227df8bae1dSRodney W. Grimes 228df8bae1dSRodney W. Grimes freeit: 229df8bae1dSRodney W. Grimes m_freem(n); 230df8bae1dSRodney W. Grimes } 231df8bae1dSRodney W. Grimes 232df8bae1dSRodney W. Grimes static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 233df8bae1dSRodney W. Grimes static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 234df8bae1dSRodney W. Grimes static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 235df8bae1dSRodney W. Grimes 236df8bae1dSRodney W. Grimes /* 237df8bae1dSRodney W. Grimes * Process a received ICMP message. 238df8bae1dSRodney W. Grimes */ 239df8bae1dSRodney W. Grimes void 240f0ffb944SJulian Elischer icmp_input(m, off) 241df8bae1dSRodney W. Grimes register struct mbuf *m; 242f0ffb944SJulian Elischer int off; 243df8bae1dSRodney W. Grimes { 2446a800098SYoshinobu Inoue int hlen = off; 245df8bae1dSRodney W. Grimes register struct icmp *icp; 246df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 247df8bae1dSRodney W. Grimes int icmplen = ip->ip_len; 248df8bae1dSRodney W. Grimes register int i; 249df8bae1dSRodney W. Grimes struct in_ifaddr *ia; 2504d77a549SAlfred Perlstein void (*ctlfunc)(int, struct sockaddr *, void *); 251df8bae1dSRodney W. Grimes int code; 252df8bae1dSRodney W. Grimes 253df8bae1dSRodney W. Grimes /* 254df8bae1dSRodney W. Grimes * Locate icmp structure in mbuf, and check 255df8bae1dSRodney W. Grimes * that not corrupted and of at least minimum length. 256df8bae1dSRodney W. Grimes */ 257df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 2582b758395SGarrett Wollman if (icmpprintfs) { 2592b758395SGarrett Wollman char buf[4 * sizeof "123"]; 2602b758395SGarrett Wollman strcpy(buf, inet_ntoa(ip->ip_src)); 2612b758395SGarrett Wollman printf("icmp_input from %s to %s, len %d\n", 2622b758395SGarrett Wollman buf, inet_ntoa(ip->ip_dst), icmplen); 2632b758395SGarrett Wollman } 264df8bae1dSRodney W. Grimes #endif 265df8bae1dSRodney W. Grimes if (icmplen < ICMP_MINLEN) { 266df8bae1dSRodney W. Grimes icmpstat.icps_tooshort++; 267df8bae1dSRodney W. Grimes goto freeit; 268df8bae1dSRodney W. Grimes } 269df8bae1dSRodney W. Grimes i = hlen + min(icmplen, ICMP_ADVLENMIN); 270df8bae1dSRodney W. Grimes if (m->m_len < i && (m = m_pullup(m, i)) == 0) { 271df8bae1dSRodney W. Grimes icmpstat.icps_tooshort++; 272df8bae1dSRodney W. Grimes return; 273df8bae1dSRodney W. Grimes } 274df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 275df8bae1dSRodney W. Grimes m->m_len -= hlen; 276df8bae1dSRodney W. Grimes m->m_data += hlen; 277df8bae1dSRodney W. Grimes icp = mtod(m, struct icmp *); 278df8bae1dSRodney W. Grimes if (in_cksum(m, icmplen)) { 279df8bae1dSRodney W. Grimes icmpstat.icps_checksum++; 280df8bae1dSRodney W. Grimes goto freeit; 281df8bae1dSRodney W. Grimes } 282df8bae1dSRodney W. Grimes m->m_len += hlen; 283df8bae1dSRodney W. Grimes m->m_data -= hlen; 284df8bae1dSRodney W. Grimes 2856a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 2866a800098SYoshinobu Inoue /* 2876a800098SYoshinobu Inoue * Deliver very specific ICMP type only. 2886a800098SYoshinobu Inoue */ 2896a800098SYoshinobu Inoue switch (icp->icmp_type) { 2906a800098SYoshinobu Inoue case ICMP_UNREACH: 2916a800098SYoshinobu Inoue case ICMP_TIMXCEED: 2926a800098SYoshinobu Inoue break; 2936a800098SYoshinobu Inoue default: 2946a800098SYoshinobu Inoue goto freeit; 2956a800098SYoshinobu Inoue } 2966a800098SYoshinobu Inoue } 2976a800098SYoshinobu Inoue 298df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 299df8bae1dSRodney W. Grimes if (icmpprintfs) 300df8bae1dSRodney W. Grimes printf("icmp_input, type %d code %d\n", icp->icmp_type, 301df8bae1dSRodney W. Grimes icp->icmp_code); 302df8bae1dSRodney W. Grimes #endif 3035b7ee6edSGarrett Wollman 3045b7ee6edSGarrett Wollman /* 3055b7ee6edSGarrett Wollman * Message type specific processing. 3065b7ee6edSGarrett Wollman */ 307df8bae1dSRodney W. Grimes if (icp->icmp_type > ICMP_MAXTYPE) 308df8bae1dSRodney W. Grimes goto raw; 309df8bae1dSRodney W. Grimes icmpstat.icps_inhist[icp->icmp_type]++; 310df8bae1dSRodney W. Grimes code = icp->icmp_code; 311df8bae1dSRodney W. Grimes switch (icp->icmp_type) { 312df8bae1dSRodney W. Grimes 313df8bae1dSRodney W. Grimes case ICMP_UNREACH: 314df8bae1dSRodney W. Grimes switch (code) { 315df8bae1dSRodney W. Grimes case ICMP_UNREACH_NET: 316df8bae1dSRodney W. Grimes case ICMP_UNREACH_HOST: 317df8bae1dSRodney W. Grimes case ICMP_UNREACH_SRCFAIL: 318e4bb5b05SJonathan Lemon case ICMP_UNREACH_NET_UNKNOWN: 319e4bb5b05SJonathan Lemon case ICMP_UNREACH_HOST_UNKNOWN: 320e4bb5b05SJonathan Lemon case ICMP_UNREACH_ISOLATED: 321e4bb5b05SJonathan Lemon case ICMP_UNREACH_TOSNET: 322e4bb5b05SJonathan Lemon case ICMP_UNREACH_TOSHOST: 323e4bb5b05SJonathan Lemon case ICMP_UNREACH_HOST_PRECEDENCE: 324e4bb5b05SJonathan Lemon case ICMP_UNREACH_PRECEDENCE_CUTOFF: 325e4bb5b05SJonathan Lemon code = PRC_UNREACH_NET; 326df8bae1dSRodney W. Grimes break; 327df8bae1dSRodney W. Grimes 328df8bae1dSRodney W. Grimes case ICMP_UNREACH_NEEDFRAG: 329df8bae1dSRodney W. Grimes code = PRC_MSGSIZE; 330df8bae1dSRodney W. Grimes break; 331df8bae1dSRodney W. Grimes 332e4bb5b05SJonathan Lemon /* 333e4bb5b05SJonathan Lemon * RFC 1122, Sections 3.2.2.1 and 4.2.3.9. 334e4bb5b05SJonathan Lemon * Treat subcodes 2,3 as immediate RST 335e4bb5b05SJonathan Lemon */ 336e4bb5b05SJonathan Lemon case ICMP_UNREACH_PROTOCOL: 337e4bb5b05SJonathan Lemon case ICMP_UNREACH_PORT: 338b77d155dSJesper Skriver code = PRC_UNREACH_PORT; 339b11d7a4aSPoul-Henning Kamp break; 34090fcbbd6SPoul-Henning Kamp 34190fcbbd6SPoul-Henning Kamp case ICMP_UNREACH_NET_PROHIB: 34290fcbbd6SPoul-Henning Kamp case ICMP_UNREACH_HOST_PROHIB: 3439c4b2574SPaul Traina case ICMP_UNREACH_FILTER_PROHIB: 34490fcbbd6SPoul-Henning Kamp code = PRC_UNREACH_ADMIN_PROHIB; 345b11d7a4aSPoul-Henning Kamp break; 346b11d7a4aSPoul-Henning Kamp 347df8bae1dSRodney W. Grimes default: 348df8bae1dSRodney W. Grimes goto badcode; 349df8bae1dSRodney W. Grimes } 350df8bae1dSRodney W. Grimes goto deliver; 351df8bae1dSRodney W. Grimes 352df8bae1dSRodney W. Grimes case ICMP_TIMXCEED: 353df8bae1dSRodney W. Grimes if (code > 1) 354df8bae1dSRodney W. Grimes goto badcode; 355df8bae1dSRodney W. Grimes code += PRC_TIMXCEED_INTRANS; 356df8bae1dSRodney W. Grimes goto deliver; 357df8bae1dSRodney W. Grimes 358df8bae1dSRodney W. Grimes case ICMP_PARAMPROB: 359df8bae1dSRodney W. Grimes if (code > 1) 360df8bae1dSRodney W. Grimes goto badcode; 361df8bae1dSRodney W. Grimes code = PRC_PARAMPROB; 362df8bae1dSRodney W. Grimes goto deliver; 363df8bae1dSRodney W. Grimes 364df8bae1dSRodney W. Grimes case ICMP_SOURCEQUENCH: 365df8bae1dSRodney W. Grimes if (code) 366df8bae1dSRodney W. Grimes goto badcode; 367df8bae1dSRodney W. Grimes code = PRC_QUENCH; 368df8bae1dSRodney W. Grimes deliver: 369df8bae1dSRodney W. Grimes /* 370df8bae1dSRodney W. Grimes * Problem with datagram; advise higher level routines. 371df8bae1dSRodney W. Grimes */ 372df8bae1dSRodney W. Grimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 3735e2d0696SGarrett Wollman IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { 374df8bae1dSRodney W. Grimes icmpstat.icps_badlen++; 375df8bae1dSRodney W. Grimes goto freeit; 376df8bae1dSRodney W. Grimes } 377fd8e4ebcSMike Barcroft icp->icmp_ip.ip_len = ntohs(icp->icmp_ip.ip_len); 3785b7ee6edSGarrett Wollman /* Discard ICMP's in response to multicast packets */ 3795b7ee6edSGarrett Wollman if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr))) 3805b7ee6edSGarrett Wollman goto badcode; 381df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 382df8bae1dSRodney W. Grimes if (icmpprintfs) 383df8bae1dSRodney W. Grimes printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 384df8bae1dSRodney W. Grimes #endif 385df8bae1dSRodney W. Grimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 386b7a44e34SGarrett Wollman #if 1 3875cbf3e08SGarrett Wollman /* 3885cbf3e08SGarrett Wollman * MTU discovery: 3895cbf3e08SGarrett Wollman * If we got a needfrag and there is a host route to the 3905cbf3e08SGarrett Wollman * original destination, and the MTU is not locked, then 3915cbf3e08SGarrett Wollman * set the MTU in the route to the suggested new value 3925cbf3e08SGarrett Wollman * (if given) and then notify as usual. The ULPs will 3935cbf3e08SGarrett Wollman * notice that the MTU has changed and adapt accordingly. 3945cbf3e08SGarrett Wollman * If no new MTU was suggested, then we guess a new one 3955cbf3e08SGarrett Wollman * less than the current value. If the new MTU is 3965cbf3e08SGarrett Wollman * unreasonably small (arbitrarily set at 296), then 3975cbf3e08SGarrett Wollman * we reset the MTU to the interface value and enable the 3985cbf3e08SGarrett Wollman * lock bit, indicating that we are no longer doing MTU 3995cbf3e08SGarrett Wollman * discovery. 4005cbf3e08SGarrett Wollman */ 4015cbf3e08SGarrett Wollman if (code == PRC_MSGSIZE) { 4025cbf3e08SGarrett Wollman struct rtentry *rt; 4035cbf3e08SGarrett Wollman int mtu; 4045cbf3e08SGarrett Wollman 4055cbf3e08SGarrett Wollman rt = rtalloc1((struct sockaddr *)&icmpsrc, 0, 4065cbf3e08SGarrett Wollman RTF_CLONING | RTF_PRCLONING); 4075cbf3e08SGarrett Wollman if (rt && (rt->rt_flags & RTF_HOST) 4085cbf3e08SGarrett Wollman && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { 4095cbf3e08SGarrett Wollman mtu = ntohs(icp->icmp_nextmtu); 4105cbf3e08SGarrett Wollman if (!mtu) 4115cbf3e08SGarrett Wollman mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu, 4125cbf3e08SGarrett Wollman 1); 413be070f43SGarrett Wollman #ifdef DEBUG_MTUDISC 414be070f43SGarrett Wollman printf("MTU for %s reduced to %d\n", 415be070f43SGarrett Wollman inet_ntoa(icmpsrc.sin_addr), mtu); 416be070f43SGarrett Wollman #endif 417be070f43SGarrett Wollman if (mtu < 296) { 418b7a44e34SGarrett Wollman /* rt->rt_rmx.rmx_mtu = 419b7a44e34SGarrett Wollman rt->rt_ifp->if_mtu; */ 4205cbf3e08SGarrett Wollman rt->rt_rmx.rmx_locks |= RTV_MTU; 4215cbf3e08SGarrett Wollman } else if (rt->rt_rmx.rmx_mtu > mtu) { 4225cbf3e08SGarrett Wollman rt->rt_rmx.rmx_mtu = mtu; 4235cbf3e08SGarrett Wollman } 4245cbf3e08SGarrett Wollman } 4255cbf3e08SGarrett Wollman if (rt) 4265cbf3e08SGarrett Wollman RTFREE(rt); 4275cbf3e08SGarrett Wollman } 4285cbf3e08SGarrett Wollman 429b7a44e34SGarrett Wollman #endif 4306a800098SYoshinobu Inoue /* 4316a800098SYoshinobu Inoue * XXX if the packet contains [IPv4 AH TCP], we can't make a 4326a800098SYoshinobu Inoue * notification to TCP layer. 4336a800098SYoshinobu Inoue */ 434623ae52eSPoul-Henning Kamp ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput; 435623ae52eSPoul-Henning Kamp if (ctlfunc) 436df8bae1dSRodney W. Grimes (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, 437b62d102cSBruce Evans (void *)&icp->icmp_ip); 438df8bae1dSRodney W. Grimes break; 439df8bae1dSRodney W. Grimes 440df8bae1dSRodney W. Grimes badcode: 441df8bae1dSRodney W. Grimes icmpstat.icps_badcode++; 442df8bae1dSRodney W. Grimes break; 443df8bae1dSRodney W. Grimes 444df8bae1dSRodney W. Grimes case ICMP_ECHO: 4457022ea0aSGarrett Wollman if (!icmpbmcastecho 446d311884fSDavid Greenman && (m->m_flags & (M_MCAST | M_BCAST)) != 0) { 4477022ea0aSGarrett Wollman icmpstat.icps_bmcastecho++; 4487022ea0aSGarrett Wollman break; 4497022ea0aSGarrett Wollman } 450df8bae1dSRodney W. Grimes icp->icmp_type = ICMP_ECHOREPLY; 451a57815efSBosko Milekic if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0) 45209f81a46SBosko Milekic goto freeit; 45309f81a46SBosko Milekic else 454df8bae1dSRodney W. Grimes goto reflect; 455df8bae1dSRodney W. Grimes 456df8bae1dSRodney W. Grimes case ICMP_TSTAMP: 457fe0fb8abSGarrett Wollman if (!icmpbmcastecho 458d311884fSDavid Greenman && (m->m_flags & (M_MCAST | M_BCAST)) != 0) { 459fe0fb8abSGarrett Wollman icmpstat.icps_bmcasttstamp++; 460fe0fb8abSGarrett Wollman break; 461fe0fb8abSGarrett Wollman } 462df8bae1dSRodney W. Grimes if (icmplen < ICMP_TSLEN) { 463df8bae1dSRodney W. Grimes icmpstat.icps_badlen++; 464df8bae1dSRodney W. Grimes break; 465df8bae1dSRodney W. Grimes } 466df8bae1dSRodney W. Grimes icp->icmp_type = ICMP_TSTAMPREPLY; 467df8bae1dSRodney W. Grimes icp->icmp_rtime = iptime(); 468df8bae1dSRodney W. Grimes icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 469a57815efSBosko Milekic if (badport_bandlim(BANDLIM_ICMP_TSTAMP) < 0) 47009f81a46SBosko Milekic goto freeit; 47109f81a46SBosko Milekic else 472df8bae1dSRodney W. Grimes goto reflect; 473df8bae1dSRodney W. Grimes 474df8bae1dSRodney W. Grimes case ICMP_MASKREQ: 475df8bae1dSRodney W. Grimes if (icmpmaskrepl == 0) 476df8bae1dSRodney W. Grimes break; 477df8bae1dSRodney W. Grimes /* 478df8bae1dSRodney W. Grimes * We are not able to respond with all ones broadcast 479df8bae1dSRodney W. Grimes * unless we receive it over a point-to-point interface. 480df8bae1dSRodney W. Grimes */ 481df8bae1dSRodney W. Grimes if (icmplen < ICMP_MASKLEN) 482df8bae1dSRodney W. Grimes break; 483df8bae1dSRodney W. Grimes switch (ip->ip_dst.s_addr) { 484df8bae1dSRodney W. Grimes 485df8bae1dSRodney W. Grimes case INADDR_BROADCAST: 486df8bae1dSRodney W. Grimes case INADDR_ANY: 487df8bae1dSRodney W. Grimes icmpdst.sin_addr = ip->ip_src; 488df8bae1dSRodney W. Grimes break; 489df8bae1dSRodney W. Grimes 490df8bae1dSRodney W. Grimes default: 491df8bae1dSRodney W. Grimes icmpdst.sin_addr = ip->ip_dst; 492df8bae1dSRodney W. Grimes } 493df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)ifaof_ifpforaddr( 494df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); 495df8bae1dSRodney W. Grimes if (ia == 0) 496df8bae1dSRodney W. Grimes break; 4977e6f7714SPoul-Henning Kamp if (ia->ia_ifp == 0) 4987e6f7714SPoul-Henning Kamp break; 499df8bae1dSRodney W. Grimes icp->icmp_type = ICMP_MASKREPLY; 500df8bae1dSRodney W. Grimes icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 501df8bae1dSRodney W. Grimes if (ip->ip_src.s_addr == 0) { 502df8bae1dSRodney W. Grimes if (ia->ia_ifp->if_flags & IFF_BROADCAST) 503df8bae1dSRodney W. Grimes ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; 504df8bae1dSRodney W. Grimes else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 505df8bae1dSRodney W. Grimes ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; 506df8bae1dSRodney W. Grimes } 507df8bae1dSRodney W. Grimes reflect: 508df8bae1dSRodney W. Grimes ip->ip_len += hlen; /* since ip_input deducts this */ 509df8bae1dSRodney W. Grimes icmpstat.icps_reflect++; 510df8bae1dSRodney W. Grimes icmpstat.icps_outhist[icp->icmp_type]++; 511df8bae1dSRodney W. Grimes icmp_reflect(m); 512df8bae1dSRodney W. Grimes return; 513df8bae1dSRodney W. Grimes 514df8bae1dSRodney W. Grimes case ICMP_REDIRECT: 51518d3153eSDag-Erling Smørgrav if (log_redirect) { 51618d3153eSDag-Erling Smørgrav u_long src, dst, gw; 51718d3153eSDag-Erling Smørgrav 51818d3153eSDag-Erling Smørgrav src = ntohl(ip->ip_src.s_addr); 51918d3153eSDag-Erling Smørgrav dst = ntohl(icp->icmp_ip.ip_dst.s_addr); 52018d3153eSDag-Erling Smørgrav gw = ntohl(icp->icmp_gwaddr.s_addr); 52118d3153eSDag-Erling Smørgrav printf("icmp redirect from %d.%d.%d.%d: " 52218d3153eSDag-Erling Smørgrav "%d.%d.%d.%d => %d.%d.%d.%d\n", 52318d3153eSDag-Erling Smørgrav (int)(src >> 24), (int)((src >> 16) & 0xff), 52418d3153eSDag-Erling Smørgrav (int)((src >> 8) & 0xff), (int)(src & 0xff), 52518d3153eSDag-Erling Smørgrav (int)(dst >> 24), (int)((dst >> 16) & 0xff), 52618d3153eSDag-Erling Smørgrav (int)((dst >> 8) & 0xff), (int)(dst & 0xff), 52718d3153eSDag-Erling Smørgrav (int)(gw >> 24), (int)((gw >> 16) & 0xff), 52818d3153eSDag-Erling Smørgrav (int)((gw >> 8) & 0xff), (int)(gw & 0xff)); 52918d3153eSDag-Erling Smørgrav } 53018d3153eSDag-Erling Smørgrav if (drop_redirect) 53118d3153eSDag-Erling Smørgrav break; 532df8bae1dSRodney W. Grimes if (code > 3) 533df8bae1dSRodney W. Grimes goto badcode; 534df8bae1dSRodney W. Grimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 5355e2d0696SGarrett Wollman IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { 536df8bae1dSRodney W. Grimes icmpstat.icps_badlen++; 537df8bae1dSRodney W. Grimes break; 538df8bae1dSRodney W. Grimes } 539df8bae1dSRodney W. Grimes /* 540df8bae1dSRodney W. Grimes * Short circuit routing redirects to force 541df8bae1dSRodney W. Grimes * immediate change in the kernel's routing 542df8bae1dSRodney W. Grimes * tables. The message is also handed to anyone 543df8bae1dSRodney W. Grimes * listening on a raw socket (e.g. the routing 544df8bae1dSRodney W. Grimes * daemon for use in updating its tables). 545df8bae1dSRodney W. Grimes */ 546df8bae1dSRodney W. Grimes icmpgw.sin_addr = ip->ip_src; 547df8bae1dSRodney W. Grimes icmpdst.sin_addr = icp->icmp_gwaddr; 548df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 5492b758395SGarrett Wollman if (icmpprintfs) { 5502b758395SGarrett Wollman char buf[4 * sizeof "123"]; 5512b758395SGarrett Wollman strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst)); 5522b758395SGarrett Wollman 5532b758395SGarrett Wollman printf("redirect dst %s to %s\n", 5542b758395SGarrett Wollman buf, inet_ntoa(icp->icmp_gwaddr)); 5552b758395SGarrett Wollman } 556df8bae1dSRodney W. Grimes #endif 557df8bae1dSRodney W. Grimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 558df8bae1dSRodney W. Grimes rtredirect((struct sockaddr *)&icmpsrc, 559df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpdst, 560df8bae1dSRodney W. Grimes (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 561df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpgw, (struct rtentry **)0); 562df8bae1dSRodney W. Grimes pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); 5636a800098SYoshinobu Inoue #ifdef IPSEC 5646a800098SYoshinobu Inoue key_sa_routechange((struct sockaddr *)&icmpsrc); 5656a800098SYoshinobu Inoue #endif 566df8bae1dSRodney W. Grimes break; 567df8bae1dSRodney W. Grimes 568df8bae1dSRodney W. Grimes /* 569df8bae1dSRodney W. Grimes * No kernel processing for the following; 570df8bae1dSRodney W. Grimes * just fall through to send to raw listener. 571df8bae1dSRodney W. Grimes */ 572df8bae1dSRodney W. Grimes case ICMP_ECHOREPLY: 573df8bae1dSRodney W. Grimes case ICMP_ROUTERADVERT: 574df8bae1dSRodney W. Grimes case ICMP_ROUTERSOLICIT: 575df8bae1dSRodney W. Grimes case ICMP_TSTAMPREPLY: 576df8bae1dSRodney W. Grimes case ICMP_IREQREPLY: 577df8bae1dSRodney W. Grimes case ICMP_MASKREPLY: 578df8bae1dSRodney W. Grimes default: 579df8bae1dSRodney W. Grimes break; 580df8bae1dSRodney W. Grimes } 581df8bae1dSRodney W. Grimes 582df8bae1dSRodney W. Grimes raw: 583f0ffb944SJulian Elischer rip_input(m, off); 584df8bae1dSRodney W. Grimes return; 585df8bae1dSRodney W. Grimes 586df8bae1dSRodney W. Grimes freeit: 587df8bae1dSRodney W. Grimes m_freem(m); 588df8bae1dSRodney W. Grimes } 589df8bae1dSRodney W. Grimes 590df8bae1dSRodney W. Grimes /* 591df8bae1dSRodney W. Grimes * Reflect the ip packet back to the source 592df8bae1dSRodney W. Grimes */ 5930312fbe9SPoul-Henning Kamp static void 594df8bae1dSRodney W. Grimes icmp_reflect(m) 595df8bae1dSRodney W. Grimes struct mbuf *m; 596df8bae1dSRodney W. Grimes { 597ca925d9cSJonathan Lemon struct ip *ip = mtod(m, struct ip *); 598ca925d9cSJonathan Lemon struct ifaddr *ifa; 599ca925d9cSJonathan Lemon struct in_ifaddr *ia; 600df8bae1dSRodney W. Grimes struct in_addr t; 601b5e8ce9fSBruce Evans struct mbuf *opts = 0; 6025e2d0696SGarrett Wollman int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip); 603bd714208SRuslan Ermilov struct route *ro = NULL, rt; 604df8bae1dSRodney W. Grimes 605df8bae1dSRodney W. Grimes if (!in_canforward(ip->ip_src) && 606df8bae1dSRodney W. Grimes ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) != 607df8bae1dSRodney W. Grimes (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { 608df8bae1dSRodney W. Grimes m_freem(m); /* Bad return address */ 609bd714208SRuslan Ermilov icmpstat.icps_badaddr++; 610df8bae1dSRodney W. Grimes goto done; /* Ip_output() will check for broadcast */ 611df8bae1dSRodney W. Grimes } 612df8bae1dSRodney W. Grimes t = ip->ip_dst; 613df8bae1dSRodney W. Grimes ip->ip_dst = ip->ip_src; 614e3f406b3SRuslan Ermilov ro = &rt; 615e3f406b3SRuslan Ermilov bzero(ro, sizeof(*ro)); 616df8bae1dSRodney W. Grimes /* 617df8bae1dSRodney W. Grimes * If the incoming packet was addressed directly to us, 618df8bae1dSRodney W. Grimes * use dst as the src for the reply. Otherwise (broadcast 619df8bae1dSRodney W. Grimes * or anonymous), use the address which corresponds 620df8bae1dSRodney W. Grimes * to the incoming interface. 621df8bae1dSRodney W. Grimes */ 622ca925d9cSJonathan Lemon LIST_FOREACH(ia, INADDR_HASH(t.s_addr), ia_hash) 623df8bae1dSRodney W. Grimes if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) 624ca925d9cSJonathan Lemon goto match; 62584caf008SRuslan Ermilov if (m->m_pkthdr.rcvif != NULL && 62684caf008SRuslan Ermilov m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) { 627ca925d9cSJonathan Lemon TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) { 628ca925d9cSJonathan Lemon if (ifa->ifa_addr->sa_family != AF_INET) 629ca925d9cSJonathan Lemon continue; 630ca925d9cSJonathan Lemon ia = ifatoia(ifa); 631ca925d9cSJonathan Lemon if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 632ca925d9cSJonathan Lemon t.s_addr) 633ca925d9cSJonathan Lemon goto match; 634df8bae1dSRodney W. Grimes } 635ca925d9cSJonathan Lemon } 636bd714208SRuslan Ermilov ia = ip_rtaddr(ip->ip_dst, ro); 637bd714208SRuslan Ermilov /* We need a route to do anything useful. */ 6380d4bef5dSDima Dorfman if (ia == NULL) { 6390d4bef5dSDima Dorfman m_freem(m); 640bd714208SRuslan Ermilov icmpstat.icps_noroute++; 6410d4bef5dSDima Dorfman goto done; 6420d4bef5dSDima Dorfman } 643ca925d9cSJonathan Lemon match: 644df8bae1dSRodney W. Grimes t = IA_SIN(ia)->sin_addr; 645df8bae1dSRodney W. Grimes ip->ip_src = t; 6468ce3f3ddSRuslan Ermilov ip->ip_ttl = ip_defttl; 647df8bae1dSRodney W. Grimes 648df8bae1dSRodney W. Grimes if (optlen > 0) { 649df8bae1dSRodney W. Grimes register u_char *cp; 650df8bae1dSRodney W. Grimes int opt, cnt; 651df8bae1dSRodney W. Grimes u_int len; 652df8bae1dSRodney W. Grimes 653df8bae1dSRodney W. Grimes /* 654df8bae1dSRodney W. Grimes * Retrieve any source routing from the incoming packet; 655df8bae1dSRodney W. Grimes * add on any record-route or timestamp options. 656df8bae1dSRodney W. Grimes */ 657df8bae1dSRodney W. Grimes cp = (u_char *) (ip + 1); 658df8bae1dSRodney W. Grimes if ((opts = ip_srcroute()) == 0 && 659df8bae1dSRodney W. Grimes (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 660df8bae1dSRodney W. Grimes opts->m_len = sizeof(struct in_addr); 661df8bae1dSRodney W. Grimes mtod(opts, struct in_addr *)->s_addr = 0; 662df8bae1dSRodney W. Grimes } 663df8bae1dSRodney W. Grimes if (opts) { 664df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 665df8bae1dSRodney W. Grimes if (icmpprintfs) 666df8bae1dSRodney W. Grimes printf("icmp_reflect optlen %d rt %d => ", 667df8bae1dSRodney W. Grimes optlen, opts->m_len); 668df8bae1dSRodney W. Grimes #endif 669df8bae1dSRodney W. Grimes for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 670df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 671df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 672df8bae1dSRodney W. Grimes break; 673df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 674df8bae1dSRodney W. Grimes len = 1; 675df8bae1dSRodney W. Grimes else { 676707d00a3SJonathan Lemon if (cnt < IPOPT_OLEN + sizeof(*cp)) 677707d00a3SJonathan Lemon break; 678df8bae1dSRodney W. Grimes len = cp[IPOPT_OLEN]; 679707d00a3SJonathan Lemon if (len < IPOPT_OLEN + sizeof(*cp) || 680707d00a3SJonathan Lemon len > cnt) 681df8bae1dSRodney W. Grimes break; 682df8bae1dSRodney W. Grimes } 683df8bae1dSRodney W. Grimes /* 684df8bae1dSRodney W. Grimes * Should check for overflow, but it "can't happen" 685df8bae1dSRodney W. Grimes */ 686df8bae1dSRodney W. Grimes if (opt == IPOPT_RR || opt == IPOPT_TS || 687df8bae1dSRodney W. Grimes opt == IPOPT_SECURITY) { 688df8bae1dSRodney W. Grimes bcopy((caddr_t)cp, 689df8bae1dSRodney W. Grimes mtod(opts, caddr_t) + opts->m_len, len); 690df8bae1dSRodney W. Grimes opts->m_len += len; 691df8bae1dSRodney W. Grimes } 692df8bae1dSRodney W. Grimes } 693df8bae1dSRodney W. Grimes /* Terminate & pad, if necessary */ 694623ae52eSPoul-Henning Kamp cnt = opts->m_len % 4; 695623ae52eSPoul-Henning Kamp if (cnt) { 696df8bae1dSRodney W. Grimes for (; cnt < 4; cnt++) { 697df8bae1dSRodney W. Grimes *(mtod(opts, caddr_t) + opts->m_len) = 698df8bae1dSRodney W. Grimes IPOPT_EOL; 699df8bae1dSRodney W. Grimes opts->m_len++; 700df8bae1dSRodney W. Grimes } 701df8bae1dSRodney W. Grimes } 702df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 703df8bae1dSRodney W. Grimes if (icmpprintfs) 704df8bae1dSRodney W. Grimes printf("%d\n", opts->m_len); 705df8bae1dSRodney W. Grimes #endif 706df8bae1dSRodney W. Grimes } 707df8bae1dSRodney W. Grimes /* 708df8bae1dSRodney W. Grimes * Now strip out original options by copying rest of first 709df8bae1dSRodney W. Grimes * mbuf's data back, and adjust the IP length. 710df8bae1dSRodney W. Grimes */ 711df8bae1dSRodney W. Grimes ip->ip_len -= optlen; 7125e2d0696SGarrett Wollman ip->ip_vhl = IP_VHL_BORING; 713df8bae1dSRodney W. Grimes m->m_len -= optlen; 714df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 715df8bae1dSRodney W. Grimes m->m_pkthdr.len -= optlen; 716df8bae1dSRodney W. Grimes optlen += sizeof(struct ip); 717df8bae1dSRodney W. Grimes bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 718df8bae1dSRodney W. Grimes (unsigned)(m->m_len - sizeof(struct ip))); 719df8bae1dSRodney W. Grimes } 720df8bae1dSRodney W. Grimes m->m_flags &= ~(M_BCAST|M_MCAST); 721bd714208SRuslan Ermilov icmp_send(m, opts, ro); 722df8bae1dSRodney W. Grimes done: 723df8bae1dSRodney W. Grimes if (opts) 724df8bae1dSRodney W. Grimes (void)m_free(opts); 725bd714208SRuslan Ermilov if (ro && ro->ro_rt) 726bd714208SRuslan Ermilov RTFREE(ro->ro_rt); 727df8bae1dSRodney W. Grimes } 728df8bae1dSRodney W. Grimes 729df8bae1dSRodney W. Grimes /* 730df8bae1dSRodney W. Grimes * Send an icmp packet back to the ip level, 731df8bae1dSRodney W. Grimes * after supplying a checksum. 732df8bae1dSRodney W. Grimes */ 7330312fbe9SPoul-Henning Kamp static void 734bd714208SRuslan Ermilov icmp_send(m, opts, rt) 735df8bae1dSRodney W. Grimes register struct mbuf *m; 736df8bae1dSRodney W. Grimes struct mbuf *opts; 737bd714208SRuslan Ermilov struct route *rt; 738df8bae1dSRodney W. Grimes { 739df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 740df8bae1dSRodney W. Grimes register int hlen; 741df8bae1dSRodney W. Grimes register struct icmp *icp; 742df8bae1dSRodney W. Grimes 7435e2d0696SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 744df8bae1dSRodney W. Grimes m->m_data += hlen; 745df8bae1dSRodney W. Grimes m->m_len -= hlen; 746df8bae1dSRodney W. Grimes icp = mtod(m, struct icmp *); 747df8bae1dSRodney W. Grimes icp->icmp_cksum = 0; 748df8bae1dSRodney W. Grimes icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 749df8bae1dSRodney W. Grimes m->m_data -= hlen; 750df8bae1dSRodney W. Grimes m->m_len += hlen; 75194446a2eSArchie Cobbs m->m_pkthdr.rcvif = (struct ifnet *)0; 752df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 7532b758395SGarrett Wollman if (icmpprintfs) { 7542b758395SGarrett Wollman char buf[4 * sizeof "123"]; 7552b758395SGarrett Wollman strcpy(buf, inet_ntoa(ip->ip_dst)); 7562b758395SGarrett Wollman printf("icmp_send dst %s src %s\n", 7572b758395SGarrett Wollman buf, inet_ntoa(ip->ip_src)); 7582b758395SGarrett Wollman } 759df8bae1dSRodney W. Grimes #endif 7605d846453SSam Leffler (void) ip_output(m, opts, rt, 0, NULL, NULL); 761df8bae1dSRodney W. Grimes } 762df8bae1dSRodney W. Grimes 763df8bae1dSRodney W. Grimes n_time 764df8bae1dSRodney W. Grimes iptime() 765df8bae1dSRodney W. Grimes { 766df8bae1dSRodney W. Grimes struct timeval atv; 767df8bae1dSRodney W. Grimes u_long t; 768df8bae1dSRodney W. Grimes 76916cd6db0SBill Fumerola getmicrotime(&atv); 770df8bae1dSRodney W. Grimes t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 771df8bae1dSRodney W. Grimes return (htonl(t)); 772df8bae1dSRodney W. Grimes } 773df8bae1dSRodney W. Grimes 774b7a44e34SGarrett Wollman #if 1 7755cbf3e08SGarrett Wollman /* 7765cbf3e08SGarrett Wollman * Return the next larger or smaller MTU plateau (table from RFC 1191) 7775cbf3e08SGarrett Wollman * given current value MTU. If DIR is less than zero, a larger plateau 7785cbf3e08SGarrett Wollman * is returned; otherwise, a smaller value is returned. 7795cbf3e08SGarrett Wollman */ 780f708ef1bSPoul-Henning Kamp static int 7815cbf3e08SGarrett Wollman ip_next_mtu(mtu, dir) 7825cbf3e08SGarrett Wollman int mtu; 7835cbf3e08SGarrett Wollman int dir; 7845cbf3e08SGarrett Wollman { 7855cbf3e08SGarrett Wollman static int mtutab[] = { 7865cbf3e08SGarrett Wollman 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296, 7875cbf3e08SGarrett Wollman 68, 0 7885cbf3e08SGarrett Wollman }; 7895cbf3e08SGarrett Wollman int i; 7905cbf3e08SGarrett Wollman 7915cbf3e08SGarrett Wollman for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) { 7925cbf3e08SGarrett Wollman if (mtu >= mtutab[i]) 7935cbf3e08SGarrett Wollman break; 7945cbf3e08SGarrett Wollman } 7955cbf3e08SGarrett Wollman 7965cbf3e08SGarrett Wollman if (dir < 0) { 7975cbf3e08SGarrett Wollman if (i == 0) { 7985cbf3e08SGarrett Wollman return 0; 7995cbf3e08SGarrett Wollman } else { 8005cbf3e08SGarrett Wollman return mtutab[i - 1]; 8015cbf3e08SGarrett Wollman } 8025cbf3e08SGarrett Wollman } else { 8035cbf3e08SGarrett Wollman if (mtutab[i] == 0) { 8045cbf3e08SGarrett Wollman return 0; 8055cbf3e08SGarrett Wollman } else if(mtu > mtutab[i]) { 8065cbf3e08SGarrett Wollman return mtutab[i]; 8075cbf3e08SGarrett Wollman } else { 8085cbf3e08SGarrett Wollman return mtutab[i + 1]; 8095cbf3e08SGarrett Wollman } 8105cbf3e08SGarrett Wollman } 8115cbf3e08SGarrett Wollman } 812b7a44e34SGarrett Wollman #endif 81351508de1SMatthew Dillon 81451508de1SMatthew Dillon 81551508de1SMatthew Dillon /* 81651508de1SMatthew Dillon * badport_bandlim() - check for ICMP bandwidth limit 81751508de1SMatthew Dillon * 81851508de1SMatthew Dillon * Return 0 if it is ok to send an ICMP error response, -1 if we have 81951508de1SMatthew Dillon * hit our bandwidth limit and it is not ok. 82051508de1SMatthew Dillon * 82151508de1SMatthew Dillon * If icmplim is <= 0, the feature is disabled and 0 is returned. 82251508de1SMatthew Dillon * 82351508de1SMatthew Dillon * For now we separate the TCP and UDP subsystems w/ different 'which' 82451508de1SMatthew Dillon * values. We may eventually remove this separation (and simplify the 82551508de1SMatthew Dillon * code further). 82651508de1SMatthew Dillon * 82751508de1SMatthew Dillon * Note that the printing of the error message is delayed so we can 82851508de1SMatthew Dillon * properly print the icmp error rate that the system was trying to do 82951508de1SMatthew Dillon * (i.e. 22000/100 pps, etc...). This can cause long delays in printing 83051508de1SMatthew Dillon * the 'final' error, but it doesn't make sense to solve the printing 83151508de1SMatthew Dillon * delay with more complex code. 83251508de1SMatthew Dillon */ 83351508de1SMatthew Dillon 83451508de1SMatthew Dillon int 83551508de1SMatthew Dillon badport_bandlim(int which) 83651508de1SMatthew Dillon { 83709f81a46SBosko Milekic static int lticks[BANDLIM_MAX + 1]; 83809f81a46SBosko Milekic static int lpackets[BANDLIM_MAX + 1]; 83951508de1SMatthew Dillon int dticks; 84009f81a46SBosko Milekic const char *bandlimittype[] = { 84109f81a46SBosko Milekic "Limiting icmp unreach response", 84209f81a46SBosko Milekic "Limiting icmp ping response", 843a57815efSBosko Milekic "Limiting icmp tstamp response", 844a57815efSBosko Milekic "Limiting closed port RST response", 845a57815efSBosko Milekic "Limiting open port RST response" 84609f81a46SBosko Milekic }; 84751508de1SMatthew Dillon 84851508de1SMatthew Dillon /* 84951508de1SMatthew Dillon * Return ok status if feature disabled or argument out of 85051508de1SMatthew Dillon * ranage. 85151508de1SMatthew Dillon */ 85251508de1SMatthew Dillon 85309f81a46SBosko Milekic if (icmplim <= 0 || which > BANDLIM_MAX || which < 0) 85451508de1SMatthew Dillon return(0); 85551508de1SMatthew Dillon dticks = ticks - lticks[which]; 85651508de1SMatthew Dillon 85751508de1SMatthew Dillon /* 85851508de1SMatthew Dillon * reset stats when cumulative dt exceeds one second. 85951508de1SMatthew Dillon */ 86051508de1SMatthew Dillon 86151508de1SMatthew Dillon if ((unsigned int)dticks > hz) { 8624f14ee00SDan Moschuk if (lpackets[which] > icmplim && icmplim_output) { 86309f81a46SBosko Milekic printf("%s from %d to %d packets per second\n", 86409f81a46SBosko Milekic bandlimittype[which], 86551508de1SMatthew Dillon lpackets[which], 86651508de1SMatthew Dillon icmplim 86751508de1SMatthew Dillon ); 86851508de1SMatthew Dillon } 86951508de1SMatthew Dillon lticks[which] = ticks; 87051508de1SMatthew Dillon lpackets[which] = 0; 87151508de1SMatthew Dillon } 87251508de1SMatthew Dillon 87351508de1SMatthew Dillon /* 87451508de1SMatthew Dillon * bump packet count 87551508de1SMatthew Dillon */ 87651508de1SMatthew Dillon 87751508de1SMatthew Dillon if (++lpackets[which] > icmplim) { 87851508de1SMatthew Dillon return(-1); 87951508de1SMatthew Dillon } 88051508de1SMatthew Dillon return(0); 88151508de1SMatthew Dillon } 88251508de1SMatthew Dillon 883