📄 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#endifextern 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;#elseextern struct inpcbhead ripcb;#endifextern 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;#endifstatic 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_PPSRATECHECKstatic int ppsratecheck __P((struct timeval *, int *, int));#endifstatic 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 *));#endifvoidicmp6_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 voidicmp6_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. */voidicmp6_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. */voidicmp6_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) m = m_pullup(m, preplen); if (m == NULL) { nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__)); return; } nip6 = mtod(m, struct ip6_hdr *); nip6->ip6_src = *nip6_srcp; nip6->ip6_dst = oip6->ip6_dst; if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src)) oip6->ip6_src.s6_addr16[1] = 0; if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst)) oip6->ip6_dst.s6_addr16[1] = 0; icmp6 = (struct icmp6_hdr *)(nip6 + 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -