📄 icmp6.c
字号:
//==========================================================================
//
// src/sys/netinet6/icmp6.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
/* $KAME: icmp6.c,v 1.269 2001/12/18 02:19:16 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* 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. Neither the name of the project 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 PROJECT 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 PROJECT 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.
*/
/*
* 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
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/domain.h>
#include <net/if.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#if defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#endif
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet/icmp6.h>
#include <netinet6/mld6_var.h>
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
#include <netinet/in_pcb.h>
#include <netinet6/in6_pcb.h>
#elif defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)
#include <netinet/in_pcb.h>
#else
#include <netinet6/in6_pcb.h>
#endif
#include <netinet6/nd6.h>
#include <netinet6/in6_ifattach.h>
#include <netinet6/ip6protosw.h>
#ifdef __OpenBSD__ /* KAME IPSEC */
#undef IPSEC
#endif
#ifdef IPSEC
#include <netinet6/ipsec.h>
#include <netkey/key.h>
#endif
#ifdef MIP6
#include <netinet6/mip6.h>
#endif
#ifdef HAVE_NRL_INPCB
/* inpcb members */
#define in6pcb inpcb
#define in6p_laddr inp_laddr6
#define in6p_faddr inp_faddr6
#define in6p_icmp6filt inp_icmp6filt
#define in6p_route inp_route
#define in6p_socket inp_socket
#define in6p_flags inp_flags
#define in6p_moptions inp_moptions6
#define in6p_outputopts inp_outputopts6
#define in6p_ip6 inp_ipv6
#define in6p_flowinfo inp_flowinfo
#define in6p_sp inp_sp
#define in6p_next inp_next
#define in6p_prev inp_prev
/*
* for KAME src sync over BSD*'s. XXX: FreeBSD (>=3) are VERY different from
* others...
*/
#define in6p_ip6_nxt inp_ipv6.ip6_nxt
#endif
extern struct domain inet6domain;
extern struct ip6protosw inet6sw[];
extern u_char ip6_protox[];
struct icmp6stat icmp6stat;
#if defined (__OpenBSD__)
extern struct inpcbtable rawin6pcbtable;
#elif !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
extern struct in6pcb rawin6pcb;
#else
extern struct inpcbhead ripcb;
#endif
extern int icmp6errppslim;
static int icmp6errpps_count = 0;
static struct timeval icmp6errppslim_last;
extern int icmp6_nodeinfo;
#if defined(__NetBSD__) || defined(__OpenBSD__)
/*
* List of callbacks to notify when Path MTU changes are made.
*/
struct icmp6_mtudisc_callback {
LIST_ENTRY(icmp6_mtudisc_callback) mc_list;
void (*mc_func) __P((struct in6_addr *));
};
LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks =
LIST_HEAD_INITIALIZER(&icmp6_mtudisc_callbacks);
static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
extern int pmtu_expire;
/* XXX do these values make any sense? */
static int icmp6_mtudisc_hiwat = 1280;
static int icmp6_mtudisc_lowat = 256;
/*
* keep track of # of redirect routes.
*/
static struct rttimer_queue *icmp6_redirect_timeout_q = NULL;
/* XXX do these values make any sense? */
static int icmp6_redirect_hiwat = 1280;
static int icmp6_redirect_lowat = 1024;
#endif
static void icmp6_errcount __P((struct icmp6errstat *, int, int));
static int icmp6_rip6_input __P((struct mbuf **, int));
static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
static const char *icmp6_redirect_diag __P((struct in6_addr *,
struct in6_addr *, struct in6_addr *));
#ifndef HAVE_PPSRATECHECK
static int ppsratecheck __P((struct timeval *, int *, int));
#endif
static struct mbuf *ni6_input __P((struct mbuf *, int));
static struct mbuf *ni6_nametodns __P((const char *, int, int));
static int ni6_dnsmatch __P((const char *, int, const char *, int));
static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
struct ifnet **, char *));
static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
struct ifnet *, int));
static int icmp6_notify_error __P((struct mbuf *, int, int, int));
static int icmp6_recover_src __P((struct mbuf *));
#if defined(__NetBSD__) || defined(__OpenBSD__)
static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *));
static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *));
static void icmp6_redirect_timeout __P((struct rtentry *, struct rttimer *));
#endif
void
icmp6_init()
{
mld6_init();
#if defined(__NetBSD__) || defined(__OpenBSD__)
icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout);
#endif
}
static void
icmp6_errcount(stat, type, code)
struct icmp6errstat *stat;
int type, code;
{
switch (type) {
case ICMP6_DST_UNREACH:
switch (code) {
case ICMP6_DST_UNREACH_NOROUTE:
stat->icp6errs_dst_unreach_noroute++;
return;
case ICMP6_DST_UNREACH_ADMIN:
stat->icp6errs_dst_unreach_admin++;
return;
case ICMP6_DST_UNREACH_BEYONDSCOPE:
stat->icp6errs_dst_unreach_beyondscope++;
return;
case ICMP6_DST_UNREACH_ADDR:
stat->icp6errs_dst_unreach_addr++;
return;
case ICMP6_DST_UNREACH_NOPORT:
stat->icp6errs_dst_unreach_noport++;
return;
}
break;
case ICMP6_PACKET_TOO_BIG:
stat->icp6errs_packet_too_big++;
return;
case ICMP6_TIME_EXCEEDED:
switch (code) {
case ICMP6_TIME_EXCEED_TRANSIT:
stat->icp6errs_time_exceed_transit++;
return;
case ICMP6_TIME_EXCEED_REASSEMBLY:
stat->icp6errs_time_exceed_reassembly++;
return;
}
break;
case ICMP6_PARAM_PROB:
switch (code) {
case ICMP6_PARAMPROB_HEADER:
stat->icp6errs_paramprob_header++;
return;
case ICMP6_PARAMPROB_NEXTHEADER:
stat->icp6errs_paramprob_nextheader++;
return;
case ICMP6_PARAMPROB_OPTION:
stat->icp6errs_paramprob_option++;
return;
}
break;
case ND_REDIRECT:
stat->icp6errs_redirect++;
return;
}
stat->icp6errs_unknown++;
}
#if defined(__NetBSD__) || defined(__OpenBSD__)
/*
* Register a Path MTU Discovery callback.
*/
void
icmp6_mtudisc_callback_register(func)
void (*func) __P((struct in6_addr *));
{
struct icmp6_mtudisc_callback *mc;
for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
mc = LIST_NEXT(mc, mc_list)) {
if (mc->mc_func == func)
return;
}
mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT);
if (mc == NULL)
panic("icmp6_mtudisc_callback_register");
mc->mc_func = func;
LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list);
}
#endif
/*
* Generate an error packet of type error in response to bad IP6 packet.
*/
void
icmp6_error(m, type, code, param)
struct mbuf *m;
int type, code, param;
{
struct ip6_hdr *oip6, *nip6;
struct icmp6_hdr *icmp6;
struct mbuf *n;
struct ip6aux *ip6a;
struct in6_addr nip6_src, *nip6_srcp;
u_int preplen;
int off;
int nxt;
icmp6stat.icp6s_error++;
/* count per-type-code statistics */
icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code);
#ifdef M_DECRYPTED /* not openbsd */
if (m->m_flags & M_DECRYPTED) {
icmp6stat.icp6s_canterror++;
goto freeit;
}
#endif
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
#else
if (m->m_len < sizeof(struct ip6_hdr)) {
m = m_pullup(m, sizeof(struct ip6_hdr));
if (m == NULL)
return;
}
#endif
oip6 = mtod(m, struct ip6_hdr *);
/*
* If the destination address of the erroneous packet is a multicast
* address, or the packet was sent using link-layer multicast,
* we should basically suppress sending an error (RFC 2463, Section
* 2.4).
* We have two exceptions (the item e.2 in that section):
* - the Pakcet Too Big message can be sent for path MTU discovery.
* - the Parameter Problem Message that can be allowed an icmp6 error
* in the option type field. This check has been done in
* ip6_unknown_opt(), so we can just check the type and code.
*/
if ((m->m_flags & (M_BCAST|M_MCAST) ||
IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
(type != ICMP6_PACKET_TOO_BIG &&
(type != ICMP6_PARAM_PROB ||
code != ICMP6_PARAMPROB_OPTION)))
goto freeit;
/*
* RFC 2463, 2.4 (e.5): source address check.
* XXX: the case of anycast source?
*/
if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
goto freeit;
/*
* If we are about to send ICMPv6 against ICMPv6 error/redirect,
* don't do it.
*/
nxt = -1;
off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
if (off >= 0 && nxt == IPPROTO_ICMPV6) {
struct icmp6_hdr *icp;
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
#else
IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
sizeof(*icp));
if (icp == NULL) {
icmp6stat.icp6s_tooshort++;
return;
}
#endif
if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
icp->icmp6_type == ND_REDIRECT) {
/*
* ICMPv6 error
* Special case: for redirect (which is
* informational) we must not send icmp6 error.
*/
icmp6stat.icp6s_canterror++;
goto freeit;
} else {
/* ICMPv6 informational - send the error */
}
}
#if 0 /* controversial */
else if (off >= 0 && nxt == IPPROTO_ESP) {
/*
* It could be ICMPv6 error inside ESP. Take a safer side,
* don't respond.
*/
icmp6stat.icp6s_canterror++;
goto freeit;
}
#endif
else {
/* non-ICMPv6 - send the error */
}
oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
/* Finally, do rate limitation check. */
if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
icmp6stat.icp6s_toofreq++;
goto freeit;
}
/*
* OK, ICMP6 can be generated.
*/
/*
* Recover the original ip6_src if the src and the homeaddr
* have been swapped while dest6 processing (see dest6.c). To
* avoid m_pulldown, we had better to swap addresses before
* m_prepend below.
*
* XXX: We should consider the other candidate to keep the
* icmp6 error packet correct that not swapping ip6_src and
* homeaddr in the dest6 processing.
*/
nip6_srcp = &oip6->ip6_src;
n = ip6_findaux(m);
if (n != NULL) {
ip6a = mtod(n, struct ip6aux *);
if ((ip6a->ip6a_flags & IP6A_HASEEN) != 0 &&
(ip6a->ip6a_flags & IP6A_SWAP) != 0) {
nip6_src = oip6->ip6_src;
nip6_srcp = &nip6_src;
if (icmp6_recover_src(m)) {
/* mbuf is freed in icmp6_recover_src */
return;
}
oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
}
}
if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
M_PREPEND(m, preplen, M_DONTWAIT);
if (m && m->m_len < preplen)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -