Line data Source code
1 : /* $OpenBSD: icmp6.c,v 1.226 2018/09/05 09:47:18 miko Exp $ */
2 : /* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
3 :
4 : /*
5 : * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. Neither the name of the project nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : */
32 :
33 : /*
34 : * Copyright (c) 1982, 1986, 1988, 1993
35 : * The Regents of the University of California. All rights reserved.
36 : *
37 : * Redistribution and use in source and binary forms, with or without
38 : * modification, are permitted provided that the following conditions
39 : * are met:
40 : * 1. Redistributions of source code must retain the above copyright
41 : * notice, this list of conditions and the following disclaimer.
42 : * 2. Redistributions in binary form must reproduce the above copyright
43 : * notice, this list of conditions and the following disclaimer in the
44 : * documentation and/or other materials provided with the distribution.
45 : * 3. Neither the name of the University nor the names of its contributors
46 : * may be used to endorse or promote products derived from this software
47 : * without specific prior written permission.
48 : *
49 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 : * SUCH DAMAGE.
60 : *
61 : * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
62 : */
63 :
64 : #include "carp.h"
65 : #include "pf.h"
66 :
67 : #include <sys/param.h>
68 : #include <sys/systm.h>
69 : #include <sys/malloc.h>
70 : #include <sys/mbuf.h>
71 : #include <sys/sysctl.h>
72 : #include <sys/protosw.h>
73 : #include <sys/socket.h>
74 : #include <sys/socketvar.h>
75 : #include <sys/time.h>
76 : #include <sys/kernel.h>
77 : #include <sys/syslog.h>
78 : #include <sys/domain.h>
79 :
80 : #include <net/if.h>
81 : #include <net/if_var.h>
82 : #include <net/route.h>
83 : #include <net/if_dl.h>
84 : #include <net/if_types.h>
85 :
86 : #include <netinet/in.h>
87 : #include <netinet/ip.h>
88 : #include <netinet6/in6_var.h>
89 : #include <netinet/ip6.h>
90 : #include <netinet6/ip6_var.h>
91 : #include <netinet/icmp6.h>
92 : #include <netinet6/mld6_var.h>
93 : #include <netinet/in_pcb.h>
94 : #include <netinet6/nd6.h>
95 : #include <netinet6/ip6protosw.h>
96 :
97 : #if NCARP > 0
98 : #include <netinet/ip_carp.h>
99 : #endif
100 :
101 : #if NPF > 0
102 : #include <net/pfvar.h>
103 : #endif
104 :
105 : struct cpumem *icmp6counters;
106 :
107 : extern int icmp6errppslim;
108 : static int icmp6errpps_count = 0;
109 : static struct timeval icmp6errppslim_last;
110 :
111 : /*
112 : * List of callbacks to notify when Path MTU changes are made.
113 : */
114 : struct icmp6_mtudisc_callback {
115 : LIST_ENTRY(icmp6_mtudisc_callback) mc_list;
116 : void (*mc_func)(struct sockaddr_in6 *, u_int);
117 : };
118 :
119 : LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks =
120 : LIST_HEAD_INITIALIZER(icmp6_mtudisc_callbacks);
121 :
122 : struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
123 :
124 : /* XXX do these values make any sense? */
125 : static int icmp6_mtudisc_hiwat = 1280;
126 : static int icmp6_mtudisc_lowat = 256;
127 :
128 : /*
129 : * keep track of # of redirect routes.
130 : */
131 : static struct rttimer_queue *icmp6_redirect_timeout_q = NULL;
132 :
133 : /* XXX experimental, turned off */
134 : static int icmp6_redirect_lowat = -1;
135 :
136 : void icmp6_errcount(int, int);
137 : int icmp6_ratelimit(const struct in6_addr *, const int, const int);
138 : const char *icmp6_redirect_diag(struct in6_addr *, struct in6_addr *,
139 : struct in6_addr *);
140 : int icmp6_notify_error(struct mbuf *, int, int, int);
141 : struct rtentry *icmp6_mtudisc_clone(struct sockaddr *, u_int);
142 : void icmp6_mtudisc_timeout(struct rtentry *, struct rttimer *);
143 : void icmp6_redirect_timeout(struct rtentry *, struct rttimer *);
144 :
145 : void
146 0 : icmp6_init(void)
147 : {
148 0 : mld6_init();
149 0 : icmp6_mtudisc_timeout_q = rt_timer_queue_create(ip6_mtudisc_timeout);
150 0 : icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout);
151 0 : icmp6counters = counters_alloc(icp6s_ncounters);
152 0 : }
153 :
154 : void
155 0 : icmp6_errcount(int type, int code)
156 : {
157 : enum icmp6stat_counters c = icp6s_ounknown;
158 :
159 0 : switch (type) {
160 : case ICMP6_DST_UNREACH:
161 0 : switch (code) {
162 : case ICMP6_DST_UNREACH_NOROUTE:
163 : c = icp6s_odst_unreach_noroute;
164 0 : break;
165 : case ICMP6_DST_UNREACH_ADMIN:
166 : c = icp6s_odst_unreach_admin;
167 0 : break;
168 : case ICMP6_DST_UNREACH_BEYONDSCOPE:
169 : c = icp6s_odst_unreach_beyondscope;
170 0 : break;
171 : case ICMP6_DST_UNREACH_ADDR:
172 : c = icp6s_odst_unreach_addr;
173 0 : break;
174 : case ICMP6_DST_UNREACH_NOPORT:
175 : c = icp6s_odst_unreach_noport;
176 0 : break;
177 : }
178 : break;
179 : case ICMP6_PACKET_TOO_BIG:
180 : c = icp6s_opacket_too_big;
181 0 : break;
182 : case ICMP6_TIME_EXCEEDED:
183 0 : switch (code) {
184 : case ICMP6_TIME_EXCEED_TRANSIT:
185 : c = icp6s_otime_exceed_transit;
186 0 : break;
187 : case ICMP6_TIME_EXCEED_REASSEMBLY:
188 : c = icp6s_otime_exceed_reassembly;
189 0 : break;
190 : }
191 : break;
192 : case ICMP6_PARAM_PROB:
193 0 : switch (code) {
194 : case ICMP6_PARAMPROB_HEADER:
195 : c = icp6s_oparamprob_header;
196 0 : break;
197 : case ICMP6_PARAMPROB_NEXTHEADER:
198 : c = icp6s_oparamprob_nextheader;
199 0 : break;
200 : case ICMP6_PARAMPROB_OPTION:
201 : c = icp6s_oparamprob_option;
202 0 : break;
203 : }
204 : break;
205 : case ND_REDIRECT:
206 : c = icp6s_oredirect;
207 0 : break;
208 : }
209 :
210 0 : icmp6stat_inc(c);
211 0 : }
212 :
213 : /*
214 : * Register a Path MTU Discovery callback.
215 : */
216 : void
217 0 : icmp6_mtudisc_callback_register(void (*func)(struct sockaddr_in6 *, u_int))
218 : {
219 : struct icmp6_mtudisc_callback *mc;
220 :
221 0 : LIST_FOREACH(mc, &icmp6_mtudisc_callbacks, mc_list) {
222 0 : if (mc->mc_func == func)
223 0 : return;
224 : }
225 :
226 0 : mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT);
227 0 : if (mc == NULL)
228 0 : panic("icmp6_mtudisc_callback_register");
229 :
230 0 : mc->mc_func = func;
231 0 : LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list);
232 0 : }
233 :
234 : /*
235 : * Generate an error packet of type error in response to bad IP6 packet.
236 : */
237 : void
238 0 : icmp6_error(struct mbuf *m, int type, int code, int param)
239 : {
240 : struct ip6_hdr *oip6, *nip6;
241 : struct icmp6_hdr *icmp6;
242 : u_int preplen;
243 : int off;
244 0 : int nxt;
245 :
246 0 : icmp6stat_inc(icp6s_error);
247 :
248 : /* count per-type-code statistics */
249 0 : icmp6_errcount(type, code);
250 :
251 0 : if (m->m_len < sizeof(struct ip6_hdr)) {
252 0 : m = m_pullup(m, sizeof(struct ip6_hdr));
253 0 : if (m == NULL)
254 0 : return;
255 : }
256 0 : oip6 = mtod(m, struct ip6_hdr *);
257 :
258 : /*
259 : * If the destination address of the erroneous packet is a multicast
260 : * address, or the packet was sent using link-layer multicast,
261 : * we should basically suppress sending an error (RFC 2463, Section
262 : * 2.4).
263 : * We have two exceptions (the item e.2 in that section):
264 : * - the Packet Too Big message can be sent for path MTU discovery.
265 : * - the Parameter Problem Message that can be allowed an icmp6 error
266 : * in the option type field. This check has been done in
267 : * ip6_unknown_opt(), so we can just check the type and code.
268 : */
269 0 : if ((m->m_flags & (M_BCAST|M_MCAST) ||
270 0 : IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
271 0 : (type != ICMP6_PACKET_TOO_BIG &&
272 0 : (type != ICMP6_PARAM_PROB ||
273 0 : code != ICMP6_PARAMPROB_OPTION)))
274 : goto freeit;
275 :
276 : /*
277 : * RFC 2463, 2.4 (e.5): source address check.
278 : * XXX: the case of anycast source?
279 : */
280 0 : if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
281 0 : IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
282 : goto freeit;
283 :
284 : /*
285 : * If we are about to send ICMPv6 against ICMPv6 error/redirect,
286 : * don't do it.
287 : */
288 0 : nxt = -1;
289 0 : off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
290 0 : if (off >= 0 && nxt == IPPROTO_ICMPV6) {
291 : struct icmp6_hdr *icp;
292 :
293 0 : IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
294 : sizeof(*icp));
295 0 : if (icp == NULL) {
296 0 : icmp6stat_inc(icp6s_tooshort);
297 0 : return;
298 : }
299 0 : if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
300 0 : icp->icmp6_type == ND_REDIRECT) {
301 : /*
302 : * ICMPv6 error
303 : * Special case: for redirect (which is
304 : * informational) we must not send icmp6 error.
305 : */
306 0 : icmp6stat_inc(icp6s_canterror);
307 0 : goto freeit;
308 : } else {
309 : /* ICMPv6 informational - send the error */
310 : }
311 0 : }
312 : else {
313 : /* non-ICMPv6 - send the error */
314 : }
315 :
316 0 : oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
317 :
318 : /* Finally, do rate limitation check. */
319 0 : if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
320 0 : icmp6stat_inc(icp6s_toofreq);
321 0 : goto freeit;
322 : }
323 :
324 : /*
325 : * OK, ICMP6 can be generated.
326 : */
327 :
328 0 : if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
329 0 : m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
330 :
331 : preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
332 0 : M_PREPEND(m, preplen, M_DONTWAIT);
333 0 : if (m && m->m_len < preplen)
334 0 : m = m_pullup(m, preplen);
335 0 : if (m == NULL) {
336 0 : nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__));
337 0 : return;
338 : }
339 :
340 0 : nip6 = mtod(m, struct ip6_hdr *);
341 0 : nip6->ip6_src = oip6->ip6_src;
342 0 : nip6->ip6_dst = oip6->ip6_dst;
343 :
344 0 : if (IN6_IS_SCOPE_EMBED(&oip6->ip6_src))
345 0 : oip6->ip6_src.s6_addr16[1] = 0;
346 0 : if (IN6_IS_SCOPE_EMBED(&oip6->ip6_dst))
347 0 : oip6->ip6_dst.s6_addr16[1] = 0;
348 :
349 0 : icmp6 = (struct icmp6_hdr *)(nip6 + 1);
350 0 : icmp6->icmp6_type = type;
351 0 : icmp6->icmp6_code = code;
352 0 : icmp6->icmp6_pptr = htonl((u_int32_t)param);
353 :
354 : /*
355 : * icmp6_reflect() is designed to be in the input path.
356 : * icmp6_error() can be called from both input and outut path,
357 : * and if we are in output path rcvif could contain bogus value.
358 : * clear m->m_pkthdr.ph_ifidx for safety, we should have enough
359 : * scope information in ip header (nip6).
360 : */
361 0 : m->m_pkthdr.ph_ifidx = 0;
362 :
363 0 : icmp6stat_inc(icp6s_outhist + type);
364 0 : icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */
365 :
366 0 : return;
367 :
368 : freeit:
369 : /*
370 : * If we can't tell wheter or not we can generate ICMP6, free it.
371 : */
372 0 : m_freem(m);
373 0 : }
374 :
375 : /*
376 : * Process a received ICMP6 message.
377 : */
378 : int
379 0 : icmp6_input(struct mbuf **mp, int *offp, int proto, int af)
380 : {
381 : #if NCARP > 0
382 : struct ifnet *ifp;
383 : #endif
384 0 : struct mbuf *m = *mp, *n;
385 : struct ip6_hdr *ip6, *nip6;
386 : struct icmp6_hdr *icmp6, *nicmp6;
387 0 : int off = *offp;
388 0 : int icmp6len = m->m_pkthdr.len - *offp;
389 : int code, sum, noff;
390 0 : char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
391 :
392 : /*
393 : * Locate icmp6 structure in mbuf, and check
394 : * that not corrupted and of at least minimum length
395 : */
396 :
397 0 : ip6 = mtod(m, struct ip6_hdr *);
398 0 : if (icmp6len < sizeof(struct icmp6_hdr)) {
399 0 : icmp6stat_inc(icp6s_tooshort);
400 0 : goto freeit;
401 : }
402 :
403 : /*
404 : * calculate the checksum
405 : */
406 0 : IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
407 0 : if (icmp6 == NULL) {
408 0 : icmp6stat_inc(icp6s_tooshort);
409 0 : return IPPROTO_DONE;
410 : }
411 0 : code = icmp6->icmp6_code;
412 :
413 0 : if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
414 0 : nd6log((LOG_ERR,
415 : "ICMP6 checksum error(%d|%x) %s\n",
416 : icmp6->icmp6_type, sum,
417 : inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src))));
418 0 : icmp6stat_inc(icp6s_checksum);
419 0 : goto freeit;
420 : }
421 :
422 : #if NPF > 0
423 0 : if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
424 0 : switch (icmp6->icmp6_type) {
425 : /*
426 : * These ICMP6 types map to other connections. They must be
427 : * delivered to pr_ctlinput() also for diverted connections.
428 : */
429 : case ICMP6_DST_UNREACH:
430 : case ICMP6_PACKET_TOO_BIG:
431 : case ICMP6_TIME_EXCEEDED:
432 : case ICMP6_PARAM_PROB:
433 : /*
434 : * Do not use the divert-to property of the TCP or UDP
435 : * rule when doing the PCB lookup for the raw socket.
436 : */
437 0 : m->m_pkthdr.pf.flags &=~ PF_TAG_DIVERTED;
438 : break;
439 : default:
440 : goto raw;
441 : }
442 0 : }
443 : #endif /* NPF */
444 :
445 : #if NCARP > 0
446 0 : ifp = if_get(m->m_pkthdr.ph_ifidx);
447 0 : if (ifp == NULL)
448 : goto freeit;
449 :
450 0 : if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST &&
451 0 : carp_lsdrop(ifp, m, AF_INET6, ip6->ip6_src.s6_addr32,
452 0 : ip6->ip6_dst.s6_addr32, 1)) {
453 0 : if_put(ifp);
454 0 : goto freeit;
455 : }
456 :
457 0 : if_put(ifp);
458 : #endif
459 0 : icmp6stat_inc(icp6s_inhist + icmp6->icmp6_type);
460 :
461 0 : switch (icmp6->icmp6_type) {
462 : case ICMP6_DST_UNREACH:
463 0 : switch (code) {
464 : case ICMP6_DST_UNREACH_NOROUTE:
465 : code = PRC_UNREACH_NET;
466 0 : break;
467 : case ICMP6_DST_UNREACH_ADMIN:
468 : code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
469 0 : break;
470 : case ICMP6_DST_UNREACH_ADDR:
471 : code = PRC_HOSTDEAD;
472 0 : break;
473 : case ICMP6_DST_UNREACH_BEYONDSCOPE:
474 : /* I mean "source address was incorrect." */
475 : code = PRC_PARAMPROB;
476 0 : break;
477 : case ICMP6_DST_UNREACH_NOPORT:
478 : code = PRC_UNREACH_PORT;
479 0 : break;
480 : default:
481 : goto badcode;
482 : }
483 : goto deliver;
484 :
485 : case ICMP6_PACKET_TOO_BIG:
486 : /* MTU is checked in icmp6_mtudisc_update. */
487 : code = PRC_MSGSIZE;
488 :
489 : /*
490 : * Updating the path MTU will be done after examining
491 : * intermediate extension headers.
492 : */
493 0 : goto deliver;
494 :
495 : case ICMP6_TIME_EXCEEDED:
496 0 : switch (code) {
497 : case ICMP6_TIME_EXCEED_TRANSIT:
498 : code = PRC_TIMXCEED_INTRANS;
499 0 : break;
500 : case ICMP6_TIME_EXCEED_REASSEMBLY:
501 : code = PRC_TIMXCEED_REASS;
502 0 : break;
503 : default:
504 : goto badcode;
505 : }
506 : goto deliver;
507 :
508 : case ICMP6_PARAM_PROB:
509 0 : switch (code) {
510 : case ICMP6_PARAMPROB_NEXTHEADER:
511 : code = PRC_UNREACH_PROTOCOL;
512 0 : break;
513 : case ICMP6_PARAMPROB_HEADER:
514 : case ICMP6_PARAMPROB_OPTION:
515 : code = PRC_PARAMPROB;
516 0 : break;
517 : default:
518 : goto badcode;
519 : }
520 : goto deliver;
521 :
522 : case ICMP6_ECHO_REQUEST:
523 0 : if (code != 0)
524 : goto badcode;
525 : /*
526 : * Copy mbuf to send to two data paths: userland socket(s),
527 : * and to the querier (echo reply).
528 : * m: a copy for socket, n: a copy for querier
529 : */
530 0 : if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
531 : /* Give up local */
532 : n = m;
533 0 : m = *mp = NULL;
534 0 : goto deliverecho;
535 : }
536 : /*
537 : * If the first mbuf is shared, or the first mbuf is too short,
538 : * copy the first part of the data into a fresh mbuf.
539 : * Otherwise, we will wrongly overwrite both copies.
540 : */
541 0 : if ((n->m_flags & M_EXT) != 0 ||
542 0 : n->m_len < off + sizeof(struct icmp6_hdr)) {
543 : struct mbuf *n0 = n;
544 : const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
545 :
546 : /*
547 : * Prepare an internal mbuf. m_pullup() doesn't
548 : * always copy the length we specified.
549 : */
550 : if (maxlen >= MCLBYTES) {
551 : /* Give up remote */
552 : m_freem(n0);
553 : break;
554 : }
555 0 : MGETHDR(n, M_DONTWAIT, n0->m_type);
556 : if (n && maxlen >= MHLEN) {
557 : MCLGET(n, M_DONTWAIT);
558 : if ((n->m_flags & M_EXT) == 0) {
559 : m_free(n);
560 : n = NULL;
561 : }
562 : }
563 0 : if (n == NULL) {
564 : /* Give up local */
565 0 : m_freem(n0);
566 : n = m;
567 0 : m = *mp = NULL;
568 0 : goto deliverecho;
569 : }
570 0 : M_MOVE_PKTHDR(n, n0);
571 : /*
572 : * Copy IPv6 and ICMPv6 only.
573 : */
574 0 : nip6 = mtod(n, struct ip6_hdr *);
575 0 : bcopy(ip6, nip6, sizeof(struct ip6_hdr));
576 0 : nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
577 0 : bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
578 : noff = sizeof(struct ip6_hdr);
579 0 : n->m_len = noff + sizeof(struct icmp6_hdr);
580 : /*
581 : * Adjust mbuf. ip6_plen will be adjusted in
582 : * ip6_output().
583 : * n->m_pkthdr.len == n0->m_pkthdr.len at this point.
584 : */
585 0 : n->m_pkthdr.len += noff + sizeof(struct icmp6_hdr);
586 0 : n->m_pkthdr.len -= (off + sizeof(struct icmp6_hdr));
587 0 : m_adj(n0, off + sizeof(struct icmp6_hdr));
588 0 : n->m_next = n0;
589 0 : } else {
590 : deliverecho:
591 0 : IP6_EXTHDR_GET(nicmp6, struct icmp6_hdr *, n, off,
592 : sizeof(*nicmp6));
593 : noff = off;
594 : }
595 0 : if (n) {
596 0 : nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
597 0 : nicmp6->icmp6_code = 0;
598 0 : icmp6stat_inc(icp6s_reflect);
599 0 : icmp6stat_inc(icp6s_outhist + ICMP6_ECHO_REPLY);
600 0 : icmp6_reflect(n, noff);
601 0 : }
602 0 : if (!m)
603 : goto freeit;
604 : break;
605 :
606 : case ICMP6_ECHO_REPLY:
607 0 : if (code != 0)
608 : goto badcode;
609 : break;
610 :
611 : case MLD_LISTENER_QUERY:
612 : case MLD_LISTENER_REPORT:
613 0 : if (icmp6len < sizeof(struct mld_hdr))
614 : goto badlen;
615 0 : if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
616 : /* give up local */
617 0 : mld6_input(m, off);
618 : m = NULL;
619 0 : goto freeit;
620 : }
621 0 : mld6_input(n, off);
622 : /* m stays. */
623 0 : break;
624 :
625 : case MLD_LISTENER_DONE:
626 0 : if (icmp6len < sizeof(struct mld_hdr)) /* necessary? */
627 : goto badlen;
628 : break; /* nothing to be done in kernel */
629 :
630 : case MLD_MTRACE_RESP:
631 : case MLD_MTRACE:
632 : /* XXX: these two are experimental. not officially defined. */
633 : /* XXX: per-interface statistics? */
634 : break; /* just pass it to applications */
635 :
636 : case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */
637 : /* IPv6 Node Information Queries are not supported */
638 : break;
639 : case ICMP6_WRUREPLY:
640 : break;
641 :
642 : case ND_ROUTER_SOLICIT:
643 : case ND_ROUTER_ADVERT:
644 0 : if (code != 0)
645 : goto badcode;
646 0 : if ((icmp6->icmp6_type == ND_ROUTER_SOLICIT && icmp6len <
647 0 : sizeof(struct nd_router_solicit)) ||
648 0 : (icmp6->icmp6_type == ND_ROUTER_ADVERT && icmp6len <
649 : sizeof(struct nd_router_advert)))
650 : goto badlen;
651 :
652 0 : if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
653 : /* give up local */
654 0 : nd6_rtr_cache(m, off, icmp6len,
655 0 : icmp6->icmp6_type);
656 : m = NULL;
657 0 : goto freeit;
658 : }
659 0 : nd6_rtr_cache(n, off, icmp6len, icmp6->icmp6_type);
660 : /* m stays. */
661 0 : break;
662 :
663 : case ND_NEIGHBOR_SOLICIT:
664 0 : if (code != 0)
665 : goto badcode;
666 0 : if (icmp6len < sizeof(struct nd_neighbor_solicit))
667 : goto badlen;
668 0 : if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
669 : /* give up local */
670 0 : nd6_ns_input(m, off, icmp6len);
671 : m = NULL;
672 0 : goto freeit;
673 : }
674 0 : nd6_ns_input(n, off, icmp6len);
675 : /* m stays. */
676 0 : break;
677 :
678 : case ND_NEIGHBOR_ADVERT:
679 0 : if (code != 0)
680 : goto badcode;
681 0 : if (icmp6len < sizeof(struct nd_neighbor_advert))
682 : goto badlen;
683 0 : if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
684 : /* give up local */
685 0 : nd6_na_input(m, off, icmp6len);
686 : m = NULL;
687 0 : goto freeit;
688 : }
689 0 : nd6_na_input(n, off, icmp6len);
690 : /* m stays. */
691 0 : break;
692 :
693 : case ND_REDIRECT:
694 0 : if (code != 0)
695 : goto badcode;
696 0 : if (icmp6len < sizeof(struct nd_redirect))
697 : goto badlen;
698 0 : if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
699 : /* give up local */
700 0 : icmp6_redirect_input(m, off);
701 : m = NULL;
702 0 : goto freeit;
703 : }
704 0 : icmp6_redirect_input(n, off);
705 : /* m stays. */
706 0 : break;
707 :
708 : case ICMP6_ROUTER_RENUMBERING:
709 0 : if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
710 0 : code != ICMP6_ROUTER_RENUMBERING_RESULT)
711 : goto badcode;
712 0 : if (icmp6len < sizeof(struct icmp6_router_renum))
713 : goto badlen;
714 : break;
715 :
716 : default:
717 0 : nd6log((LOG_DEBUG,
718 : "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%u)\n",
719 : icmp6->icmp6_type,
720 : inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src)),
721 : inet_ntop(AF_INET6, &ip6->ip6_dst, dst, sizeof(dst)),
722 : m->m_pkthdr.ph_ifidx));
723 0 : if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
724 : /* ICMPv6 error: MUST deliver it by spec... */
725 : code = PRC_NCMDS;
726 : /* deliver */
727 : } else {
728 : /* ICMPv6 informational: MUST not deliver */
729 : break;
730 : }
731 : deliver:
732 0 : if (icmp6_notify_error(m, off, icmp6len, code)) {
733 : /* In this case, m should've been freed. */
734 0 : return (IPPROTO_DONE);
735 : }
736 : break;
737 :
738 : badcode:
739 0 : icmp6stat_inc(icp6s_badcode);
740 0 : break;
741 :
742 : badlen:
743 0 : icmp6stat_inc(icp6s_badlen);
744 0 : break;
745 : }
746 :
747 : #if NPF > 0
748 : raw:
749 : #endif
750 : /* deliver the packet to appropriate sockets */
751 0 : return rip6_input(mp, offp, proto, af);
752 :
753 : freeit:
754 0 : m_freem(m);
755 0 : return IPPROTO_DONE;
756 0 : }
757 :
758 : int
759 0 : icmp6_notify_error(struct mbuf *m, int off, int icmp6len, int code)
760 : {
761 : struct icmp6_hdr *icmp6;
762 : struct ip6_hdr *eip6;
763 0 : u_int32_t notifymtu;
764 0 : struct sockaddr_in6 icmp6src, icmp6dst;
765 :
766 0 : if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
767 0 : icmp6stat_inc(icp6s_tooshort);
768 0 : goto freeit;
769 : }
770 0 : IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
771 : sizeof(*icmp6) + sizeof(struct ip6_hdr));
772 0 : if (icmp6 == NULL) {
773 0 : icmp6stat_inc(icp6s_tooshort);
774 0 : return (-1);
775 : }
776 0 : eip6 = (struct ip6_hdr *)(icmp6 + 1);
777 :
778 : /* Detect the upper level protocol */
779 : {
780 : void (*ctlfunc)(int, struct sockaddr *, u_int, void *);
781 0 : u_int8_t nxt = eip6->ip6_nxt;
782 0 : int eoff = off + sizeof(struct icmp6_hdr) +
783 : sizeof(struct ip6_hdr);
784 0 : struct ip6ctlparam ip6cp;
785 : struct in6_addr *finaldst = NULL;
786 0 : int icmp6type = icmp6->icmp6_type;
787 : struct ip6_frag *fh;
788 : struct ip6_rthdr *rth;
789 : struct ip6_rthdr0 *rth0;
790 : int rthlen;
791 :
792 0 : while (1) { /* XXX: should avoid infinite loop explicitly? */
793 : struct ip6_ext *eh;
794 :
795 0 : switch (nxt) {
796 : case IPPROTO_HOPOPTS:
797 : case IPPROTO_DSTOPTS:
798 : case IPPROTO_AH:
799 0 : IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
800 : eoff, sizeof(*eh));
801 0 : if (eh == NULL) {
802 0 : icmp6stat_inc(icp6s_tooshort);
803 0 : return (-1);
804 : }
805 :
806 0 : if (nxt == IPPROTO_AH)
807 0 : eoff += (eh->ip6e_len + 2) << 2;
808 : else
809 0 : eoff += (eh->ip6e_len + 1) << 3;
810 0 : nxt = eh->ip6e_nxt;
811 0 : break;
812 : case IPPROTO_ROUTING:
813 : /*
814 : * When the erroneous packet contains a
815 : * routing header, we should examine the
816 : * header to determine the final destination.
817 : * Otherwise, we can't properly update
818 : * information that depends on the final
819 : * destination (e.g. path MTU).
820 : */
821 0 : IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
822 : eoff, sizeof(*rth));
823 0 : if (rth == NULL) {
824 0 : icmp6stat_inc(icp6s_tooshort);
825 0 : return (-1);
826 : }
827 0 : rthlen = (rth->ip6r_len + 1) << 3;
828 : /*
829 : * XXX: currently there is no
830 : * officially defined type other
831 : * than type-0.
832 : * Note that if the segment left field
833 : * is 0, all intermediate hops must
834 : * have been passed.
835 : */
836 0 : if (rth->ip6r_segleft &&
837 0 : rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
838 : int hops;
839 :
840 0 : IP6_EXTHDR_GET(rth0,
841 : struct ip6_rthdr0 *, m,
842 : eoff, rthlen);
843 0 : if (rth0 == NULL) {
844 0 : icmp6stat_inc(icp6s_tooshort);
845 0 : return (-1);
846 : }
847 : /* just ignore a bogus header */
848 0 : if ((rth0->ip6r0_len % 2) == 0 &&
849 0 : (hops = rth0->ip6r0_len/2))
850 0 : finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
851 0 : }
852 0 : eoff += rthlen;
853 0 : nxt = rth->ip6r_nxt;
854 0 : break;
855 : case IPPROTO_FRAGMENT:
856 0 : IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
857 : eoff, sizeof(*fh));
858 0 : if (fh == NULL) {
859 0 : icmp6stat_inc(icp6s_tooshort);
860 0 : return (-1);
861 : }
862 : /*
863 : * Data after a fragment header is meaningless
864 : * unless it is the first fragment, but
865 : * we'll go to the notify label for path MTU
866 : * discovery.
867 : */
868 0 : if (fh->ip6f_offlg & IP6F_OFF_MASK)
869 0 : goto notify;
870 :
871 0 : eoff += sizeof(struct ip6_frag);
872 0 : nxt = fh->ip6f_nxt;
873 0 : break;
874 : default:
875 : /*
876 : * This case includes ESP and the No Next
877 : * Header. In such cases going to the notify
878 : * label does not have any meaning
879 : * (i.e. ctlfunc will be NULL), but we go
880 : * anyway since we might have to update
881 : * path MTU information.
882 : */
883 0 : goto notify;
884 : }
885 0 : }
886 : notify:
887 0 : IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
888 : sizeof(*icmp6) + sizeof(struct ip6_hdr));
889 0 : if (icmp6 == NULL) {
890 0 : icmp6stat_inc(icp6s_tooshort);
891 0 : return (-1);
892 : }
893 :
894 0 : eip6 = (struct ip6_hdr *)(icmp6 + 1);
895 0 : bzero(&icmp6dst, sizeof(icmp6dst));
896 0 : icmp6dst.sin6_len = sizeof(struct sockaddr_in6);
897 0 : icmp6dst.sin6_family = AF_INET6;
898 0 : if (finaldst == NULL)
899 0 : icmp6dst.sin6_addr = eip6->ip6_dst;
900 : else
901 0 : icmp6dst.sin6_addr = *finaldst;
902 0 : icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
903 : &icmp6dst.sin6_addr);
904 0 : if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst, NULL)) {
905 : /* should be impossbile */
906 0 : nd6log((LOG_DEBUG,
907 : "icmp6_notify_error: in6_embedscope failed\n"));
908 0 : goto freeit;
909 : }
910 :
911 : /*
912 : * retrieve parameters from the inner IPv6 header, and convert
913 : * them into sockaddr structures.
914 : */
915 0 : bzero(&icmp6src, sizeof(icmp6src));
916 0 : icmp6src.sin6_len = sizeof(struct sockaddr_in6);
917 0 : icmp6src.sin6_family = AF_INET6;
918 0 : icmp6src.sin6_addr = eip6->ip6_src;
919 0 : icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
920 : &icmp6src.sin6_addr);
921 0 : if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src, NULL)) {
922 : /* should be impossbile */
923 0 : nd6log((LOG_DEBUG,
924 : "icmp6_notify_error: in6_embedscope failed\n"));
925 0 : goto freeit;
926 : }
927 0 : icmp6src.sin6_flowinfo =
928 0 : (eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
929 :
930 0 : if (finaldst == NULL)
931 0 : finaldst = &eip6->ip6_dst;
932 0 : ip6cp.ip6c_m = m;
933 0 : ip6cp.ip6c_icmp6 = icmp6;
934 0 : ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
935 0 : ip6cp.ip6c_off = eoff;
936 0 : ip6cp.ip6c_finaldst = finaldst;
937 0 : ip6cp.ip6c_src = &icmp6src;
938 0 : ip6cp.ip6c_nxt = nxt;
939 : #if NPF > 0
940 0 : pf_pkt_addr_changed(m);
941 : #endif
942 :
943 0 : if (icmp6type == ICMP6_PACKET_TOO_BIG) {
944 0 : notifymtu = ntohl(icmp6->icmp6_mtu);
945 0 : ip6cp.ip6c_cmdarg = (void *)¬ifymtu;
946 0 : }
947 :
948 0 : ctlfunc = inet6sw[ip6_protox[nxt]].pr_ctlinput;
949 0 : if (ctlfunc)
950 0 : (*ctlfunc)(code, sin6tosa(&icmp6dst),
951 0 : m->m_pkthdr.ph_rtableid, &ip6cp);
952 0 : }
953 0 : return (0);
954 :
955 : freeit:
956 0 : m_freem(m);
957 0 : return (-1);
958 0 : }
959 :
960 : void
961 0 : icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated)
962 : {
963 : unsigned long rtcount;
964 : struct icmp6_mtudisc_callback *mc;
965 0 : struct in6_addr *dst = ip6cp->ip6c_finaldst;
966 0 : struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6;
967 0 : struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */
968 0 : u_int mtu = ntohl(icmp6->icmp6_mtu);
969 : struct rtentry *rt = NULL;
970 0 : struct sockaddr_in6 sin6;
971 :
972 0 : if (mtu < IPV6_MMTU)
973 0 : return;
974 :
975 : /*
976 : * allow non-validated cases if memory is plenty, to make traffic
977 : * from non-connected pcb happy.
978 : */
979 0 : rtcount = rt_timer_queue_count(icmp6_mtudisc_timeout_q);
980 0 : if (validated) {
981 0 : if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat)
982 0 : return;
983 : else if (0 <= icmp6_mtudisc_lowat &&
984 : rtcount > icmp6_mtudisc_lowat) {
985 : /*
986 : * XXX nuke a victim, install the new one.
987 : */
988 : }
989 : } else {
990 0 : if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat)
991 0 : return;
992 : }
993 :
994 0 : bzero(&sin6, sizeof(sin6));
995 0 : sin6.sin6_family = PF_INET6;
996 0 : sin6.sin6_len = sizeof(struct sockaddr_in6);
997 0 : sin6.sin6_addr = *dst;
998 : /* XXX normally, this won't happen */
999 0 : if (IN6_IS_ADDR_LINKLOCAL(dst)) {
1000 0 : sin6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.ph_ifidx);
1001 0 : }
1002 0 : sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
1003 : &sin6.sin6_addr);
1004 :
1005 0 : rt = icmp6_mtudisc_clone(sin6tosa(&sin6), m->m_pkthdr.ph_rtableid);
1006 :
1007 0 : if (rt != NULL && ISSET(rt->rt_flags, RTF_HOST) &&
1008 0 : !(rt->rt_locks & RTV_MTU) &&
1009 0 : (rt->rt_mtu > mtu || rt->rt_mtu == 0)) {
1010 : struct ifnet *ifp;
1011 :
1012 0 : ifp = if_get(rt->rt_ifidx);
1013 0 : if (ifp != NULL && mtu < ifp->if_mtu) {
1014 0 : icmp6stat_inc(icp6s_pmtuchg);
1015 0 : rt->rt_mtu = mtu;
1016 0 : }
1017 0 : if_put(ifp);
1018 0 : }
1019 0 : rtfree(rt);
1020 :
1021 : /*
1022 : * Notify protocols that the MTU for this destination
1023 : * has changed.
1024 : */
1025 0 : LIST_FOREACH(mc, &icmp6_mtudisc_callbacks, mc_list)
1026 0 : (*mc->mc_func)(&sin6, m->m_pkthdr.ph_rtableid);
1027 0 : }
1028 :
1029 : /*
1030 : * Reflect the ip6 packet back to the source.
1031 : * OFF points to the icmp6 header, counted from the top of the mbuf.
1032 : */
1033 : void
1034 0 : icmp6_reflect(struct mbuf *m, size_t off)
1035 : {
1036 : struct rtentry *rt = NULL;
1037 : struct ip6_hdr *ip6;
1038 : struct icmp6_hdr *icmp6;
1039 0 : struct in6_addr t, *src = NULL;
1040 0 : struct sockaddr_in6 sa6_src, sa6_dst;
1041 : u_int rtableid;
1042 :
1043 : CTASSERT(sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) <= MHLEN);
1044 :
1045 : /* too short to reflect */
1046 0 : if (off < sizeof(struct ip6_hdr)) {
1047 0 : nd6log((LOG_DEBUG,
1048 : "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
1049 : (u_long)off, (u_long)sizeof(struct ip6_hdr),
1050 : __FILE__, __LINE__));
1051 : goto bad;
1052 : }
1053 :
1054 0 : if (m->m_pkthdr.ph_loopcnt++ >= M_MAXLOOP)
1055 : goto bad;
1056 0 : rtableid = m->m_pkthdr.ph_rtableid;
1057 0 : m_resethdr(m);
1058 0 : m->m_pkthdr.ph_rtableid = rtableid;
1059 :
1060 : /*
1061 : * If there are extra headers between IPv6 and ICMPv6, strip
1062 : * off that header first.
1063 : */
1064 0 : if (off > sizeof(struct ip6_hdr)) {
1065 : size_t l;
1066 0 : struct ip6_hdr nip6;
1067 :
1068 0 : l = off - sizeof(struct ip6_hdr);
1069 0 : m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
1070 0 : m_adj(m, l);
1071 : l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
1072 0 : if (m->m_len < l) {
1073 0 : if ((m = m_pullup(m, l)) == NULL)
1074 0 : return;
1075 : }
1076 0 : memcpy(mtod(m, caddr_t), &nip6, sizeof(nip6));
1077 0 : } else /* off == sizeof(struct ip6_hdr) */ {
1078 : size_t l;
1079 : l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
1080 0 : if (m->m_len < l) {
1081 0 : if ((m = m_pullup(m, l)) == NULL)
1082 0 : return;
1083 : }
1084 0 : }
1085 0 : ip6 = mtod(m, struct ip6_hdr *);
1086 0 : ip6->ip6_nxt = IPPROTO_ICMPV6;
1087 0 : icmp6 = (struct icmp6_hdr *)(ip6 + 1);
1088 :
1089 0 : t = ip6->ip6_dst;
1090 : /*
1091 : * ip6_input() drops a packet if its src is multicast.
1092 : * So, the src is never multicast.
1093 : */
1094 0 : ip6->ip6_dst = ip6->ip6_src;
1095 :
1096 : /*
1097 : * XXX: make sure to embed scope zone information, using
1098 : * already embedded IDs or the received interface (if any).
1099 : * Note that rcvif may be NULL.
1100 : * TODO: scoped routing case (XXX).
1101 : */
1102 0 : bzero(&sa6_src, sizeof(sa6_src));
1103 0 : sa6_src.sin6_family = AF_INET6;
1104 0 : sa6_src.sin6_len = sizeof(sa6_src);
1105 0 : sa6_src.sin6_addr = ip6->ip6_dst;
1106 0 : bzero(&sa6_dst, sizeof(sa6_dst));
1107 0 : sa6_dst.sin6_family = AF_INET6;
1108 0 : sa6_dst.sin6_len = sizeof(sa6_dst);
1109 0 : sa6_dst.sin6_addr = t;
1110 :
1111 : /*
1112 : * If the incoming packet was addressed directly to us (i.e. unicast),
1113 : * use dst as the src for the reply.
1114 : * The IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED case would be VERY rare,
1115 : * but is possible (for example) when we encounter an error while
1116 : * forwarding procedure destined to a duplicated address of ours.
1117 : */
1118 0 : rt = rtalloc(sin6tosa(&sa6_dst), 0, rtableid);
1119 0 : if (rtisvalid(rt) && ISSET(rt->rt_flags, RTF_LOCAL) &&
1120 0 : !ISSET(ifatoia6(rt->rt_ifa)->ia6_flags,
1121 : IN6_IFF_ANYCAST|IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)) {
1122 : src = &t;
1123 0 : }
1124 0 : rtfree(rt);
1125 : rt = NULL;
1126 :
1127 0 : if (src == NULL) {
1128 : /*
1129 : * This case matches to multicasts, our anycast, or unicasts
1130 : * that we do not own. Select a source address based on the
1131 : * source address of the erroneous packet.
1132 : */
1133 0 : rt = rtalloc(sin6tosa(&sa6_src), RT_RESOLVE, rtableid);
1134 0 : if (!rtisvalid(rt)) {
1135 0 : char addr[INET6_ADDRSTRLEN];
1136 :
1137 0 : nd6log((LOG_DEBUG,
1138 : "%s: source can't be determined: dst=%s\n",
1139 : __func__, inet_ntop(AF_INET6, &sa6_src.sin6_addr,
1140 : addr, sizeof(addr))));
1141 0 : rtfree(rt);
1142 : goto bad;
1143 0 : }
1144 0 : src = &ifatoia6(rt->rt_ifa)->ia_addr.sin6_addr;
1145 0 : }
1146 :
1147 0 : ip6->ip6_src = *src;
1148 0 : rtfree(rt);
1149 :
1150 0 : ip6->ip6_flow = 0;
1151 0 : ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
1152 0 : ip6->ip6_vfc |= IPV6_VERSION;
1153 0 : ip6->ip6_nxt = IPPROTO_ICMPV6;
1154 0 : ip6->ip6_hlim = ip6_defhlim;
1155 :
1156 0 : icmp6->icmp6_cksum = 0;
1157 0 : m->m_pkthdr.csum_flags = M_ICMP_CSUM_OUT;
1158 :
1159 : /*
1160 : * XXX option handling
1161 : */
1162 :
1163 0 : m->m_flags &= ~(M_BCAST|M_MCAST);
1164 :
1165 0 : ip6_send(m);
1166 0 : return;
1167 :
1168 : bad:
1169 0 : m_freem(m);
1170 0 : return;
1171 0 : }
1172 :
1173 : void
1174 0 : icmp6_fasttimo(void)
1175 : {
1176 :
1177 0 : mld6_fasttimeo();
1178 0 : }
1179 :
1180 : const char *
1181 0 : icmp6_redirect_diag(struct in6_addr *src6, struct in6_addr *dst6,
1182 : struct in6_addr *tgt6)
1183 : {
1184 : static char buf[1024]; /* XXX */
1185 0 : char src[INET6_ADDRSTRLEN];
1186 0 : char dst[INET6_ADDRSTRLEN];
1187 0 : char tgt[INET6_ADDRSTRLEN];
1188 :
1189 0 : snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)",
1190 0 : inet_ntop(AF_INET6, src6, src, sizeof(src)),
1191 0 : inet_ntop(AF_INET6, dst6, dst, sizeof(dst)),
1192 0 : inet_ntop(AF_INET6, tgt6, tgt, sizeof(tgt)));
1193 0 : return buf;
1194 0 : }
1195 :
1196 : void
1197 0 : icmp6_redirect_input(struct mbuf *m, int off)
1198 : {
1199 : struct ifnet *ifp;
1200 0 : struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1201 : struct nd_redirect *nd_rd;
1202 0 : int icmp6len = ntohs(ip6->ip6_plen);
1203 : char *lladdr = NULL;
1204 : int lladdrlen = 0;
1205 : struct rtentry *rt = NULL;
1206 : int is_router;
1207 : int is_onlink;
1208 0 : struct in6_addr src6 = ip6->ip6_src;
1209 0 : struct in6_addr redtgt6;
1210 0 : struct in6_addr reddst6;
1211 0 : union nd_opts ndopts;
1212 0 : char addr[INET6_ADDRSTRLEN];
1213 :
1214 0 : ifp = if_get(m->m_pkthdr.ph_ifidx);
1215 0 : if (ifp == NULL)
1216 0 : return;
1217 :
1218 : /* XXX if we are router, we don't update route by icmp6 redirect */
1219 0 : if (ip6_forwarding)
1220 : goto freeit;
1221 0 : if (!(ifp->if_xflags & IFXF_AUTOCONF6))
1222 : goto freeit;
1223 :
1224 0 : IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
1225 0 : if (nd_rd == NULL) {
1226 0 : icmp6stat_inc(icp6s_tooshort);
1227 0 : if_put(ifp);
1228 0 : return;
1229 : }
1230 0 : redtgt6 = nd_rd->nd_rd_target;
1231 0 : reddst6 = nd_rd->nd_rd_dst;
1232 :
1233 0 : if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
1234 0 : redtgt6.s6_addr16[1] = htons(ifp->if_index);
1235 0 : if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
1236 0 : reddst6.s6_addr16[1] = htons(ifp->if_index);
1237 :
1238 : /* validation */
1239 0 : if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
1240 0 : nd6log((LOG_ERR,
1241 : "ICMP6 redirect sent from %s rejected; "
1242 : "must be from linklocal\n",
1243 : inet_ntop(AF_INET6, &src6, addr, sizeof(addr))));
1244 : goto bad;
1245 : }
1246 0 : if (ip6->ip6_hlim != 255) {
1247 0 : nd6log((LOG_ERR,
1248 : "ICMP6 redirect sent from %s rejected; "
1249 : "hlim=%d (must be 255)\n",
1250 : inet_ntop(AF_INET6, &src6, addr, sizeof(addr)),
1251 : ip6->ip6_hlim));
1252 : goto bad;
1253 : }
1254 0 : if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
1255 0 : nd6log((LOG_ERR,
1256 : "ICMP6 redirect rejected; "
1257 : "redirect dst must be unicast: %s\n",
1258 : icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
1259 : goto bad;
1260 : }
1261 : {
1262 : /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
1263 0 : struct sockaddr_in6 sin6;
1264 : struct in6_addr *gw6;
1265 :
1266 0 : bzero(&sin6, sizeof(sin6));
1267 0 : sin6.sin6_family = AF_INET6;
1268 0 : sin6.sin6_len = sizeof(struct sockaddr_in6);
1269 0 : memcpy(&sin6.sin6_addr, &reddst6, sizeof(reddst6));
1270 0 : rt = rtalloc(sin6tosa(&sin6), 0, m->m_pkthdr.ph_rtableid);
1271 0 : if (rt) {
1272 0 : if (rt->rt_gateway == NULL ||
1273 0 : rt->rt_gateway->sa_family != AF_INET6) {
1274 0 : nd6log((LOG_ERR,
1275 : "ICMP6 redirect rejected; no route "
1276 : "with inet6 gateway found for redirect dst: %s\n",
1277 : icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
1278 0 : rtfree(rt);
1279 0 : goto bad;
1280 : }
1281 :
1282 0 : gw6 = &(satosin6(rt->rt_gateway)->sin6_addr);
1283 0 : if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
1284 0 : nd6log((LOG_ERR,
1285 : "ICMP6 redirect rejected; "
1286 : "not equal to gw-for-src=%s (must be same): "
1287 : "%s\n",
1288 : inet_ntop(AF_INET6, gw6, addr, sizeof(addr)),
1289 : icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
1290 0 : rtfree(rt);
1291 0 : goto bad;
1292 : }
1293 : } else {
1294 0 : nd6log((LOG_ERR,
1295 : "ICMP6 redirect rejected; "
1296 : "no route found for redirect dst: %s\n",
1297 : icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
1298 0 : goto bad;
1299 : }
1300 0 : rtfree(rt);
1301 : rt = NULL;
1302 0 : }
1303 :
1304 : is_router = is_onlink = 0;
1305 0 : if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
1306 0 : is_router = 1; /* router case */
1307 0 : if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0)
1308 0 : is_onlink = 1; /* on-link destination case */
1309 0 : if (!is_router && !is_onlink) {
1310 0 : nd6log((LOG_ERR,
1311 : "ICMP6 redirect rejected; "
1312 : "neither router case nor onlink case: %s\n",
1313 : icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
1314 : goto bad;
1315 : }
1316 : /* validation passed */
1317 :
1318 0 : icmp6len -= sizeof(*nd_rd);
1319 0 : nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
1320 0 : if (nd6_options(&ndopts) < 0) {
1321 0 : nd6log((LOG_INFO, "icmp6_redirect_input: "
1322 : "invalid ND option, rejected: %s\n",
1323 : icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
1324 : /* nd6_options have incremented stats */
1325 : goto freeit;
1326 : }
1327 :
1328 0 : if (ndopts.nd_opts_tgt_lladdr) {
1329 0 : lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
1330 0 : lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
1331 0 : }
1332 :
1333 0 : if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
1334 0 : nd6log((LOG_INFO,
1335 : "icmp6_redirect_input: lladdrlen mismatch for %s "
1336 : "(if %d, icmp6 packet %d): %s\n",
1337 : inet_ntop(AF_INET6, &redtgt6, addr, sizeof(addr)),
1338 : ifp->if_addrlen, lladdrlen - 2,
1339 : icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
1340 : goto bad;
1341 : }
1342 :
1343 : /* RFC 2461 8.3 */
1344 0 : nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
1345 0 : is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
1346 :
1347 0 : if (!is_onlink) { /* better router case. perform rtredirect. */
1348 : /* perform rtredirect */
1349 0 : struct sockaddr_in6 sdst;
1350 0 : struct sockaddr_in6 sgw;
1351 0 : struct sockaddr_in6 ssrc;
1352 : unsigned long rtcount;
1353 0 : struct rtentry *newrt = NULL;
1354 :
1355 : /*
1356 : * do not install redirect route, if the number of entries
1357 : * is too much (> hiwat). note that, the node (= host) will
1358 : * work just fine even if we do not install redirect route
1359 : * (there will be additional hops, though).
1360 : */
1361 0 : rtcount = rt_timer_queue_count(icmp6_redirect_timeout_q);
1362 0 : if (0 <= ip6_maxdynroutes && rtcount >= ip6_maxdynroutes)
1363 0 : goto freeit;
1364 0 : else if (0 <= icmp6_redirect_lowat &&
1365 : rtcount > icmp6_redirect_lowat) {
1366 : /*
1367 : * XXX nuke a victim, install the new one.
1368 : */
1369 : }
1370 :
1371 0 : bzero(&sdst, sizeof(sdst));
1372 0 : bzero(&sgw, sizeof(sgw));
1373 0 : bzero(&ssrc, sizeof(ssrc));
1374 0 : sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
1375 0 : sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
1376 : sizeof(struct sockaddr_in6);
1377 0 : memcpy(&sgw.sin6_addr, &redtgt6, sizeof(struct in6_addr));
1378 0 : memcpy(&sdst.sin6_addr, &reddst6, sizeof(struct in6_addr));
1379 0 : memcpy(&ssrc.sin6_addr, &src6, sizeof(struct in6_addr));
1380 0 : rtredirect(sin6tosa(&sdst), sin6tosa(&sgw), sin6tosa(&ssrc),
1381 0 : &newrt, m->m_pkthdr.ph_rtableid);
1382 :
1383 0 : if (newrt) {
1384 0 : (void)rt_timer_add(newrt, icmp6_redirect_timeout,
1385 0 : icmp6_redirect_timeout_q, m->m_pkthdr.ph_rtableid);
1386 0 : rtfree(newrt);
1387 0 : }
1388 0 : }
1389 : /* finally update cached route in each socket via pfctlinput */
1390 : {
1391 0 : struct sockaddr_in6 sdst;
1392 :
1393 0 : bzero(&sdst, sizeof(sdst));
1394 0 : sdst.sin6_family = AF_INET6;
1395 0 : sdst.sin6_len = sizeof(struct sockaddr_in6);
1396 0 : memcpy(&sdst.sin6_addr, &reddst6, sizeof(struct in6_addr));
1397 0 : pfctlinput(PRC_REDIRECT_HOST, sin6tosa(&sdst));
1398 0 : }
1399 :
1400 : freeit:
1401 0 : if_put(ifp);
1402 0 : m_freem(m);
1403 0 : return;
1404 :
1405 : bad:
1406 0 : if_put(ifp);
1407 0 : icmp6stat_inc(icp6s_badredirect);
1408 0 : m_freem(m);
1409 0 : }
1410 :
1411 : void
1412 0 : icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
1413 : {
1414 : struct ifnet *ifp = NULL;
1415 : struct in6_addr *ifp_ll6;
1416 : struct in6_addr *nexthop;
1417 : struct ip6_hdr *sip6; /* m0 as struct ip6_hdr */
1418 : struct mbuf *m = NULL; /* newly allocated one */
1419 : struct ip6_hdr *ip6; /* m as struct ip6_hdr */
1420 : struct nd_redirect *nd_rd;
1421 : size_t maxlen;
1422 : u_char *p;
1423 0 : struct sockaddr_in6 src_sa;
1424 :
1425 0 : icmp6_errcount(ND_REDIRECT, 0);
1426 :
1427 : /* if we are not router, we don't send icmp6 redirect */
1428 0 : if (!ip6_forwarding)
1429 : goto fail;
1430 :
1431 : /* sanity check */
1432 0 : if (m0 == NULL || !rtisvalid(rt))
1433 : goto fail;
1434 :
1435 0 : ifp = if_get(rt->rt_ifidx);
1436 0 : if (ifp == NULL)
1437 : goto fail;
1438 :
1439 : /*
1440 : * Address check:
1441 : * the source address must identify a neighbor, and
1442 : * the destination address must not be a multicast address
1443 : * [RFC 2461, sec 8.2]
1444 : */
1445 0 : sip6 = mtod(m0, struct ip6_hdr *);
1446 0 : bzero(&src_sa, sizeof(src_sa));
1447 0 : src_sa.sin6_family = AF_INET6;
1448 0 : src_sa.sin6_len = sizeof(src_sa);
1449 0 : src_sa.sin6_addr = sip6->ip6_src;
1450 : /* we don't currently use sin6_scope_id, but eventually use it */
1451 0 : src_sa.sin6_scope_id = in6_addr2scopeid(ifp->if_index, &sip6->ip6_src);
1452 0 : if (nd6_is_addr_neighbor(&src_sa, ifp) == 0)
1453 : goto fail;
1454 0 : if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
1455 : goto fail; /* what should we do here? */
1456 :
1457 : /* rate limit */
1458 0 : if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0))
1459 : goto fail;
1460 :
1461 : /*
1462 : * Since we are going to append up to 1280 bytes (= IPV6_MMTU),
1463 : * we almost always ask for an mbuf cluster for simplicity.
1464 : * (MHLEN < IPV6_MMTU is almost always true)
1465 : */
1466 : #if IPV6_MMTU >= MCLBYTES
1467 : # error assumption failed about IPV6_MMTU and MCLBYTES
1468 : #endif
1469 0 : MGETHDR(m, M_DONTWAIT, MT_HEADER);
1470 0 : if (m && IPV6_MMTU >= MHLEN)
1471 0 : MCLGET(m, M_DONTWAIT);
1472 0 : if (!m)
1473 : goto fail;
1474 0 : m->m_pkthdr.ph_ifidx = 0;
1475 0 : m->m_len = 0;
1476 0 : maxlen = M_TRAILINGSPACE(m);
1477 0 : maxlen = min(IPV6_MMTU, maxlen);
1478 : /* just for safety */
1479 0 : if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
1480 0 : ((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
1481 : goto fail;
1482 : }
1483 :
1484 : {
1485 : /* get ip6 linklocal address for ifp(my outgoing interface). */
1486 : struct in6_ifaddr *ia6;
1487 0 : if ((ia6 = in6ifa_ifpforlinklocal(ifp, IN6_IFF_TENTATIVE|
1488 0 : IN6_IFF_DUPLICATED|IN6_IFF_ANYCAST)) == NULL)
1489 0 : goto fail;
1490 0 : ifp_ll6 = &ia6->ia_addr.sin6_addr;
1491 0 : }
1492 :
1493 : /* get ip6 linklocal address for the router. */
1494 0 : if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) {
1495 : struct sockaddr_in6 *sin6;
1496 0 : sin6 = satosin6(rt->rt_gateway);
1497 0 : nexthop = &sin6->sin6_addr;
1498 0 : if (!IN6_IS_ADDR_LINKLOCAL(nexthop))
1499 0 : nexthop = NULL;
1500 0 : } else
1501 : nexthop = NULL;
1502 :
1503 : /* ip6 */
1504 0 : ip6 = mtod(m, struct ip6_hdr *);
1505 0 : ip6->ip6_flow = 0;
1506 0 : ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
1507 0 : ip6->ip6_vfc |= IPV6_VERSION;
1508 : /* ip6->ip6_plen will be set later */
1509 0 : ip6->ip6_nxt = IPPROTO_ICMPV6;
1510 0 : ip6->ip6_hlim = 255;
1511 : /* ip6->ip6_src must be linklocal addr for my outgoing if. */
1512 0 : bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr));
1513 0 : bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr));
1514 :
1515 : /* ND Redirect */
1516 0 : nd_rd = (struct nd_redirect *)(ip6 + 1);
1517 0 : nd_rd->nd_rd_type = ND_REDIRECT;
1518 0 : nd_rd->nd_rd_code = 0;
1519 0 : nd_rd->nd_rd_reserved = 0;
1520 0 : if (rt->rt_flags & RTF_GATEWAY) {
1521 : /*
1522 : * nd_rd->nd_rd_target must be a link-local address in
1523 : * better router cases.
1524 : */
1525 0 : if (!nexthop)
1526 : goto fail;
1527 0 : bcopy(nexthop, &nd_rd->nd_rd_target,
1528 : sizeof(nd_rd->nd_rd_target));
1529 0 : bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
1530 : sizeof(nd_rd->nd_rd_dst));
1531 0 : } else {
1532 : /* make sure redtgt == reddst */
1533 : nexthop = &sip6->ip6_dst;
1534 0 : bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target,
1535 : sizeof(nd_rd->nd_rd_target));
1536 0 : bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
1537 : sizeof(nd_rd->nd_rd_dst));
1538 : }
1539 :
1540 0 : p = (u_char *)(nd_rd + 1);
1541 :
1542 : {
1543 : /* target lladdr option */
1544 : struct rtentry *nrt;
1545 : int len;
1546 : struct sockaddr_dl *sdl;
1547 : struct nd_opt_hdr *nd_opt;
1548 : char *lladdr;
1549 :
1550 0 : len = sizeof(*nd_opt) + ifp->if_addrlen;
1551 0 : len = (len + 7) & ~7; /* round by 8 */
1552 : /* safety check */
1553 0 : if (len + (p - (u_char *)ip6) > maxlen)
1554 0 : goto nolladdropt;
1555 0 : nrt = nd6_lookup(nexthop, 0, ifp, ifp->if_rdomain);
1556 0 : if ((nrt != NULL) &&
1557 0 : (nrt->rt_flags & (RTF_GATEWAY|RTF_LLINFO)) == RTF_LLINFO &&
1558 0 : (nrt->rt_gateway->sa_family == AF_LINK) &&
1559 0 : (sdl = satosdl(nrt->rt_gateway)) &&
1560 0 : sdl->sdl_alen) {
1561 0 : nd_opt = (struct nd_opt_hdr *)p;
1562 0 : nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
1563 0 : nd_opt->nd_opt_len = len >> 3;
1564 0 : lladdr = (char *)(nd_opt + 1);
1565 0 : bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
1566 0 : p += len;
1567 0 : }
1568 0 : rtfree(nrt);
1569 0 : }
1570 : nolladdropt:;
1571 :
1572 0 : m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
1573 :
1574 : /* just to be safe */
1575 0 : if (p - (u_char *)ip6 > maxlen)
1576 : goto noredhdropt;
1577 :
1578 : {
1579 : /* redirected header option */
1580 : int len;
1581 : struct nd_opt_rd_hdr *nd_opt_rh;
1582 :
1583 : /*
1584 : * compute the maximum size for icmp6 redirect header option.
1585 : * XXX room for auth header?
1586 : */
1587 0 : len = maxlen - (p - (u_char *)ip6);
1588 0 : len &= ~7;
1589 :
1590 : /*
1591 : * Redirected header option spec (RFC2461 4.6.3) talks nothing
1592 : * about padding/truncate rule for the original IP packet.
1593 : * From the discussion on IPv6imp in Feb 1999,
1594 : * the consensus was:
1595 : * - "attach as much as possible" is the goal
1596 : * - pad if not aligned (original size can be guessed by
1597 : * original ip6 header)
1598 : * Following code adds the padding if it is simple enough,
1599 : * and truncates if not.
1600 : */
1601 0 : if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) {
1602 : /* not enough room, truncate */
1603 0 : m_adj(m0, (len - sizeof(*nd_opt_rh)) -
1604 : m0->m_pkthdr.len);
1605 0 : } else {
1606 : /*
1607 : * enough room, truncate if not aligned.
1608 : * we don't pad here for simplicity.
1609 : */
1610 : size_t extra;
1611 :
1612 0 : extra = m0->m_pkthdr.len % 8;
1613 0 : if (extra) {
1614 : /* truncate */
1615 0 : m_adj(m0, -extra);
1616 0 : }
1617 0 : len = m0->m_pkthdr.len + sizeof(*nd_opt_rh);
1618 : }
1619 :
1620 0 : nd_opt_rh = (struct nd_opt_rd_hdr *)p;
1621 0 : bzero(nd_opt_rh, sizeof(*nd_opt_rh));
1622 0 : nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
1623 0 : nd_opt_rh->nd_opt_rh_len = len >> 3;
1624 0 : p += sizeof(*nd_opt_rh);
1625 0 : m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
1626 :
1627 : /* connect m0 to m */
1628 0 : m->m_pkthdr.len += m0->m_pkthdr.len;
1629 0 : m_cat(m, m0);
1630 : m0 = NULL;
1631 0 : }
1632 : noredhdropt:
1633 0 : m_freem(m0);
1634 : m0 = NULL;
1635 :
1636 0 : sip6 = mtod(m, struct ip6_hdr *);
1637 0 : if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
1638 0 : sip6->ip6_src.s6_addr16[1] = 0;
1639 0 : if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst))
1640 0 : sip6->ip6_dst.s6_addr16[1] = 0;
1641 : #if 0
1642 : if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src))
1643 : ip6->ip6_src.s6_addr16[1] = 0;
1644 : if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
1645 : ip6->ip6_dst.s6_addr16[1] = 0;
1646 : #endif
1647 0 : if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target))
1648 0 : nd_rd->nd_rd_target.s6_addr16[1] = 0;
1649 0 : if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst))
1650 0 : nd_rd->nd_rd_dst.s6_addr16[1] = 0;
1651 :
1652 0 : ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
1653 :
1654 0 : nd_rd->nd_rd_cksum = 0;
1655 0 : m->m_pkthdr.csum_flags = M_ICMP_CSUM_OUT;
1656 :
1657 : /* send the packet to outside... */
1658 0 : ip6_output(m, NULL, NULL, 0, NULL, NULL);
1659 :
1660 0 : icmp6stat_inc(icp6s_outhist + ND_REDIRECT);
1661 :
1662 0 : if_put(ifp);
1663 0 : return;
1664 :
1665 : fail:
1666 0 : if_put(ifp);
1667 0 : m_freem(m);
1668 0 : m_freem(m0);
1669 0 : }
1670 :
1671 : /*
1672 : * ICMPv6 socket option processing.
1673 : */
1674 : int
1675 0 : icmp6_ctloutput(int op, struct socket *so, int level, int optname,
1676 : struct mbuf *m)
1677 : {
1678 : int error = 0;
1679 0 : struct inpcb *in6p = sotoinpcb(so);
1680 :
1681 0 : if (level != IPPROTO_ICMPV6)
1682 0 : return EINVAL;
1683 :
1684 0 : switch (op) {
1685 : case PRCO_SETOPT:
1686 0 : switch (optname) {
1687 : case ICMP6_FILTER:
1688 : {
1689 : struct icmp6_filter *p;
1690 :
1691 0 : if (m == NULL || m->m_len != sizeof(*p)) {
1692 : error = EMSGSIZE;
1693 0 : break;
1694 : }
1695 0 : p = mtod(m, struct icmp6_filter *);
1696 0 : if (!p || !in6p->inp_icmp6filt) {
1697 : error = EINVAL;
1698 0 : break;
1699 : }
1700 0 : bcopy(p, in6p->inp_icmp6filt,
1701 : sizeof(struct icmp6_filter));
1702 : error = 0;
1703 0 : break;
1704 : }
1705 :
1706 : default:
1707 : error = ENOPROTOOPT;
1708 0 : break;
1709 : }
1710 : break;
1711 :
1712 : case PRCO_GETOPT:
1713 0 : switch (optname) {
1714 : case ICMP6_FILTER:
1715 : {
1716 : struct icmp6_filter *p;
1717 :
1718 0 : if (!in6p->inp_icmp6filt) {
1719 : error = EINVAL;
1720 0 : break;
1721 : }
1722 0 : m->m_len = sizeof(struct icmp6_filter);
1723 0 : p = mtod(m, struct icmp6_filter *);
1724 0 : bcopy(in6p->inp_icmp6filt, p,
1725 : sizeof(struct icmp6_filter));
1726 : error = 0;
1727 0 : break;
1728 : }
1729 :
1730 : default:
1731 : error = ENOPROTOOPT;
1732 0 : break;
1733 : }
1734 : break;
1735 : }
1736 :
1737 0 : return (error);
1738 0 : }
1739 :
1740 : /*
1741 : * Perform rate limit check.
1742 : * Returns 0 if it is okay to send the icmp6 packet.
1743 : * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
1744 : * limitation.
1745 : *
1746 : * XXX per-destination/type check necessary?
1747 : *
1748 : * dst - not used at this moment
1749 : * type - not used at this moment
1750 : * code - not used at this moment
1751 : */
1752 : int
1753 0 : icmp6_ratelimit(const struct in6_addr *dst, const int type, const int code)
1754 : {
1755 : /* PPS limit */
1756 0 : if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count,
1757 0 : icmp6errppslim))
1758 0 : return 1; /* The packet is subject to rate limit */
1759 0 : return 0; /* okay to send */
1760 0 : }
1761 :
1762 : struct rtentry *
1763 0 : icmp6_mtudisc_clone(struct sockaddr *dst, u_int rtableid)
1764 : {
1765 : struct rtentry *rt;
1766 : int error;
1767 :
1768 0 : rt = rtalloc(dst, RT_RESOLVE, rtableid);
1769 :
1770 : /* Check if the route is actually usable */
1771 0 : if (!rtisvalid(rt) || (rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)))
1772 : goto bad;
1773 :
1774 : /*
1775 : * No PMTU for local routes and permanent neighbors,
1776 : * ARP and NDP use the same expire timer as the route.
1777 : */
1778 0 : if (ISSET(rt->rt_flags, RTF_LOCAL) ||
1779 0 : (ISSET(rt->rt_flags, RTF_LLINFO) && rt->rt_expire == 0))
1780 : goto bad;
1781 :
1782 : /* If we didn't get a host route, allocate one */
1783 0 : if ((rt->rt_flags & RTF_HOST) == 0) {
1784 0 : struct rtentry *nrt;
1785 0 : struct rt_addrinfo info;
1786 0 : struct sockaddr_rtlabel sa_rl;
1787 :
1788 0 : memset(&info, 0, sizeof(info));
1789 0 : info.rti_ifa = rt->rt_ifa;
1790 0 : info.rti_flags = RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC;
1791 0 : info.rti_info[RTAX_DST] = dst;
1792 0 : info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
1793 0 : info.rti_info[RTAX_LABEL] =
1794 0 : rtlabel_id2sa(rt->rt_labelid, &sa_rl);
1795 :
1796 0 : error = rtrequest(RTM_ADD, &info, rt->rt_priority, &nrt,
1797 : rtableid);
1798 0 : if (error)
1799 0 : goto bad;
1800 0 : nrt->rt_rmx = rt->rt_rmx;
1801 0 : rtfree(rt);
1802 0 : rt = nrt;
1803 0 : rtm_send(rt, RTM_ADD, 0, rtableid);
1804 0 : }
1805 0 : error = rt_timer_add(rt, icmp6_mtudisc_timeout, icmp6_mtudisc_timeout_q,
1806 : rtableid);
1807 0 : if (error)
1808 : goto bad;
1809 :
1810 0 : return (rt);
1811 : bad:
1812 0 : rtfree(rt);
1813 0 : return (NULL);
1814 0 : }
1815 :
1816 : void
1817 0 : icmp6_mtudisc_timeout(struct rtentry *rt, struct rttimer *r)
1818 : {
1819 : struct ifnet *ifp;
1820 :
1821 0 : NET_ASSERT_LOCKED();
1822 :
1823 0 : ifp = if_get(rt->rt_ifidx);
1824 0 : if (ifp == NULL)
1825 0 : return;
1826 :
1827 0 : if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
1828 0 : rtdeletemsg(rt, ifp, r->rtt_tableid);
1829 0 : } else {
1830 0 : if (!(rt->rt_locks & RTV_MTU))
1831 0 : rt->rt_mtu = 0;
1832 : }
1833 :
1834 0 : if_put(ifp);
1835 0 : }
1836 :
1837 : void
1838 0 : icmp6_redirect_timeout(struct rtentry *rt, struct rttimer *r)
1839 : {
1840 : struct ifnet *ifp;
1841 :
1842 0 : NET_ASSERT_LOCKED();
1843 :
1844 0 : ifp = if_get(rt->rt_ifidx);
1845 0 : if (ifp == NULL)
1846 0 : return;
1847 :
1848 0 : if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
1849 0 : rtdeletemsg(rt, ifp, r->rtt_tableid);
1850 0 : }
1851 :
1852 0 : if_put(ifp);
1853 0 : }
1854 :
1855 : int *icmpv6ctl_vars[ICMPV6CTL_MAXID] = ICMPV6CTL_VARS;
1856 :
1857 : int
1858 0 : icmp6_sysctl_icmp6stat(void *oldp, size_t *oldlenp, void *newp)
1859 : {
1860 : struct icmp6stat *icmp6stat;
1861 : int ret;
1862 :
1863 : CTASSERT(sizeof(*icmp6stat) == icp6s_ncounters * sizeof(uint64_t));
1864 0 : icmp6stat = malloc(sizeof(*icmp6stat), M_TEMP, M_WAITOK|M_ZERO);
1865 0 : counters_read(icmp6counters, (uint64_t *)icmp6stat, icp6s_ncounters);
1866 0 : ret = sysctl_rdstruct(oldp, oldlenp, newp,
1867 : icmp6stat, sizeof(*icmp6stat));
1868 0 : free(icmp6stat, M_TEMP, sizeof(*icmp6stat));
1869 :
1870 0 : return (ret);
1871 : }
1872 :
1873 : int
1874 0 : icmp6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
1875 : void *newp, size_t newlen)
1876 : {
1877 : int error;
1878 :
1879 : /* All sysctl names at this level are terminal. */
1880 0 : if (namelen != 1)
1881 0 : return ENOTDIR;
1882 :
1883 0 : switch (name[0]) {
1884 :
1885 : case ICMPV6CTL_STATS:
1886 0 : return icmp6_sysctl_icmp6stat(oldp, oldlenp, newp);
1887 : default:
1888 0 : if (name[0] < ICMPV6CTL_MAXID) {
1889 0 : NET_LOCK();
1890 0 : error = sysctl_int_arr(icmpv6ctl_vars, name, namelen,
1891 : oldp, oldlenp, newp, newlen);
1892 0 : NET_UNLOCK();
1893 0 : return (error);
1894 : }
1895 0 : return ENOPROTOOPT;
1896 : }
1897 : /* NOTREACHED */
1898 0 : }
|