1139823Simp/*- 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 * 4. Neither the name of the University nor the names of its contributors 141541Srgrimes * may be used to endorse or promote products derived from this software 151541Srgrimes * without specific prior written permission. 161541Srgrimes * 171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes * 291541Srgrimes * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 301541Srgrimes */ 311541Srgrimes 32172467Ssilby#include <sys/cdefs.h> 33172467Ssilby__FBSDID("$FreeBSD: stable/11/sys/netinet/ip_icmp.c 345688 2019-03-29 13:38:47Z markj $"); 34172467Ssilby 35221134Sbz#include "opt_inet.h" 3655009Sshin 371541Srgrimes#include <sys/param.h> 381541Srgrimes#include <sys/systm.h> 391541Srgrimes#include <sys/mbuf.h> 401541Srgrimes#include <sys/protosw.h> 411541Srgrimes#include <sys/socket.h> 421541Srgrimes#include <sys/time.h> 431541Srgrimes#include <sys/kernel.h> 44286001Sae#include <sys/lock.h> 45286001Sae#include <sys/rmlock.h> 467090Sbde#include <sys/sysctl.h> 47211316Sandre#include <sys/syslog.h> 481541Srgrimes 491541Srgrimes#include <net/if.h> 50257176Sglebius#include <net/if_var.h> 5183934Sbrooks#include <net/if_types.h> 521541Srgrimes#include <net/route.h> 53195699Srwatson#include <net/vnet.h> 541541Srgrimes 551541Srgrimes#include <netinet/in.h> 56292015Smelifaro#include <netinet/in_fib.h> 57122922Sandre#include <netinet/in_pcb.h> 581541Srgrimes#include <netinet/in_systm.h> 591541Srgrimes#include <netinet/in_var.h> 601541Srgrimes#include <netinet/ip.h> 611541Srgrimes#include <netinet/ip_icmp.h> 627090Sbde#include <netinet/ip_var.h> 63152592Sandre#include <netinet/ip_options.h> 64300699Stuexen#include <netinet/sctp.h> 65122922Sandre#include <netinet/tcp.h> 66122922Sandre#include <netinet/tcp_var.h> 67122922Sandre#include <netinet/tcpip.h> 681541Srgrimes#include <netinet/icmp_var.h> 691541Srgrimes 70221134Sbz#ifdef INET 71105199Ssam 7260105Sjlemon#include <machine/in_cksum.h> 7360105Sjlemon 74163606Srwatson#include <security/mac/mac_framework.h> 75221134Sbz#endif /* INET */ 76163606Srwatson 771541Srgrimes/* 781541Srgrimes * ICMP routines: error generation, receive packet processing, and 791541Srgrimes * routines to turnaround packets back to the originator, and 801541Srgrimes * host table maintenance routines. 811541Srgrimes */ 82221134Sbzstatic VNET_DEFINE(int, icmplim) = 200; 83221134Sbz#define V_icmplim VNET(icmplim) 84274225SglebiusSYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_VNET | CTLFLAG_RW, 85221134Sbz &VNET_NAME(icmplim), 0, 86221134Sbz "Maximum number of ICMP responses per second"); 87221134Sbz 88221134Sbzstatic VNET_DEFINE(int, icmplim_output) = 1; 89221134Sbz#define V_icmplim_output VNET(icmplim_output) 90274225SglebiusSYSCTL_INT(_net_inet_icmp, OID_AUTO, icmplim_output, CTLFLAG_VNET | CTLFLAG_RW, 91221134Sbz &VNET_NAME(icmplim_output), 0, 92229749Seadler "Enable logging of ICMP response rate limiting"); 93221134Sbz 94221134Sbz#ifdef INET 95253084SaeVNET_PCPUSTAT_DEFINE(struct icmpstat, icmpstat); 96253084SaeVNET_PCPUSTAT_SYSINIT(icmpstat); 97253084SaeSYSCTL_VNET_PCPUSTAT(_net_inet_icmp, ICMPCTL_STATS, stats, struct icmpstat, 98253084Sae icmpstat, "ICMP statistics (struct icmpstat, netinet/icmp_var.h)"); 99195699Srwatson 100253084Sae#ifdef VIMAGE 101253084SaeVNET_PCPUSTAT_SYSUNINIT(icmpstat); 102253084Sae#endif /* VIMAGE */ 103253084Sae 104215701Sdimstatic VNET_DEFINE(int, icmpmaskrepl) = 0; 105207369Sbz#define V_icmpmaskrepl VNET(icmpmaskrepl) 106274225SglebiusSYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_VNET | CTLFLAG_RW, 107195699Srwatson &VNET_NAME(icmpmaskrepl), 0, 108299828Smarkj "Reply to ICMP Address Mask Request packets"); 10912296Sphk 110215701Sdimstatic VNET_DEFINE(u_int, icmpmaskfake) = 0; 111207369Sbz#define V_icmpmaskfake VNET(icmpmaskfake) 112274225SglebiusSYSCTL_UINT(_net_inet_icmp, OID_AUTO, maskfake, CTLFLAG_VNET | CTLFLAG_RW, 113195699Srwatson &VNET_NAME(icmpmaskfake), 0, 114299828Smarkj "Fake reply to ICMP Address Mask Request packets"); 115112465Smdodd 116241406SmelifaroVNET_DEFINE(int, drop_redirect) = 0; 117274363Smelifaro#define V_drop_redirect VNET(drop_redirect) 118274363SmelifaroSYSCTL_INT(_net_inet_icmp, OID_AUTO, drop_redirect, CTLFLAG_VNET | CTLFLAG_RW, 119299828Smarkj &VNET_NAME(drop_redirect), 0, 120299828Smarkj "Ignore ICMP redirects"); 12151282Sdes 122215701Sdimstatic VNET_DEFINE(int, log_redirect) = 0; 123207369Sbz#define V_log_redirect VNET(log_redirect) 124274225SglebiusSYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_VNET | CTLFLAG_RW, 125195699Srwatson &VNET_NAME(log_redirect), 0, 126195699Srwatson "Log ICMP redirects to the console"); 12749603Sdes 128215701Sdimstatic VNET_DEFINE(char, reply_src[IFNAMSIZ]); 129207369Sbz#define V_reply_src VNET(reply_src) 130274225SglebiusSYSCTL_STRING(_net_inet_icmp, OID_AUTO, reply_src, CTLFLAG_VNET | CTLFLAG_RW, 131195699Srwatson &VNET_NAME(reply_src), IFNAMSIZ, 132299828Smarkj "ICMP reply source for non-local packets"); 133125360Sandre 134215701Sdimstatic VNET_DEFINE(int, icmp_rfi) = 0; 135207369Sbz#define V_icmp_rfi VNET(icmp_rfi) 136274225SglebiusSYSCTL_INT(_net_inet_icmp, OID_AUTO, reply_from_interface, CTLFLAG_VNET | CTLFLAG_RW, 137195699Srwatson &VNET_NAME(icmp_rfi), 0, 138195699Srwatson "ICMP reply from incoming interface for non-local packets"); 139149347Sandre 140215701Sdimstatic VNET_DEFINE(int, icmp_quotelen) = 8; 141207369Sbz#define V_icmp_quotelen VNET(icmp_quotelen) 142274225SglebiusSYSCTL_INT(_net_inet_icmp, OID_AUTO, quotelen, CTLFLAG_VNET | CTLFLAG_RW, 143195699Srwatson &VNET_NAME(icmp_quotelen), 0, 144195699Srwatson "Number of bytes from original packet to quote in ICMP reply"); 145149349Sandre 146215701Sdimstatic VNET_DEFINE(int, icmpbmcastecho) = 0; 147207369Sbz#define V_icmpbmcastecho VNET(icmpbmcastecho) 148274225SglebiusSYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_VNET | CTLFLAG_RW, 149195699Srwatson &VNET_NAME(icmpbmcastecho), 0, 150299828Smarkj "Reply to multicast ICMP Echo Request and Timestamp packets"); 15128683Swollman 152272378Smarkjstatic VNET_DEFINE(int, icmptstamprepl) = 1; 153272378Smarkj#define V_icmptstamprepl VNET(icmptstamprepl) 154345688SmarkjSYSCTL_INT(_net_inet_icmp, OID_AUTO, tstamprepl, CTLFLAG_VNET | CTLFLAG_RW, 155299828Smarkj &VNET_NAME(icmptstamprepl), 0, 156299828Smarkj "Respond to ICMP Timestamp packets"); 15741487Sdillon 158340673Seugenstatic VNET_DEFINE(int, error_keeptags) = 0; 159340670Seugen#define V_error_keeptags VNET(error_keeptags) 160340670SeugenSYSCTL_INT(_net_inet_icmp, OID_AUTO, error_keeptags, CTLFLAG_VNET | CTLFLAG_RW, 161340670Seugen &VNET_NAME(error_keeptags), 0, 162340670Seugen "ICMP error response keeps copy of mbuf_tags of original packet"); 163340670Seugen 1641541Srgrimes#ifdef ICMPPRINTFS 1651541Srgrimesint icmpprintfs = 0; 1661541Srgrimes#endif 1671541Srgrimes 16892723Salfredstatic void icmp_reflect(struct mbuf *); 169122708Sandrestatic void icmp_send(struct mbuf *, struct mbuf *); 17012296Sphk 1711541Srgrimesextern struct protosw inetsw[]; 1721541Srgrimes 1731541Srgrimes/* 174196039Srwatson * Kernel module interface for updating icmpstat. The argument is an index 175196039Srwatson * into icmpstat treated as an array of u_long. While this encodes the 176196039Srwatson * general layout of icmpstat into the caller, it doesn't encode its 177196039Srwatson * location, so that future changes to add, for example, per-CPU stats 178196039Srwatson * support won't cause binary compatibility problems for kernel modules. 179196039Srwatson */ 180196039Srwatsonvoid 181196039Srwatsonkmod_icmpstat_inc(int statnum) 182196039Srwatson{ 183196039Srwatson 184253084Sae counter_u64_add(VNET(icmpstat)[statnum], 1); 185196039Srwatson} 186196039Srwatson 187196039Srwatson/* 1881541Srgrimes * Generate an error packet of type error 1891541Srgrimes * in response to bad packet ip. 1901541Srgrimes */ 1911541Srgrimesvoid 192188578Sluigiicmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu) 1931541Srgrimes{ 194324426Sae struct ip *oip, *nip; 195324426Sae struct icmp *icp; 196324426Sae struct mbuf *m; 197324426Sae unsigned icmplen, icmpelen, nlen, oiphlen; 1981541Srgrimes 199324426Sae KASSERT((u_int)type <= ICMP_MAXTYPE, ("%s: illegal ICMP type", 200324426Sae __func__)); 201324426Sae 2021541Srgrimes if (type != ICMP_REDIRECT) 203190964Srwatson ICMPSTAT_INC(icps_error); 2041541Srgrimes /* 205152582Sandre * Don't send error: 206152582Sandre * if the original packet was encrypted. 207152582Sandre * if not the first fragment of message. 208152582Sandre * in response to a multicast or broadcast packet. 209152582Sandre * if the old packet protocol was an ICMP error message. 2101541Srgrimes */ 211130183Sume if (n->m_flags & M_DECRYPTED) 212130183Sume goto freeit; 213324426Sae if (n->m_flags & (M_BCAST|M_MCAST)) 214324426Sae goto freeit; 215324426Sae 216324426Sae /* Drop if IP header plus 8 bytes is not contiguous in first mbuf. */ 217324426Sae if (n->m_len < sizeof(struct ip) + ICMP_MINLEN) 218324426Sae goto freeit; 219324426Sae oip = mtod(n, struct ip *); 220324426Sae oiphlen = oip->ip_hl << 2; 221324426Sae if (n->m_len < oiphlen + ICMP_MINLEN) 222324426Sae goto freeit; 223324426Sae#ifdef ICMPPRINTFS 224324426Sae if (icmpprintfs) 225324426Sae printf("icmp_error(%p, %x, %d)\n", oip, type, code); 226324426Sae#endif 227241913Sglebius if (oip->ip_off & htons(~(IP_MF|IP_DF))) 2281541Srgrimes goto freeit; 2291541Srgrimes if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 230324426Sae !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + 231324426Sae oiphlen))->icmp_type)) { 232190964Srwatson ICMPSTAT_INC(icps_oldicmp); 2331541Srgrimes goto freeit; 2341541Srgrimes } 2351541Srgrimes /* 236149349Sandre * Calculate length to quote from original packet and 237149349Sandre * prevent the ICMP mbuf from overflowing. 238298995Spfg * Unfortunately this is non-trivial since ip_forward() 239152582Sandre * sends us truncated packets. 240149349Sandre */ 241152582Sandre nlen = m_length(n, NULL); 242149370Sandre if (oip->ip_p == IPPROTO_TCP) { 243149370Sandre struct tcphdr *th; 244149370Sandre int tcphlen; 245149370Sandre 246152582Sandre if (oiphlen + sizeof(struct tcphdr) > n->m_len && 247152582Sandre n->m_next == NULL) 248152582Sandre goto stdreply; 249152582Sandre if (n->m_len < oiphlen + sizeof(struct tcphdr) && 250324426Sae (n = m_pullup(n, oiphlen + sizeof(struct tcphdr))) == NULL) 251149370Sandre goto freeit; 252324426Sae oip = mtod(n, struct ip *); 253324426Sae th = mtodo(n, oiphlen); 254149370Sandre tcphlen = th->th_off << 2; 255149370Sandre if (tcphlen < sizeof(struct tcphdr)) 256149370Sandre goto freeit; 257241913Sglebius if (ntohs(oip->ip_len) < oiphlen + tcphlen) 258149370Sandre goto freeit; 259152582Sandre if (oiphlen + tcphlen > n->m_len && n->m_next == NULL) 260152582Sandre goto stdreply; 261324426Sae if (n->m_len < oiphlen + tcphlen && 262324426Sae (n = m_pullup(n, oiphlen + tcphlen)) == NULL) 263149370Sandre goto freeit; 264241913Sglebius icmpelen = max(tcphlen, min(V_icmp_quotelen, 265241913Sglebius ntohs(oip->ip_len) - oiphlen)); 266300699Stuexen } else if (oip->ip_p == IPPROTO_SCTP) { 267300699Stuexen struct sctphdr *sh; 268300699Stuexen struct sctp_chunkhdr *ch; 269300699Stuexen 270300699Stuexen if (ntohs(oip->ip_len) < oiphlen + sizeof(struct sctphdr)) 271300699Stuexen goto stdreply; 272300699Stuexen if (oiphlen + sizeof(struct sctphdr) > n->m_len && 273300699Stuexen n->m_next == NULL) 274300699Stuexen goto stdreply; 275300699Stuexen if (n->m_len < oiphlen + sizeof(struct sctphdr) && 276300699Stuexen (n = m_pullup(n, oiphlen + sizeof(struct sctphdr))) == NULL) 277300699Stuexen goto freeit; 278324426Sae oip = mtod(n, struct ip *); 279300699Stuexen icmpelen = max(sizeof(struct sctphdr), 280300699Stuexen min(V_icmp_quotelen, ntohs(oip->ip_len) - oiphlen)); 281324426Sae sh = mtodo(n, oiphlen); 282300699Stuexen if (ntohl(sh->v_tag) == 0 && 283324426Sae ntohs(oip->ip_len) >= oiphlen + 284324426Sae sizeof(struct sctphdr) + 8 && 285300699Stuexen (n->m_len >= oiphlen + sizeof(struct sctphdr) + 8 || 286300699Stuexen n->m_next != NULL)) { 287300699Stuexen if (n->m_len < oiphlen + sizeof(struct sctphdr) + 8 && 288324426Sae (n = m_pullup(n, oiphlen + 289324426Sae sizeof(struct sctphdr) + 8)) == NULL) 290300699Stuexen goto freeit; 291324426Sae oip = mtod(n, struct ip *); 292324426Sae sh = mtodo(n, oiphlen); 293300699Stuexen ch = (struct sctp_chunkhdr *)(sh + 1); 294300699Stuexen if (ch->chunk_type == SCTP_INITIATION) { 295300699Stuexen icmpelen = max(sizeof(struct sctphdr) + 8, 296324426Sae min(V_icmp_quotelen, ntohs(oip->ip_len) - 297324426Sae oiphlen)); 298300699Stuexen } 299300699Stuexen } 300149370Sandre } else 301324426Saestdreply: icmpelen = max(8, min(V_icmp_quotelen, ntohs(oip->ip_len) - 302324426Sae oiphlen)); 303152582Sandre 304152582Sandre icmplen = min(oiphlen + icmpelen, nlen); 30573996Siedowse if (icmplen < sizeof(struct ip)) 306149378Sandre goto freeit; 307152582Sandre 308152582Sandre if (MHLEN > sizeof(struct ip) + ICMP_MINLEN + icmplen) 309243882Sglebius m = m_gethdr(M_NOWAIT, MT_DATA); 310152582Sandre else 311243882Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 312152582Sandre if (m == NULL) 313152582Sandre goto freeit; 314152582Sandre#ifdef MAC 315173102Srwatson mac_netinet_icmp_reply(n, m); 316152582Sandre#endif 317324426Sae icmplen = min(icmplen, M_TRAILINGSPACE(m) - 318324426Sae sizeof(struct ip) - ICMP_MINLEN); 319340268Sgjb m_align(m, sizeof(struct ip) + ICMP_MINLEN + icmplen); 320340268Sgjb m->m_data += sizeof(struct ip); 321152582Sandre m->m_len = ICMP_MINLEN + icmplen; 322152582Sandre 323178888Sjulian /* XXX MRT make the outgoing packet use the same FIB 324178888Sjulian * that was associated with the incoming packet 325178888Sjulian */ 326178888Sjulian M_SETFIB(m, M_GETFIB(n)); 3271541Srgrimes icp = mtod(m, struct icmp *); 328190964Srwatson ICMPSTAT_INC(icps_outhist[type]); 3291541Srgrimes icp->icmp_type = type; 3301541Srgrimes if (type == ICMP_REDIRECT) 3311541Srgrimes icp->icmp_gwaddr.s_addr = dest; 3321541Srgrimes else { 3331541Srgrimes icp->icmp_void = 0; 3348876Srgrimes /* 3351541Srgrimes * The following assignments assume an overlay with the 336152582Sandre * just zeroed icmp_void field. 3371541Srgrimes */ 3381541Srgrimes if (type == ICMP_PARAMPROB) { 3391541Srgrimes icp->icmp_pptr = code; 3401541Srgrimes code = 0; 3411541Srgrimes } else if (type == ICMP_UNREACH && 342145863Sandre code == ICMP_UNREACH_NEEDFRAG && mtu) { 343145863Sandre icp->icmp_nextmtu = htons(mtu); 3441541Srgrimes } 3451541Srgrimes } 3461541Srgrimes icp->icmp_code = code; 3471541Srgrimes 3481541Srgrimes /* 349152582Sandre * Copy the quotation into ICMP message and 350152582Sandre * convert quoted IP header back to network representation. 35165327Sru */ 352152582Sandre m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip); 353152582Sandre nip = &icp->icmp_ip; 35465327Sru 35565327Sru /* 356152582Sandre * Set up ICMP message mbuf and copy old IP header (without options 357152582Sandre * in front of ICMP message. 358132280Smlaier * If the original mbuf was meant to bypass the firewall, the error 359132280Smlaier * reply should bypass as well. 360132280Smlaier */ 361132280Smlaier m->m_flags |= n->m_flags & M_SKIP_FIREWALL; 362340268Sgjb KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ip), 363340268Sgjb ("insufficient space for ip header")); 3641541Srgrimes m->m_data -= sizeof(struct ip); 3651541Srgrimes m->m_len += sizeof(struct ip); 3661541Srgrimes m->m_pkthdr.len = m->m_len; 3671541Srgrimes m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 3681541Srgrimes nip = mtod(m, struct ip *); 3691541Srgrimes bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); 370241913Sglebius nip->ip_len = htons(m->m_len); 371105586Sphk nip->ip_v = IPVERSION; 372105586Sphk nip->ip_hl = 5; 3731541Srgrimes nip->ip_p = IPPROTO_ICMP; 3741541Srgrimes nip->ip_tos = 0; 375263966Sae nip->ip_off = 0; 376340670Seugen 377340670Seugen if (V_error_keeptags) 378340670Seugen m_tag_copy_chain(m, n, M_NOWAIT); 379340670Seugen 3801541Srgrimes icmp_reflect(m); 3811541Srgrimes 3821541Srgrimesfreeit: 3831541Srgrimes m_freem(n); 3841541Srgrimes} 3851541Srgrimes 3861541Srgrimes/* 3871541Srgrimes * Process a received ICMP message. 3881541Srgrimes */ 389269699Skevloint 390269699Skevloicmp_input(struct mbuf **mp, int *offp, int proto) 3911541Srgrimes{ 392122593Sandre struct icmp *icp; 393122593Sandre struct in_ifaddr *ia; 394269699Skevlo struct mbuf *m = *mp; 395122593Sandre struct ip *ip = mtod(m, struct ip *); 396122593Sandre struct sockaddr_in icmpsrc, icmpdst, icmpgw; 397269699Skevlo int hlen = *offp; 398269699Skevlo int icmplen = ntohs(ip->ip_len) - *offp; 399122593Sandre int i, code; 40092723Salfred void (*ctlfunc)(int, struct sockaddr *, void *); 401178888Sjulian int fibnum; 4021541Srgrimes 403269699Skevlo *mp = NULL; 404269699Skevlo 4051541Srgrimes /* 4061541Srgrimes * Locate icmp structure in mbuf, and check 4071541Srgrimes * that not corrupted and of at least minimum length. 4081541Srgrimes */ 4091541Srgrimes#ifdef ICMPPRINTFS 41010421Swollman if (icmpprintfs) { 411315456Svangyzen char srcbuf[INET_ADDRSTRLEN]; 412315456Svangyzen char dstbuf[INET_ADDRSTRLEN]; 413315456Svangyzen 41410421Swollman printf("icmp_input from %s to %s, len %d\n", 415315456Svangyzen inet_ntoa_r(ip->ip_src, srcbuf), 416315456Svangyzen inet_ntoa_r(ip->ip_dst, dstbuf), icmplen); 41710421Swollman } 4181541Srgrimes#endif 4191541Srgrimes if (icmplen < ICMP_MINLEN) { 420190964Srwatson ICMPSTAT_INC(icps_tooshort); 4211541Srgrimes goto freeit; 4221541Srgrimes } 4231541Srgrimes i = hlen + min(icmplen, ICMP_ADVLENMIN); 424198050Sbz if (m->m_len < i && (m = m_pullup(m, i)) == NULL) { 425190964Srwatson ICMPSTAT_INC(icps_tooshort); 426269699Skevlo return (IPPROTO_DONE); 4271541Srgrimes } 4281541Srgrimes ip = mtod(m, struct ip *); 4291541Srgrimes m->m_len -= hlen; 4301541Srgrimes m->m_data += hlen; 4311541Srgrimes icp = mtod(m, struct icmp *); 4321541Srgrimes if (in_cksum(m, icmplen)) { 433190964Srwatson ICMPSTAT_INC(icps_checksum); 4341541Srgrimes goto freeit; 4351541Srgrimes } 4361541Srgrimes m->m_len += hlen; 4371541Srgrimes m->m_data -= hlen; 4381541Srgrimes 4391541Srgrimes#ifdef ICMPPRINTFS 4401541Srgrimes if (icmpprintfs) 4411541Srgrimes printf("icmp_input, type %d code %d\n", icp->icmp_type, 4421541Srgrimes icp->icmp_code); 4431541Srgrimes#endif 4449472Swollman 4459472Swollman /* 4469472Swollman * Message type specific processing. 4479472Swollman */ 4481541Srgrimes if (icp->icmp_type > ICMP_MAXTYPE) 4491541Srgrimes goto raw; 450122593Sandre 451122593Sandre /* Initialize */ 452122593Sandre bzero(&icmpsrc, sizeof(icmpsrc)); 453122593Sandre icmpsrc.sin_len = sizeof(struct sockaddr_in); 454122593Sandre icmpsrc.sin_family = AF_INET; 455122593Sandre bzero(&icmpdst, sizeof(icmpdst)); 456122593Sandre icmpdst.sin_len = sizeof(struct sockaddr_in); 457122593Sandre icmpdst.sin_family = AF_INET; 458122593Sandre bzero(&icmpgw, sizeof(icmpgw)); 459122593Sandre icmpgw.sin_len = sizeof(struct sockaddr_in); 460122593Sandre icmpgw.sin_family = AF_INET; 461122593Sandre 462190964Srwatson ICMPSTAT_INC(icps_inhist[icp->icmp_type]); 4631541Srgrimes code = icp->icmp_code; 4641541Srgrimes switch (icp->icmp_type) { 4651541Srgrimes 4661541Srgrimes case ICMP_UNREACH: 4671541Srgrimes switch (code) { 4681541Srgrimes case ICMP_UNREACH_NET: 4691541Srgrimes case ICMP_UNREACH_HOST: 4701541Srgrimes case ICMP_UNREACH_SRCFAIL: 47172959Sjlemon case ICMP_UNREACH_NET_UNKNOWN: 47272959Sjlemon case ICMP_UNREACH_HOST_UNKNOWN: 47372959Sjlemon case ICMP_UNREACH_ISOLATED: 47472959Sjlemon case ICMP_UNREACH_TOSNET: 47572959Sjlemon case ICMP_UNREACH_TOSHOST: 47672959Sjlemon case ICMP_UNREACH_HOST_PRECEDENCE: 47772959Sjlemon case ICMP_UNREACH_PRECEDENCE_CUTOFF: 47872959Sjlemon code = PRC_UNREACH_NET; 4791541Srgrimes break; 4801541Srgrimes 4811541Srgrimes case ICMP_UNREACH_NEEDFRAG: 4821541Srgrimes code = PRC_MSGSIZE; 4831541Srgrimes break; 4848876Srgrimes 48572959Sjlemon /* 48672959Sjlemon * RFC 1122, Sections 3.2.2.1 and 4.2.3.9. 48772959Sjlemon * Treat subcodes 2,3 as immediate RST 48872959Sjlemon */ 48972959Sjlemon case ICMP_UNREACH_PROTOCOL: 490310208Stuexen code = PRC_UNREACH_PROTOCOL; 491310208Stuexen break; 49272959Sjlemon case ICMP_UNREACH_PORT: 49374937Sjesper code = PRC_UNREACH_PORT; 49472638Sphk break; 49572638Sphk 4961541Srgrimes case ICMP_UNREACH_NET_PROHIB: 4971541Srgrimes case ICMP_UNREACH_HOST_PROHIB: 49818416Spst case ICMP_UNREACH_FILTER_PROHIB: 49972638Sphk code = PRC_UNREACH_ADMIN_PROHIB; 50072638Sphk break; 50170103Sphk 5021541Srgrimes default: 5031541Srgrimes goto badcode; 5041541Srgrimes } 5051541Srgrimes goto deliver; 5061541Srgrimes 5071541Srgrimes case ICMP_TIMXCEED: 5081541Srgrimes if (code > 1) 5091541Srgrimes goto badcode; 5101541Srgrimes code += PRC_TIMXCEED_INTRANS; 5111541Srgrimes goto deliver; 5121541Srgrimes 5131541Srgrimes case ICMP_PARAMPROB: 5141541Srgrimes if (code > 1) 5151541Srgrimes goto badcode; 5161541Srgrimes code = PRC_PARAMPROB; 5171541Srgrimes deliver: 5181541Srgrimes /* 5191541Srgrimes * Problem with datagram; advise higher level routines. 5201541Srgrimes */ 5211541Srgrimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 522105586Sphk icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 523190964Srwatson ICMPSTAT_INC(icps_badlen); 5241541Srgrimes goto freeit; 5251541Srgrimes } 5269472Swollman /* Discard ICMP's in response to multicast packets */ 5279472Swollman if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr))) 5289472Swollman goto badcode; 5291541Srgrimes#ifdef ICMPPRINTFS 5301541Srgrimes if (icmpprintfs) 5311541Srgrimes printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 5321541Srgrimes#endif 5331541Srgrimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 53410881Swollman /* 53555009Sshin * XXX if the packet contains [IPv4 AH TCP], we can't make a 53655009Sshin * notification to TCP layer. 53755009Sshin */ 538297989Stuexen i = sizeof(struct ip) + min(icmplen, ICMP_ADVLENPREF(icp)); 539297989Stuexen ip_stripoptions(m); 540297989Stuexen if (m->m_len < i && (m = m_pullup(m, i)) == NULL) { 541297989Stuexen /* This should actually not happen */ 542297989Stuexen ICMPSTAT_INC(icps_tooshort); 543297989Stuexen return (IPPROTO_DONE); 544297989Stuexen } 545297989Stuexen ip = mtod(m, struct ip *); 546297989Stuexen icp = (struct icmp *)(ip + 1); 547297989Stuexen /* 548297989Stuexen * The upper layer handler can rely on: 549297989Stuexen * - The outer IP header has no options. 550297989Stuexen * - The outer IP header, the ICMP header, the inner IP header, 551297989Stuexen * and the first n bytes of the inner payload are contiguous. 552297989Stuexen * n is at least 8, but might be larger based on 553297989Stuexen * ICMP_ADVLENPREF. See its definition in ip_icmp.h. 554297989Stuexen */ 5553311Sphk ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput; 5563311Sphk if (ctlfunc) 5571541Srgrimes (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, 55812881Sbde (void *)&icp->icmp_ip); 5591541Srgrimes break; 5601541Srgrimes 5611541Srgrimes badcode: 562190964Srwatson ICMPSTAT_INC(icps_badcode); 5631541Srgrimes break; 5641541Srgrimes 5651541Srgrimes case ICMP_ECHO: 566183550Szec if (!V_icmpbmcastecho 56736393Sdg && (m->m_flags & (M_MCAST | M_BCAST)) != 0) { 568190964Srwatson ICMPSTAT_INC(icps_bmcastecho); 56928683Swollman break; 57028683Swollman } 57172357Sbmilekic if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0) 57270070Sbmilekic goto freeit; 573332840Sjtl icp->icmp_type = ICMP_ECHOREPLY; 574332840Sjtl goto reflect; 5751541Srgrimes 5761541Srgrimes case ICMP_TSTAMP: 577272378Smarkj if (V_icmptstamprepl == 0) 578272378Smarkj break; 579183550Szec if (!V_icmpbmcastecho 58036393Sdg && (m->m_flags & (M_MCAST | M_BCAST)) != 0) { 581190964Srwatson ICMPSTAT_INC(icps_bmcasttstamp); 58228723Swollman break; 58328723Swollman } 5841541Srgrimes if (icmplen < ICMP_TSLEN) { 585190964Srwatson ICMPSTAT_INC(icps_badlen); 5861541Srgrimes break; 5871541Srgrimes } 588332840Sjtl if (badport_bandlim(BANDLIM_ICMP_TSTAMP) < 0) 589332840Sjtl goto freeit; 5901541Srgrimes icp->icmp_type = ICMP_TSTAMPREPLY; 5911541Srgrimes icp->icmp_rtime = iptime(); 5921541Srgrimes icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 593332840Sjtl goto reflect; 5948876Srgrimes 5951541Srgrimes case ICMP_MASKREQ: 596183550Szec if (V_icmpmaskrepl == 0) 5971541Srgrimes break; 5981541Srgrimes /* 5991541Srgrimes * We are not able to respond with all ones broadcast 6001541Srgrimes * unless we receive it over a point-to-point interface. 6011541Srgrimes */ 6021541Srgrimes if (icmplen < ICMP_MASKLEN) 6031541Srgrimes break; 6041541Srgrimes switch (ip->ip_dst.s_addr) { 6051541Srgrimes 6061541Srgrimes case INADDR_BROADCAST: 6071541Srgrimes case INADDR_ANY: 6081541Srgrimes icmpdst.sin_addr = ip->ip_src; 6091541Srgrimes break; 6101541Srgrimes 6111541Srgrimes default: 6121541Srgrimes icmpdst.sin_addr = ip->ip_dst; 6131541Srgrimes } 6141541Srgrimes ia = (struct in_ifaddr *)ifaof_ifpforaddr( 6151541Srgrimes (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); 616194760Srwatson if (ia == NULL) 6171541Srgrimes break; 618194760Srwatson if (ia->ia_ifp == NULL) { 619194760Srwatson ifa_free(&ia->ia_ifa); 62014998Sphk break; 621194760Srwatson } 6221541Srgrimes icp->icmp_type = ICMP_MASKREPLY; 623183550Szec if (V_icmpmaskfake == 0) 624112465Smdodd icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 625112465Smdodd else 626183550Szec icp->icmp_mask = V_icmpmaskfake; 6271541Srgrimes if (ip->ip_src.s_addr == 0) { 6281541Srgrimes if (ia->ia_ifp->if_flags & IFF_BROADCAST) 6291541Srgrimes ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; 6301541Srgrimes else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 6311541Srgrimes ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; 6321541Srgrimes } 633194760Srwatson ifa_free(&ia->ia_ifa); 6341541Srgrimesreflect: 635190964Srwatson ICMPSTAT_INC(icps_reflect); 636190964Srwatson ICMPSTAT_INC(icps_outhist[icp->icmp_type]); 6371541Srgrimes icmp_reflect(m); 638269699Skevlo return (IPPROTO_DONE); 6391541Srgrimes 6401541Srgrimes case ICMP_REDIRECT: 641183550Szec if (V_log_redirect) { 64249603Sdes u_long src, dst, gw; 64349603Sdes 64449603Sdes src = ntohl(ip->ip_src.s_addr); 64549603Sdes dst = ntohl(icp->icmp_ip.ip_dst.s_addr); 64649603Sdes gw = ntohl(icp->icmp_gwaddr.s_addr); 64749603Sdes printf("icmp redirect from %d.%d.%d.%d: " 64849603Sdes "%d.%d.%d.%d => %d.%d.%d.%d\n", 64949603Sdes (int)(src >> 24), (int)((src >> 16) & 0xff), 65049603Sdes (int)((src >> 8) & 0xff), (int)(src & 0xff), 65149603Sdes (int)(dst >> 24), (int)((dst >> 16) & 0xff), 65249603Sdes (int)((dst >> 8) & 0xff), (int)(dst & 0xff), 65349603Sdes (int)(gw >> 24), (int)((gw >> 16) & 0xff), 65449603Sdes (int)((gw >> 8) & 0xff), (int)(gw & 0xff)); 65549603Sdes } 656124198Sandre /* 657124198Sandre * RFC1812 says we must ignore ICMP redirects if we 658124198Sandre * are acting as router. 659124198Sandre */ 660183550Szec if (V_drop_redirect || V_ipforwarding) 66149603Sdes break; 6621541Srgrimes if (code > 3) 6631541Srgrimes goto badcode; 6641541Srgrimes if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 665105586Sphk icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 666190964Srwatson ICMPSTAT_INC(icps_badlen); 6671541Srgrimes break; 6681541Srgrimes } 6691541Srgrimes /* 6701541Srgrimes * Short circuit routing redirects to force 6711541Srgrimes * immediate change in the kernel's routing 6721541Srgrimes * tables. The message is also handed to anyone 6731541Srgrimes * listening on a raw socket (e.g. the routing 6741541Srgrimes * daemon for use in updating its tables). 6751541Srgrimes */ 6761541Srgrimes icmpgw.sin_addr = ip->ip_src; 6771541Srgrimes icmpdst.sin_addr = icp->icmp_gwaddr; 6781541Srgrimes#ifdef ICMPPRINTFS 67910421Swollman if (icmpprintfs) { 680315456Svangyzen char dstbuf[INET_ADDRSTRLEN]; 681315456Svangyzen char gwbuf[INET_ADDRSTRLEN]; 68210421Swollman 68310421Swollman printf("redirect dst %s to %s\n", 684315456Svangyzen inet_ntoa_r(icp->icmp_ip.ip_dst, dstbuf), 685315456Svangyzen inet_ntoa_r(icp->icmp_gwaddr, gwbuf)); 68610421Swollman } 6871541Srgrimes#endif 6881541Srgrimes icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 689178888Sjulian for ( fibnum = 0; fibnum < rt_numfibs; fibnum++) { 690178888Sjulian in_rtredirect((struct sockaddr *)&icmpsrc, 691178888Sjulian (struct sockaddr *)&icmpdst, 692178888Sjulian (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 693178888Sjulian (struct sockaddr *)&icmpgw, fibnum); 694178888Sjulian } 6951541Srgrimes pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); 6961541Srgrimes break; 6971541Srgrimes 6981541Srgrimes /* 6991541Srgrimes * No kernel processing for the following; 7001541Srgrimes * just fall through to send to raw listener. 7011541Srgrimes */ 7021541Srgrimes case ICMP_ECHOREPLY: 7031541Srgrimes case ICMP_ROUTERADVERT: 7041541Srgrimes case ICMP_ROUTERSOLICIT: 7051541Srgrimes case ICMP_TSTAMPREPLY: 7061541Srgrimes case ICMP_IREQREPLY: 7071541Srgrimes case ICMP_MASKREPLY: 708274359Smelifaro case ICMP_SOURCEQUENCH: 7091541Srgrimes default: 7101541Srgrimes break; 7111541Srgrimes } 7121541Srgrimes 7131541Srgrimesraw: 714269699Skevlo *mp = m; 715269699Skevlo rip_input(mp, offp, proto); 716269699Skevlo return (IPPROTO_DONE); 7171541Srgrimes 7181541Srgrimesfreeit: 7191541Srgrimes m_freem(m); 720269699Skevlo return (IPPROTO_DONE); 7211541Srgrimes} 7221541Srgrimes 7231541Srgrimes/* 7241541Srgrimes * Reflect the ip packet back to the source 7251541Srgrimes */ 72612296Sphkstatic void 727169454Srwatsonicmp_reflect(struct mbuf *m) 7281541Srgrimes{ 729286001Sae struct rm_priotracker in_ifa_tracker; 73084102Sjlemon struct ip *ip = mtod(m, struct ip *); 73184102Sjlemon struct ifaddr *ifa; 732191311Srwatson struct ifnet *ifp; 73384102Sjlemon struct in_ifaddr *ia; 7341541Srgrimes struct in_addr t; 735292015Smelifaro struct nhop4_extended nh_ext; 736298066Spfg struct mbuf *opts = NULL; 737105586Sphk int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 7381541Srgrimes 739178280Sgnn if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)) || 740178280Sgnn IN_EXPERIMENTAL(ntohl(ip->ip_src.s_addr)) || 741178280Sgnn IN_ZERONET(ntohl(ip->ip_src.s_addr)) ) { 7421541Srgrimes m_freem(m); /* Bad return address */ 743190964Srwatson ICMPSTAT_INC(icps_badaddr); 7441541Srgrimes goto done; /* Ip_output() will check for broadcast */ 7451541Srgrimes } 746178280Sgnn 7471541Srgrimes t = ip->ip_dst; 7481541Srgrimes ip->ip_dst = ip->ip_src; 749125349Sandre 7501541Srgrimes /* 751125349Sandre * Source selection for ICMP replies: 752125349Sandre * 753125349Sandre * If the incoming packet was addressed directly to one of our 754125349Sandre * own addresses, use dst as the src for the reply. 7551541Srgrimes */ 756286001Sae IN_IFADDR_RLOCK(&in_ifa_tracker); 757191311Srwatson LIST_FOREACH(ia, INADDR_HASH(t.s_addr), ia_hash) { 758191311Srwatson if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) { 759191311Srwatson t = IA_SIN(ia)->sin_addr; 760286001Sae IN_IFADDR_RUNLOCK(&in_ifa_tracker); 76184102Sjlemon goto match; 762191311Srwatson } 763191311Srwatson } 764286001Sae IN_IFADDR_RUNLOCK(&in_ifa_tracker); 765194951Srwatson 766125349Sandre /* 767125349Sandre * If the incoming packet was addressed to one of our broadcast 768125349Sandre * addresses, use the first non-broadcast address which corresponds 769125349Sandre * to the incoming interface. 770125349Sandre */ 771191311Srwatson ifp = m->m_pkthdr.rcvif; 772191311Srwatson if (ifp != NULL && ifp->if_flags & IFF_BROADCAST) { 773229621Sjhb IF_ADDR_RLOCK(ifp); 774191311Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 77584102Sjlemon if (ifa->ifa_addr->sa_family != AF_INET) 77684102Sjlemon continue; 77787914Sjlemon ia = ifatoia(ifa); 77887914Sjlemon if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 779191311Srwatson t.s_addr) { 780191311Srwatson t = IA_SIN(ia)->sin_addr; 781229621Sjhb IF_ADDR_RUNLOCK(ifp); 78287914Sjlemon goto match; 783191311Srwatson } 78487914Sjlemon } 785229621Sjhb IF_ADDR_RUNLOCK(ifp); 78687914Sjlemon } 787125360Sandre /* 788149347Sandre * If the packet was transiting through us, use the address of 789149347Sandre * the interface the packet came through in. If that interface 790149347Sandre * doesn't have a suitable IP address, the normal selection 791149347Sandre * criteria apply. 792149347Sandre */ 793191311Srwatson if (V_icmp_rfi && ifp != NULL) { 794229621Sjhb IF_ADDR_RLOCK(ifp); 795191311Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 796149347Sandre if (ifa->ifa_addr->sa_family != AF_INET) 797149347Sandre continue; 798149347Sandre ia = ifatoia(ifa); 799191311Srwatson t = IA_SIN(ia)->sin_addr; 800229621Sjhb IF_ADDR_RUNLOCK(ifp); 801149347Sandre goto match; 802149347Sandre } 803229621Sjhb IF_ADDR_RUNLOCK(ifp); 804149347Sandre } 805149347Sandre /* 806125360Sandre * If the incoming packet was not addressed directly to us, use 807125360Sandre * designated interface for icmp replies specified by sysctl 808125360Sandre * net.inet.icmp.reply_src (default not set). Otherwise continue 809125360Sandre * with normal source selection. 810125360Sandre */ 811191311Srwatson if (V_reply_src[0] != '\0' && (ifp = ifunit(V_reply_src))) { 812229621Sjhb IF_ADDR_RLOCK(ifp); 813191311Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 814125360Sandre if (ifa->ifa_addr->sa_family != AF_INET) 815125360Sandre continue; 816125360Sandre ia = ifatoia(ifa); 817191311Srwatson t = IA_SIN(ia)->sin_addr; 818229621Sjhb IF_ADDR_RUNLOCK(ifp); 819125360Sandre goto match; 820125360Sandre } 821229621Sjhb IF_ADDR_RUNLOCK(ifp); 822125360Sandre } 823133874Srwatson /* 824125349Sandre * If the packet was transiting through us, use the address of 825125349Sandre * the interface that is the closest to the packet source. 826125349Sandre * When we don't have a route back to the packet source, stop here 827125349Sandre * and drop the packet. 828125349Sandre */ 829292015Smelifaro if (fib4_lookup_nh_ext(M_GETFIB(m), ip->ip_dst, 0, 0, &nh_ext) != 0) { 83086999Sdd m_freem(m); 831190964Srwatson ICMPSTAT_INC(icps_noroute); 83286999Sdd goto done; 83386999Sdd } 834292015Smelifaro t = nh_ext.nh_src; 83584102Sjlemonmatch: 836119245Srwatson#ifdef MAC 837173102Srwatson mac_netinet_icmp_replyinplace(m); 838119245Srwatson#endif 8391541Srgrimes ip->ip_src = t; 840181803Sbz ip->ip_ttl = V_ip_defttl; 8411541Srgrimes 8421541Srgrimes if (optlen > 0) { 843331643Sdim u_char *cp; 8441541Srgrimes int opt, cnt; 8451541Srgrimes u_int len; 8461541Srgrimes 8471541Srgrimes /* 8481541Srgrimes * Retrieve any source routing from the incoming packet; 8491541Srgrimes * add on any record-route or timestamp options. 8501541Srgrimes */ 8511541Srgrimes cp = (u_char *) (ip + 1); 852298066Spfg if ((opts = ip_srcroute(m)) == NULL && 853243882Sglebius (opts = m_gethdr(M_NOWAIT, MT_DATA))) { 8541541Srgrimes opts->m_len = sizeof(struct in_addr); 8551541Srgrimes mtod(opts, struct in_addr *)->s_addr = 0; 8561541Srgrimes } 8571541Srgrimes if (opts) { 8581541Srgrimes#ifdef ICMPPRINTFS 8591541Srgrimes if (icmpprintfs) 8601541Srgrimes printf("icmp_reflect optlen %d rt %d => ", 8611541Srgrimes optlen, opts->m_len); 8621541Srgrimes#endif 8631541Srgrimes for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 8641541Srgrimes opt = cp[IPOPT_OPTVAL]; 8651541Srgrimes if (opt == IPOPT_EOL) 8661541Srgrimes break; 8671541Srgrimes if (opt == IPOPT_NOP) 8681541Srgrimes len = 1; 8691541Srgrimes else { 87061183Sjlemon if (cnt < IPOPT_OLEN + sizeof(*cp)) 87161183Sjlemon break; 8721541Srgrimes len = cp[IPOPT_OLEN]; 87361183Sjlemon if (len < IPOPT_OLEN + sizeof(*cp) || 87461183Sjlemon len > cnt) 8751541Srgrimes break; 8761541Srgrimes } 8771541Srgrimes /* 8781541Srgrimes * Should check for overflow, but it "can't happen" 8791541Srgrimes */ 8808876Srgrimes if (opt == IPOPT_RR || opt == IPOPT_TS || 8811541Srgrimes opt == IPOPT_SECURITY) { 8821541Srgrimes bcopy((caddr_t)cp, 8831541Srgrimes mtod(opts, caddr_t) + opts->m_len, len); 8841541Srgrimes opts->m_len += len; 8851541Srgrimes } 8861541Srgrimes } 8871541Srgrimes /* Terminate & pad, if necessary */ 8883311Sphk cnt = opts->m_len % 4; 8893311Sphk if (cnt) { 8901541Srgrimes for (; cnt < 4; cnt++) { 8911541Srgrimes *(mtod(opts, caddr_t) + opts->m_len) = 8921541Srgrimes IPOPT_EOL; 8931541Srgrimes opts->m_len++; 8941541Srgrimes } 8951541Srgrimes } 8961541Srgrimes#ifdef ICMPPRINTFS 8971541Srgrimes if (icmpprintfs) 8981541Srgrimes printf("%d\n", opts->m_len); 8991541Srgrimes#endif 9001541Srgrimes } 901241926Sglebius ip_stripoptions(m); 9021541Srgrimes } 903121645Ssam m_tag_delete_nonpersistent(m); 9041541Srgrimes m->m_flags &= ~(M_BCAST|M_MCAST); 905122708Sandre icmp_send(m, opts); 9061541Srgrimesdone: 9071541Srgrimes if (opts) 9081541Srgrimes (void)m_free(opts); 9091541Srgrimes} 9101541Srgrimes 9111541Srgrimes/* 9121541Srgrimes * Send an icmp packet back to the ip level, 9131541Srgrimes * after supplying a checksum. 9141541Srgrimes */ 91512296Sphkstatic void 916169454Srwatsonicmp_send(struct mbuf *m, struct mbuf *opts) 9171541Srgrimes{ 918331643Sdim struct ip *ip = mtod(m, struct ip *); 919331643Sdim int hlen; 920331643Sdim struct icmp *icp; 9211541Srgrimes 922105586Sphk hlen = ip->ip_hl << 2; 9231541Srgrimes m->m_data += hlen; 9241541Srgrimes m->m_len -= hlen; 9251541Srgrimes icp = mtod(m, struct icmp *); 9261541Srgrimes icp->icmp_cksum = 0; 927241913Sglebius icp->icmp_cksum = in_cksum(m, ntohs(ip->ip_len) - hlen); 9281541Srgrimes m->m_data -= hlen; 9291541Srgrimes m->m_len += hlen; 93044528Sarchie m->m_pkthdr.rcvif = (struct ifnet *)0; 9311541Srgrimes#ifdef ICMPPRINTFS 93210421Swollman if (icmpprintfs) { 933315456Svangyzen char dstbuf[INET_ADDRSTRLEN]; 934315456Svangyzen char srcbuf[INET_ADDRSTRLEN]; 935315456Svangyzen 93610421Swollman printf("icmp_send dst %s src %s\n", 937315456Svangyzen inet_ntoa_r(ip->ip_dst, dstbuf), 938315456Svangyzen inet_ntoa_r(ip->ip_src, srcbuf)); 93910421Swollman } 9401541Srgrimes#endif 941122708Sandre (void) ip_output(m, opts, NULL, 0, NULL, NULL); 9421541Srgrimes} 9431541Srgrimes 944188578Sluigi/* 945275985Simp * Return milliseconds since 00:00 UTC in network format. 946188578Sluigi */ 947188578Sluigiuint32_t 948169454Srwatsoniptime(void) 9491541Srgrimes{ 9501541Srgrimes struct timeval atv; 9511541Srgrimes u_long t; 9521541Srgrimes 95370105Sbillf getmicrotime(&atv); 9541541Srgrimes t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 9551541Srgrimes return (htonl(t)); 9561541Srgrimes} 9571541Srgrimes 95810881Swollman/* 95910881Swollman * Return the next larger or smaller MTU plateau (table from RFC 1191) 96010881Swollman * given current value MTU. If DIR is less than zero, a larger plateau 96110881Swollman * is returned; otherwise, a smaller value is returned. 96210881Swollman */ 963145360Sandreint 964169454Srwatsonip_next_mtu(int mtu, int dir) 96510881Swollman{ 96610881Swollman static int mtutab[] = { 967145866Sandre 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1280, 1006, 508, 968145866Sandre 296, 68, 0 96910881Swollman }; 970154728Sandre int i, size; 97110881Swollman 972154728Sandre size = (sizeof mtutab) / (sizeof mtutab[0]); 973154728Sandre if (dir >= 0) { 974154733Sglebius for (i = 0; i < size; i++) 975154728Sandre if (mtu > mtutab[i]) 976154728Sandre return mtutab[i]; 97710881Swollman } else { 978154728Sandre for (i = size - 1; i >= 0; i--) 979154728Sandre if (mtu < mtutab[i]) 980154728Sandre return mtutab[i]; 981154728Sandre if (mtu == mtutab[0]) 982154728Sandre return mtutab[0]; 98310881Swollman } 984154728Sandre return 0; 98510881Swollman} 986221134Sbz#endif /* INET */ 98741487Sdillon 98841487Sdillon 98941487Sdillon/* 99041487Sdillon * badport_bandlim() - check for ICMP bandwidth limit 99141487Sdillon * 99241487Sdillon * Return 0 if it is ok to send an ICMP error response, -1 if we have 993133874Srwatson * hit our bandwidth limit and it is not ok. 99441487Sdillon * 99541487Sdillon * If icmplim is <= 0, the feature is disabled and 0 is returned. 99641487Sdillon * 99741487Sdillon * For now we separate the TCP and UDP subsystems w/ different 'which' 99841487Sdillon * values. We may eventually remove this separation (and simplify the 99941487Sdillon * code further). 100041487Sdillon * 100141487Sdillon * Note that the printing of the error message is delayed so we can 100241487Sdillon * properly print the icmp error rate that the system was trying to do 100341487Sdillon * (i.e. 22000/100 pps, etc...). This can cause long delays in printing 1004133874Srwatson * the 'final' error, but it doesn't make sense to solve the printing 100541487Sdillon * delay with more complex code. 100641487Sdillon */ 100741487Sdillon 100841487Sdillonint 100941487Sdillonbadport_bandlim(int which) 101041487Sdillon{ 1011183550Szec 1012108144Ssam#define N(a) (sizeof (a) / sizeof (a[0])) 1013108144Ssam static struct rate { 1014108144Ssam const char *type; 1015108144Ssam struct timeval lasttime; 1016132107Sstefanf int curpps; 1017108144Ssam } rates[BANDLIM_MAX+1] = { 1018108144Ssam { "icmp unreach response" }, 1019108144Ssam { "icmp ping response" }, 1020108144Ssam { "icmp tstamp response" }, 1021108144Ssam { "closed port RST response" }, 1022171508Srwatson { "open port RST response" }, 1023237230Stuexen { "icmp6 unreach response" }, 1024237230Stuexen { "sctp ootb response" } 1025108144Ssam }; 102641487Sdillon 102741487Sdillon /* 1028108144Ssam * Return ok status if feature disabled or argument out of range. 102941487Sdillon */ 1030183550Szec if (V_icmplim > 0 && (u_int) which < N(rates)) { 1031108144Ssam struct rate *r = &rates[which]; 1032108144Ssam int opps = r->curpps; 103341487Sdillon 1034183550Szec if (!ppsratecheck(&r->lasttime, &r->curpps, V_icmplim)) 1035108144Ssam return -1; /* discard packet */ 1036108144Ssam /* 1037108144Ssam * If we've dropped below the threshold after having 1038108144Ssam * rate-limited traffic print the message. This preserves 1039108144Ssam * the previous behaviour at the expense of added complexity. 1040108144Ssam */ 1041183550Szec if (V_icmplim_output && opps > V_icmplim) 1042211316Sandre log(LOG_NOTICE, "Limiting %s from %d to %d packets/sec\n", 1043183550Szec r->type, opps, V_icmplim); 104441487Sdillon } 1045108144Ssam return 0; /* okay to send packet */ 1046108144Ssam#undef N 104741487Sdillon} 1048