📄 ip_icmp.c
字号:
/* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 * $Id: ip_icmp.c,v 1.2 1999/02/02 21:15:15 joel Exp $ */#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/protosw.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/kernel.h>#include <sys/socket.h>#include <sys/sysctl.h>#include <net/if.h>#include <net/route.h>#define _IP_VHL#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#include <netinet/ip_var.h>#include <netinet/icmp_var.h>/* * ICMP routines: error generation, receive packet processing, and * routines to turnaround packets back to the originator, and * host table maintenance routines. */ struct icmpstat icmpstat;SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD, &icmpstat, icmpstat, "");static int icmpmaskrepl = 0;SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW, &icmpmaskrepl, 0, "");static int icmpbmcastecho = 1;SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, &icmpbmcastecho, 0, "");/* #define ICMPPRINTFS 1 */#ifdef ICMPPRINTFSint icmpprintfs = 0;#endifstatic void icmp_reflect __P((struct mbuf *));static void icmp_send __P((struct mbuf *, struct mbuf *));static int ip_next_mtu __P((int, int));extern struct protosw inetsw[];/* * Generate an error packet of type error * in response to bad packet ip. */voidicmp_error(n, type, code, dest, destifp) struct mbuf *n; int type, code; n_long dest; struct ifnet *destifp;{ register struct ip *oip = mtod(n, struct ip *), *nip; register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2; register struct icmp *icp; register struct mbuf *m; unsigned icmplen;#ifdef ICMPPRINTFS if (icmpprintfs) printf("icmp_error(%p, %x, %d)\n", oip, type, code);#endif if (type != ICMP_REDIRECT) icmpstat.icps_error++; /* * Don't send error if not the first fragment of message. * Don't error if the old packet protocol was ICMP * error message, only known informational types. */ if (oip->ip_off &~ (IP_MF|IP_DF)) goto freeit; if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && n->m_len >= oiplen + ICMP_MINLEN && !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { icmpstat.icps_oldicmp++; goto freeit; } /* Don't send error in response to a multicast or broadcast packet */ if (n->m_flags & (M_BCAST|M_MCAST)) goto freeit; /* * First, formulate icmp message */ m = m_gethdr(M_DONTWAIT, MT_HEADER); if (m == NULL) goto freeit; icmplen = oiplen + min(8, oip->ip_len); m->m_len = icmplen + ICMP_MINLEN; MH_ALIGN(m, m->m_len); icp = mtod(m, struct icmp *); if ((u_int)type > ICMP_MAXTYPE) panic("icmp_error"); icmpstat.icps_outhist[type]++; icp->icmp_type = type; if (type == ICMP_REDIRECT) icp->icmp_gwaddr.s_addr = dest; else { icp->icmp_void = 0; /* * The following assignments assume an overlay with the * zeroed icmp_void field. */ if (type == ICMP_PARAMPROB) { icp->icmp_pptr = code; code = 0; } else if (type == ICMP_UNREACH && code == ICMP_UNREACH_NEEDFRAG && destifp) { icp->icmp_nextmtu = htons(destifp->if_mtu); } } icp->icmp_code = code; bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); nip = &icp->icmp_ip; nip->ip_len = htons((u_short)(nip->ip_len + oiplen)); /* * Now, copy old ip header (without options) * in front of icmp message. */ if (m->m_data - sizeof(struct ip) < m->m_pktdat) panic("icmp len"); m->m_data -= sizeof(struct ip); m->m_len += sizeof(struct ip); m->m_pkthdr.len = m->m_len; m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; nip = mtod(m, struct ip *); bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip)); nip->ip_len = m->m_len; nip->ip_vhl = IP_VHL_BORING; nip->ip_p = IPPROTO_ICMP; nip->ip_tos = 0; icmp_reflect(m);freeit: m_freem(n);}static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };/* * Process a received ICMP message. */voidicmp_input(m, hlen) register struct mbuf *m; int hlen;{ register struct icmp *icp; register struct ip *ip = mtod(m, struct ip *); int icmplen = ip->ip_len; register int i; struct in_ifaddr *ia; void (*ctlfunc) __P((int, struct sockaddr *, void *)); int code; /* * Locate icmp structure in mbuf, and check * that not corrupted and of at least minimum length. */#ifdef ICMPPRINTFS if (icmpprintfs) { char buf[4 * sizeof "123"]; strcpy(buf, inet_ntoa(ip->ip_src)); printf("icmp_input from %s to %s, len %d\n", buf, inet_ntoa(ip->ip_dst), icmplen); }#endif if (icmplen < ICMP_MINLEN) { icmpstat.icps_tooshort++; goto freeit; } i = hlen + min(icmplen, ICMP_ADVLENMIN); if (m->m_len < i && (m = m_pullup(m, i)) == 0) { icmpstat.icps_tooshort++; return; } ip = mtod(m, struct ip *); m->m_len -= hlen; m->m_data += hlen; icp = mtod(m, struct icmp *); if (in_cksum(m, icmplen)) { icmpstat.icps_checksum++; goto freeit; } m->m_len += hlen; m->m_data -= hlen;#ifdef ICMPPRINTFS if (icmpprintfs) printf("icmp_input, type %d code %d\n", icp->icmp_type, icp->icmp_code);#endif /* * Message type specific processing. */ if (icp->icmp_type > ICMP_MAXTYPE) goto raw; icmpstat.icps_inhist[icp->icmp_type]++; code = icp->icmp_code; switch (icp->icmp_type) { case ICMP_UNREACH: switch (code) { case ICMP_UNREACH_NET: case ICMP_UNREACH_HOST: case ICMP_UNREACH_PROTOCOL: case ICMP_UNREACH_PORT: case ICMP_UNREACH_SRCFAIL: code += PRC_UNREACH_NET; break; case ICMP_UNREACH_NEEDFRAG: code = PRC_MSGSIZE; break; case ICMP_UNREACH_NET_UNKNOWN: case ICMP_UNREACH_NET_PROHIB: case ICMP_UNREACH_TOSNET: code = PRC_UNREACH_NET; break; case ICMP_UNREACH_HOST_UNKNOWN: case ICMP_UNREACH_ISOLATED: case ICMP_UNREACH_HOST_PROHIB: case ICMP_UNREACH_TOSHOST: code = PRC_UNREACH_HOST; break; case ICMP_UNREACH_FILTER_PROHIB: case ICMP_UNREACH_HOST_PRECEDENCE: case ICMP_UNREACH_PRECEDENCE_CUTOFF: code = PRC_UNREACH_PORT; break; default: goto badcode; } goto deliver; case ICMP_TIMXCEED: if (code > 1) goto badcode; code += PRC_TIMXCEED_INTRANS; goto deliver; case ICMP_PARAMPROB: if (code > 1) goto badcode; code = PRC_PARAMPROB; goto deliver; case ICMP_SOURCEQUENCH: if (code) goto badcode; code = PRC_QUENCH; deliver: /* * Problem with datagram; advise higher level routines. */ if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) { icmpstat.icps_badlen++; goto freeit; } NTOHS(icp->icmp_ip.ip_len); /* Discard ICMP's in response to multicast packets */ if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr))) goto badcode;#ifdef ICMPPRINTFS if (icmpprintfs) printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);#endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst;#if 1 /* * MTU discovery: * If we got a needfrag and there is a host route to the * original destination, and the MTU is not locked, then * set the MTU in the route to the suggested new value * (if given) and then notify as usual. The ULPs will * notice that the MTU has changed and adapt accordingly. * If no new MTU was suggested, then we guess a new one * less than the current value. If the new MTU is * unreasonably small (arbitrarily set at 296), then * we reset the MTU to the interface value and enable the * lock bit, indicating that we are no longer doing MTU * discovery. */ if (code == PRC_MSGSIZE) { struct rtentry *rt; int mtu; rt = rtalloc1((struct sockaddr *)&icmpsrc, 0, RTF_CLONING | RTF_PRCLONING); if (rt && (rt->rt_flags & RTF_HOST) && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { mtu = ntohs(icp->icmp_nextmtu); if (!mtu) mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu, 1);#ifdef DEBUG_MTUDISC printf("MTU for %s reduced to %d\n", inet_ntoa(icmpsrc.sin_addr), mtu);#endif if (mtu < 296) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -