FreeBSD/Linux Kernel Cross Reference
sys/netinet6/icmp6.c
1 /*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $KAME: icmp6.c,v 1.211 2001/04/04 05:56:20 itojun Exp $
30 */
31
32 /*-
33 * Copyright (c) 1982, 1986, 1988, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
61 */
62
63 #include <sys/cdefs.h>
64 __FBSDID("$FreeBSD: src/sys/netinet6/icmp6.c,v 1.95 2008/12/02 21:37:28 bz Exp $");
65
66 #include "opt_inet.h"
67 #include "opt_inet6.h"
68 #include "opt_ipsec.h"
69
70 #include <sys/param.h>
71 #include <sys/domain.h>
72 #include <sys/kernel.h>
73 #include <sys/lock.h>
74 #include <sys/malloc.h>
75 #include <sys/mbuf.h>
76 #include <sys/protosw.h>
77 #include <sys/signalvar.h>
78 #include <sys/socket.h>
79 #include <sys/socketvar.h>
80 #include <sys/sx.h>
81 #include <sys/syslog.h>
82 #include <sys/systm.h>
83 #include <sys/time.h>
84 #include <sys/vimage.h>
85
86 #include <net/if.h>
87 #include <net/if_dl.h>
88 #include <net/if_types.h>
89 #include <net/route.h>
90 #include <net/vnet.h>
91
92 #include <netinet/in.h>
93 #include <netinet/in_pcb.h>
94 #include <netinet/in_var.h>
95 #include <netinet/ip6.h>
96 #include <netinet/icmp6.h>
97 #include <netinet/tcp_var.h>
98 #include <netinet/vinet.h>
99
100 #include <netinet6/in6_ifattach.h>
101 #include <netinet6/in6_pcb.h>
102 #include <netinet6/ip6protosw.h>
103 #include <netinet6/ip6_var.h>
104 #include <netinet6/scope6_var.h>
105 #include <netinet6/mld6_var.h>
106 #include <netinet6/nd6.h>
107 #include <netinet6/vinet6.h>
108
109 #ifdef IPSEC
110 #include <netipsec/ipsec.h>
111 #include <netipsec/key.h>
112 #endif
113
114 extern struct domain inet6domain;
115
116 #ifdef VIMAGE_GLOBALS
117 extern struct inpcbinfo ripcbinfo;
118 extern struct inpcbhead ripcb;
119 extern int icmp6errppslim;
120 extern int icmp6_nodeinfo;
121
122 struct icmp6stat icmp6stat;
123 static int icmp6errpps_count;
124 static struct timeval icmp6errppslim_last;
125 #endif
126
127 static void icmp6_errcount(struct icmp6errstat *, int, int);
128 static int icmp6_rip6_input(struct mbuf **, int);
129 static int icmp6_ratelimit(const struct in6_addr *, const int, const int);
130 static const char *icmp6_redirect_diag __P((struct in6_addr *,
131 struct in6_addr *, struct in6_addr *));
132 static struct mbuf *ni6_input(struct mbuf *, int);
133 static struct mbuf *ni6_nametodns(const char *, int, int);
134 static int ni6_dnsmatch(const char *, int, const char *, int);
135 static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *,
136 struct ifnet **, struct in6_addr *));
137 static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
138 struct ifnet *, int));
139 static int icmp6_notify_error(struct mbuf **, int, int, int);
140
141
142 void
143 icmp6_init(void)
144 {
145 INIT_VNET_INET6(curvnet);
146
147 V_icmp6errpps_count = 0;
148
149 mld6_init();
150 }
151
152 static void
153 icmp6_errcount(struct icmp6errstat *stat, int type, int code)
154 {
155 switch (type) {
156 case ICMP6_DST_UNREACH:
157 switch (code) {
158 case ICMP6_DST_UNREACH_NOROUTE:
159 stat->icp6errs_dst_unreach_noroute++;
160 return;
161 case ICMP6_DST_UNREACH_ADMIN:
162 stat->icp6errs_dst_unreach_admin++;
163 return;
164 case ICMP6_DST_UNREACH_BEYONDSCOPE:
165 stat->icp6errs_dst_unreach_beyondscope++;
166 return;
167 case ICMP6_DST_UNREACH_ADDR:
168 stat->icp6errs_dst_unreach_addr++;
169 return;
170 case ICMP6_DST_UNREACH_NOPORT:
171 stat->icp6errs_dst_unreach_noport++;
172 return;
173 }
174 break;
175 case ICMP6_PACKET_TOO_BIG:
176 stat->icp6errs_packet_too_big++;
177 return;
178 case ICMP6_TIME_EXCEEDED:
179 switch (code) {
180 case ICMP6_TIME_EXCEED_TRANSIT:
181 stat->icp6errs_time_exceed_transit++;
182 return;
183 case ICMP6_TIME_EXCEED_REASSEMBLY:
184 stat->icp6errs_time_exceed_reassembly++;
185 return;
186 }
187 break;
188 case ICMP6_PARAM_PROB:
189 switch (code) {
190 case ICMP6_PARAMPROB_HEADER:
191 stat->icp6errs_paramprob_header++;
192 return;
193 case ICMP6_PARAMPROB_NEXTHEADER:
194 stat->icp6errs_paramprob_nextheader++;
195 return;
196 case ICMP6_PARAMPROB_OPTION:
197 stat->icp6errs_paramprob_option++;
198 return;
199 }
200 break;
201 case ND_REDIRECT:
202 stat->icp6errs_redirect++;
203 return;
204 }
205 stat->icp6errs_unknown++;
206 }
207
208 /*
209 * A wrapper function for icmp6_error() necessary when the erroneous packet
210 * may not contain enough scope zone information.
211 */
212 void
213 icmp6_error2(struct mbuf *m, int type, int code, int param,
214 struct ifnet *ifp)
215 {
216 INIT_VNET_INET6(curvnet);
217 struct ip6_hdr *ip6;
218
219 if (ifp == NULL)
220 return;
221
222 #ifndef PULLDOWN_TEST
223 IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
224 #else
225 if (m->m_len < sizeof(struct ip6_hdr)) {
226 m = m_pullup(m, sizeof(struct ip6_hdr));
227 if (m == NULL)
228 return;
229 }
230 #endif
231
232 ip6 = mtod(m, struct ip6_hdr *);
233
234 if (in6_setscope(&ip6->ip6_src, ifp, NULL) != 0)
235 return;
236 if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0)
237 return;
238
239 icmp6_error(m, type, code, param);
240 }
241
242 /*
243 * Generate an error packet of type error in response to bad IP6 packet.
244 */
245 void
246 icmp6_error(struct mbuf *m, int type, int code, int param)
247 {
248 INIT_VNET_INET6(curvnet);
249 struct ip6_hdr *oip6, *nip6;
250 struct icmp6_hdr *icmp6;
251 u_int preplen;
252 int off;
253 int nxt;
254
255 V_icmp6stat.icp6s_error++;
256
257 /* count per-type-code statistics */
258 icmp6_errcount(&V_icmp6stat.icp6s_outerrhist, type, code);
259
260 #ifdef M_DECRYPTED /*not openbsd*/
261 if (m->m_flags & M_DECRYPTED) {
262 V_icmp6stat.icp6s_canterror++;
263 goto freeit;
264 }
265 #endif
266
267 #ifndef PULLDOWN_TEST
268 IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
269 #else
270 if (m->m_len < sizeof(struct ip6_hdr)) {
271 m = m_pullup(m, sizeof(struct ip6_hdr));
272 if (m == NULL)
273 return;
274 }
275 #endif
276 oip6 = mtod(m, struct ip6_hdr *);
277
278 /*
279 * If the destination address of the erroneous packet is a multicast
280 * address, or the packet was sent using link-layer multicast,
281 * we should basically suppress sending an error (RFC 2463, Section
282 * 2.4).
283 * We have two exceptions (the item e.2 in that section):
284 * - the Pakcet Too Big message can be sent for path MTU discovery.
285 * - the Parameter Problem Message that can be allowed an icmp6 error
286 * in the option type field. This check has been done in
287 * ip6_unknown_opt(), so we can just check the type and code.
288 */
289 if ((m->m_flags & (M_BCAST|M_MCAST) ||
290 IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
291 (type != ICMP6_PACKET_TOO_BIG &&
292 (type != ICMP6_PARAM_PROB ||
293 code != ICMP6_PARAMPROB_OPTION)))
294 goto freeit;
295
296 /*
297 * RFC 2463, 2.4 (e.5): source address check.
298 * XXX: the case of anycast source?
299 */
300 if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
301 IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
302 goto freeit;
303
304 /*
305 * If we are about to send ICMPv6 against ICMPv6 error/redirect,
306 * don't do it.
307 */
308 nxt = -1;
309 off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
310 if (off >= 0 && nxt == IPPROTO_ICMPV6) {
311 struct icmp6_hdr *icp;
312
313 #ifndef PULLDOWN_TEST
314 IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
315 icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
316 #else
317 IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
318 sizeof(*icp));
319 if (icp == NULL) {
320 V_icmp6stat.icp6s_tooshort++;
321 return;
322 }
323 #endif
324 if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
325 icp->icmp6_type == ND_REDIRECT) {
326 /*
327 * ICMPv6 error
328 * Special case: for redirect (which is
329 * informational) we must not send icmp6 error.
330 */
331 V_icmp6stat.icp6s_canterror++;
332 goto freeit;
333 } else {
334 /* ICMPv6 informational - send the error */
335 }
336 } else {
337 /* non-ICMPv6 - send the error */
338 }
339
340 oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
341
342 /* Finally, do rate limitation check. */
343 if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
344 V_icmp6stat.icp6s_toofreq++;
345 goto freeit;
346 }
347
348 /*
349 * OK, ICMP6 can be generated.
350 */
351
352 if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
353 m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
354
355 preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
356 M_PREPEND(m, preplen, M_DONTWAIT);
357 if (m && m->m_len < preplen)
358 m = m_pullup(m, preplen);
359 if (m == NULL) {
360 nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__));
361 return;
362 }
363
364 nip6 = mtod(m, struct ip6_hdr *);
365 nip6->ip6_src = oip6->ip6_src;
366 nip6->ip6_dst = oip6->ip6_dst;
367
368 in6_clearscope(&oip6->ip6_src);
369 in6_clearscope(&oip6->ip6_dst);
370
371 icmp6 = (struct icmp6_hdr *)(nip6 + 1);
372 icmp6->icmp6_type = type;
373 icmp6->icmp6_code = code;
374 icmp6->icmp6_pptr = htonl((u_int32_t)param);
375
376 /*
377 * icmp6_reflect() is designed to be in the input path.
378 * icmp6_error() can be called from both input and output path,
379 * and if we are in output path rcvif could contain bogus value.
380 * clear m->m_pkthdr.rcvif for safety, we should have enough scope
381 * information in ip header (nip6).
382 */
383 m->m_pkthdr.rcvif = NULL;
384
385 V_icmp6stat.icp6s_outhist[type]++;
386 icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */
387
388 return;
389
390 freeit:
391 /*
392 * If we can't tell whether or not we can generate ICMP6, free it.
393 */
394 m_freem(m);
395 }
396
397 /*
398 * Process a received ICMP6 message.
399 */
400 int
401 icmp6_input(struct mbuf **mp, int *offp, int proto)
402 {
403 INIT_VNET_INET6(curvnet);
404 INIT_VPROCG(TD_TO_VPROCG(curthread)); /* XXX V_hostname needs this */
405 struct mbuf *m = *mp, *n;
406 struct ip6_hdr *ip6, *nip6;
407 struct icmp6_hdr *icmp6, *nicmp6;
408 int off = *offp;
409 int icmp6len = m->m_pkthdr.len - *offp;
410 int code, sum, noff;
411 char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
412
413 #ifndef PULLDOWN_TEST
414 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
415 /* m might change if M_LOOP. So, call mtod after this */
416 #endif
417
418 /*
419 * Locate icmp6 structure in mbuf, and check
420 * that not corrupted and of at least minimum length
421 */
422
423 ip6 = mtod(m, struct ip6_hdr *);
424 if (icmp6len < sizeof(struct icmp6_hdr)) {
425 V_icmp6stat.icp6s_tooshort++;
426 goto freeit;
427 }
428
429 /*
430 * calculate the checksum
431 */
432 #ifndef PULLDOWN_TEST
433 icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
434 #else
435 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
436 if (icmp6 == NULL) {
437 V_icmp6stat.icp6s_tooshort++;
438 return IPPROTO_DONE;
439 }
440 #endif
441 code = icmp6->icmp6_code;
442
443 if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
444 nd6log((LOG_ERR,
445 "ICMP6 checksum error(%d|%x) %s\n",
446 icmp6->icmp6_type, sum,
447 ip6_sprintf(ip6bufs, &ip6->ip6_src)));
448 V_icmp6stat.icp6s_checksum++;
449 goto freeit;
450 }
451
452 if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
453 /*
454 * Deliver very specific ICMP6 type only.
455 * This is important to deliver TOOBIG. Otherwise PMTUD
456 * will not work.
457 */
458 switch (icmp6->icmp6_type) {
459 case ICMP6_DST_UNREACH:
460 case ICMP6_PACKET_TOO_BIG:
461 case ICMP6_TIME_EXCEEDED:
462 break;
463 default:
464 goto freeit;
465 }
466 }
467
468 V_icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
469 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
470 if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
471 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
472
473 switch (icmp6->icmp6_type) {
474 case ICMP6_DST_UNREACH:
475 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
476 switch (code) {
477 case ICMP6_DST_UNREACH_NOROUTE:
478 code = PRC_UNREACH_NET;
479 break;
480 case ICMP6_DST_UNREACH_ADMIN:
481 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
482 code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
483 break;
484 case ICMP6_DST_UNREACH_ADDR:
485 code = PRC_HOSTDEAD;
486 break;
487 case ICMP6_DST_UNREACH_BEYONDSCOPE:
488 /* I mean "source address was incorrect." */
489 code = PRC_PARAMPROB;
490 break;
491 case ICMP6_DST_UNREACH_NOPORT:
492 code = PRC_UNREACH_PORT;
493 break;
494 default:
495 goto badcode;
496 }
497 goto deliver;
498 break;
499
500 case ICMP6_PACKET_TOO_BIG:
501 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
502
503 /* validation is made in icmp6_mtudisc_update */
504
505 code = PRC_MSGSIZE;
506
507 /*
508 * Updating the path MTU will be done after examining
509 * intermediate extension headers.
510 */
511 goto deliver;
512 break;
513
514 case ICMP6_TIME_EXCEEDED:
515 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);
516 switch (code) {
517 case ICMP6_TIME_EXCEED_TRANSIT:
518 code = PRC_TIMXCEED_INTRANS;
519 break;
520 case ICMP6_TIME_EXCEED_REASSEMBLY:
521 code = PRC_TIMXCEED_REASS;
522 break;
523 default:
524 goto badcode;
525 }
526 goto deliver;
527 break;
528
529 case ICMP6_PARAM_PROB:
530 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);
531 switch (code) {
532 case ICMP6_PARAMPROB_NEXTHEADER:
533 code = PRC_UNREACH_PROTOCOL;
534 break;
535 case ICMP6_PARAMPROB_HEADER:
536 case ICMP6_PARAMPROB_OPTION:
537 code = PRC_PARAMPROB;
538 break;
539 default:
540 goto badcode;
541 }
542 goto deliver;
543 break;
544
545 case ICMP6_ECHO_REQUEST:
546 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);
547 if (code != 0)
548 goto badcode;
549 if ((n = m_copy(m, 0, M_COPYALL)) == NULL) {
550 /* Give up remote */
551 break;
552 }
553 if ((n->m_flags & M_EXT) != 0
554 || n->m_len < off + sizeof(struct icmp6_hdr)) {
555 struct mbuf *n0 = n;
556 const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
557 int n0len;
558
559 MGETHDR(n, M_DONTWAIT, n0->m_type);
560 n0len = n0->m_pkthdr.len; /* save for use below */
561 if (n)
562 M_MOVE_PKTHDR(n, n0);
563 if (n && maxlen >= MHLEN) {
564 MCLGET(n, M_DONTWAIT);
565 if ((n->m_flags & M_EXT) == 0) {
566 m_free(n);
567 n = NULL;
568 }
569 }
570 if (n == NULL) {
571 /* Give up remote */
572 m_freem(n0);
573 break;
574 }
575 /*
576 * Copy IPv6 and ICMPv6 only.
577 */
578 nip6 = mtod(n, struct ip6_hdr *);
579 bcopy(ip6, nip6, sizeof(struct ip6_hdr));
580 nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
581 bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
582 noff = sizeof(struct ip6_hdr);
583 /* new mbuf contains only ipv6+icmpv6 headers */
584 n->m_len = noff + sizeof(struct icmp6_hdr);
585 /*
586 * Adjust mbuf. ip6_plen will be adjusted in
587 * ip6_output().
588 */
589 m_adj(n0, off + sizeof(struct icmp6_hdr));
590 /* recalculate complete packet size */
591 n->m_pkthdr.len = n0len + (noff - off);
592 n->m_next = n0;
593 } else {
594 nip6 = mtod(n, struct ip6_hdr *);
595 IP6_EXTHDR_GET(nicmp6, struct icmp6_hdr *, n, off,
596 sizeof(*nicmp6));
597 noff = off;
598 }
599 nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
600 nicmp6->icmp6_code = 0;
601 if (n) {
602 V_icmp6stat.icp6s_reflect++;
603 V_icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
604 icmp6_reflect(n, noff);
605 }
606 break;
607
608 case ICMP6_ECHO_REPLY:
609 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);
610 if (code != 0)
611 goto badcode;
612 break;
613
614 case MLD_LISTENER_QUERY:
615 case MLD_LISTENER_REPORT:
616 if (icmp6len < sizeof(struct mld_hdr))
617 goto badlen;
618 if (icmp6->icmp6_type == MLD_LISTENER_QUERY) /* XXX: ugly... */
619 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
620 else
621 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
622 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
623 /* give up local */
624 mld6_input(m, off);
625 m = NULL;
626 goto freeit;
627 }
628 mld6_input(n, off);
629 /* m stays. */
630 break;
631
632 case MLD_LISTENER_DONE:
633 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone);
634 if (icmp6len < sizeof(struct mld_hdr)) /* necessary? */
635 goto badlen;
636 break; /* nothing to be done in kernel */
637
638 case MLD_MTRACE_RESP:
639 case MLD_MTRACE:
640 /* XXX: these two are experimental. not officially defined. */
641 /* XXX: per-interface statistics? */
642 break; /* just pass it to applications */
643
644 case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */
645 {
646 enum { WRU, FQDN } mode;
647
648 if (!V_icmp6_nodeinfo)
649 break;
650
651 if (icmp6len == sizeof(struct icmp6_hdr) + 4)
652 mode = WRU;
653 else if (icmp6len >= sizeof(struct icmp6_nodeinfo))
654 mode = FQDN;
655 else
656 goto badlen;
657
658 #define hostnamelen strlen(V_hostname)
659 if (mode == FQDN) {
660 #ifndef PULLDOWN_TEST
661 IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
662 IPPROTO_DONE);
663 #endif
664 n = m_copy(m, 0, M_COPYALL);
665 if (n)
666 n = ni6_input(n, off);
667 /* XXX meaningless if n == NULL */
668 noff = sizeof(struct ip6_hdr);
669 } else {
670 u_char *p;
671 int maxlen, maxhlen;
672
673 /*
674 * XXX: this combination of flags is pointless,
675 * but should we keep this for compatibility?
676 */
677 if ((V_icmp6_nodeinfo & 5) != 5)
678 break;
679
680 if (code != 0)
681 goto badcode;
682 maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
683 if (maxlen >= MCLBYTES) {
684 /* Give up remote */
685 break;
686 }
687 MGETHDR(n, M_DONTWAIT, m->m_type);
688 if (n && maxlen > MHLEN) {
689 MCLGET(n, M_DONTWAIT);
690 if ((n->m_flags & M_EXT) == 0) {
691 m_free(n);
692 n = NULL;
693 }
694 }
695 if (n && !m_dup_pkthdr(n, m, M_DONTWAIT)) {
696 /*
697 * Previous code did a blind M_COPY_PKTHDR
698 * and said "just for rcvif". If true, then
699 * we could tolerate the dup failing (due to
700 * the deep copy of the tag chain). For now
701 * be conservative and just fail.
702 */
703 m_free(n);
704 n = NULL;
705 }
706 if (n == NULL) {
707 /* Give up remote */
708 break;
709 }
710 n->m_pkthdr.rcvif = NULL;
711 n->m_len = 0;
712 maxhlen = M_TRAILINGSPACE(n) - maxlen;
713 mtx_lock(&hostname_mtx);
714 if (maxhlen > hostnamelen)
715 maxhlen = hostnamelen;
716 /*
717 * Copy IPv6 and ICMPv6 only.
718 */
719 nip6 = mtod(n, struct ip6_hdr *);
720 bcopy(ip6, nip6, sizeof(struct ip6_hdr));
721 nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
722 bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
723 p = (u_char *)(nicmp6 + 1);
724 bzero(p, 4);
725 bcopy(V_hostname, p + 4, maxhlen); /* meaningless TTL */
726 mtx_unlock(&hostname_mtx);
727 noff = sizeof(struct ip6_hdr);
728 n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
729 sizeof(struct icmp6_hdr) + 4 + maxhlen;
730 nicmp6->icmp6_type = ICMP6_WRUREPLY;
731 nicmp6->icmp6_code = 0;
732 }
733 #undef hostnamelen
734 if (n) {
735 V_icmp6stat.icp6s_reflect++;
736 V_icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;
737 icmp6_reflect(n, noff);
738 }
739 break;
740 }
741
742 case ICMP6_WRUREPLY:
743 if (code != 0)
744 goto badcode;
745 break;
746
747 case ND_ROUTER_SOLICIT:
748 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);
749 if (code != 0)
750 goto badcode;
751 if (icmp6len < sizeof(struct nd_router_solicit))
752 goto badlen;
753 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
754 /* give up local */
755 nd6_rs_input(m, off, icmp6len);
756 m = NULL;
757 goto freeit;
758 }
759 nd6_rs_input(n, off, icmp6len);
760 /* m stays. */
761 break;
762
763 case ND_ROUTER_ADVERT:
764 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);
765 if (code != 0)
766 goto badcode;
767 if (icmp6len < sizeof(struct nd_router_advert))
768 goto badlen;
769 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
770 /* give up local */
771 nd6_ra_input(m, off, icmp6len);
772 m = NULL;
773 goto freeit;
774 }
775 nd6_ra_input(n, off, icmp6len);
776 /* m stays. */
777 break;
778
779 case ND_NEIGHBOR_SOLICIT:
780 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);
781 if (code != 0)
782 goto badcode;
783 if (icmp6len < sizeof(struct nd_neighbor_solicit))
784 goto badlen;
785 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
786 /* give up local */
787 nd6_ns_input(m, off, icmp6len);
788 m = NULL;
789 goto freeit;
790 }
791 nd6_ns_input(n, off, icmp6len);
792 /* m stays. */
793 break;
794
795 case ND_NEIGHBOR_ADVERT:
796 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);
797 if (code != 0)
798 goto badcode;
799 if (icmp6len < sizeof(struct nd_neighbor_advert))
800 goto badlen;
801 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
802 /* give up local */
803 nd6_na_input(m, off, icmp6len);
804 m = NULL;
805 goto freeit;
806 }
807 nd6_na_input(n, off, icmp6len);
808 /* m stays. */
809 break;
810
811 case ND_REDIRECT:
812 icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);
813 if (code != 0)
814 goto badcode;
815 if (icmp6len < sizeof(struct nd_redirect))
816 goto badlen;
817 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
818 /* give up local */
819 icmp6_redirect_input(m, off);
820 m = NULL;
821 goto freeit;
822 }
823 icmp6_redirect_input(n, off);
824 /* m stays. */
825 break;
826
827 case ICMP6_ROUTER_RENUMBERING:
828 if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
829 code != ICMP6_ROUTER_RENUMBERING_RESULT)
830 goto badcode;
831 if (icmp6len < sizeof(struct icmp6_router_renum))
832 goto badlen;
833 break;
834
835 default:
836 nd6log((LOG_DEBUG,
837 "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
838 icmp6->icmp6_type, ip6_sprintf(ip6bufs, &ip6->ip6_src),
839 ip6_sprintf(ip6bufd, &ip6->ip6_dst),
840 m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0));
841 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
842 /* ICMPv6 error: MUST deliver it by spec... */
843 code = PRC_NCMDS;
844 /* deliver */
845 } else {
846 /* ICMPv6 informational: MUST not deliver */
847 break;
848 }
849 deliver:
850 if (icmp6_notify_error(&m, off, icmp6len, code)) {
851 /* In this case, m should've been freed. */
852 return (IPPROTO_DONE);
853 }
854 break;
855
856 badcode:
857 V_icmp6stat.icp6s_badcode++;
858 break;
859
860 badlen:
861 V_icmp6stat.icp6s_badlen++;
862 break;
863 }
864
865 /* deliver the packet to appropriate sockets */
866 icmp6_rip6_input(&m, *offp);
867
868 return IPPROTO_DONE;
869
870 freeit:
871 m_freem(m);
872 return IPPROTO_DONE;
873 }
874
875 static int
876 icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code)
877 {
878 INIT_VNET_INET6(curvnet);
879 struct mbuf *m = *mp;
880 struct icmp6_hdr *icmp6;
881 struct ip6_hdr *eip6;
882 u_int32_t notifymtu;
883 struct sockaddr_in6 icmp6src, icmp6dst;
884
885 if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
886 V_icmp6stat.icp6s_tooshort++;
887 goto freeit;
888 }
889 #ifndef PULLDOWN_TEST
890 IP6_EXTHDR_CHECK(m, off,
891 sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), -1);
892 icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
893 #else
894 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
895 sizeof(*icmp6) + sizeof(struct ip6_hdr));
896 if (icmp6 == NULL) {
897 V_icmp6stat.icp6s_tooshort++;
898 return (-1);
899 }
900 #endif
901 eip6 = (struct ip6_hdr *)(icmp6 + 1);
902
903 /* Detect the upper level protocol */
904 {
905 void (*ctlfunc)(int, struct sockaddr *, void *);
906 u_int8_t nxt = eip6->ip6_nxt;
907 int eoff = off + sizeof(struct icmp6_hdr) +
908 sizeof(struct ip6_hdr);
909 struct ip6ctlparam ip6cp;
910 struct in6_addr *finaldst = NULL;
911 int icmp6type = icmp6->icmp6_type;
912 struct ip6_frag *fh;
913 struct ip6_rthdr *rth;
914 struct ip6_rthdr0 *rth0;
915 int rthlen;
916
917 while (1) { /* XXX: should avoid infinite loop explicitly? */
918 struct ip6_ext *eh;
919
920 switch (nxt) {
921 case IPPROTO_HOPOPTS:
922 case IPPROTO_DSTOPTS:
923 case IPPROTO_AH:
924 #ifndef PULLDOWN_TEST
925 IP6_EXTHDR_CHECK(m, 0,
926 eoff + sizeof(struct ip6_ext), -1);
927 eh = (struct ip6_ext *)(mtod(m, caddr_t) + eoff);
928 #else
929 IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
930 eoff, sizeof(*eh));
931 if (eh == NULL) {
932 V_icmp6stat.icp6s_tooshort++;
933 return (-1);
934 }
935 #endif
936
937 if (nxt == IPPROTO_AH)
938 eoff += (eh->ip6e_len + 2) << 2;
939 else
940 eoff += (eh->ip6e_len + 1) << 3;
941 nxt = eh->ip6e_nxt;
942 break;
943 case IPPROTO_ROUTING:
944 /*
945 * When the erroneous packet contains a
946 * routing header, we should examine the
947 * header to determine the final destination.
948 * Otherwise, we can't properly update
949 * information that depends on the final
950 * destination (e.g. path MTU).
951 */
952 #ifndef PULLDOWN_TEST
953 IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth), -1);
954 rth = (struct ip6_rthdr *)
955 (mtod(m, caddr_t) + eoff);
956 #else
957 IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
958 eoff, sizeof(*rth));
959 if (rth == NULL) {
960 V_icmp6stat.icp6s_tooshort++;
961 return (-1);
962 }
963 #endif
964 rthlen = (rth->ip6r_len + 1) << 3;
965 /*
966 * XXX: currently there is no
967 * officially defined type other
968 * than type-0.
969 * Note that if the segment left field
970 * is 0, all intermediate hops must
971 * have been passed.
972 */
973 if (rth->ip6r_segleft &&
974 rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
975 int hops;
976
977 #ifndef PULLDOWN_TEST
978 IP6_EXTHDR_CHECK(m, 0, eoff + rthlen, -1);
979 rth0 = (struct ip6_rthdr0 *)
980 (mtod(m, caddr_t) + eoff);
981 #else
982 IP6_EXTHDR_GET(rth0,
983 struct ip6_rthdr0 *, m,
984 eoff, rthlen);
985 if (rth0 == NULL) {
986 V_icmp6stat.icp6s_tooshort++;
987 return (-1);
988 }
989 #endif
990 /* just ignore a bogus header */
991 if ((rth0->ip6r0_len % 2) == 0 &&
992 (hops = rth0->ip6r0_len/2))
993 finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
994 }
995 eoff += rthlen;
996 nxt = rth->ip6r_nxt;
997 break;
998 case IPPROTO_FRAGMENT:
999 #ifndef PULLDOWN_TEST
1000 IP6_EXTHDR_CHECK(m, 0, eoff +
1001 sizeof(struct ip6_frag), -1);
1002 fh = (struct ip6_frag *)(mtod(m, caddr_t) +
1003 eoff);
1004 #else
1005 IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
1006 eoff, sizeof(*fh));
1007 if (fh == NULL) {
1008 V_icmp6stat.icp6s_tooshort++;
1009 return (-1);
1010 }
1011 #endif
|