📄 ip_icmp.c
字号:
//==========================================================================
//
// sys/netinet/ip_icmp.c
//
//
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2000-01-10
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
/* $OpenBSD: ip_icmp.c,v 1.19 1999/12/08 06:50:19 itojun Exp $ */
/* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */
/*
* 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
*/
/*
%%% portions-copyright-nrl-95
Portions of this software are Copyright 1995-1998 by Randall Atkinson,
Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
Reserved. All rights under this copyright have been assigned to the US
Naval Research Laboratory (NRL). The NRL Copyright Notice and License
Agreement Version 1.1 (January 17, 1995) applies to these portions of the
software.
You should have received a copy of the license with this software. If you
didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
*/
#include <sys/param.h>
#ifndef __ECOS
#include <sys/systm.h>
#endif
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/kernel.h>
#ifndef __ECOS
#include <sys/proc.h>
#include <vm/vm.h>
#include <sys/sysctl.h>
#endif
#include <net/if.h>
#include <net/route.h>
#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>
#if 0 /*KAME IPSEC*/
#include <netinet6/ipsec.h>
#include <netkey/key.h>
#include <netkey/key_debug.h>
#endif
#include <machine/stdarg.h>
/*
* ICMP routines: error generation, receive packet processing, and
* routines to turnaround packets back to the originator, and
* host table maintenance routines.
*/
int icmpmaskrepl = 0;
int icmpbmcastecho = 0;
#ifdef ICMPPRINTFS
int icmpprintfs = 0;
#endif
#if 0
static int ip_next_mtu __P((int, int));
#else
/*static*/ int ip_next_mtu __P((int, int));
#endif
extern struct protosw inetsw[];
/*
* Generate an error packet of type error
* in response to bad packet ip.
*
* The ip packet inside has ip_off and ip_len in host byte order.
*/
void
icmp_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 = oip->ip_hl << 2;
register struct icmp *icp;
struct mbuf *m, m0;
unsigned icmplen;
#ifdef ICMPPRINTFS
if (icmpprintfs)
printf("icmp_error(%x, %d, %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_off = htons(nip->ip_off);
nip->ip_len = htons(nip->ip_len);
m0.m_next = NULL; /* correct nip->ip_sum */
m0.m_data = (char *)nip;
m0.m_len = nip->ip_hl << 2;
nip->ip_sum = 0;
nip->ip_sum = in_cksum(&m0, nip->ip_hl << 2);
/*
* 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_off = htons(nip->ip_off);
nip->ip_len = m->m_len;
nip->ip_hl = sizeof(struct ip) >> 2;
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 };
struct sockaddr_in icmpmask = { 8, 0 };
/*
* Process a received ICMP message.
*/
void
#if __STDC__
icmp_input(struct mbuf *m, ...)
#else
icmp_input(m, va_alist)
struct mbuf *m;
va_dcl
#endif
{
int proto;
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;
extern u_char ip_protox[];
int hlen;
va_list ap;
va_start(ap, m);
hlen = va_arg(ap, int);
proto = va_arg(ap, int);
va_end(ap);
/*
* 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_dst));
printf("icmp_input from %s to %s, len %d\n",
inet_ntoa(ip->ip_src), buf, 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
/*
* Message type specific processing.
*/
if (icmpprintfs)
printf("icmp_input, type %d code %d\n", icp->icmp_type,
icp->icmp_code);
#endif
#if 0 /*KAME IPSEC*/
/* drop it if it does not match the policy */
if (ipsec4_in_reject(m, NULL)) {
ipsecstat.in_polvio++;
goto freeit;
}
#endif
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:
#if 0 /*NRL INET6*/
if (icp->icmp_nextmtu) {
extern int ipv6_trans_mtu
__P((struct mbuf **, int, int));
struct mbuf *m0 = m;
/*
* Do cool v4-related path MTU, for now,
* only v6-in-v4 can handle it.
*/
if (icmplen >= ICMP_V6ADVLENMIN &&
icmplen >= ICMP_V6ADVLEN(icp) &&
icp->icmp_ip.ip_p == IPPROTO_IPV6) {
/*
* ipv6_trans_mtu returns 1 if
* the mbuf is still intact.
*/
if (ipv6_trans_mtu(&m0,icp->icmp_nextmtu,
hlen + ICMP_V6ADVLEN(icp))) {
m = m0;
goto raw;
} else
return;
}
}
#endif /* INET6 */
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:
case ICMP_UNREACH_FILTER_PROHIB:
case ICMP_UNREACH_HOST_PRECEDENCE:
case ICMP_UNREACH_PRECEDENCE_CUTOFF:
code = PRC_UNREACH_HOST;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -