Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/icmp6.c
Show First 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | |||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
VNET_PCPUSTAT_SYSUNINIT(icmp6stat); | VNET_PCPUSTAT_SYSUNINIT(icmp6stat); | ||||
#endif /* VIMAGE */ | #endif /* VIMAGE */ | ||||
VNET_DECLARE(struct inpcbinfo, ripcbinfo); | VNET_DECLARE(struct inpcbinfo, ripcbinfo); | ||||
VNET_DECLARE(struct inpcbhead, ripcb); | VNET_DECLARE(struct inpcbhead, ripcb); | ||||
VNET_DECLARE(int, icmp6errppslim); | VNET_DECLARE(int, icmp6errppslim); | ||||
static VNET_DEFINE(int, icmp6errpps_count) = 0; | VNET_DECLARE(int, icmp6infoppslim); | ||||
static VNET_DEFINE(struct timeval, icmp6errppslim_last); | VNET_DECLARE(int, icmp6errppslim_output); | ||||
VNET_DECLARE(int, icmp6infoppslim_output); | |||||
VNET_DECLARE(int, icmp6_nodeinfo); | VNET_DECLARE(int, icmp6_nodeinfo); | ||||
#define V_ripcbinfo VNET(ripcbinfo) | #define V_ripcbinfo VNET(ripcbinfo) | ||||
#define V_ripcb VNET(ripcb) | #define V_ripcb VNET(ripcb) | ||||
#define V_icmp6errppslim VNET(icmp6errppslim) | #define V_icmp6errppslim VNET(icmp6errppslim) | ||||
#define V_icmp6errpps_count VNET(icmp6errpps_count) | #define V_icmp6infoppslim VNET(icmp6infoppslim) | ||||
#define V_icmp6errppslim_last VNET(icmp6errppslim_last) | #define V_icmp6errppslim_output VNET(icmp6errppslim_output) | ||||
#define V_icmp6infoppslim_output VNET(icmp6infoppslim_output) | |||||
#define V_icmp6_nodeinfo VNET(icmp6_nodeinfo) | #define V_icmp6_nodeinfo VNET(icmp6_nodeinfo) | ||||
static void icmp6_errcount(int, int); | static void icmp6_errcount(int, int); | ||||
static int icmp6_rip6_input(struct mbuf **, int); | static int icmp6_rip6_input(struct mbuf **, int); | ||||
static int icmp6_ratelimit(const struct in6_addr *, const int, const int); | |||||
static const char *icmp6_redirect_diag(struct in6_addr *, | static const char *icmp6_redirect_diag(struct in6_addr *, | ||||
struct in6_addr *, struct in6_addr *); | struct in6_addr *, struct in6_addr *); | ||||
static struct mbuf *ni6_input(struct mbuf *, int); | static struct mbuf *ni6_input(struct mbuf *, int); | ||||
static struct mbuf *ni6_nametodns(const char *, int, int); | static struct mbuf *ni6_nametodns(const char *, int, int); | ||||
static int ni6_dnsmatch(const char *, int, const char *, int); | static int ni6_dnsmatch(const char *, int, const char *, int); | ||||
static int ni6_addrs(struct icmp6_nodeinfo *, struct mbuf *, | static int ni6_addrs(struct icmp6_nodeinfo *, struct mbuf *, | ||||
struct ifnet **, struct in6_addr *); | struct ifnet **, struct in6_addr *); | ||||
static int ni6_store_addrs(struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, | static int ni6_store_addrs(struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, | ||||
▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
} else { | } else { | ||||
/* non-ICMPv6 - send the error */ | /* non-ICMPv6 - send the error */ | ||||
} | } | ||||
oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */ | oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */ | ||||
/* Finally, do rate limitation check. */ | /* Finally, do rate limitation check. */ | ||||
if (icmp6_ratelimit(&oip6->ip6_src, type, code)) { | if (counter_ratecheck(BANDLIM_ICMP6_ERRORS) < 0) { | ||||
ICMP6STAT_INC(icp6s_toofreq); | ICMP6STAT_INC(icp6s_toofreq); | ||||
goto freeit; | goto freeit; | ||||
} | } | ||||
/* | /* | ||||
* OK, ICMP6 can be generated. | * OK, ICMP6 can be generated. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 187 Lines • ▼ Show 20 Lines | case ICMP6_PARAM_PROB: | ||||
} | } | ||||
goto deliver; | goto deliver; | ||||
break; | break; | ||||
case ICMP6_ECHO_REQUEST: | case ICMP6_ECHO_REQUEST: | ||||
icmp6_ifstat_inc(ifp, ifs6_in_echo); | icmp6_ifstat_inc(ifp, ifs6_in_echo); | ||||
if (code != 0) | if (code != 0) | ||||
goto badcode; | goto badcode; | ||||
if (counter_ratecheck(BANDLIM_ICMP6_INFOREPLIES) < 0) | |||||
break; | |||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) { | if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) { | ||||
/* Give up remote */ | /* Give up remote */ | ||||
break; | break; | ||||
} | } | ||||
if (!M_WRITABLE(n) | if (!M_WRITABLE(n) | ||||
|| n->m_len < off + sizeof(struct icmp6_hdr)) { | || n->m_len < off + sizeof(struct icmp6_hdr)) { | ||||
struct mbuf *n0 = n; | struct mbuf *n0 = n; | ||||
int n0len; | int n0len; | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | case MLDV2_LISTENER_REPORT: | ||||
break; | break; | ||||
case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */ | case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */ | ||||
{ | { | ||||
enum { WRU, FQDN } mode; | enum { WRU, FQDN } mode; | ||||
if (!V_icmp6_nodeinfo) | if (!V_icmp6_nodeinfo) | ||||
break; | break; | ||||
if (counter_ratecheck(BANDLIM_ICMP6_INFOREPLIES) < 0) | |||||
break; | |||||
if (icmp6len == sizeof(struct icmp6_hdr) + 4) | if (icmp6len == sizeof(struct icmp6_hdr) + 4) | ||||
mode = WRU; | mode = WRU; | ||||
else if (icmp6len >= sizeof(struct icmp6_nodeinfo)) | else if (icmp6len >= sizeof(struct icmp6_nodeinfo)) | ||||
mode = FQDN; | mode = FQDN; | ||||
else | else | ||||
goto badlen; | goto badlen; | ||||
▲ Show 20 Lines • Show All 1,809 Lines • ▼ Show 20 Lines | icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt) | ||||
src_sa.sin6_len = sizeof(src_sa); | src_sa.sin6_len = sizeof(src_sa); | ||||
src_sa.sin6_addr = sip6->ip6_src; | src_sa.sin6_addr = sip6->ip6_src; | ||||
if (nd6_is_addr_neighbor(&src_sa, ifp) == 0) | if (nd6_is_addr_neighbor(&src_sa, ifp) == 0) | ||||
goto fail; | goto fail; | ||||
if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst)) | if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst)) | ||||
goto fail; /* what should we do here? */ | goto fail; /* what should we do here? */ | ||||
/* rate limit */ | /* rate limit */ | ||||
if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0)) | if (counter_ratecheck(BANDLIM_ICMP6_ERRORS) < 0) | ||||
goto fail; | goto fail; | ||||
/* | /* | ||||
* Since we are going to append up to 1280 bytes (= IPV6_MMTU), | * Since we are going to append up to 1280 bytes (= IPV6_MMTU), | ||||
* we almost always ask for an mbuf cluster for simplicity. | * we almost always ask for an mbuf cluster for simplicity. | ||||
* (MHLEN < IPV6_MMTU is almost always true) | * (MHLEN < IPV6_MMTU is almost always true) | ||||
*/ | */ | ||||
#if IPV6_MMTU >= MCLBYTES | #if IPV6_MMTU >= MCLBYTES | ||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | default: | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | static void | ||||
* Perform rate limit check. | icmp6_bandlimit_init(void) | ||||
* Returns 0 if it is okay to send the icmp6 packet. | |||||
* Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate | |||||
* limitation. | |||||
* | |||||
* XXX per-destination/type check necessary? | |||||
* | |||||
* dst - not used at this moment | |||||
* type - not used at this moment | |||||
* code - not used at this moment | |||||
*/ | |||||
static int | |||||
icmp6_ratelimit(const struct in6_addr *dst, const int type, | |||||
const int code) | |||||
{ | { | ||||
int ret; | |||||
ret = 0; /* okay to send */ | counter_rate_register(BANDLIM_ICMP6_INFOREPLIES, | ||||
"icmp6 informational responses", &V_icmp6infoppslim, | |||||
/* PPS limit */ | &V_icmp6errppslim_output); | ||||
if (!ppsratecheck(&V_icmp6errppslim_last, &V_icmp6errpps_count, | counter_rate_register(BANDLIM_ICMP6_ERRORS, | ||||
V_icmp6errppslim)) { | "icmp6 error responses", &V_icmp6errppslim, | ||||
/* The packet is subject to rate limit */ | &V_icmp6errppslim_output); | ||||
ret++; | |||||
} | } | ||||
VNET_SYSINIT(icmp6_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, | |||||
icmp6_bandlimit_init, NULL); | |||||
return ret; | static void | ||||
icmp6_bandlimit_uninit(void) | |||||
{ | |||||
counter_rate_unregister(BANDLIM_ICMP6_INFOREPLIES); | |||||
counter_rate_unregister(BANDLIM_ICMP6_ERRORS); | |||||
} | } | ||||
VNET_SYSUNINIT(icmp6_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, | |||||
icmp6_bandlimit_uninit, NULL); |