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" 386a800098SYoshinobu Inoue 39df8bae1dSRodney W. Grimes #include <sys/param.h> 40df8bae1dSRodney W. Grimes #include <sys/systm.h> 41df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 42df8bae1dSRodney W. Grimes #include <sys/protosw.h> 43df8bae1dSRodney W. Grimes #include <sys/socket.h> 44df8bae1dSRodney W. Grimes #include <sys/time.h> 45df8bae1dSRodney W. Grimes #include <sys/kernel.h> 46b5e8ce9fSBruce Evans #include <sys/sysctl.h> 47df8bae1dSRodney W. Grimes 48df8bae1dSRodney W. Grimes #include <net/if.h> 49df8bae1dSRodney W. Grimes #include <net/route.h> 50df8bae1dSRodney W. Grimes 515e2d0696SGarrett Wollman #define _IP_VHL 52df8bae1dSRodney W. Grimes #include <netinet/in.h> 53df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 54df8bae1dSRodney W. Grimes #include <netinet/in_var.h> 55df8bae1dSRodney W. Grimes #include <netinet/ip.h> 56df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 57b5e8ce9fSBruce Evans #include <netinet/ip_var.h> 58df8bae1dSRodney W. Grimes #include <netinet/icmp_var.h> 59df8bae1dSRodney W. Grimes 606a800098SYoshinobu Inoue #ifdef IPSEC 616a800098SYoshinobu Inoue #include <netinet6/ipsec.h> 626a800098SYoshinobu Inoue #include <netkey/key.h> 636a800098SYoshinobu Inoue #endif 646a800098SYoshinobu Inoue 656a800098SYoshinobu Inoue #include "faith.h" 666a800098SYoshinobu Inoue #if defined(NFAITH) && NFAITH > 0 676a800098SYoshinobu Inoue #include <net/if_types.h> 686a800098SYoshinobu Inoue #endif 696a800098SYoshinobu Inoue 7072a52a35SJonathan Lemon #include <machine/in_cksum.h> 7172a52a35SJonathan Lemon 72df8bae1dSRodney W. Grimes /* 73df8bae1dSRodney W. Grimes * ICMP routines: error generation, receive packet processing, and 74df8bae1dSRodney W. Grimes * routines to turnaround packets back to the originator, and 75df8bae1dSRodney W. Grimes * host table maintenance routines. 76df8bae1dSRodney W. Grimes */ 77df8bae1dSRodney W. Grimes 78f708ef1bSPoul-Henning Kamp static struct icmpstat icmpstat; 790312fbe9SPoul-Henning Kamp SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD, 800312fbe9SPoul-Henning Kamp &icmpstat, icmpstat, ""); 810312fbe9SPoul-Henning Kamp 820312fbe9SPoul-Henning Kamp static int icmpmaskrepl = 0; 830312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW, 840312fbe9SPoul-Henning Kamp &icmpmaskrepl, 0, ""); 850312fbe9SPoul-Henning Kamp 8618d3153eSDag-Erling Smørgrav static int drop_redirect = 0; 8718d3153eSDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_RW, 8818d3153eSDag-Erling Smørgrav &drop_redirect, 0, ""); 8918d3153eSDag-Erling Smørgrav 906c3b5f69SDag-Erling Smørgrav static int log_redirect = 0; 916c3b5f69SDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW, 926c3b5f69SDag-Erling Smørgrav &log_redirect, 0, ""); 936c3b5f69SDag-Erling Smørgrav 94173c0f9fSWarner Losh static int icmplim = 200; 9551508de1SMatthew Dillon SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW, 9651508de1SMatthew Dillon &icmplim, 0, ""); 975fce7fc4SMatthew Dillon 984f14ee00SDan Moschuk static int icmplim_output = 1; 994f14ee00SDan Moschuk SYSCTL_INT(_net_inet_icmp, OID_AUTO, icmplim_output, CTLFLAG_RW, 1004f14ee00SDan Moschuk &icmplim_output, 0, ""); 10151508de1SMatthew Dillon 1025fce7fc4SMatthew Dillon /* 1035fce7fc4SMatthew Dillon * ICMP broadcast echo sysctl 1045fce7fc4SMatthew Dillon */ 1055fce7fc4SMatthew Dillon 10661a4defdSJoseph Koshy static int icmpbmcastecho = 0; 10718d3153eSDag-Erling Smørgrav SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, 10818d3153eSDag-Erling Smørgrav &icmpbmcastecho, 0, ""); 1097022ea0aSGarrett Wollman 11051508de1SMatthew Dillon 111df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 112df8bae1dSRodney W. Grimes int icmpprintfs = 0; 113df8bae1dSRodney W. Grimes #endif 114df8bae1dSRodney W. Grimes 1150312fbe9SPoul-Henning Kamp static void icmp_reflect __P((struct mbuf *)); 1160312fbe9SPoul-Henning Kamp static void icmp_send __P((struct mbuf *, struct mbuf *)); 117f708ef1bSPoul-Henning Kamp static int ip_next_mtu __P((int, int)); 1180312fbe9SPoul-Henning Kamp 119df8bae1dSRodney W. Grimes extern struct protosw inetsw[]; 120df8bae1dSRodney W. Grimes 121df8bae1dSRodney W. Grimes /* 122df8bae1dSRodney W. Grimes * Generate an error packet of type error 123df8bae1dSRodney W. Grimes * in response to bad packet ip. 124df8bae1dSRodney W. Grimes */ 125df8bae1dSRodney W. Grimes void 126df8bae1dSRodney W. Grimes icmp_error(n, type, code, dest, destifp) 127df8bae1dSRodney W. Grimes struct mbuf *n; 128df8bae1dSRodney W. Grimes int type, code; 129df8bae1dSRodney W. Grimes n_long dest; 130df8bae1dSRodney W. Grimes struct ifnet *destifp; 131df8bae1dSRodney W. Grimes { 132df8bae1dSRodney W. Grimes register struct ip *oip = mtod(n, struct ip *), *nip; 1335e2d0696SGarrett Wollman register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2; 134df8bae1dSRodney W. Grimes register struct icmp *icp; 135df8bae1dSRodney W. Grimes register struct mbuf *m; 136df8bae1dSRodney W. Grimes unsigned icmplen; 137df8bae1dSRodney W. Grimes 138df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 139df8bae1dSRodney W. Grimes if (icmpprintfs) 140623ae52eSPoul-Henning Kamp printf("icmp_error(%p, %x, %d)\n", oip, type, code); 141df8bae1dSRodney W. Grimes #endif 142df8bae1dSRodney W. Grimes if (type != ICMP_REDIRECT) 143df8bae1dSRodney W. Grimes icmpstat.icps_error++; 144df8bae1dSRodney W. Grimes /* 145df8bae1dSRodney W. Grimes * Don't send error if not the first fragment of message. 146df8bae1dSRodney W. Grimes * Don't error if the old packet protocol was ICMP 147df8bae1dSRodney W. Grimes * error message, only known informational types. 148df8bae1dSRodney W. Grimes */ 149df8bae1dSRodney W. Grimes if (oip->ip_off &~ (IP_MF|IP_DF)) 150df8bae1dSRodney W. Grimes goto freeit; 151df8bae1dSRodney W. Grimes if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 152df8bae1dSRodney W. Grimes n->m_len >= oiplen + ICMP_MINLEN && 153df8bae1dSRodney W. Grimes !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { 154df8bae1dSRodney W. Grimes icmpstat.icps_oldicmp++; 155df8bae1dSRodney W. Grimes goto freeit; 156df8bae1dSRodney W. Grimes } 157df8bae1dSRodney W. Grimes /* Don't send error in response to a multicast or broadcast packet */ 158df8bae1dSRodney W. Grimes if (n->m_flags & (M_BCAST|M_MCAST)) 159df8bae1dSRodney W. Grimes goto freeit; 160df8bae1dSRodney W. Grimes /* 161df8bae1dSRodney W. Grimes * First, formulate icmp message 162df8bae1dSRodney W. Grimes */ 163df8bae1dSRodney W. Grimes m = m_gethdr(M_DONTWAIT, MT_HEADER); 164df8bae1dSRodney W. Grimes if (m == NULL) 165df8bae1dSRodney W. Grimes goto freeit; 1661d027522SRuslan Ermilov icmplen = min(oiplen + 8, oip->ip_len); 167df8bae1dSRodney W. Grimes m->m_len = icmplen + ICMP_MINLEN; 168df8bae1dSRodney W. Grimes MH_ALIGN(m, m->m_len); 169df8bae1dSRodney W. Grimes icp = mtod(m, struct icmp *); 170df8bae1dSRodney W. Grimes if ((u_int)type > ICMP_MAXTYPE) 171df8bae1dSRodney W. Grimes panic("icmp_error"); 172df8bae1dSRodney W. Grimes icmpstat.icps_outhist[type]++; 173df8bae1dSRodney W. Grimes icp->icmp_type = type; 174df8bae1dSRodney W. Grimes if (type == ICMP_REDIRECT) 175df8bae1dSRodney W. Grimes icp->icmp_gwaddr.s_addr = dest; 176df8bae1dSRodney W. Grimes else { 177df8bae1dSRodney W. Grimes icp->icmp_void = 0; 178df8bae1dSRodney W. Grimes /* 179df8bae1dSRodney W. Grimes * The following assignments assume an overlay with the 180df8bae1dSRodney W. Grimes * zeroed icmp_void field. 181df8bae1dSRodney W. Grimes */ 182df8bae1dSRodney W. Grimes if (type == ICMP_PARAMPROB) { 183df8bae1dSRodney W. Grimes icp->icmp_pptr = code; 184df8bae1dSRodney W. Grimes code = 0; 185df8bae1dSRodney W. Grimes } else if (type == ICMP_UNREACH && 186df8bae1dSRodney W. Grimes code == ICMP_UNREACH_NEEDFRAG && destifp) { 187df8bae1dSRodney W. Grimes icp->icmp_nextmtu = htons(destifp->if_mtu); 188df8bae1dSRodney W. Grimes } 189df8bae1dSRodney W. Grimes } 190df8bae1dSRodney W. Grimes 191df8bae1dSRodney W. Grimes icp->icmp_code = code; 192df8bae1dSRodney W. Grimes bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); 193df8bae1dSRodney W. Grimes nip = &icp->icmp_ip; 19404287599SRuslan Ermilov 19504287599SRuslan Ermilov /* 19604287599SRuslan Ermilov * Convert fields to network representation. 19704287599SRuslan Ermilov */ 19804287599SRuslan Ermilov HTONS(nip->ip_len); 19904287599SRuslan Ermilov HTONS(nip->ip_off); 200df8bae1dSRodney W. Grimes 201df8bae1dSRodney W. Grimes /* 202df8bae1dSRodney W. Grimes * Now, copy old ip header (without options) 203df8bae1dSRodney W. Grimes * in front of icmp message. 204df8bae1dSRodney W. Grimes */ 205df8bae1dSRodney W. Grimes if (m->m_data - sizeof(struct ip) < m->m_pktdat) 206df8bae1dSRodney W. Grimes panic("icmp len"); 207df8bae1dSRodney W. Grimes m->m_data -= sizeof(struct ip); 208df8bae1dSRodney W. Grimes m->m_len += sizeof(struct ip); 209df8bae1dSRodney W. Grimes m->m_pkthdr.len = m->m_len; 210df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 211df8bae1dSRodney W. Grimes nip = mtod(m, struct ip *); 212df8bae1dSRodney W. Grimes bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); 213df8bae1dSRodney W. Grimes nip->ip_len = m->m_len; 2145e2d0696SGarrett Wollman nip->ip_vhl = IP_VHL_BORING; 215df8bae1dSRodney W. Grimes nip->ip_p = IPPROTO_ICMP; 216df8bae1dSRodney W. Grimes nip->ip_tos = 0; 217df8bae1dSRodney W. Grimes icmp_reflect(m); 218df8bae1dSRodney W. Grimes 219df8bae1dSRodney W. Grimes freeit: 220df8bae1dSRodney W. Grimes m_freem(n); 221df8bae1dSRodney W. Grimes } 222df8bae1dSRodney W. Grimes 223df8bae1dSRodney W. Grimes static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 224df8bae1dSRodney W. Grimes static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 225df8bae1dSRodney W. Grimes static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 226df8bae1dSRodney W. Grimes 227df8bae1dSRodney W. Grimes /* 228df8bae1dSRodney W. Grimes * Process a received ICMP message. 229df8bae1dSRodney W. Grimes */ 230df8bae1dSRodney W. Grimes void 2316a800098SYoshinobu Inoue icmp_input(m, off, proto) 232df8bae1dSRodney W. Grimes register struct mbuf *m; 2336a800098SYoshinobu Inoue int off, proto; 234df8bae1dSRodney W. Grimes { 2356a800098SYoshinobu Inoue int hlen = off; 236df8bae1dSRodney W. Grimes register struct icmp *icp; 237df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 238df8bae1dSRodney W. Grimes int icmplen = ip->ip_len; 239df8bae1dSRodney W. Grimes register int i; 240df8bae1dSRodney W. Grimes struct in_ifaddr *ia; 241b62d102cSBruce Evans void (*ctlfunc) __P((int, struct sockaddr *, void *)); 242df8bae1dSRodney W. Grimes int code; 243df8bae1dSRodney W. Grimes 244df8bae1dSRodney W. Grimes /* 245df8bae1dSRodney W. Grimes * Locate icmp structure in mbuf, and check 246df8bae1dSRodney W. Grimes * that not corrupted and of at least minimum length. 247df8bae1dSRodney W. Grimes */ 248df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 2492b758395SGarrett Wollman if (icmpprintfs) { 2502b758395SGarrett Wollman char buf[4 * sizeof "123"]; 2512b758395SGarrett Wollman strcpy(buf, inet_ntoa(ip->ip_src)); 2522b758395SGarrett Wollman printf("icmp_input from %s to %s, len %d\n", 2532b758395SGarrett Wollman buf, inet_ntoa(ip->ip_dst), icmplen); 2542b758395SGarrett Wollman } 255df8bae1dSRodney W. Grimes #endif 256df8bae1dSRodney W. Grimes if (icmplen < ICMP_MINLEN) { 257df8bae1dSRodney W. Grimes icmpstat.icps_tooshort++; 258df8bae1dSRodney W. Grimes goto freeit; 259df8bae1dSRodney W. Grimes } 260df8bae1dSRodney W. Grimes i = hlen + min(icmplen, ICMP_ADVLENMIN); 261df8bae1dSRodney W. Grimes if (m->m_len < i && (m = m_pullup(m, i)) == 0) { 262df8bae1dSRodney W. Grimes icmpstat.icps_tooshort++; 263df8bae1dSRodney W. Grimes return; 264df8bae1dSRodney W. Grimes } 265df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 266df8bae1dSRodney W. Grimes m->m_len -= hlen; 267df8bae1dSRodney W. Grimes m->m_data += hlen; 268df8bae1dSRodney W. Grimes icp = mtod(m, struct icmp *); 269df8bae1dSRodney W. Grimes if (in_cksum(m, icmplen)) { 270df8bae1dSRodney W. Grimes icmpstat.icps_checksum++; 271df8bae1dSRodney W. Grimes goto freeit; 272df8bae1dSRodney W. Grimes } 273df8bae1dSRodney W. Grimes m->m_len += hlen; 274df8bae1dSRodney W. Grimes m->m_data -= hlen; 275df8bae1dSRodney W. Grimes 2766a800098SYoshinobu Inoue #if defined(NFAITH) && 0 < NFAITH 2776a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 2786a800098SYoshinobu Inoue /* 2796a800098SYoshinobu Inoue * Deliver very specific ICMP type only. 2806a800098SYoshinobu Inoue */ 2816a800098SYoshinobu Inoue switch (icp->icmp_type) { 2826a800098SYoshinobu Inoue case ICMP_UNREACH: 2836a800098SYoshinobu Inoue case ICMP_TIMXCEED: 2846a800098SYoshinobu Inoue break; 2856a800098SYoshinobu Inoue default: 2866a800098SYoshinobu Inoue goto freeit; 2876a800098SYoshinobu Inoue } 2886a800098SYoshinobu Inoue } 2896a800098SYoshinobu Inoue #endif 2906a800098SYoshinobu Inoue 291df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 292df8bae1dSRodney W. Grimes if (icmpprintfs) 293df8bae1dSRodney W. Grimes printf("icmp_input, type %d code %d\n", icp->icmp_type, 294df8bae1dSRodney W. Grimes icp->icmp_code); 295df8bae1dSRodney W. Grimes #endif 2965b7ee6edSGarrett Wollman 2976a800098SYoshinobu Inoue #ifdef IPSEC 2986a800098SYoshinobu Inoue /* drop it if it does not match the policy */ 2996a800098SYoshinobu Inoue /* XXX Is there meaning of check in here ? */ 3006a800098SYoshinobu Inoue if (ipsec4_in_reject(m, NULL)) { 3016a800098SYoshinobu Inoue ipsecstat.in_polvio++; 3026a800098SYoshinobu Inoue goto freeit; 3036a800098SYoshinobu Inoue } 3046a800098SYoshinobu Inoue #endif 3056a800098SYoshinobu Inoue 3065b7ee6edSGarrett Wollman /* 3075b7ee6edSGarrett Wollman * Message type specific processing. 3085b7ee6edSGarrett Wollman */ 309df8bae1dSRodney W. Grimes if (icp->icmp_type > ICMP_MAXTYPE) 310df8bae1dSRodney W. Grimes goto raw; 311df8bae1dSRodney W. Grimes icmpstat.icps_inhist[icp->icmp_type]++; 312df8bae1dSRodney W. Grimes code = icp->icmp_code; 313df8bae1dSRodney W. Grimes switch (icp->icmp_type) { 314df8bae1dSRodney W. Grimes 315df8bae1dSRodney W. Grimes case ICMP_UNREACH: 316df8bae1dSRodney W. Grimes switch (code) { 317df8bae1dSRodney W. Grimes case ICMP_UNREACH_NET: 318df8bae1dSRodney W. Grimes case ICMP_UNREACH_HOST: 319df8bae1dSRodney W. Grimes case ICMP_UNREACH_PROTOCOL: 320df8bae1dSRodney W. Grimes case ICMP_UNREACH_PORT: 321df8bae1dSRodney W. Grimes case ICMP_UNREACH_SRCFAIL: 322df8bae1dSRodney W. Grimes code += PRC_UNREACH_NET; 323df8bae1dSRodney W. Grimes break; 324df8bae1dSRodney W. Grimes 325df8bae1dSRodney W. Grimes case ICMP_UNREACH_NEEDFRAG: 326df8bae1dSRodney W. Grimes code = PRC_MSGSIZE; 327df8bae1dSRodney W. Grimes break; 328df8bae1dSRodney W. Grimes 329df8bae1dSRodney W. Grimes case ICMP_UNREACH_NET_UNKNOWN: 330df8bae1dSRodney W. Grimes case ICMP_UNREACH_NET_PROHIB: 331df8bae1dSRodney W. Grimes case ICMP_UNREACH_TOSNET: 332df8bae1dSRodney W. Grimes code = PRC_UNREACH_NET; 333df8bae1dSRodney W. Grimes break; 334df8bae1dSRodney W. Grimes 335df8bae1dSRodney W. Grimes case ICMP_UNREACH_HOST_UNKNOWN: 336df8bae1dSRodney W. Grimes case ICMP_UNREACH_ISOLATED: 337df8bae1dSRodney W. Grimes case ICMP_UNREACH_HOST_PROHIB: 338df8bae1dSRodney W. Grimes case ICMP_UNREACH_TOSHOST: 339df8bae1dSRodney W. Grimes code = PRC_UNREACH_HOST; 340df8bae1dSRodney W. Grimes break; 341df8bae1dSRodney W. Grimes 3429c4b2574SPaul Traina case ICMP_UNREACH_FILTER_PROHIB: 3439c4b2574SPaul Traina case ICMP_UNREACH_HOST_PRECEDENCE: 3449c4b2574SPaul Traina case ICMP_UNREACH_PRECEDENCE_CUTOFF: 3459c4b2574SPaul Traina code = PRC_UNREACH_PORT; 3469c4b2574SPaul Traina break; 3479c4b2574SPaul Traina 348df8bae1dSRodney W. Grimes default: 349df8bae1dSRodney W. Grimes goto badcode; 350df8bae1dSRodney W. Grimes } 351df8bae1dSRodney W. Grimes goto deliver; 352df8bae1dSRodney W. Grimes 353df8bae1dSRodney W. Grimes case ICMP_TIMXCEED: 354df8bae1dSRodney W. Grimes if (code > 1) 355df8bae1dSRodney W. Grimes goto badcode; 356df8bae1dSRodney W. Grimes code += PRC_TIMXCEED_INTRANS; 357df8bae1dSRodney W. Grimes goto deliver; 358df8bae1dSRodney W. Grimes 359df8bae1dSRodney W. Grimes case ICMP_PARAMPROB: 360df8bae1dSRodney W. Grimes if (code > 1) 361df8bae1dSRodney W. Grimes goto badcode; 362df8bae1dSRodney W. Grimes code = PRC_PARAMPROB; 363df8bae1dSRodney W. Grimes goto deliver; 364df8bae1dSRodney W. Grimes 365df8bae1dSRodney W. Grimes case ICMP_SOURCEQUENCH: 366df8bae1dSRodney W. Grimes if (code) 367df8bae1dSRodney W. Grimes goto badcode; 368df8bae1dSRodney W. Grimes code = PRC_QUENCH; 369df8bae1dSRodney W. Grimes deliver: 370df8bae1dSRodney W. Grimes /* 371df8bae1dSRodney W. Grimes * Problem with datagram; advise higher level routines. 372df8bae1dSRodney W. Grimes */ 373df8bae1dSRodney W. Grimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 3745e2d0696SGarrett Wollman IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { 375df8bae1dSRodney W. Grimes icmpstat.icps_badlen++; 376df8bae1dSRodney W. Grimes goto freeit; 377df8bae1dSRodney W. Grimes } 378df8bae1dSRodney W. Grimes NTOHS(icp->icmp_ip.ip_len); 3795b7ee6edSGarrett Wollman /* Discard ICMP's in response to multicast packets */ 3805b7ee6edSGarrett Wollman if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr))) 3815b7ee6edSGarrett Wollman goto badcode; 382df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 383df8bae1dSRodney W. Grimes if (icmpprintfs) 384df8bae1dSRodney W. Grimes printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 385df8bae1dSRodney W. Grimes #endif 386df8bae1dSRodney W. Grimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 387b7a44e34SGarrett Wollman #if 1 3885cbf3e08SGarrett Wollman /* 3895cbf3e08SGarrett Wollman * MTU discovery: 3905cbf3e08SGarrett Wollman * If we got a needfrag and there is a host route to the 3915cbf3e08SGarrett Wollman * original destination, and the MTU is not locked, then 3925cbf3e08SGarrett Wollman * set the MTU in the route to the suggested new value 3935cbf3e08SGarrett Wollman * (if given) and then notify as usual. The ULPs will 3945cbf3e08SGarrett Wollman * notice that the MTU has changed and adapt accordingly. 3955cbf3e08SGarrett Wollman * If no new MTU was suggested, then we guess a new one 3965cbf3e08SGarrett Wollman * less than the current value. If the new MTU is 3975cbf3e08SGarrett Wollman * unreasonably small (arbitrarily set at 296), then 3985cbf3e08SGarrett Wollman * we reset the MTU to the interface value and enable the 3995cbf3e08SGarrett Wollman * lock bit, indicating that we are no longer doing MTU 4005cbf3e08SGarrett Wollman * discovery. 4015cbf3e08SGarrett Wollman */ 4025cbf3e08SGarrett Wollman if (code == PRC_MSGSIZE) { 4035cbf3e08SGarrett Wollman struct rtentry *rt; 4045cbf3e08SGarrett Wollman int mtu; 4055cbf3e08SGarrett Wollman 4065cbf3e08SGarrett Wollman rt = rtalloc1((struct sockaddr *)&icmpsrc, 0, 4075cbf3e08SGarrett Wollman RTF_CLONING | RTF_PRCLONING); 4085cbf3e08SGarrett Wollman if (rt && (rt->rt_flags & RTF_HOST) 4095cbf3e08SGarrett Wollman && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { 4105cbf3e08SGarrett Wollman mtu = ntohs(icp->icmp_nextmtu); 4115cbf3e08SGarrett Wollman if (!mtu) 4125cbf3e08SGarrett Wollman mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu, 4135cbf3e08SGarrett Wollman 1); 414be070f43SGarrett Wollman #ifdef DEBUG_MTUDISC 415be070f43SGarrett Wollman printf("MTU for %s reduced to %d\n", 416be070f43SGarrett Wollman inet_ntoa(icmpsrc.sin_addr), mtu); 417be070f43SGarrett Wollman #endif 418be070f43SGarrett Wollman if (mtu < 296) { 419b7a44e34SGarrett Wollman /* rt->rt_rmx.rmx_mtu = 420b7a44e34SGarrett Wollman rt->rt_ifp->if_mtu; */ 4215cbf3e08SGarrett Wollman rt->rt_rmx.rmx_locks |= RTV_MTU; 4225cbf3e08SGarrett Wollman } else if (rt->rt_rmx.rmx_mtu > mtu) { 4235cbf3e08SGarrett Wollman rt->rt_rmx.rmx_mtu = mtu; 4245cbf3e08SGarrett Wollman } 4255cbf3e08SGarrett Wollman } 4265cbf3e08SGarrett Wollman if (rt) 4275cbf3e08SGarrett Wollman RTFREE(rt); 4285cbf3e08SGarrett Wollman } 4295cbf3e08SGarrett Wollman 430b7a44e34SGarrett Wollman #endif 4316a800098SYoshinobu Inoue /* 4326a800098SYoshinobu Inoue * XXX if the packet contains [IPv4 AH TCP], we can't make a 4336a800098SYoshinobu Inoue * notification to TCP layer. 4346a800098SYoshinobu Inoue */ 435623ae52eSPoul-Henning Kamp ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput; 436623ae52eSPoul-Henning Kamp if (ctlfunc) 437df8bae1dSRodney W. Grimes (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, 438b62d102cSBruce Evans (void *)&icp->icmp_ip); 439df8bae1dSRodney W. Grimes break; 440df8bae1dSRodney W. Grimes 441df8bae1dSRodney W. Grimes badcode: 442df8bae1dSRodney W. Grimes icmpstat.icps_badcode++; 443df8bae1dSRodney W. Grimes break; 444df8bae1dSRodney W. Grimes 445df8bae1dSRodney W. Grimes case ICMP_ECHO: 4467022ea0aSGarrett Wollman if (!icmpbmcastecho 447d311884fSDavid Greenman && (m->m_flags & (M_MCAST | M_BCAST)) != 0) { 4487022ea0aSGarrett Wollman icmpstat.icps_bmcastecho++; 4497022ea0aSGarrett Wollman break; 4507022ea0aSGarrett Wollman } 451df8bae1dSRodney W. Grimes icp->icmp_type = ICMP_ECHOREPLY; 45209f81a46SBosko Milekic if (badport_bandlim(BANDLIM_ECHO) < 0) 45309f81a46SBosko Milekic goto freeit; 45409f81a46SBosko Milekic else 455df8bae1dSRodney W. Grimes goto reflect; 456df8bae1dSRodney W. Grimes 457df8bae1dSRodney W. Grimes case ICMP_TSTAMP: 458fe0fb8abSGarrett Wollman if (!icmpbmcastecho 459d311884fSDavid Greenman && (m->m_flags & (M_MCAST | M_BCAST)) != 0) { 460fe0fb8abSGarrett Wollman icmpstat.icps_bmcasttstamp++; 461fe0fb8abSGarrett Wollman break; 462fe0fb8abSGarrett Wollman } 463df8bae1dSRodney W. Grimes if (icmplen < ICMP_TSLEN) { 464df8bae1dSRodney W. Grimes icmpstat.icps_badlen++; 465df8bae1dSRodney W. Grimes break; 466df8bae1dSRodney W. Grimes } 467df8bae1dSRodney W. Grimes icp->icmp_type = ICMP_TSTAMPREPLY; 468df8bae1dSRodney W. Grimes icp->icmp_rtime = iptime(); 469df8bae1dSRodney W. Grimes icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 47009f81a46SBosko Milekic if (badport_bandlim(BANDLIM_TSTAMP) < 0) 47109f81a46SBosko Milekic goto freeit; 47209f81a46SBosko Milekic else 473df8bae1dSRodney W. Grimes goto reflect; 474df8bae1dSRodney W. Grimes 475df8bae1dSRodney W. Grimes case ICMP_MASKREQ: 476df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 477df8bae1dSRodney W. Grimes if (icmpmaskrepl == 0) 478df8bae1dSRodney W. Grimes break; 479df8bae1dSRodney W. Grimes /* 480df8bae1dSRodney W. Grimes * We are not able to respond with all ones broadcast 481df8bae1dSRodney W. Grimes * unless we receive it over a point-to-point interface. 482df8bae1dSRodney W. Grimes */ 483df8bae1dSRodney W. Grimes if (icmplen < ICMP_MASKLEN) 484df8bae1dSRodney W. Grimes break; 485df8bae1dSRodney W. Grimes switch (ip->ip_dst.s_addr) { 486df8bae1dSRodney W. Grimes 487df8bae1dSRodney W. Grimes case INADDR_BROADCAST: 488df8bae1dSRodney W. Grimes case INADDR_ANY: 489df8bae1dSRodney W. Grimes icmpdst.sin_addr = ip->ip_src; 490df8bae1dSRodney W. Grimes break; 491df8bae1dSRodney W. Grimes 492df8bae1dSRodney W. Grimes default: 493df8bae1dSRodney W. Grimes icmpdst.sin_addr = ip->ip_dst; 494df8bae1dSRodney W. Grimes } 495df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)ifaof_ifpforaddr( 496df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); 497df8bae1dSRodney W. Grimes if (ia == 0) 498df8bae1dSRodney W. Grimes break; 4997e6f7714SPoul-Henning Kamp if (ia->ia_ifp == 0) 5007e6f7714SPoul-Henning Kamp break; 501df8bae1dSRodney W. Grimes icp->icmp_type = ICMP_MASKREPLY; 502df8bae1dSRodney W. Grimes icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 503df8bae1dSRodney W. Grimes if (ip->ip_src.s_addr == 0) { 504df8bae1dSRodney W. Grimes if (ia->ia_ifp->if_flags & IFF_BROADCAST) 505df8bae1dSRodney W. Grimes ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; 506df8bae1dSRodney W. Grimes else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 507df8bae1dSRodney W. Grimes ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; 508df8bae1dSRodney W. Grimes } 509df8bae1dSRodney W. Grimes reflect: 510df8bae1dSRodney W. Grimes ip->ip_len += hlen; /* since ip_input deducts this */ 511df8bae1dSRodney W. Grimes icmpstat.icps_reflect++; 512df8bae1dSRodney W. Grimes icmpstat.icps_outhist[icp->icmp_type]++; 513df8bae1dSRodney W. Grimes icmp_reflect(m); 514df8bae1dSRodney W. Grimes return; 515df8bae1dSRodney W. Grimes 516df8bae1dSRodney W. Grimes case ICMP_REDIRECT: 51718d3153eSDag-Erling Smørgrav if (log_redirect) { 51818d3153eSDag-Erling Smørgrav u_long src, dst, gw; 51918d3153eSDag-Erling Smørgrav 52018d3153eSDag-Erling Smørgrav src = ntohl(ip->ip_src.s_addr); 52118d3153eSDag-Erling Smørgrav dst = ntohl(icp->icmp_ip.ip_dst.s_addr); 52218d3153eSDag-Erling Smørgrav gw = ntohl(icp->icmp_gwaddr.s_addr); 52318d3153eSDag-Erling Smørgrav printf("icmp redirect from %d.%d.%d.%d: " 52418d3153eSDag-Erling Smørgrav "%d.%d.%d.%d => %d.%d.%d.%d\n", 52518d3153eSDag-Erling Smørgrav (int)(src >> 24), (int)((src >> 16) & 0xff), 52618d3153eSDag-Erling Smørgrav (int)((src >> 8) & 0xff), (int)(src & 0xff), 52718d3153eSDag-Erling Smørgrav (int)(dst >> 24), (int)((dst >> 16) & 0xff), 52818d3153eSDag-Erling Smørgrav (int)((dst >> 8) & 0xff), (int)(dst & 0xff), 52918d3153eSDag-Erling Smørgrav (int)(gw >> 24), (int)((gw >> 16) & 0xff), 53018d3153eSDag-Erling Smørgrav (int)((gw >> 8) & 0xff), (int)(gw & 0xff)); 53118d3153eSDag-Erling Smørgrav } 53218d3153eSDag-Erling Smørgrav if (drop_redirect) 53318d3153eSDag-Erling Smørgrav break; 534df8bae1dSRodney W. Grimes if (code > 3) 535df8bae1dSRodney W. Grimes goto badcode; 536df8bae1dSRodney W. Grimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 5375e2d0696SGarrett Wollman IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { 538df8bae1dSRodney W. Grimes icmpstat.icps_badlen++; 539df8bae1dSRodney W. Grimes break; 540df8bae1dSRodney W. Grimes } 541df8bae1dSRodney W. Grimes /* 542df8bae1dSRodney W. Grimes * Short circuit routing redirects to force 543df8bae1dSRodney W. Grimes * immediate change in the kernel's routing 544df8bae1dSRodney W. Grimes * tables. The message is also handed to anyone 545df8bae1dSRodney W. Grimes * listening on a raw socket (e.g. the routing 546df8bae1dSRodney W. Grimes * daemon for use in updating its tables). 547df8bae1dSRodney W. Grimes */ 548df8bae1dSRodney W. Grimes icmpgw.sin_addr = ip->ip_src; 549df8bae1dSRodney W. Grimes icmpdst.sin_addr = icp->icmp_gwaddr; 550df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 5512b758395SGarrett Wollman if (icmpprintfs) { 5522b758395SGarrett Wollman char buf[4 * sizeof "123"]; 5532b758395SGarrett Wollman strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst)); 5542b758395SGarrett Wollman 5552b758395SGarrett Wollman printf("redirect dst %s to %s\n", 5562b758395SGarrett Wollman buf, inet_ntoa(icp->icmp_gwaddr)); 5572b758395SGarrett Wollman } 558df8bae1dSRodney W. Grimes #endif 559df8bae1dSRodney W. Grimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 560df8bae1dSRodney W. Grimes rtredirect((struct sockaddr *)&icmpsrc, 561df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpdst, 562df8bae1dSRodney W. Grimes (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 563df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpgw, (struct rtentry **)0); 564df8bae1dSRodney W. Grimes pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); 5656a800098SYoshinobu Inoue #ifdef IPSEC 5666a800098SYoshinobu Inoue key_sa_routechange((struct sockaddr *)&icmpsrc); 5676a800098SYoshinobu Inoue #endif 568df8bae1dSRodney W. Grimes break; 569df8bae1dSRodney W. Grimes 570df8bae1dSRodney W. Grimes /* 571df8bae1dSRodney W. Grimes * No kernel processing for the following; 572df8bae1dSRodney W. Grimes * just fall through to send to raw listener. 573df8bae1dSRodney W. Grimes */ 574df8bae1dSRodney W. Grimes case ICMP_ECHOREPLY: 575df8bae1dSRodney W. Grimes case ICMP_ROUTERADVERT: 576df8bae1dSRodney W. Grimes case ICMP_ROUTERSOLICIT: 577df8bae1dSRodney W. Grimes case ICMP_TSTAMPREPLY: 578df8bae1dSRodney W. Grimes case ICMP_IREQREPLY: 579df8bae1dSRodney W. Grimes case ICMP_MASKREPLY: 580df8bae1dSRodney W. Grimes default: 581df8bae1dSRodney W. Grimes break; 582df8bae1dSRodney W. Grimes } 583df8bae1dSRodney W. Grimes 584df8bae1dSRodney W. Grimes raw: 5856a800098SYoshinobu Inoue rip_input(m, off, proto); 586df8bae1dSRodney W. Grimes return; 587df8bae1dSRodney W. Grimes 588df8bae1dSRodney W. Grimes freeit: 589df8bae1dSRodney W. Grimes m_freem(m); 590df8bae1dSRodney W. Grimes } 591df8bae1dSRodney W. Grimes 592df8bae1dSRodney W. Grimes /* 593df8bae1dSRodney W. Grimes * Reflect the ip packet back to the source 594df8bae1dSRodney W. Grimes */ 5950312fbe9SPoul-Henning Kamp static void 596df8bae1dSRodney W. Grimes icmp_reflect(m) 597df8bae1dSRodney W. Grimes struct mbuf *m; 598df8bae1dSRodney W. Grimes { 599df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 600df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 601df8bae1dSRodney W. Grimes struct in_addr t; 602b5e8ce9fSBruce Evans struct mbuf *opts = 0; 6035e2d0696SGarrett Wollman int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip); 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 */ 609df8bae1dSRodney W. Grimes goto done; /* Ip_output() will check for broadcast */ 610df8bae1dSRodney W. Grimes } 611df8bae1dSRodney W. Grimes t = ip->ip_dst; 612df8bae1dSRodney W. Grimes ip->ip_dst = ip->ip_src; 613df8bae1dSRodney W. Grimes /* 614df8bae1dSRodney W. Grimes * If the incoming packet was addressed directly to us, 615df8bae1dSRodney W. Grimes * use dst as the src for the reply. Otherwise (broadcast 616df8bae1dSRodney W. Grimes * or anonymous), use the address which corresponds 617df8bae1dSRodney W. Grimes * to the incoming interface. 618df8bae1dSRodney W. Grimes */ 61959562606SGarrett Wollman for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { 620df8bae1dSRodney W. Grimes if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) 621df8bae1dSRodney W. Grimes break; 6227e6f7714SPoul-Henning Kamp if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) && 623df8bae1dSRodney W. Grimes t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) 624df8bae1dSRodney W. Grimes break; 625df8bae1dSRodney W. Grimes } 626df8bae1dSRodney W. Grimes icmpdst.sin_addr = t; 62741fbdc96SJulian Elischer if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif) 628df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *)ifaof_ifpforaddr( 629df8bae1dSRodney W. Grimes (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); 630df8bae1dSRodney W. Grimes /* 631df8bae1dSRodney W. Grimes * The following happens if the packet was not addressed to us, 632df8bae1dSRodney W. Grimes * and was received on an interface with no IP address. 633df8bae1dSRodney W. Grimes */ 634df8bae1dSRodney W. Grimes if (ia == (struct in_ifaddr *)0) 63559562606SGarrett Wollman ia = in_ifaddrhead.tqh_first; 636df8bae1dSRodney W. Grimes t = IA_SIN(ia)->sin_addr; 637df8bae1dSRodney W. Grimes ip->ip_src = t; 638df8bae1dSRodney W. Grimes ip->ip_ttl = MAXTTL; 639df8bae1dSRodney W. Grimes 640df8bae1dSRodney W. Grimes if (optlen > 0) { 641df8bae1dSRodney W. Grimes register u_char *cp; 642df8bae1dSRodney W. Grimes int opt, cnt; 643df8bae1dSRodney W. Grimes u_int len; 644df8bae1dSRodney W. Grimes 645df8bae1dSRodney W. Grimes /* 646df8bae1dSRodney W. Grimes * Retrieve any source routing from the incoming packet; 647df8bae1dSRodney W. Grimes * add on any record-route or timestamp options. 648df8bae1dSRodney W. Grimes */ 649df8bae1dSRodney W. Grimes cp = (u_char *) (ip + 1); 650df8bae1dSRodney W. Grimes if ((opts = ip_srcroute()) == 0 && 651df8bae1dSRodney W. Grimes (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 652df8bae1dSRodney W. Grimes opts->m_len = sizeof(struct in_addr); 653df8bae1dSRodney W. Grimes mtod(opts, struct in_addr *)->s_addr = 0; 654df8bae1dSRodney W. Grimes } 655df8bae1dSRodney W. Grimes if (opts) { 656df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 657df8bae1dSRodney W. Grimes if (icmpprintfs) 658df8bae1dSRodney W. Grimes printf("icmp_reflect optlen %d rt %d => ", 659df8bae1dSRodney W. Grimes optlen, opts->m_len); 660df8bae1dSRodney W. Grimes #endif 661df8bae1dSRodney W. Grimes for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 662df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 663df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 664df8bae1dSRodney W. Grimes break; 665df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 666df8bae1dSRodney W. Grimes len = 1; 667df8bae1dSRodney W. Grimes else { 668707d00a3SJonathan Lemon if (cnt < IPOPT_OLEN + sizeof(*cp)) 669707d00a3SJonathan Lemon break; 670df8bae1dSRodney W. Grimes len = cp[IPOPT_OLEN]; 671707d00a3SJonathan Lemon if (len < IPOPT_OLEN + sizeof(*cp) || 672707d00a3SJonathan Lemon len > cnt) 673df8bae1dSRodney W. Grimes break; 674df8bae1dSRodney W. Grimes } 675df8bae1dSRodney W. Grimes /* 676df8bae1dSRodney W. Grimes * Should check for overflow, but it "can't happen" 677df8bae1dSRodney W. Grimes */ 678df8bae1dSRodney W. Grimes if (opt == IPOPT_RR || opt == IPOPT_TS || 679df8bae1dSRodney W. Grimes opt == IPOPT_SECURITY) { 680df8bae1dSRodney W. Grimes bcopy((caddr_t)cp, 681df8bae1dSRodney W. Grimes mtod(opts, caddr_t) + opts->m_len, len); 682df8bae1dSRodney W. Grimes opts->m_len += len; 683df8bae1dSRodney W. Grimes } 684df8bae1dSRodney W. Grimes } 685df8bae1dSRodney W. Grimes /* Terminate & pad, if necessary */ 686623ae52eSPoul-Henning Kamp cnt = opts->m_len % 4; 687623ae52eSPoul-Henning Kamp if (cnt) { 688df8bae1dSRodney W. Grimes for (; cnt < 4; cnt++) { 689df8bae1dSRodney W. Grimes *(mtod(opts, caddr_t) + opts->m_len) = 690df8bae1dSRodney W. Grimes IPOPT_EOL; 691df8bae1dSRodney W. Grimes opts->m_len++; 692df8bae1dSRodney W. Grimes } 693df8bae1dSRodney W. Grimes } 694df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 695df8bae1dSRodney W. Grimes if (icmpprintfs) 696df8bae1dSRodney W. Grimes printf("%d\n", opts->m_len); 697df8bae1dSRodney W. Grimes #endif 698df8bae1dSRodney W. Grimes } 699df8bae1dSRodney W. Grimes /* 700df8bae1dSRodney W. Grimes * Now strip out original options by copying rest of first 701df8bae1dSRodney W. Grimes * mbuf's data back, and adjust the IP length. 702df8bae1dSRodney W. Grimes */ 703df8bae1dSRodney W. Grimes ip->ip_len -= optlen; 7045e2d0696SGarrett Wollman ip->ip_vhl = IP_VHL_BORING; 705df8bae1dSRodney W. Grimes m->m_len -= optlen; 706df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 707df8bae1dSRodney W. Grimes m->m_pkthdr.len -= optlen; 708df8bae1dSRodney W. Grimes optlen += sizeof(struct ip); 709df8bae1dSRodney W. Grimes bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 710df8bae1dSRodney W. Grimes (unsigned)(m->m_len - sizeof(struct ip))); 711df8bae1dSRodney W. Grimes } 712df8bae1dSRodney W. Grimes m->m_flags &= ~(M_BCAST|M_MCAST); 713df8bae1dSRodney W. Grimes icmp_send(m, opts); 714df8bae1dSRodney W. Grimes done: 715df8bae1dSRodney W. Grimes if (opts) 716df8bae1dSRodney W. Grimes (void)m_free(opts); 717df8bae1dSRodney W. Grimes } 718df8bae1dSRodney W. Grimes 719df8bae1dSRodney W. Grimes /* 720df8bae1dSRodney W. Grimes * Send an icmp packet back to the ip level, 721df8bae1dSRodney W. Grimes * after supplying a checksum. 722df8bae1dSRodney W. Grimes */ 7230312fbe9SPoul-Henning Kamp static void 724df8bae1dSRodney W. Grimes icmp_send(m, opts) 725df8bae1dSRodney W. Grimes register struct mbuf *m; 726df8bae1dSRodney W. Grimes struct mbuf *opts; 727df8bae1dSRodney W. Grimes { 728df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 729df8bae1dSRodney W. Grimes register int hlen; 730df8bae1dSRodney W. Grimes register struct icmp *icp; 731d3d20ad1SGarrett Wollman struct route ro; 732df8bae1dSRodney W. Grimes 7335e2d0696SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 734df8bae1dSRodney W. Grimes m->m_data += hlen; 735df8bae1dSRodney W. Grimes m->m_len -= hlen; 736df8bae1dSRodney W. Grimes icp = mtod(m, struct icmp *); 737df8bae1dSRodney W. Grimes icp->icmp_cksum = 0; 738df8bae1dSRodney W. Grimes icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 739df8bae1dSRodney W. Grimes m->m_data -= hlen; 740df8bae1dSRodney W. Grimes m->m_len += hlen; 74194446a2eSArchie Cobbs m->m_pkthdr.rcvif = (struct ifnet *)0; 742df8bae1dSRodney W. Grimes #ifdef ICMPPRINTFS 7432b758395SGarrett Wollman if (icmpprintfs) { 7442b758395SGarrett Wollman char buf[4 * sizeof "123"]; 7452b758395SGarrett Wollman strcpy(buf, inet_ntoa(ip->ip_dst)); 7462b758395SGarrett Wollman printf("icmp_send dst %s src %s\n", 7472b758395SGarrett Wollman buf, inet_ntoa(ip->ip_src)); 7482b758395SGarrett Wollman } 749df8bae1dSRodney W. Grimes #endif 750d3d20ad1SGarrett Wollman bzero(&ro, sizeof ro); 751d3d20ad1SGarrett Wollman (void) ip_output(m, opts, &ro, 0, NULL); 752d3d20ad1SGarrett Wollman if (ro.ro_rt) 753d3d20ad1SGarrett Wollman RTFREE(ro.ro_rt); 754df8bae1dSRodney W. Grimes } 755df8bae1dSRodney W. Grimes 756df8bae1dSRodney W. Grimes n_time 757df8bae1dSRodney W. Grimes iptime() 758df8bae1dSRodney W. Grimes { 759df8bae1dSRodney W. Grimes struct timeval atv; 760df8bae1dSRodney W. Grimes u_long t; 761df8bae1dSRodney W. Grimes 762df8bae1dSRodney W. Grimes microtime(&atv); 763df8bae1dSRodney W. Grimes t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 764df8bae1dSRodney W. Grimes return (htonl(t)); 765df8bae1dSRodney W. Grimes } 766df8bae1dSRodney W. Grimes 767b7a44e34SGarrett Wollman #if 1 7685cbf3e08SGarrett Wollman /* 7695cbf3e08SGarrett Wollman * Return the next larger or smaller MTU plateau (table from RFC 1191) 7705cbf3e08SGarrett Wollman * given current value MTU. If DIR is less than zero, a larger plateau 7715cbf3e08SGarrett Wollman * is returned; otherwise, a smaller value is returned. 7725cbf3e08SGarrett Wollman */ 773f708ef1bSPoul-Henning Kamp static int 7745cbf3e08SGarrett Wollman ip_next_mtu(mtu, dir) 7755cbf3e08SGarrett Wollman int mtu; 7765cbf3e08SGarrett Wollman int dir; 7775cbf3e08SGarrett Wollman { 7785cbf3e08SGarrett Wollman static int mtutab[] = { 7795cbf3e08SGarrett Wollman 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296, 7805cbf3e08SGarrett Wollman 68, 0 7815cbf3e08SGarrett Wollman }; 7825cbf3e08SGarrett Wollman int i; 7835cbf3e08SGarrett Wollman 7845cbf3e08SGarrett Wollman for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) { 7855cbf3e08SGarrett Wollman if (mtu >= mtutab[i]) 7865cbf3e08SGarrett Wollman break; 7875cbf3e08SGarrett Wollman } 7885cbf3e08SGarrett Wollman 7895cbf3e08SGarrett Wollman if (dir < 0) { 7905cbf3e08SGarrett Wollman if (i == 0) { 7915cbf3e08SGarrett Wollman return 0; 7925cbf3e08SGarrett Wollman } else { 7935cbf3e08SGarrett Wollman return mtutab[i - 1]; 7945cbf3e08SGarrett Wollman } 7955cbf3e08SGarrett Wollman } else { 7965cbf3e08SGarrett Wollman if (mtutab[i] == 0) { 7975cbf3e08SGarrett Wollman return 0; 7985cbf3e08SGarrett Wollman } else if(mtu > mtutab[i]) { 7995cbf3e08SGarrett Wollman return mtutab[i]; 8005cbf3e08SGarrett Wollman } else { 8015cbf3e08SGarrett Wollman return mtutab[i + 1]; 8025cbf3e08SGarrett Wollman } 8035cbf3e08SGarrett Wollman } 8045cbf3e08SGarrett Wollman } 805b7a44e34SGarrett Wollman #endif 80651508de1SMatthew Dillon 80751508de1SMatthew Dillon 80851508de1SMatthew Dillon /* 80951508de1SMatthew Dillon * badport_bandlim() - check for ICMP bandwidth limit 81051508de1SMatthew Dillon * 81151508de1SMatthew Dillon * Return 0 if it is ok to send an ICMP error response, -1 if we have 81251508de1SMatthew Dillon * hit our bandwidth limit and it is not ok. 81351508de1SMatthew Dillon * 81451508de1SMatthew Dillon * If icmplim is <= 0, the feature is disabled and 0 is returned. 81551508de1SMatthew Dillon * 81651508de1SMatthew Dillon * For now we separate the TCP and UDP subsystems w/ different 'which' 81751508de1SMatthew Dillon * values. We may eventually remove this separation (and simplify the 81851508de1SMatthew Dillon * code further). 81951508de1SMatthew Dillon * 82051508de1SMatthew Dillon * Note that the printing of the error message is delayed so we can 82151508de1SMatthew Dillon * properly print the icmp error rate that the system was trying to do 82251508de1SMatthew Dillon * (i.e. 22000/100 pps, etc...). This can cause long delays in printing 82351508de1SMatthew Dillon * the 'final' error, but it doesn't make sense to solve the printing 82451508de1SMatthew Dillon * delay with more complex code. 82551508de1SMatthew Dillon */ 82651508de1SMatthew Dillon 82751508de1SMatthew Dillon int 82851508de1SMatthew Dillon badport_bandlim(int which) 82951508de1SMatthew Dillon { 83009f81a46SBosko Milekic static int lticks[BANDLIM_MAX + 1]; 83109f81a46SBosko Milekic static int lpackets[BANDLIM_MAX + 1]; 83251508de1SMatthew Dillon int dticks; 83309f81a46SBosko Milekic const char *bandlimittype[] = { 83409f81a46SBosko Milekic "Limiting icmp unreach response", 83509f81a46SBosko Milekic "Limiting closed port RST response", 83609f81a46SBosko Milekic "Limiting open port RST response", 83709f81a46SBosko Milekic "Limiting icmp ping response", 83809f81a46SBosko Milekic "Limiting icmp tstamp response" 83909f81a46SBosko Milekic }; 84051508de1SMatthew Dillon 84151508de1SMatthew Dillon /* 84251508de1SMatthew Dillon * Return ok status if feature disabled or argument out of 84351508de1SMatthew Dillon * ranage. 84451508de1SMatthew Dillon */ 84551508de1SMatthew Dillon 84609f81a46SBosko Milekic if (icmplim <= 0 || which > BANDLIM_MAX || which < 0) 84751508de1SMatthew Dillon return(0); 84851508de1SMatthew Dillon dticks = ticks - lticks[which]; 84951508de1SMatthew Dillon 85051508de1SMatthew Dillon /* 85151508de1SMatthew Dillon * reset stats when cumulative dt exceeds one second. 85251508de1SMatthew Dillon */ 85351508de1SMatthew Dillon 85451508de1SMatthew Dillon if ((unsigned int)dticks > hz) { 8554f14ee00SDan Moschuk if (lpackets[which] > icmplim && icmplim_output) { 85609f81a46SBosko Milekic printf("%s from %d to %d packets per second\n", 85709f81a46SBosko Milekic bandlimittype[which], 85851508de1SMatthew Dillon lpackets[which], 85951508de1SMatthew Dillon icmplim 86051508de1SMatthew Dillon ); 86151508de1SMatthew Dillon } 86251508de1SMatthew Dillon lticks[which] = ticks; 86351508de1SMatthew Dillon lpackets[which] = 0; 86451508de1SMatthew Dillon } 86551508de1SMatthew Dillon 86651508de1SMatthew Dillon /* 86751508de1SMatthew Dillon * bump packet count 86851508de1SMatthew Dillon */ 86951508de1SMatthew Dillon 87051508de1SMatthew Dillon if (++lpackets[which] > icmplim) { 87151508de1SMatthew Dillon return(-1); 87251508de1SMatthew Dillon } 87351508de1SMatthew Dillon return(0); 87451508de1SMatthew Dillon } 87551508de1SMatthew Dillon 876