Annotation of sys/netinet6/icmp6.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: icmp6.c,v 1.94 2007/06/01 00:52:38 henning 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 "faith.h"
65: #include "carp.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/protosw.h>
72: #include <sys/socket.h>
73: #include <sys/socketvar.h>
74: #include <sys/time.h>
75: #include <sys/kernel.h>
76: #include <sys/syslog.h>
77: #include <sys/domain.h>
78:
79: #include <net/if.h>
80: #include <net/route.h>
81: #include <net/if_dl.h>
82: #include <net/if_types.h>
83:
84: #include <netinet/in.h>
85: #include <netinet/in_var.h>
86: #include <netinet/in_systm.h>
87: #include <netinet/ip.h>
88: #include <netinet/ip6.h>
89: #include <netinet6/ip6_var.h>
90: #include <netinet/icmp6.h>
91: #include <netinet6/mld6_var.h>
92: #include <netinet/in_pcb.h>
93: #include <netinet6/nd6.h>
94: #include <netinet6/in6_ifattach.h>
95: #include <netinet6/ip6protosw.h>
96:
97: #if NCARP > 0
98: #include <netinet/ip_carp.h>
99: #endif
100:
101: /* inpcb members */
102: #define in6pcb inpcb
103: #define in6p_laddr inp_laddr6
104: #define in6p_faddr inp_faddr6
105: #define in6p_icmp6filt inp_icmp6filt
106: #define in6p_route inp_route
107: #define in6p_socket inp_socket
108: #define in6p_flags inp_flags
109: #define in6p_moptions inp_moptions6
110: #define in6p_outputopts inp_outputopts6
111: #define in6p_ip6 inp_ipv6
112: #define in6p_flowinfo inp_flowinfo
113: #define in6p_sp inp_sp
114: #define in6p_next inp_next
115: #define in6p_prev inp_prev
116: /* macro names */
117: #define sotoin6pcb sotoinpcb
118: /* function names */
119: #define in6_pcbdetach in_pcbdetach
120: #define in6_rtchange in_rtchange
121:
122: /*
123: * for KAME src sync over BSD*'s. XXX: FreeBSD (>=3) are VERY different from
124: * others...
125: */
126: #define in6p_ip6_nxt inp_ipv6.ip6_nxt
127:
128: extern struct domain inet6domain;
129: extern struct ip6protosw inet6sw[];
130: extern u_char ip6_protox[];
131:
132: struct icmp6stat icmp6stat;
133:
134: extern struct inpcbtable rawin6pcbtable;
135: extern int icmp6errppslim;
136: static int icmp6errpps_count = 0;
137: static struct timeval icmp6errppslim_last;
138: extern int icmp6_nodeinfo;
139:
140: /*
141: * List of callbacks to notify when Path MTU changes are made.
142: */
143: struct icmp6_mtudisc_callback {
144: LIST_ENTRY(icmp6_mtudisc_callback) mc_list;
145: void (*mc_func)(struct in6_addr *);
146: };
147:
148: LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks =
149: LIST_HEAD_INITIALIZER(&icmp6_mtudisc_callbacks);
150:
151: static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
152: extern int pmtu_expire;
153:
154: /* XXX do these values make any sense? */
155: static int icmp6_mtudisc_hiwat = 1280;
156: static int icmp6_mtudisc_lowat = 256;
157:
158: /*
159: * keep track of # of redirect routes.
160: */
161: static struct rttimer_queue *icmp6_redirect_timeout_q = NULL;
162:
163: /* XXX experimental, turned off */
164: static int icmp6_redirect_hiwat = -1;
165: static int icmp6_redirect_lowat = -1;
166:
167: static void icmp6_errcount(struct icmp6errstat *, int, int);
168: static int icmp6_rip6_input(struct mbuf **, int);
169: static int icmp6_ratelimit(const struct in6_addr *, const int, const int);
170: static const char *icmp6_redirect_diag(struct in6_addr *,
171: struct in6_addr *, struct in6_addr *);
172: static struct mbuf *ni6_input(struct mbuf *, int);
173: static struct mbuf *ni6_nametodns(const char *, int, int);
174: static int ni6_dnsmatch(const char *, int, const char *, int);
175: static int ni6_addrs(struct icmp6_nodeinfo *, struct mbuf *,
176: struct ifnet **, char *);
177: static int ni6_store_addrs(struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
178: struct ifnet *, int);
179: static int icmp6_notify_error(struct mbuf *, int, int, int);
180: static struct rtentry *icmp6_mtudisc_clone(struct sockaddr *);
181: static void icmp6_mtudisc_timeout(struct rtentry *, struct rttimer *);
182: static void icmp6_redirect_timeout(struct rtentry *, struct rttimer *);
183:
184: void
185: icmp6_init()
186: {
187: mld6_init();
188: icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
189: icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout);
190: }
191:
192: static void
193: icmp6_errcount(stat, type, code)
194: struct icmp6errstat *stat;
195: int type, code;
196: {
197: switch (type) {
198: case ICMP6_DST_UNREACH:
199: switch (code) {
200: case ICMP6_DST_UNREACH_NOROUTE:
201: stat->icp6errs_dst_unreach_noroute++;
202: return;
203: case ICMP6_DST_UNREACH_ADMIN:
204: stat->icp6errs_dst_unreach_admin++;
205: return;
206: case ICMP6_DST_UNREACH_BEYONDSCOPE:
207: stat->icp6errs_dst_unreach_beyondscope++;
208: return;
209: case ICMP6_DST_UNREACH_ADDR:
210: stat->icp6errs_dst_unreach_addr++;
211: return;
212: case ICMP6_DST_UNREACH_NOPORT:
213: stat->icp6errs_dst_unreach_noport++;
214: return;
215: }
216: break;
217: case ICMP6_PACKET_TOO_BIG:
218: stat->icp6errs_packet_too_big++;
219: return;
220: case ICMP6_TIME_EXCEEDED:
221: switch (code) {
222: case ICMP6_TIME_EXCEED_TRANSIT:
223: stat->icp6errs_time_exceed_transit++;
224: return;
225: case ICMP6_TIME_EXCEED_REASSEMBLY:
226: stat->icp6errs_time_exceed_reassembly++;
227: return;
228: }
229: break;
230: case ICMP6_PARAM_PROB:
231: switch (code) {
232: case ICMP6_PARAMPROB_HEADER:
233: stat->icp6errs_paramprob_header++;
234: return;
235: case ICMP6_PARAMPROB_NEXTHEADER:
236: stat->icp6errs_paramprob_nextheader++;
237: return;
238: case ICMP6_PARAMPROB_OPTION:
239: stat->icp6errs_paramprob_option++;
240: return;
241: }
242: break;
243: case ND_REDIRECT:
244: stat->icp6errs_redirect++;
245: return;
246: }
247: stat->icp6errs_unknown++;
248: }
249:
250: /*
251: * Register a Path MTU Discovery callback.
252: */
253: void
254: icmp6_mtudisc_callback_register(func)
255: void (*func)(struct in6_addr *);
256: {
257: struct icmp6_mtudisc_callback *mc;
258:
259: for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
260: mc = LIST_NEXT(mc, mc_list)) {
261: if (mc->mc_func == func)
262: return;
263: }
264:
265: mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT);
266: if (mc == NULL)
267: panic("icmp6_mtudisc_callback_register");
268:
269: mc->mc_func = func;
270: LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list);
271: }
272:
273: /*
274: * Generate an error packet of type error in response to bad IP6 packet.
275: */
276: void
277: icmp6_error(m, type, code, param)
278: struct mbuf *m;
279: int type, code, param;
280: {
281: struct ip6_hdr *oip6, *nip6;
282: struct icmp6_hdr *icmp6;
283: u_int preplen;
284: int off;
285: int nxt;
286:
287: icmp6stat.icp6s_error++;
288:
289: /* count per-type-code statistics */
290: icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code);
291:
292: if (m->m_len < sizeof(struct ip6_hdr)) {
293: m = m_pullup(m, sizeof(struct ip6_hdr));
294: if (m == NULL)
295: return;
296: }
297: oip6 = mtod(m, struct ip6_hdr *);
298:
299: /*
300: * If the destination address of the erroneous packet is a multicast
301: * address, or the packet was sent using link-layer multicast,
302: * we should basically suppress sending an error (RFC 2463, Section
303: * 2.4).
304: * We have two exceptions (the item e.2 in that section):
305: * - the Pakcet Too Big message can be sent for path MTU discovery.
306: * - the Parameter Problem Message that can be allowed an icmp6 error
307: * in the option type field. This check has been done in
308: * ip6_unknown_opt(), so we can just check the type and code.
309: */
310: if ((m->m_flags & (M_BCAST|M_MCAST) ||
311: IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
312: (type != ICMP6_PACKET_TOO_BIG &&
313: (type != ICMP6_PARAM_PROB ||
314: code != ICMP6_PARAMPROB_OPTION)))
315: goto freeit;
316:
317: /*
318: * RFC 2463, 2.4 (e.5): source address check.
319: * XXX: the case of anycast source?
320: */
321: if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
322: IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
323: goto freeit;
324:
325: /*
326: * If we are about to send ICMPv6 against ICMPv6 error/redirect,
327: * don't do it.
328: */
329: nxt = -1;
330: off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
331: if (off >= 0 && nxt == IPPROTO_ICMPV6) {
332: struct icmp6_hdr *icp;
333:
334: IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
335: sizeof(*icp));
336: if (icp == NULL) {
337: icmp6stat.icp6s_tooshort++;
338: return;
339: }
340: if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
341: icp->icmp6_type == ND_REDIRECT) {
342: /*
343: * ICMPv6 error
344: * Special case: for redirect (which is
345: * informational) we must not send icmp6 error.
346: */
347: icmp6stat.icp6s_canterror++;
348: goto freeit;
349: } else {
350: /* ICMPv6 informational - send the error */
351: }
352: }
353: else {
354: /* non-ICMPv6 - send the error */
355: }
356:
357: oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
358:
359: /* Finally, do rate limitation check. */
360: if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
361: icmp6stat.icp6s_toofreq++;
362: goto freeit;
363: }
364:
365: /*
366: * OK, ICMP6 can be generated.
367: */
368:
369: if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
370: m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
371:
372: preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
373: M_PREPEND(m, preplen, M_DONTWAIT);
374: if (m && m->m_len < preplen)
375: m = m_pullup(m, preplen);
376: if (m == NULL) {
377: nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__));
378: return;
379: }
380:
381: nip6 = mtod(m, struct ip6_hdr *);
382: nip6->ip6_src = oip6->ip6_src;
383: nip6->ip6_dst = oip6->ip6_dst;
384:
385: if (IN6_IS_SCOPE_EMBED(&oip6->ip6_src))
386: oip6->ip6_src.s6_addr16[1] = 0;
387: if (IN6_IS_SCOPE_EMBED(&oip6->ip6_dst))
388: oip6->ip6_dst.s6_addr16[1] = 0;
389:
390: icmp6 = (struct icmp6_hdr *)(nip6 + 1);
391: icmp6->icmp6_type = type;
392: icmp6->icmp6_code = code;
393: icmp6->icmp6_pptr = htonl((u_int32_t)param);
394:
395: /*
396: * icmp6_reflect() is designed to be in the input path.
397: * icmp6_error() can be called from both input and outut path,
398: * and if we are in output path rcvif could contain bogus value.
399: * clear m->m_pkthdr.rcvif for safety, we should have enough scope
400: * information in ip header (nip6).
401: */
402: m->m_pkthdr.rcvif = NULL;
403:
404: icmp6stat.icp6s_outhist[type]++;
405: icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */
406:
407: return;
408:
409: freeit:
410: /*
411: * If we can't tell wheter or not we can generate ICMP6, free it.
412: */
413: m_freem(m);
414: }
415:
416: /*
417: * Process a received ICMP6 message.
418: */
419: int
420: icmp6_input(mp, offp, proto)
421: struct mbuf **mp;
422: int *offp, proto;
423: {
424: struct mbuf *m = *mp, *n;
425: struct ip6_hdr *ip6, *nip6;
426: struct icmp6_hdr *icmp6, *nicmp6;
427: int off = *offp;
428: int icmp6len = m->m_pkthdr.len - *offp;
429: int code, sum, noff;
430:
431: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
432:
433: /*
434: * Locate icmp6 structure in mbuf, and check
435: * that not corrupted and of at least minimum length
436: */
437:
438: ip6 = mtod(m, struct ip6_hdr *);
439: if (icmp6len < sizeof(struct icmp6_hdr)) {
440: icmp6stat.icp6s_tooshort++;
441: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
442: goto freeit;
443: }
444:
445: /*
446: * calculate the checksum
447: */
448: IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
449: if (icmp6 == NULL) {
450: icmp6stat.icp6s_tooshort++;
451: return IPPROTO_DONE;
452: }
453: code = icmp6->icmp6_code;
454:
455: if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
456: nd6log((LOG_ERR,
457: "ICMP6 checksum error(%d|%x) %s\n",
458: icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src)));
459: icmp6stat.icp6s_checksum++;
460: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
461: goto freeit;
462: }
463:
464: #if defined(NFAITH) && 0 < NFAITH
465: if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
466: /*
467: * Deliver very specific ICMP6 type only.
468: * This is important to deliver TOOBIG. Otherwise PMTUD
469: * will not work.
470: */
471: switch (icmp6->icmp6_type) {
472: case ICMP6_DST_UNREACH:
473: case ICMP6_PACKET_TOO_BIG:
474: case ICMP6_TIME_EXCEEDED:
475: break;
476: default:
477: goto freeit;
478: }
479: }
480: #endif
481:
482: #if NCARP > 0
483: if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
484: m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
485: icmp6->icmp6_type == ICMP6_ECHO_REQUEST &&
486: carp_lsdrop(m, AF_INET6, ip6->ip6_src.s6_addr32,
487: ip6->ip6_dst.s6_addr32))
488: goto freeit;
489: #endif
490: icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
491:
492: switch (icmp6->icmp6_type) {
493: case ICMP6_DST_UNREACH:
494: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
495: switch (code) {
496: case ICMP6_DST_UNREACH_NOROUTE:
497: code = PRC_UNREACH_NET;
498: break;
499: case ICMP6_DST_UNREACH_ADMIN:
500: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
501: code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
502: break;
503: case ICMP6_DST_UNREACH_ADDR:
504: code = PRC_HOSTDEAD;
505: break;
506: #ifdef COMPAT_RFC1885
507: case ICMP6_DST_UNREACH_NOTNEIGHBOR:
508: code = PRC_UNREACH_SRCFAIL;
509: break;
510: #else
511: case ICMP6_DST_UNREACH_BEYONDSCOPE:
512: /* I mean "source address was incorrect." */
513: code = PRC_PARAMPROB;
514: break;
515: #endif
516: case ICMP6_DST_UNREACH_NOPORT:
517: code = PRC_UNREACH_PORT;
518: break;
519: default:
520: goto badcode;
521: }
522: goto deliver;
523:
524: case ICMP6_PACKET_TOO_BIG:
525: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
526:
527: code = PRC_MSGSIZE;
528:
529: /*
530: * Updating the path MTU will be done after examining
531: * intermediate extension headers.
532: */
533: goto deliver;
534:
535: case ICMP6_TIME_EXCEEDED:
536: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);
537: switch (code) {
538: case ICMP6_TIME_EXCEED_TRANSIT:
539: code = PRC_TIMXCEED_INTRANS;
540: break;
541: case ICMP6_TIME_EXCEED_REASSEMBLY:
542: code = PRC_TIMXCEED_REASS;
543: break;
544: default:
545: goto badcode;
546: }
547: goto deliver;
548:
549: case ICMP6_PARAM_PROB:
550: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);
551: switch (code) {
552: case ICMP6_PARAMPROB_NEXTHEADER:
553: code = PRC_UNREACH_PROTOCOL;
554: break;
555: case ICMP6_PARAMPROB_HEADER:
556: case ICMP6_PARAMPROB_OPTION:
557: code = PRC_PARAMPROB;
558: break;
559: default:
560: goto badcode;
561: }
562: goto deliver;
563:
564: case ICMP6_ECHO_REQUEST:
565: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);
566: if (code != 0)
567: goto badcode;
568: /*
569: * Copy mbuf to send to two data paths: userland socket(s),
570: * and to the querier (echo reply).
571: * m: a copy for socket, n: a copy for querier
572: */
573: if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
574: /* Give up local */
575: n = m;
576: m = NULL;
577: goto deliverecho;
578: }
579: /*
580: * If the first mbuf is shared, or the first mbuf is too short,
581: * copy the first part of the data into a fresh mbuf.
582: * Otherwise, we will wrongly overwrite both copies.
583: */
584: if ((n->m_flags & M_EXT) != 0 ||
585: n->m_len < off + sizeof(struct icmp6_hdr)) {
586: struct mbuf *n0 = n;
587: const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
588:
589: /*
590: * Prepare an internal mbuf. m_pullup() doesn't
591: * always copy the length we specified.
592: */
593: if (maxlen >= MCLBYTES) {
594: /* Give up remote */
595: m_freem(n0);
596: break;
597: }
598: MGETHDR(n, M_DONTWAIT, n0->m_type);
599: if (n && maxlen >= MHLEN) {
600: MCLGET(n, M_DONTWAIT);
601: if ((n->m_flags & M_EXT) == 0) {
602: m_free(n);
603: n = NULL;
604: }
605: }
606: if (n == NULL) {
607: /* Give up local */
608: m_freem(n0);
609: n = m;
610: m = NULL;
611: goto deliverecho;
612: }
613: M_MOVE_PKTHDR(n, n0);
614: /*
615: * Copy IPv6 and ICMPv6 only.
616: */
617: nip6 = mtod(n, struct ip6_hdr *);
618: bcopy(ip6, nip6, sizeof(struct ip6_hdr));
619: nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
620: bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
621: noff = sizeof(struct ip6_hdr);
622: n->m_len = noff + sizeof(struct icmp6_hdr);
623: /*
624: * Adjust mbuf. ip6_plen will be adjusted in
625: * ip6_output().
626: * n->m_pkthdr.len == n0->m_pkthdr.len at this point.
627: */
628: n->m_pkthdr.len += noff + sizeof(struct icmp6_hdr);
629: n->m_pkthdr.len -= (off + sizeof(struct icmp6_hdr));
630: m_adj(n0, off + sizeof(struct icmp6_hdr));
631: n->m_next = n0;
632: } else {
633: deliverecho:
634: nip6 = mtod(n, struct ip6_hdr *);
635: IP6_EXTHDR_GET(nicmp6, struct icmp6_hdr *, n, off,
636: sizeof(*nicmp6));
637: noff = off;
638: }
639: nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
640: nicmp6->icmp6_code = 0;
641: if (n) {
642: icmp6stat.icp6s_reflect++;
643: icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
644: icmp6_reflect(n, noff);
645: }
646: if (!m)
647: goto freeit;
648: break;
649:
650: case ICMP6_ECHO_REPLY:
651: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);
652: if (code != 0)
653: goto badcode;
654: break;
655:
656: case MLD_LISTENER_QUERY:
657: case MLD_LISTENER_REPORT:
658: if (icmp6len < sizeof(struct mld_hdr))
659: goto badlen;
660: if (icmp6->icmp6_type == MLD_LISTENER_QUERY) /* XXX: ugly... */
661: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
662: else
663: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
664: if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
665: /* give up local */
666: mld6_input(m, off);
667: m = NULL;
668: goto freeit;
669: }
670: mld6_input(n, off);
671: /* m stays. */
672: break;
673:
674: case MLD_LISTENER_DONE:
675: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone);
676: if (icmp6len < sizeof(struct mld_hdr)) /* necessary? */
677: goto badlen;
678: break; /* nothing to be done in kernel */
679:
680: case MLD_MTRACE_RESP:
681: case MLD_MTRACE:
682: /* XXX: these two are experimental. not officially defined. */
683: /* XXX: per-interface statistics? */
684: break; /* just pass it to applications */
685:
686: case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */
687: {
688: enum { WRU, FQDN } mode;
689:
690: if (!icmp6_nodeinfo)
691: break;
692:
693: if (icmp6len == sizeof(struct icmp6_hdr) + 4)
694: mode = WRU;
695: else if (icmp6len >= sizeof(struct icmp6_nodeinfo))
696: mode = FQDN;
697: else
698: goto badlen;
699:
700: if (mode == FQDN) {
701: n = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
702: if (n)
703: n = ni6_input(n, off);
704: /* XXX meaningless if n == NULL */
705: noff = sizeof(struct ip6_hdr);
706: } else {
707: u_char *p;
708: int maxlen, maxhlen;
709:
710: if ((icmp6_nodeinfo & 1) == 0)
711: break;
712:
713: if (code != 0)
714: goto badcode;
715: maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
716: if (maxlen >= MCLBYTES) {
717: /* Give up remote */
718: break;
719: }
720: MGETHDR(n, M_DONTWAIT, m->m_type);
721: if (n && maxlen > MHLEN) {
722: MCLGET(n, M_DONTWAIT);
723: if ((n->m_flags & M_EXT) == 0) {
724: m_free(n);
725: n = NULL;
726: }
727: }
728: if (n == NULL) {
729: /* Give up remote */
730: break;
731: }
732: n->m_pkthdr.rcvif = NULL;
733: n->m_len = 0;
734: maxhlen = M_TRAILINGSPACE(n) - maxlen;
735: if (maxhlen > hostnamelen)
736: maxhlen = hostnamelen;
737: /*
738: * Copy IPv6 and ICMPv6 only.
739: */
740: nip6 = mtod(n, struct ip6_hdr *);
741: bcopy(ip6, nip6, sizeof(struct ip6_hdr));
742: nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
743: bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
744: p = (u_char *)(nicmp6 + 1);
745: bzero(p, 4);
746: bcopy(hostname, p + 4, maxhlen); /* meaningless TTL */
747: noff = sizeof(struct ip6_hdr);
748: M_DUP_PKTHDR(n, m); /* just for rcvif */
749: n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
750: sizeof(struct icmp6_hdr) + 4 + maxhlen;
751: nicmp6->icmp6_type = ICMP6_WRUREPLY;
752: nicmp6->icmp6_code = 0;
753: }
754: #undef hostnamelen
755: if (n) {
756: icmp6stat.icp6s_reflect++;
757: icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;
758: icmp6_reflect(n, noff);
759: }
760: break;
761: }
762:
763: case ICMP6_WRUREPLY:
764: if (code != 0)
765: goto badcode;
766: break;
767:
768: case ND_ROUTER_SOLICIT:
769: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);
770: if (code != 0)
771: goto badcode;
772: if (icmp6len < sizeof(struct nd_router_solicit))
773: goto badlen;
774: if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
775: /* give up local */
776: nd6_rs_input(m, off, icmp6len);
777: m = NULL;
778: goto freeit;
779: }
780: nd6_rs_input(n, off, icmp6len);
781: /* m stays. */
782: break;
783:
784: case ND_ROUTER_ADVERT:
785: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);
786: if (code != 0)
787: goto badcode;
788: if (icmp6len < sizeof(struct nd_router_advert))
789: goto badlen;
790: if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
791: /* give up local */
792: nd6_ra_input(m, off, icmp6len);
793: m = NULL;
794: goto freeit;
795: }
796: nd6_ra_input(n, off, icmp6len);
797: /* m stays. */
798: break;
799:
800: case ND_NEIGHBOR_SOLICIT:
801: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);
802: if (code != 0)
803: goto badcode;
804: if (icmp6len < sizeof(struct nd_neighbor_solicit))
805: goto badlen;
806: if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
807: /* give up local */
808: nd6_ns_input(m, off, icmp6len);
809: m = NULL;
810: goto freeit;
811: }
812: nd6_ns_input(n, off, icmp6len);
813: /* m stays. */
814: break;
815:
816: case ND_NEIGHBOR_ADVERT:
817: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);
818: if (code != 0)
819: goto badcode;
820: if (icmp6len < sizeof(struct nd_neighbor_advert))
821: goto badlen;
822: if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
823: /* give up local */
824: nd6_na_input(m, off, icmp6len);
825: m = NULL;
826: goto freeit;
827: }
828: nd6_na_input(n, off, icmp6len);
829: /* m stays. */
830: break;
831:
832: case ND_REDIRECT:
833: icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);
834: if (code != 0)
835: goto badcode;
836: if (icmp6len < sizeof(struct nd_redirect))
837: goto badlen;
838: if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
839: /* give up local */
840: icmp6_redirect_input(m, off);
841: m = NULL;
842: goto freeit;
843: }
844: icmp6_redirect_input(n, off);
845: /* m stays. */
846: break;
847:
848: case ICMP6_ROUTER_RENUMBERING:
849: if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
850: code != ICMP6_ROUTER_RENUMBERING_RESULT)
851: goto badcode;
852: if (icmp6len < sizeof(struct icmp6_router_renum))
853: goto badlen;
854: break;
855:
856: default:
857: nd6log((LOG_DEBUG,
858: "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
859: icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src),
860: ip6_sprintf(&ip6->ip6_dst),
861: m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0));
862: if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
863: /* ICMPv6 error: MUST deliver it by spec... */
864: code = PRC_NCMDS;
865: /* deliver */
866: } else {
867: /* ICMPv6 informational: MUST not deliver */
868: break;
869: }
870: deliver:
871: if (icmp6_notify_error(m, off, icmp6len, code)) {
872: /* In this case, m should've been freed. */
873: return (IPPROTO_DONE);
874: }
875: break;
876:
877: badcode:
878: icmp6stat.icp6s_badcode++;
879: break;
880:
881: badlen:
882: icmp6stat.icp6s_badlen++;
883: break;
884: }
885:
886: /* deliver the packet to appropriate sockets */
887: icmp6_rip6_input(&m, *offp);
888:
889: return IPPROTO_DONE;
890:
891: freeit:
892: m_freem(m);
893: return IPPROTO_DONE;
894: }
895:
896: static int
897: icmp6_notify_error(m, off, icmp6len, code)
898: struct mbuf *m;
899: int off, icmp6len, code;
900: {
901: struct icmp6_hdr *icmp6;
902: struct ip6_hdr *eip6;
903: u_int32_t notifymtu;
904: struct sockaddr_in6 icmp6src, icmp6dst;
905:
906: if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
907: icmp6stat.icp6s_tooshort++;
908: goto freeit;
909: }
910: IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
911: sizeof(*icmp6) + sizeof(struct ip6_hdr));
912: if (icmp6 == NULL) {
913: icmp6stat.icp6s_tooshort++;
914: return (-1);
915: }
916: eip6 = (struct ip6_hdr *)(icmp6 + 1);
917:
918: /* Detect the upper level protocol */
919: {
920: void (*ctlfunc)(int, struct sockaddr *, void *);
921: u_int8_t nxt = eip6->ip6_nxt;
922: int eoff = off + sizeof(struct icmp6_hdr) +
923: sizeof(struct ip6_hdr);
924: struct ip6ctlparam ip6cp;
925: struct in6_addr *finaldst = NULL;
926: int icmp6type = icmp6->icmp6_type;
927: struct ip6_frag *fh;
928: struct ip6_rthdr *rth;
929: struct ip6_rthdr0 *rth0;
930: int rthlen;
931:
932: while (1) { /* XXX: should avoid infinite loop explicitly? */
933: struct ip6_ext *eh;
934:
935: switch (nxt) {
936: case IPPROTO_HOPOPTS:
937: case IPPROTO_DSTOPTS:
938: case IPPROTO_AH:
939: IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
940: eoff, sizeof(*eh));
941: if (eh == NULL) {
942: icmp6stat.icp6s_tooshort++;
943: return (-1);
944: }
945:
946: if (nxt == IPPROTO_AH)
947: eoff += (eh->ip6e_len + 2) << 2;
948: else
949: eoff += (eh->ip6e_len + 1) << 3;
950: nxt = eh->ip6e_nxt;
951: break;
952: case IPPROTO_ROUTING:
953: /*
954: * When the erroneous packet contains a
955: * routing header, we should examine the
956: * header to determine the final destination.
957: * Otherwise, we can't properly update
958: * information that depends on the final
959: * destination (e.g. path MTU).
960: */
961: IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
962: eoff, sizeof(*rth));
963: if (rth == NULL) {
964: icmp6stat.icp6s_tooshort++;
965: return (-1);
966: }
967: rthlen = (rth->ip6r_len + 1) << 3;
968: /*
969: * XXX: currently there is no
970: * officially defined type other
971: * than type-0.
972: * Note that if the segment left field
973: * is 0, all intermediate hops must
974: * have been passed.
975: */
976: if (rth->ip6r_segleft &&
977: rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
978: int hops;
979:
980: IP6_EXTHDR_GET(rth0,
981: struct ip6_rthdr0 *, m,
982: eoff, rthlen);
983: if (rth0 == NULL) {
984: icmp6stat.icp6s_tooshort++;
985: return (-1);
986: }
987: /* just ignore a bogus header */
988: if ((rth0->ip6r0_len % 2) == 0 &&
989: (hops = rth0->ip6r0_len/2))
990: finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
991: }
992: eoff += rthlen;
993: nxt = rth->ip6r_nxt;
994: break;
995: case IPPROTO_FRAGMENT:
996: IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
997: eoff, sizeof(*fh));
998: if (fh == NULL) {
999: icmp6stat.icp6s_tooshort++;
1000: return (-1);
1001: }
1002: /*
1003: * Data after a fragment header is meaningless
1004: * unless it is the first fragment, but
1005: * we'll go to the notify label for path MTU
1006: * discovery.
1007: */
1008: if (fh->ip6f_offlg & IP6F_OFF_MASK)
1009: goto notify;
1010:
1011: eoff += sizeof(struct ip6_frag);
1012: nxt = fh->ip6f_nxt;
1013: break;
1014: default:
1015: /*
1016: * This case includes ESP and the No Next
1017: * Header. In such cases going to the notify
1018: * label does not have any meaning
1019: * (i.e. ctlfunc will be NULL), but we go
1020: * anyway since we might have to update
1021: * path MTU information.
1022: */
1023: goto notify;
1024: }
1025: }
1026: notify:
1027: IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
1028: sizeof(*icmp6) + sizeof(struct ip6_hdr));
1029: if (icmp6 == NULL) {
1030: icmp6stat.icp6s_tooshort++;
1031: return (-1);
1032: }
1033:
1034: eip6 = (struct ip6_hdr *)(icmp6 + 1);
1035: bzero(&icmp6dst, sizeof(icmp6dst));
1036: icmp6dst.sin6_len = sizeof(struct sockaddr_in6);
1037: icmp6dst.sin6_family = AF_INET6;
1038: if (finaldst == NULL)
1039: icmp6dst.sin6_addr = eip6->ip6_dst;
1040: else
1041: icmp6dst.sin6_addr = *finaldst;
1042: icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
1043: &icmp6dst.sin6_addr);
1044: if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst,
1045: NULL, NULL)) {
1046: /* should be impossbile */
1047: nd6log((LOG_DEBUG,
1048: "icmp6_notify_error: in6_embedscope failed\n"));
1049: goto freeit;
1050: }
1051:
1052: /*
1053: * retrieve parameters from the inner IPv6 header, and convert
1054: * them into sockaddr structures.
1055: */
1056: bzero(&icmp6src, sizeof(icmp6src));
1057: icmp6src.sin6_len = sizeof(struct sockaddr_in6);
1058: icmp6src.sin6_family = AF_INET6;
1059: icmp6src.sin6_addr = eip6->ip6_src;
1060: icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
1061: &icmp6src.sin6_addr);
1062: if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src,
1063: NULL, NULL)) {
1064: /* should be impossbile */
1065: nd6log((LOG_DEBUG,
1066: "icmp6_notify_error: in6_embedscope failed\n"));
1067: goto freeit;
1068: }
1069: icmp6src.sin6_flowinfo =
1070: (eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
1071:
1072: if (finaldst == NULL)
1073: finaldst = &eip6->ip6_dst;
1074: ip6cp.ip6c_m = m;
1075: ip6cp.ip6c_icmp6 = icmp6;
1076: ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
1077: ip6cp.ip6c_off = eoff;
1078: ip6cp.ip6c_finaldst = finaldst;
1079: ip6cp.ip6c_src = &icmp6src;
1080: ip6cp.ip6c_nxt = nxt;
1081:
1082: if (icmp6type == ICMP6_PACKET_TOO_BIG) {
1083: notifymtu = ntohl(icmp6->icmp6_mtu);
1084: ip6cp.ip6c_cmdarg = (void *)¬ifymtu;
1085: }
1086:
1087: ctlfunc = (void (*)(int, struct sockaddr *, void *))
1088: (inet6sw[ip6_protox[nxt]].pr_ctlinput);
1089: if (ctlfunc) {
1090: (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst,
1091: &ip6cp);
1092: }
1093: }
1094: return (0);
1095:
1096: freeit:
1097: m_freem(m);
1098: return (-1);
1099: }
1100:
1101: void
1102: icmp6_mtudisc_update(ip6cp, validated)
1103: struct ip6ctlparam *ip6cp;
1104: int validated;
1105: {
1106: unsigned long rtcount;
1107: struct icmp6_mtudisc_callback *mc;
1108: struct in6_addr *dst = ip6cp->ip6c_finaldst;
1109: struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6;
1110: struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */
1111: u_int mtu = ntohl(icmp6->icmp6_mtu);
1112: struct rtentry *rt = NULL;
1113: struct sockaddr_in6 sin6;
1114:
1115: /*
1116: * allow non-validated cases if memory is plenty, to make traffic
1117: * from non-connected pcb happy.
1118: */
1119: rtcount = rt_timer_count(icmp6_mtudisc_timeout_q);
1120: if (validated) {
1121: if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat)
1122: return;
1123: else if (0 <= icmp6_mtudisc_lowat &&
1124: rtcount > icmp6_mtudisc_lowat) {
1125: /*
1126: * XXX nuke a victim, install the new one.
1127: */
1128: }
1129: } else {
1130: if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat)
1131: return;
1132: }
1133:
1134: bzero(&sin6, sizeof(sin6));
1135: sin6.sin6_family = PF_INET6;
1136: sin6.sin6_len = sizeof(struct sockaddr_in6);
1137: sin6.sin6_addr = *dst;
1138: /* XXX normally, this won't happen */
1139: if (IN6_IS_ADDR_LINKLOCAL(dst)) {
1140: sin6.sin6_addr.s6_addr16[1] =
1141: htons(m->m_pkthdr.rcvif->if_index);
1142: }
1143: /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */
1144: rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6);
1145:
1146: if (rt && (rt->rt_flags & RTF_HOST) &&
1147: !(rt->rt_rmx.rmx_locks & RTV_MTU) &&
1148: (rt->rt_rmx.rmx_mtu > mtu || rt->rt_rmx.rmx_mtu == 0)) {
1149: if (mtu < IN6_LINKMTU(rt->rt_ifp)) {
1150: icmp6stat.icp6s_pmtuchg++;
1151: rt->rt_rmx.rmx_mtu = mtu;
1152: }
1153: }
1154: if (rt) { /* XXX: need braces to avoid conflict with else in RTFREE. */
1155: RTFREE(rt);
1156: }
1157:
1158: /*
1159: * Notify protocols that the MTU for this destination
1160: * has changed.
1161: */
1162: for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
1163: mc = LIST_NEXT(mc, mc_list))
1164: (*mc->mc_func)(&sin6.sin6_addr);
1165: }
1166:
1167: /*
1168: * Process a Node Information Query packet, based on
1169: * draft-ietf-ipngwg-icmp-name-lookups-07.
1170: *
1171: * Spec incompatibilities:
1172: * - IPv6 Subject address handling
1173: * - IPv4 Subject address handling support missing
1174: * - Proxy reply (answer even if it's not for me)
1175: * - joins NI group address at in6_ifattach() time only, does not cope
1176: * with hostname changes by sethostname(3)
1177: */
1178: #ifndef offsetof /* XXX */
1179: #define offsetof(type, member) ((size_t)(&((type *)0)->member))
1180: #endif
1181: static struct mbuf *
1182: ni6_input(m, off)
1183: struct mbuf *m;
1184: int off;
1185: {
1186: struct icmp6_nodeinfo *ni6, *nni6;
1187: struct mbuf *n = NULL;
1188: u_int16_t qtype;
1189: int subjlen;
1190: int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
1191: struct ni_reply_fqdn *fqdn;
1192: int addrs; /* for NI_QTYPE_NODEADDR */
1193: struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
1194: struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */
1195: struct ip6_hdr *ip6;
1196: int oldfqdn = 0; /* if 1, return pascal string (03 draft) */
1197: char *subj = NULL;
1198:
1199: ip6 = mtod(m, struct ip6_hdr *);
1200: IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
1201: if (ni6 == NULL) {
1202: /* m is already reclaimed */
1203: return NULL;
1204: }
1205:
1206: /*
1207: * Validate IPv6 destination address.
1208: *
1209: * The Responder must discard the Query without further processing
1210: * unless it is one of the Responder's unicast or anycast addresses, or
1211: * a link-local scope multicast address which the Responder has joined.
1212: * [icmp-name-lookups-07, Section 4.]
1213: */
1214: bzero(&sin6, sizeof(sin6));
1215: sin6.sin6_family = AF_INET6;
1216: sin6.sin6_len = sizeof(struct sockaddr_in6);
1217: bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
1218: /* XXX scopeid */
1219: if (ifa_ifwithaddr((struct sockaddr *)&sin6))
1220: ; /* unicast/anycast, fine */
1221: else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr))
1222: ; /* link-local multicast, fine */
1223: else
1224: goto bad;
1225:
1226: /* validate query Subject field. */
1227: qtype = ntohs(ni6->ni_qtype);
1228: subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo);
1229: switch (qtype) {
1230: case NI_QTYPE_NOOP:
1231: case NI_QTYPE_SUPTYPES:
1232: /* 07 draft */
1233: if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0)
1234: break;
1235: /* FALLTHROUGH */
1236: case NI_QTYPE_FQDN:
1237: case NI_QTYPE_NODEADDR:
1238: switch (ni6->ni_code) {
1239: case ICMP6_NI_SUBJ_IPV6:
1240: #if ICMP6_NI_SUBJ_IPV6 != 0
1241: case 0:
1242: #endif
1243: /*
1244: * backward compatibility - try to accept 03 draft
1245: * format, where no Subject is present.
1246: */
1247: if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 &&
1248: subjlen == 0) {
1249: oldfqdn++;
1250: break;
1251: }
1252: #if ICMP6_NI_SUBJ_IPV6 != 0
1253: if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6)
1254: goto bad;
1255: #endif
1256:
1257: if (subjlen != sizeof(sin6.sin6_addr))
1258: goto bad;
1259:
1260: /*
1261: * Validate Subject address.
1262: *
1263: * Not sure what exactly "address belongs to the node"
1264: * means in the spec, is it just unicast, or what?
1265: *
1266: * At this moment we consider Subject address as
1267: * "belong to the node" if the Subject address equals
1268: * to the IPv6 destination address; validation for
1269: * IPv6 destination address should have done enough
1270: * check for us.
1271: *
1272: * We do not do proxy at this moment.
1273: */
1274: /* m_pulldown instead of copy? */
1275: m_copydata(m, off + sizeof(struct icmp6_nodeinfo),
1276: subjlen, (caddr_t)&sin6.sin6_addr);
1277: /* XXX kame scope hack */
1278: if (IN6_IS_SCOPE_EMBED(&sin6.sin6_addr)) {
1279: if ((m->m_flags & M_PKTHDR) != 0 &&
1280: m->m_pkthdr.rcvif) {
1281: sin6.sin6_addr.s6_addr16[1] =
1282: htons(m->m_pkthdr.rcvif->if_index);
1283: }
1284: }
1285: subj = (char *)&sin6;
1286: if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6.sin6_addr))
1287: break;
1288:
1289: /*
1290: * XXX if we are to allow other cases, we should really
1291: * be careful about scope here.
1292: * basically, we should disallow queries toward IPv6
1293: * destination X with subject Y, if scope(X) > scope(Y).
1294: * if we allow scope(X) > scope(Y), it will result in
1295: * information leakage across scope boundary.
1296: */
1297: goto bad;
1298:
1299: case ICMP6_NI_SUBJ_FQDN:
1300: /*
1301: * Validate Subject name with gethostname(3).
1302: *
1303: * The behavior may need some debate, since:
1304: * - we are not sure if the node has FQDN as
1305: * hostname (returned by gethostname(3)).
1306: * - the code does wildcard match for truncated names.
1307: * however, we are not sure if we want to perform
1308: * wildcard match, if gethostname(3) side has
1309: * truncated hostname.
1310: */
1311: n = ni6_nametodns(hostname, hostnamelen, 0);
1312: if (!n || n->m_next || n->m_len == 0)
1313: goto bad;
1314: IP6_EXTHDR_GET(subj, char *, m,
1315: off + sizeof(struct icmp6_nodeinfo), subjlen);
1316: if (subj == NULL)
1317: goto bad;
1318: if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *),
1319: n->m_len)) {
1320: goto bad;
1321: }
1322: m_freem(n);
1323: n = NULL;
1324: break;
1325:
1326: case ICMP6_NI_SUBJ_IPV4: /* XXX: to be implemented? */
1327: default:
1328: goto bad;
1329: }
1330: break;
1331: }
1332:
1333: /* refuse based on configuration. XXX ICMP6_NI_REFUSED? */
1334: switch (qtype) {
1335: case NI_QTYPE_FQDN:
1336: if ((icmp6_nodeinfo & 1) == 0)
1337: goto bad;
1338: break;
1339: case NI_QTYPE_NODEADDR:
1340: if ((icmp6_nodeinfo & 2) == 0)
1341: goto bad;
1342: break;
1343: }
1344:
1345: /* guess reply length */
1346: switch (qtype) {
1347: case NI_QTYPE_NOOP:
1348: break; /* no reply data */
1349: case NI_QTYPE_SUPTYPES:
1350: replylen += sizeof(u_int32_t);
1351: break;
1352: case NI_QTYPE_FQDN:
1353: /* XXX will append an mbuf */
1354: replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
1355: break;
1356: case NI_QTYPE_NODEADDR:
1357: addrs = ni6_addrs(ni6, m, &ifp, subj);
1358: if ((replylen += addrs * (sizeof(struct in6_addr) +
1359: sizeof(u_int32_t))) > MCLBYTES)
1360: replylen = MCLBYTES; /* XXX: will truncate pkt later */
1361: break;
1362: default:
1363: /*
1364: * XXX: We must return a reply with the ICMP6 code
1365: * `unknown Qtype' in this case. However we regard the case
1366: * as an FQDN query for backward compatibility.
1367: * Older versions set a random value to this field,
1368: * so it rarely varies in the defined qtypes.
1369: * But the mechanism is not reliable...
1370: * maybe we should obsolete older versions.
1371: */
1372: qtype = NI_QTYPE_FQDN;
1373: /* XXX will append an mbuf */
1374: replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
1375: oldfqdn++;
1376: break;
1377: }
1378:
1379: /* allocate an mbuf to reply. */
1380: MGETHDR(n, M_DONTWAIT, m->m_type);
1381: if (n == NULL) {
1382: m_freem(m);
1383: return (NULL);
1384: }
1385: M_DUP_PKTHDR(n, m); /* just for rcvif */
1386: if (replylen > MHLEN) {
1387: if (replylen > MCLBYTES) {
1388: /*
1389: * XXX: should we try to allocate more? But MCLBYTES
1390: * is probably much larger than IPV6_MMTU...
1391: */
1392: goto bad;
1393: }
1394: MCLGET(n, M_DONTWAIT);
1395: if ((n->m_flags & M_EXT) == 0) {
1396: goto bad;
1397: }
1398: }
1399: n->m_pkthdr.len = n->m_len = replylen;
1400:
1401: /* copy mbuf header and IPv6 + Node Information base headers */
1402: bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr));
1403: nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1);
1404: bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));
1405:
1406: /* qtype dependent procedure */
1407: switch (qtype) {
1408: case NI_QTYPE_NOOP:
1409: nni6->ni_code = ICMP6_NI_SUCCESS;
1410: nni6->ni_flags = 0;
1411: break;
1412: case NI_QTYPE_SUPTYPES:
1413: {
1414: u_int32_t v;
1415: nni6->ni_code = ICMP6_NI_SUCCESS;
1416: nni6->ni_flags = htons(0x0000); /* raw bitmap */
1417: /* supports NOOP, SUPTYPES, FQDN, and NODEADDR */
1418: v = (u_int32_t)htonl(0x0000000f);
1419: bcopy(&v, nni6 + 1, sizeof(u_int32_t));
1420: break;
1421: }
1422: case NI_QTYPE_FQDN:
1423: nni6->ni_code = ICMP6_NI_SUCCESS;
1424: fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
1425: sizeof(struct ip6_hdr) +
1426: sizeof(struct icmp6_nodeinfo));
1427: nni6->ni_flags = 0; /* XXX: meaningless TTL */
1428: fqdn->ni_fqdn_ttl = 0; /* ditto. */
1429: /*
1430: * XXX do we really have FQDN in variable "hostname"?
1431: */
1432: n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn);
1433: if (n->m_next == NULL)
1434: goto bad;
1435: /* XXX we assume that n->m_next is not a chain */
1436: if (n->m_next->m_next != NULL)
1437: goto bad;
1438: n->m_pkthdr.len += n->m_next->m_len;
1439: break;
1440: case NI_QTYPE_NODEADDR:
1441: {
1442: int lenlim, copied;
1443:
1444: nni6->ni_code = ICMP6_NI_SUCCESS;
1445: n->m_pkthdr.len = n->m_len =
1446: sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
1447: lenlim = M_TRAILINGSPACE(n);
1448: copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
1449: /* XXX: reset mbuf length */
1450: n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
1451: sizeof(struct icmp6_nodeinfo) + copied;
1452: break;
1453: }
1454: default:
1455: break; /* XXX impossible! */
1456: }
1457:
1458: nni6->ni_type = ICMP6_NI_REPLY;
1459: m_freem(m);
1460: return (n);
1461:
1462: bad:
1463: m_freem(m);
1464: if (n)
1465: m_freem(n);
1466: return (NULL);
1467: }
1468: #undef hostnamelen
1469:
1470: #define isupper(x) ('A' <= (x) && (x) <= 'Z')
1471: #define isalpha(x) (('A' <= (x) && (x) <= 'Z') || ('a' <= (x) && (x) <= 'z'))
1472: #define isalnum(x) (isalpha(x) || ('0' <= (x) && (x) <= '9'))
1473: #define tolower(x) (isupper(x) ? (x) + 'a' - 'A' : (x))
1474:
1475: /*
1476: * make a mbuf with DNS-encoded string. no compression support.
1477: *
1478: * XXX names with less than 2 dots (like "foo" or "foo.section") will be
1479: * treated as truncated name (two \0 at the end). this is a wild guess.
1480: */
1481: static struct mbuf *
1482: ni6_nametodns(name, namelen, old)
1483: const char *name;
1484: int namelen;
1485: int old; /* return pascal string if non-zero */
1486: {
1487: struct mbuf *m;
1488: char *cp, *ep;
1489: const char *p, *q;
1490: int i, len, nterm;
1491:
1492: if (old)
1493: len = namelen + 1;
1494: else
1495: len = MCLBYTES;
1496:
1497: /* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */
1498: MGET(m, M_DONTWAIT, MT_DATA);
1499: if (m && len > MLEN) {
1500: MCLGET(m, M_DONTWAIT);
1501: if ((m->m_flags & M_EXT) == 0)
1502: goto fail;
1503: }
1504: if (!m)
1505: goto fail;
1506: m->m_next = NULL;
1507:
1508: if (old) {
1509: m->m_len = len;
1510: *mtod(m, char *) = namelen;
1511: bcopy(name, mtod(m, char *) + 1, namelen);
1512: return m;
1513: } else {
1514: m->m_len = 0;
1515: cp = mtod(m, char *);
1516: ep = mtod(m, char *) + M_TRAILINGSPACE(m);
1517:
1518: /* if not certain about my name, return empty buffer */
1519: if (namelen == 0)
1520: return m;
1521:
1522: /*
1523: * guess if it looks like shortened hostname, or FQDN.
1524: * shortened hostname needs two trailing "\0".
1525: */
1526: i = 0;
1527: for (p = name; p < name + namelen; p++) {
1528: if (*p && *p == '.')
1529: i++;
1530: }
1531: if (i < 2)
1532: nterm = 2;
1533: else
1534: nterm = 1;
1535:
1536: p = name;
1537: while (cp < ep && p < name + namelen) {
1538: i = 0;
1539: for (q = p; q < name + namelen && *q && *q != '.'; q++)
1540: i++;
1541: /* result does not fit into mbuf */
1542: if (cp + i + 1 >= ep)
1543: goto fail;
1544: /*
1545: * DNS label length restriction, RFC1035 page 8.
1546: * "i == 0" case is included here to avoid returning
1547: * 0-length label on "foo..bar".
1548: */
1549: if (i <= 0 || i >= 64)
1550: goto fail;
1551: *cp++ = i;
1552: if (!isalpha(p[0]) || !isalnum(p[i - 1]))
1553: goto fail;
1554: while (i > 0) {
1555: if (!isalnum(*p) && *p != '-')
1556: goto fail;
1557: if (isupper(*p)) {
1558: *cp++ = tolower(*p);
1559: p++;
1560: } else
1561: *cp++ = *p++;
1562: i--;
1563: }
1564: p = q;
1565: if (p < name + namelen && *p == '.')
1566: p++;
1567: }
1568: /* termination */
1569: if (cp + nterm >= ep)
1570: goto fail;
1571: while (nterm-- > 0)
1572: *cp++ = '\0';
1573: m->m_len = cp - mtod(m, char *);
1574: return m;
1575: }
1576:
1577: panic("should not reach here");
1578: /* NOTREACHED */
1579:
1580: fail:
1581: if (m)
1582: m_freem(m);
1583: return NULL;
1584: }
1585:
1586: /*
1587: * check if two DNS-encoded string matches. takes care of truncated
1588: * form (with \0\0 at the end). no compression support.
1589: * XXX upper/lowercase match (see RFC2065)
1590: */
1591: static int
1592: ni6_dnsmatch(a, alen, b, blen)
1593: const char *a;
1594: int alen;
1595: const char *b;
1596: int blen;
1597: {
1598: const char *a0, *b0;
1599: int l;
1600:
1601: /* simplest case - need validation? */
1602: if (alen == blen && bcmp(a, b, alen) == 0)
1603: return 1;
1604:
1605: a0 = a;
1606: b0 = b;
1607:
1608: /* termination is mandatory */
1609: if (alen < 2 || blen < 2)
1610: return 0;
1611: if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0')
1612: return 0;
1613: alen--;
1614: blen--;
1615:
1616: while (a - a0 < alen && b - b0 < blen) {
1617: if (a - a0 + 1 > alen || b - b0 + 1 > blen)
1618: return 0;
1619:
1620: if ((signed char)a[0] < 0 || (signed char)b[0] < 0)
1621: return 0;
1622: /* we don't support compression yet */
1623: if (a[0] >= 64 || b[0] >= 64)
1624: return 0;
1625:
1626: /* truncated case */
1627: if (a[0] == 0 && a - a0 == alen - 1)
1628: return 1;
1629: if (b[0] == 0 && b - b0 == blen - 1)
1630: return 1;
1631: if (a[0] == 0 || b[0] == 0)
1632: return 0;
1633:
1634: if (a[0] != b[0])
1635: return 0;
1636: l = a[0];
1637: if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen)
1638: return 0;
1639: if (bcmp(a + 1, b + 1, l) != 0)
1640: return 0;
1641:
1642: a += 1 + l;
1643: b += 1 + l;
1644: }
1645:
1646: if (a - a0 == alen && b - b0 == blen)
1647: return 1;
1648: else
1649: return 0;
1650: }
1651:
1652: /*
1653: * calculate the number of addresses to be returned in the node info reply.
1654: */
1655: static int
1656: ni6_addrs(ni6, m, ifpp, subj)
1657: struct icmp6_nodeinfo *ni6;
1658: struct mbuf *m;
1659: struct ifnet **ifpp;
1660: char *subj;
1661: {
1662: struct ifnet *ifp;
1663: struct in6_ifaddr *ifa6;
1664: struct ifaddr *ifa;
1665: struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */
1666: int addrs = 0, addrsofif, iffound = 0;
1667: int niflags = ni6->ni_flags;
1668:
1669: if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {
1670: switch (ni6->ni_code) {
1671: case ICMP6_NI_SUBJ_IPV6:
1672: if (subj == NULL) /* must be impossible... */
1673: return (0);
1674: subj_ip6 = (struct sockaddr_in6 *)subj;
1675: break;
1676: default:
1677: /*
1678: * XXX: we only support IPv6 subject address for
1679: * this Qtype.
1680: */
1681: return (0);
1682: }
1683: }
1684:
1685: TAILQ_FOREACH(ifp, &ifnet, if_list) {
1686: addrsofif = 0;
1687: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1688: if (ifa->ifa_addr->sa_family != AF_INET6)
1689: continue;
1690: ifa6 = (struct in6_ifaddr *)ifa;
1691:
1692: if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 &&
1693: IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr,
1694: &ifa6->ia_addr.sin6_addr))
1695: iffound = 1;
1696:
1697: /*
1698: * IPv4-mapped addresses can only be returned by a
1699: * Node Information proxy, since they represent
1700: * addresses of IPv4-only nodes, which perforce do
1701: * not implement this protocol.
1702: * [icmp-name-lookups-07, Section 5.4]
1703: * So we don't support NI_NODEADDR_FLAG_COMPAT in
1704: * this function at this moment.
1705: */
1706:
1707: /* What do we have to do about ::1? */
1708: switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1709: case IPV6_ADDR_SCOPE_LINKLOCAL:
1710: if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
1711: continue;
1712: break;
1713: case IPV6_ADDR_SCOPE_SITELOCAL:
1714: if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0)
1715: continue;
1716: break;
1717: case IPV6_ADDR_SCOPE_GLOBAL:
1718: if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0)
1719: continue;
1720: break;
1721: default:
1722: continue;
1723: }
1724:
1725: /*
1726: * check if anycast is okay.
1727: * XXX: just experimental. not in the spec.
1728: */
1729: if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
1730: (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0)
1731: continue; /* we need only unicast addresses */
1732:
1733: addrsofif++; /* count the address */
1734: }
1735: if (iffound) {
1736: *ifpp = ifp;
1737: return (addrsofif);
1738: }
1739:
1740: addrs += addrsofif;
1741: }
1742:
1743: return (addrs);
1744: }
1745:
1746: static int
1747: ni6_store_addrs(ni6, nni6, ifp0, resid)
1748: struct icmp6_nodeinfo *ni6, *nni6;
1749: struct ifnet *ifp0;
1750: int resid;
1751: {
1752: struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
1753: struct in6_ifaddr *ifa6;
1754: struct ifaddr *ifa;
1755: struct ifnet *ifp_dep = NULL;
1756: int copied = 0, allow_deprecated = 0;
1757: u_char *cp = (u_char *)(nni6 + 1);
1758: int niflags = ni6->ni_flags;
1759: u_int32_t ltime;
1760:
1761: if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL))
1762: return (0); /* needless to copy */
1763:
1764: again:
1765:
1766: for (; ifp != TAILQ_END(&ifnet); ifp = TAILQ_NEXT(ifp, if_list)) {
1767: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1768: if (ifa->ifa_addr->sa_family != AF_INET6)
1769: continue;
1770: ifa6 = (struct in6_ifaddr *)ifa;
1771:
1772: if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 &&
1773: allow_deprecated == 0) {
1774: /*
1775: * prefererred address should be put before
1776: * deprecated addresses.
1777: */
1778:
1779: /* record the interface for later search */
1780: if (ifp_dep == NULL)
1781: ifp_dep = ifp;
1782:
1783: continue;
1784: }
1785: else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 &&
1786: allow_deprecated != 0)
1787: continue; /* we now collect deprecated addrs */
1788:
1789: /* What do we have to do about ::1? */
1790: switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
1791: case IPV6_ADDR_SCOPE_LINKLOCAL:
1792: if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
1793: continue;
1794: break;
1795: case IPV6_ADDR_SCOPE_SITELOCAL:
1796: if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0)
1797: continue;
1798: break;
1799: case IPV6_ADDR_SCOPE_GLOBAL:
1800: if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0)
1801: continue;
1802: break;
1803: default:
1804: continue;
1805: }
1806:
1807: /*
1808: * check if anycast is okay.
1809: * XXX: just experimental. not in the spec.
1810: */
1811: if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
1812: (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0)
1813: continue;
1814:
1815: /* now we can copy the address */
1816: if (resid < sizeof(struct in6_addr) +
1817: sizeof(u_int32_t)) {
1818: /*
1819: * We give up much more copy.
1820: * Set the truncate flag and return.
1821: */
1822: nni6->ni_flags |=
1823: NI_NODEADDR_FLAG_TRUNCATE;
1824: return (copied);
1825: }
1826:
1827: /*
1828: * Set the TTL of the address.
1829: * The TTL value should be one of the following
1830: * according to the specification:
1831: *
1832: * 1. The remaining lifetime of a DHCP lease on the
1833: * address, or
1834: * 2. The remaining Valid Lifetime of a prefix from
1835: * which the address was derived through Stateless
1836: * Autoconfiguration.
1837: *
1838: * Note that we currently do not support stateful
1839: * address configuration by DHCPv6, so the former
1840: * case can't happen.
1841: *
1842: * TTL must be 2^31 > TTL >= 0.
1843: */
1844: if (ifa6->ia6_lifetime.ia6t_expire == 0)
1845: ltime = ND6_INFINITE_LIFETIME;
1846: else {
1847: if (ifa6->ia6_lifetime.ia6t_expire >
1848: time_second)
1849: ltime = htonl(ifa6->ia6_lifetime.ia6t_expire - time_second);
1850: else
1851: ltime = 0;
1852: }
1853:
1854: bcopy(<ime, cp, sizeof(u_int32_t));
1855: cp += sizeof(u_int32_t);
1856:
1857: /* copy the address itself */
1858: bcopy(&ifa6->ia_addr.sin6_addr, cp,
1859: sizeof(struct in6_addr));
1860: /* XXX: KAME link-local hack; remove ifindex */
1861: if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr))
1862: ((struct in6_addr *)cp)->s6_addr16[1] = 0;
1863: cp += sizeof(struct in6_addr);
1864:
1865: resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t));
1866: copied += (sizeof(struct in6_addr) +
1867: sizeof(u_int32_t));
1868: }
1869: if (ifp0) /* we need search only on the specified IF */
1870: break;
1871: }
1872:
1873: if (allow_deprecated == 0 && ifp_dep != NULL) {
1874: ifp = ifp_dep;
1875: allow_deprecated = 1;
1876:
1877: goto again;
1878: }
1879:
1880: return (copied);
1881: }
1882:
1883: /*
1884: * XXX almost dup'ed code with rip6_input.
1885: */
1886: static int
1887: icmp6_rip6_input(mp, off)
1888: struct mbuf **mp;
1889: int off;
1890: {
1891: struct mbuf *m = *mp;
1892: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1893: struct in6pcb *in6p;
1894: struct in6pcb *last = NULL;
1895: struct sockaddr_in6 rip6src;
1896: struct icmp6_hdr *icmp6;
1897: struct mbuf *opts = NULL;
1898:
1899: IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
1900: if (icmp6 == NULL) {
1901: /* m is already reclaimed */
1902: return IPPROTO_DONE;
1903: }
1904:
1905: bzero(&rip6src, sizeof(rip6src));
1906: rip6src.sin6_len = sizeof(struct sockaddr_in6);
1907: rip6src.sin6_family = AF_INET6;
1908: /* KAME hack: recover scopeid */
1909: (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif);
1910:
1911: CIRCLEQ_FOREACH(in6p, &rawin6pcbtable.inpt_queue, inp_queue) {
1912: if (!(in6p->in6p_flags & INP_IPV6))
1913: continue;
1914: if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6)
1915: continue;
1916: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
1917: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
1918: continue;
1919: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
1920: !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
1921: continue;
1922: if (in6p->in6p_icmp6filt
1923: && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
1924: in6p->in6p_icmp6filt))
1925: continue;
1926: if (last) {
1927: struct mbuf *n;
1928: if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
1929: if (last->in6p_flags & IN6P_CONTROLOPTS)
1930: ip6_savecontrol(last, n, &opts);
1931: /* strip intermediate headers */
1932: m_adj(n, off);
1933: if (sbappendaddr(&last->in6p_socket->so_rcv,
1934: (struct sockaddr *)&rip6src,
1935: n, opts) == 0) {
1936: /* should notify about lost packet */
1937: m_freem(n);
1938: if (opts)
1939: m_freem(opts);
1940: } else
1941: sorwakeup(last->in6p_socket);
1942: opts = NULL;
1943: }
1944: }
1945: last = in6p;
1946: }
1947: if (last) {
1948: if (last->in6p_flags & IN6P_CONTROLOPTS)
1949: ip6_savecontrol(last, m, &opts);
1950: /* strip intermediate headers */
1951: m_adj(m, off);
1952: if (sbappendaddr(&last->in6p_socket->so_rcv,
1953: (struct sockaddr *)&rip6src,
1954: m, opts) == 0) {
1955: m_freem(m);
1956: if (opts)
1957: m_freem(opts);
1958: } else
1959: sorwakeup(last->in6p_socket);
1960: } else {
1961: m_freem(m);
1962: ip6stat.ip6s_delivered--;
1963: }
1964: return IPPROTO_DONE;
1965: }
1966:
1967: /*
1968: * Reflect the ip6 packet back to the source.
1969: * OFF points to the icmp6 header, counted from the top of the mbuf.
1970: *
1971: * Note: RFC 1885 required that an echo reply should be truncated if it
1972: * did not fit in with (return) path MTU, and KAME code supported the
1973: * behavior. However, as a clarification after the RFC, this limitation
1974: * was removed in a revised version of the spec, RFC 2463. We had kept the
1975: * old behavior, with a (non-default) ifdef block, while the new version of
1976: * the spec was an internet-draft status, and even after the new RFC was
1977: * published. But it would rather make sense to clean the obsoleted part
1978: * up, and to make the code simpler at this stage.
1979: */
1980: void
1981: icmp6_reflect(m, off)
1982: struct mbuf *m;
1983: size_t off;
1984: {
1985: struct ip6_hdr *ip6;
1986: struct icmp6_hdr *icmp6;
1987: struct in6_ifaddr *ia;
1988: struct in6_addr t, *src = 0;
1989: int plen;
1990: int type, code;
1991: struct ifnet *outif = NULL;
1992: struct sockaddr_in6 sa6_src, sa6_dst;
1993:
1994: /* too short to reflect */
1995: if (off < sizeof(struct ip6_hdr)) {
1996: nd6log((LOG_DEBUG,
1997: "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
1998: (u_long)off, (u_long)sizeof(struct ip6_hdr),
1999: __FILE__, __LINE__));
2000: goto bad;
2001: }
2002:
2003: /*
2004: * If there are extra headers between IPv6 and ICMPv6, strip
2005: * off that header first.
2006: */
2007: #ifdef DIAGNOSTIC
2008: if (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) > MHLEN)
2009: panic("assumption failed in icmp6_reflect");
2010: #endif
2011: if (off > sizeof(struct ip6_hdr)) {
2012: size_t l;
2013: struct ip6_hdr nip6;
2014:
2015: l = off - sizeof(struct ip6_hdr);
2016: m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
2017: m_adj(m, l);
2018: l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
2019: if (m->m_len < l) {
2020: if ((m = m_pullup(m, l)) == NULL)
2021: return;
2022: }
2023: bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6));
2024: } else /* off == sizeof(struct ip6_hdr) */ {
2025: size_t l;
2026: l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
2027: if (m->m_len < l) {
2028: if ((m = m_pullup(m, l)) == NULL)
2029: return;
2030: }
2031: }
2032: plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
2033: ip6 = mtod(m, struct ip6_hdr *);
2034: ip6->ip6_nxt = IPPROTO_ICMPV6;
2035: icmp6 = (struct icmp6_hdr *)(ip6 + 1);
2036: type = icmp6->icmp6_type; /* keep type for statistics */
2037: code = icmp6->icmp6_code; /* ditto. */
2038:
2039: t = ip6->ip6_dst;
2040: /*
2041: * ip6_input() drops a packet if its src is multicast.
2042: * So, the src is never multicast.
2043: */
2044: ip6->ip6_dst = ip6->ip6_src;
2045:
2046: /*
2047: * XXX: make sure to embed scope zone information, using
2048: * already embedded IDs or the received interface (if any).
2049: * Note that rcvif may be NULL.
2050: * TODO: scoped routing case (XXX).
2051: */
2052: bzero(&sa6_src, sizeof(sa6_src));
2053: sa6_src.sin6_family = AF_INET6;
2054: sa6_src.sin6_len = sizeof(sa6_src);
2055: sa6_src.sin6_addr = ip6->ip6_dst;
2056: in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif);
2057: in6_embedscope(&ip6->ip6_dst, &sa6_src, NULL, NULL);
2058: bzero(&sa6_dst, sizeof(sa6_dst));
2059: sa6_dst.sin6_family = AF_INET6;
2060: sa6_dst.sin6_len = sizeof(sa6_dst);
2061: sa6_dst.sin6_addr = t;
2062: in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif);
2063: in6_embedscope(&t, &sa6_dst, NULL, NULL);
2064:
2065: /*
2066: * If the incoming packet was addressed directly to us (i.e. unicast),
2067: * use dst as the src for the reply.
2068: * The IN6_IFF_NOTREADY case would be VERY rare, but is possible
2069: * (for example) when we encounter an error while forwarding procedure
2070: * destined to a duplicated address of ours.
2071: */
2072: for (ia = in6_ifaddr; ia; ia = ia->ia_next)
2073: if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
2074: (ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
2075: src = &t;
2076: break;
2077: }
2078: if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) {
2079: /*
2080: * This is the case if the dst is our link-local address
2081: * and the sender is also ourselves.
2082: */
2083: src = &t;
2084: }
2085:
2086: if (src == 0) {
2087: int e;
2088: struct route_in6 ro;
2089:
2090: /*
2091: * This case matches to multicasts, our anycast, or unicasts
2092: * that we do not own. Select a source address based on the
2093: * source address of the erroneous packet.
2094: */
2095: bzero(&ro, sizeof(ro));
2096: src = in6_selectsrc(&sa6_src, NULL, NULL, &ro, NULL, &e);
2097: if (ro.ro_rt) { /* XXX: see comments in icmp6_mtudisc_update */
2098: RTFREE(ro.ro_rt); /* XXX: we could use this */
2099: }
2100: if (src == NULL) {
2101: nd6log((LOG_DEBUG,
2102: "icmp6_reflect: source can't be determined: "
2103: "dst=%s, error=%d\n",
2104: ip6_sprintf(&sa6_src.sin6_addr), e));
2105: goto bad;
2106: }
2107: }
2108:
2109: ip6->ip6_src = *src;
2110:
2111: ip6->ip6_flow = 0;
2112: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
2113: ip6->ip6_vfc |= IPV6_VERSION;
2114: ip6->ip6_nxt = IPPROTO_ICMPV6;
2115: if (m->m_pkthdr.rcvif) {
2116: /* XXX: This may not be the outgoing interface */
2117: ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
2118: } else
2119: ip6->ip6_hlim = ip6_defhlim;
2120:
2121: icmp6->icmp6_cksum = 0;
2122: icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
2123: sizeof(struct ip6_hdr), plen);
2124:
2125: /*
2126: * XXX option handling
2127: */
2128:
2129: m->m_flags &= ~(M_BCAST|M_MCAST);
2130:
2131: /*
2132: * To avoid a "too big" situation at an intermediate router
2133: * and the path MTU discovery process, specify the IPV6_MINMTU flag.
2134: * Note that only echo and node information replies are affected,
2135: * since the length of ICMP6 errors is limited to the minimum MTU.
2136: */
2137: if (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, &outif, NULL) != 0 &&
2138: outif)
2139: icmp6_ifstat_inc(outif, ifs6_out_error);
2140:
2141: if (outif)
2142: icmp6_ifoutstat_inc(outif, type, code);
2143:
2144: return;
2145:
2146: bad:
2147: m_freem(m);
2148: return;
2149: }
2150:
2151: void
2152: icmp6_fasttimo()
2153: {
2154:
2155: mld6_fasttimeo();
2156: }
2157:
2158: static const char *
2159: icmp6_redirect_diag(src6, dst6, tgt6)
2160: struct in6_addr *src6;
2161: struct in6_addr *dst6;
2162: struct in6_addr *tgt6;
2163: {
2164: static char buf[1024];
2165: snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)",
2166: ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6));
2167: return buf;
2168: }
2169:
2170: void
2171: icmp6_redirect_input(m, off)
2172: struct mbuf *m;
2173: int off;
2174: {
2175: struct ifnet *ifp = m->m_pkthdr.rcvif;
2176: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2177: struct nd_redirect *nd_rd;
2178: int icmp6len = ntohs(ip6->ip6_plen);
2179: char *lladdr = NULL;
2180: int lladdrlen = 0;
2181: u_char *redirhdr = NULL;
2182: int redirhdrlen = 0;
2183: struct rtentry *rt = NULL;
2184: int is_router;
2185: int is_onlink;
2186: struct in6_addr src6 = ip6->ip6_src;
2187: struct in6_addr redtgt6;
2188: struct in6_addr reddst6;
2189: union nd_opts ndopts;
2190:
2191: if (!ifp)
2192: return;
2193:
2194: /* XXX if we are router, we don't update route by icmp6 redirect */
2195: if (ip6_forwarding)
2196: goto freeit;
2197: if (!icmp6_rediraccept)
2198: goto freeit;
2199:
2200: IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
2201: if (nd_rd == NULL) {
2202: icmp6stat.icp6s_tooshort++;
2203: return;
2204: }
2205: redtgt6 = nd_rd->nd_rd_target;
2206: reddst6 = nd_rd->nd_rd_dst;
2207:
2208: if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
2209: redtgt6.s6_addr16[1] = htons(ifp->if_index);
2210: if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
2211: reddst6.s6_addr16[1] = htons(ifp->if_index);
2212:
2213: /* validation */
2214: if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
2215: nd6log((LOG_ERR,
2216: "ICMP6 redirect sent from %s rejected; "
2217: "must be from linklocal\n", ip6_sprintf(&src6)));
2218: goto bad;
2219: }
2220: if (ip6->ip6_hlim != 255) {
2221: nd6log((LOG_ERR,
2222: "ICMP6 redirect sent from %s rejected; "
2223: "hlim=%d (must be 255)\n",
2224: ip6_sprintf(&src6), ip6->ip6_hlim));
2225: goto bad;
2226: }
2227: {
2228: /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
2229: struct sockaddr_in6 sin6;
2230: struct in6_addr *gw6;
2231:
2232: bzero(&sin6, sizeof(sin6));
2233: sin6.sin6_family = AF_INET6;
2234: sin6.sin6_len = sizeof(struct sockaddr_in6);
2235: bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
2236: rt = rtalloc1((struct sockaddr *)&sin6, 0, 0);
2237: if (rt) {
2238: if (rt->rt_gateway == NULL ||
2239: rt->rt_gateway->sa_family != AF_INET6) {
2240: nd6log((LOG_ERR,
2241: "ICMP6 redirect rejected; no route "
2242: "with inet6 gateway found for redirect dst: %s\n",
2243: icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2244: RTFREE(rt);
2245: goto bad;
2246: }
2247:
2248: gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
2249: if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
2250: nd6log((LOG_ERR,
2251: "ICMP6 redirect rejected; "
2252: "not equal to gw-for-src=%s (must be same): "
2253: "%s\n",
2254: ip6_sprintf(gw6),
2255: icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2256: RTFREE(rt);
2257: goto bad;
2258: }
2259: } else {
2260: nd6log((LOG_ERR,
2261: "ICMP6 redirect rejected; "
2262: "no route found for redirect dst: %s\n",
2263: icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2264: goto bad;
2265: }
2266: RTFREE(rt);
2267: rt = NULL;
2268: }
2269: if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
2270: nd6log((LOG_ERR,
2271: "ICMP6 redirect rejected; "
2272: "redirect dst must be unicast: %s\n",
2273: icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2274: goto bad;
2275: }
2276:
2277: is_router = is_onlink = 0;
2278: if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
2279: is_router = 1; /* router case */
2280: if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0)
2281: is_onlink = 1; /* on-link destination case */
2282: if (!is_router && !is_onlink) {
2283: nd6log((LOG_ERR,
2284: "ICMP6 redirect rejected; "
2285: "neither router case nor onlink case: %s\n",
2286: icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2287: goto bad;
2288: }
2289: /* validation passed */
2290:
2291: icmp6len -= sizeof(*nd_rd);
2292: nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
2293: if (nd6_options(&ndopts) < 0) {
2294: nd6log((LOG_INFO, "icmp6_redirect_input: "
2295: "invalid ND option, rejected: %s\n",
2296: icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2297: /* nd6_options have incremented stats */
2298: goto freeit;
2299: }
2300:
2301: if (ndopts.nd_opts_tgt_lladdr) {
2302: lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
2303: lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
2304: }
2305:
2306: if (ndopts.nd_opts_rh) {
2307: redirhdrlen = ndopts.nd_opts_rh->nd_opt_rh_len;
2308: redirhdr = (u_char *)(ndopts.nd_opts_rh + 1); /* xxx */
2309: }
2310:
2311: if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
2312: nd6log((LOG_INFO,
2313: "icmp6_redirect_input: lladdrlen mismatch for %s "
2314: "(if %d, icmp6 packet %d): %s\n",
2315: ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2,
2316: icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
2317: goto bad;
2318: }
2319:
2320: /* RFC 2461 8.3 */
2321: nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
2322: is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
2323:
2324: if (!is_onlink) { /* better router case. perform rtredirect. */
2325: /* perform rtredirect */
2326: struct sockaddr_in6 sdst;
2327: struct sockaddr_in6 sgw;
2328: struct sockaddr_in6 ssrc;
2329: unsigned long rtcount;
2330: struct rtentry *newrt = NULL;
2331:
2332: /*
2333: * do not install redirect route, if the number of entries
2334: * is too much (> hiwat). note that, the node (= host) will
2335: * work just fine even if we do not install redirect route
2336: * (there will be additional hops, though).
2337: */
2338: rtcount = rt_timer_count(icmp6_redirect_timeout_q);
2339: if (0 <= icmp6_redirect_hiwat && rtcount > icmp6_redirect_hiwat)
2340: return;
2341: else if (0 <= icmp6_redirect_lowat &&
2342: rtcount > icmp6_redirect_lowat) {
2343: /*
2344: * XXX nuke a victim, install the new one.
2345: */
2346: }
2347:
2348: bzero(&sdst, sizeof(sdst));
2349: bzero(&sgw, sizeof(sgw));
2350: bzero(&ssrc, sizeof(ssrc));
2351: sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
2352: sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
2353: sizeof(struct sockaddr_in6);
2354: bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
2355: bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
2356: bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
2357: rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw,
2358: (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST,
2359: (struct sockaddr *)&ssrc,
2360: &newrt);
2361:
2362: if (newrt) {
2363: (void)rt_timer_add(newrt, icmp6_redirect_timeout,
2364: icmp6_redirect_timeout_q);
2365: rtfree(newrt);
2366: }
2367: }
2368: /* finally update cached route in each socket via pfctlinput */
2369: {
2370: struct sockaddr_in6 sdst;
2371:
2372: bzero(&sdst, sizeof(sdst));
2373: sdst.sin6_family = AF_INET6;
2374: sdst.sin6_len = sizeof(struct sockaddr_in6);
2375: bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
2376: pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst);
2377: }
2378:
2379: freeit:
2380: m_freem(m);
2381: return;
2382:
2383: bad:
2384: icmp6stat.icp6s_badredirect++;
2385: m_freem(m);
2386: }
2387:
2388: void
2389: icmp6_redirect_output(m0, rt)
2390: struct mbuf *m0;
2391: struct rtentry *rt;
2392: {
2393: struct ifnet *ifp; /* my outgoing interface */
2394: struct in6_addr *ifp_ll6;
2395: struct in6_addr *nexthop;
2396: struct ip6_hdr *sip6; /* m0 as struct ip6_hdr */
2397: struct mbuf *m = NULL; /* newly allocated one */
2398: struct ip6_hdr *ip6; /* m as struct ip6_hdr */
2399: struct nd_redirect *nd_rd;
2400: size_t maxlen;
2401: u_char *p;
2402: struct sockaddr_in6 src_sa;
2403:
2404: icmp6_errcount(&icmp6stat.icp6s_outerrhist, ND_REDIRECT, 0);
2405:
2406: /* if we are not router, we don't send icmp6 redirect */
2407: if (!ip6_forwarding)
2408: goto fail;
2409:
2410: /* sanity check */
2411: if (!m0 || !rt || !(rt->rt_flags & RTF_UP) || !(ifp = rt->rt_ifp))
2412: goto fail;
2413:
2414: /*
2415: * Address check:
2416: * the source address must identify a neighbor, and
2417: * the destination address must not be a multicast address
2418: * [RFC 2461, sec 8.2]
2419: */
2420: sip6 = mtod(m0, struct ip6_hdr *);
2421: bzero(&src_sa, sizeof(src_sa));
2422: src_sa.sin6_family = AF_INET6;
2423: src_sa.sin6_len = sizeof(src_sa);
2424: src_sa.sin6_addr = sip6->ip6_src;
2425: /* we don't currently use sin6_scope_id, but eventually use it */
2426: src_sa.sin6_scope_id = in6_addr2scopeid(ifp, &sip6->ip6_src);
2427: if (nd6_is_addr_neighbor(&src_sa, ifp) == 0)
2428: goto fail;
2429: if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
2430: goto fail; /* what should we do here? */
2431:
2432: /* rate limit */
2433: if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0))
2434: goto fail;
2435:
2436: /*
2437: * Since we are going to append up to 1280 bytes (= IPV6_MMTU),
2438: * we almost always ask for an mbuf cluster for simplicity.
2439: * (MHLEN < IPV6_MMTU is almost always true)
2440: */
2441: #if IPV6_MMTU >= MCLBYTES
2442: # error assumption failed about IPV6_MMTU and MCLBYTES
2443: #endif
2444: MGETHDR(m, M_DONTWAIT, MT_HEADER);
2445: if (m && IPV6_MMTU >= MHLEN)
2446: MCLGET(m, M_DONTWAIT);
2447: if (!m)
2448: goto fail;
2449: m->m_pkthdr.rcvif = NULL;
2450: m->m_len = 0;
2451: maxlen = M_TRAILINGSPACE(m);
2452: maxlen = min(IPV6_MMTU, maxlen);
2453: /* just for safety */
2454: if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
2455: ((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
2456: goto fail;
2457: }
2458:
2459: {
2460: /* get ip6 linklocal address for ifp(my outgoing interface). */
2461: struct in6_ifaddr *ia;
2462: if ((ia = in6ifa_ifpforlinklocal(ifp,
2463: IN6_IFF_NOTREADY|
2464: IN6_IFF_ANYCAST)) == NULL)
2465: goto fail;
2466: ifp_ll6 = &ia->ia_addr.sin6_addr;
2467: }
2468:
2469: /* get ip6 linklocal address for the router. */
2470: if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) {
2471: struct sockaddr_in6 *sin6;
2472: sin6 = (struct sockaddr_in6 *)rt->rt_gateway;
2473: nexthop = &sin6->sin6_addr;
2474: if (!IN6_IS_ADDR_LINKLOCAL(nexthop))
2475: nexthop = NULL;
2476: } else
2477: nexthop = NULL;
2478:
2479: /* ip6 */
2480: ip6 = mtod(m, struct ip6_hdr *);
2481: ip6->ip6_flow = 0;
2482: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
2483: ip6->ip6_vfc |= IPV6_VERSION;
2484: /* ip6->ip6_plen will be set later */
2485: ip6->ip6_nxt = IPPROTO_ICMPV6;
2486: ip6->ip6_hlim = 255;
2487: /* ip6->ip6_src must be linklocal addr for my outgoing if. */
2488: bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr));
2489: bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr));
2490:
2491: /* ND Redirect */
2492: nd_rd = (struct nd_redirect *)(ip6 + 1);
2493: nd_rd->nd_rd_type = ND_REDIRECT;
2494: nd_rd->nd_rd_code = 0;
2495: nd_rd->nd_rd_reserved = 0;
2496: if (rt->rt_flags & RTF_GATEWAY) {
2497: /*
2498: * nd_rd->nd_rd_target must be a link-local address in
2499: * better router cases.
2500: */
2501: if (!nexthop)
2502: goto fail;
2503: bcopy(nexthop, &nd_rd->nd_rd_target,
2504: sizeof(nd_rd->nd_rd_target));
2505: bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
2506: sizeof(nd_rd->nd_rd_dst));
2507: } else {
2508: /* make sure redtgt == reddst */
2509: nexthop = &sip6->ip6_dst;
2510: bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target,
2511: sizeof(nd_rd->nd_rd_target));
2512: bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
2513: sizeof(nd_rd->nd_rd_dst));
2514: }
2515:
2516: p = (u_char *)(nd_rd + 1);
2517:
2518: {
2519: /* target lladdr option */
2520: struct rtentry *rt_nexthop = NULL;
2521: int len;
2522: struct sockaddr_dl *sdl;
2523: struct nd_opt_hdr *nd_opt;
2524: char *lladdr;
2525:
2526: rt_nexthop = nd6_lookup(nexthop, 0, ifp);
2527: if (!rt_nexthop)
2528: goto nolladdropt;
2529: len = sizeof(*nd_opt) + ifp->if_addrlen;
2530: len = (len + 7) & ~7; /* round by 8 */
2531: /* safety check */
2532: if (len + (p - (u_char *)ip6) > maxlen)
2533: goto nolladdropt;
2534: if (!(rt_nexthop->rt_flags & RTF_GATEWAY) &&
2535: (rt_nexthop->rt_flags & RTF_LLINFO) &&
2536: (rt_nexthop->rt_gateway->sa_family == AF_LINK) &&
2537: (sdl = (struct sockaddr_dl *)rt_nexthop->rt_gateway) &&
2538: sdl->sdl_alen) {
2539: nd_opt = (struct nd_opt_hdr *)p;
2540: nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
2541: nd_opt->nd_opt_len = len >> 3;
2542: lladdr = (char *)(nd_opt + 1);
2543: bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
2544: p += len;
2545: }
2546: }
2547: nolladdropt:;
2548:
2549: m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
2550:
2551: /* just to be safe */
2552: if (p - (u_char *)ip6 > maxlen)
2553: goto noredhdropt;
2554:
2555: {
2556: /* redirected header option */
2557: int len;
2558: struct nd_opt_rd_hdr *nd_opt_rh;
2559:
2560: /*
2561: * compute the maximum size for icmp6 redirect header option.
2562: * XXX room for auth header?
2563: */
2564: len = maxlen - (p - (u_char *)ip6);
2565: len &= ~7;
2566:
2567: /*
2568: * Redirected header option spec (RFC2461 4.6.3) talks nothing
2569: * about padding/truncate rule for the original IP packet.
2570: * From the discussion on IPv6imp in Feb 1999,
2571: * the consensus was:
2572: * - "attach as much as possible" is the goal
2573: * - pad if not aligned (original size can be guessed by
2574: * original ip6 header)
2575: * Following code adds the padding if it is simple enough,
2576: * and truncates if not.
2577: */
2578: if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) {
2579: /* not enough room, truncate */
2580: m_adj(m0, (len - sizeof(*nd_opt_rh)) -
2581: m0->m_pkthdr.len);
2582: } else {
2583: /*
2584: * enough room, truncate if not aligned.
2585: * we don't pad here for simplicity.
2586: */
2587: size_t extra;
2588:
2589: extra = m0->m_pkthdr.len % 8;
2590: if (extra) {
2591: /* truncate */
2592: m_adj(m0, -extra);
2593: }
2594: len = m0->m_pkthdr.len + sizeof(*nd_opt_rh);
2595: }
2596:
2597: nd_opt_rh = (struct nd_opt_rd_hdr *)p;
2598: bzero(nd_opt_rh, sizeof(*nd_opt_rh));
2599: nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
2600: nd_opt_rh->nd_opt_rh_len = len >> 3;
2601: p += sizeof(*nd_opt_rh);
2602: m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
2603:
2604: /* connect m0 to m */
2605: m->m_pkthdr.len += m0->m_pkthdr.len;
2606: m_cat(m, m0);
2607: m0 = NULL;
2608: }
2609: noredhdropt:
2610: if (m0) {
2611: m_freem(m0);
2612: m0 = NULL;
2613: }
2614:
2615: sip6 = mtod(m, struct ip6_hdr *);
2616: if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
2617: sip6->ip6_src.s6_addr16[1] = 0;
2618: if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst))
2619: sip6->ip6_dst.s6_addr16[1] = 0;
2620: #if 0
2621: if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src))
2622: ip6->ip6_src.s6_addr16[1] = 0;
2623: if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
2624: ip6->ip6_dst.s6_addr16[1] = 0;
2625: #endif
2626: if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target))
2627: nd_rd->nd_rd_target.s6_addr16[1] = 0;
2628: if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst))
2629: nd_rd->nd_rd_dst.s6_addr16[1] = 0;
2630:
2631: ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
2632:
2633: nd_rd->nd_rd_cksum = 0;
2634: nd_rd->nd_rd_cksum
2635: = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen));
2636:
2637: /* send the packet to outside... */
2638: if (ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL) != 0)
2639: icmp6_ifstat_inc(ifp, ifs6_out_error);
2640:
2641: icmp6_ifstat_inc(ifp, ifs6_out_msg);
2642: icmp6_ifstat_inc(ifp, ifs6_out_redirect);
2643: icmp6stat.icp6s_outhist[ND_REDIRECT]++;
2644:
2645: return;
2646:
2647: fail:
2648: if (m)
2649: m_freem(m);
2650: if (m0)
2651: m_freem(m0);
2652: }
2653:
2654: /* NRL PCB */
2655: #define sotoin6pcb sotoinpcb
2656: #define in6pcb inpcb
2657: #define in6p_icmp6filt inp_icmp6filt
2658:
2659: /*
2660: * ICMPv6 socket option processing.
2661: */
2662: int
2663: icmp6_ctloutput(op, so, level, optname, mp)
2664: int op;
2665: struct socket *so;
2666: int level, optname;
2667: struct mbuf **mp;
2668: {
2669: int error = 0;
2670: int optlen;
2671: struct in6pcb *in6p = sotoin6pcb(so);
2672: struct mbuf *m = *mp;
2673:
2674: optlen = m ? m->m_len : 0;
2675:
2676: if (level != IPPROTO_ICMPV6) {
2677: if (op == PRCO_SETOPT && m)
2678: (void)m_free(m);
2679: return EINVAL;
2680: }
2681:
2682: switch (op) {
2683: case PRCO_SETOPT:
2684: switch (optname) {
2685: case ICMP6_FILTER:
2686: {
2687: struct icmp6_filter *p;
2688:
2689: if (optlen != sizeof(*p)) {
2690: error = EMSGSIZE;
2691: break;
2692: }
2693: p = mtod(m, struct icmp6_filter *);
2694: if (!p || !in6p->in6p_icmp6filt) {
2695: error = EINVAL;
2696: break;
2697: }
2698: bcopy(p, in6p->in6p_icmp6filt,
2699: sizeof(struct icmp6_filter));
2700: error = 0;
2701: break;
2702: }
2703:
2704: default:
2705: error = ENOPROTOOPT;
2706: break;
2707: }
2708: if (m)
2709: (void)m_freem(m);
2710: break;
2711:
2712: case PRCO_GETOPT:
2713: switch (optname) {
2714: case ICMP6_FILTER:
2715: {
2716: struct icmp6_filter *p;
2717:
2718: if (!in6p->in6p_icmp6filt) {
2719: error = EINVAL;
2720: break;
2721: }
2722: *mp = m = m_get(M_WAIT, MT_SOOPTS);
2723: m->m_len = sizeof(struct icmp6_filter);
2724: p = mtod(m, struct icmp6_filter *);
2725: bcopy(in6p->in6p_icmp6filt, p,
2726: sizeof(struct icmp6_filter));
2727: error = 0;
2728: break;
2729: }
2730:
2731: default:
2732: error = ENOPROTOOPT;
2733: break;
2734: }
2735: break;
2736: }
2737:
2738: return (error);
2739: }
2740:
2741: /* NRL PCB */
2742: #undef sotoin6pcb
2743: #undef in6pcb
2744: #undef in6p_icmp6filt
2745:
2746: /*
2747: * Perform rate limit check.
2748: * Returns 0 if it is okay to send the icmp6 packet.
2749: * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
2750: * limitation.
2751: *
2752: * XXX per-destination/type check necessary?
2753: */
2754: static int
2755: icmp6_ratelimit(dst, type, code)
2756: const struct in6_addr *dst; /* not used at this moment */
2757: const int type; /* not used at this moment */
2758: const int code; /* not used at this moment */
2759: {
2760: int ret;
2761:
2762: ret = 0; /* okay to send */
2763:
2764: /* PPS limit */
2765: if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count,
2766: icmp6errppslim)) {
2767: /* The packet is subject to rate limit */
2768: ret++;
2769: }
2770:
2771: return ret;
2772: }
2773:
2774: static struct rtentry *
2775: icmp6_mtudisc_clone(dst)
2776: struct sockaddr *dst;
2777: {
2778: struct rtentry *rt;
2779: int error;
2780:
2781: rt = rtalloc1(dst, 1, 0);
2782: if (rt == 0)
2783: return NULL;
2784:
2785: /* If we didn't get a host route, allocate one */
2786: if ((rt->rt_flags & RTF_HOST) == 0) {
2787: struct rtentry *nrt;
2788:
2789: error = rtrequest((int) RTM_ADD, dst,
2790: (struct sockaddr *) rt->rt_gateway,
2791: (struct sockaddr *) 0,
2792: RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt, 0);
2793: if (error) {
2794: rtfree(rt);
2795: return NULL;
2796: }
2797: nrt->rt_rmx = rt->rt_rmx;
2798: rtfree(rt);
2799: rt = nrt;
2800: }
2801: error = rt_timer_add(rt, icmp6_mtudisc_timeout,
2802: icmp6_mtudisc_timeout_q);
2803: if (error) {
2804: rtfree(rt);
2805: return NULL;
2806: }
2807:
2808: return rt; /* caller need to call rtfree() */
2809: }
2810:
2811: static void
2812: icmp6_mtudisc_timeout(rt, r)
2813: struct rtentry *rt;
2814: struct rttimer *r;
2815: {
2816: if (rt == NULL)
2817: panic("icmp6_mtudisc_timeout: bad route to timeout");
2818: if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
2819: (RTF_DYNAMIC | RTF_HOST)) {
2820: rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
2821: rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0, 0);
2822: } else {
2823: if (!(rt->rt_rmx.rmx_locks & RTV_MTU))
2824: rt->rt_rmx.rmx_mtu = 0;
2825: }
2826: }
2827:
2828: static void
2829: icmp6_redirect_timeout(rt, r)
2830: struct rtentry *rt;
2831: struct rttimer *r;
2832: {
2833: if (rt == NULL)
2834: panic("icmp6_redirect_timeout: bad route to timeout");
2835: if ((rt->rt_flags & (RTF_GATEWAY | RTF_DYNAMIC | RTF_HOST)) ==
2836: (RTF_GATEWAY | RTF_DYNAMIC | RTF_HOST)) {
2837: rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
2838: rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0, 0);
2839: }
2840: }
2841:
2842: #include <uvm/uvm_extern.h>
2843: #include <sys/sysctl.h>
2844:
2845: int *icmpv6ctl_vars[ICMPV6CTL_MAXID] = ICMPV6CTL_VARS;
2846:
2847: int
2848: icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
2849: int *name;
2850: u_int namelen;
2851: void *oldp;
2852: size_t *oldlenp;
2853: void *newp;
2854: size_t newlen;
2855: {
2856:
2857: /* All sysctl names at this level are terminal. */
2858: if (namelen != 1)
2859: return ENOTDIR;
2860:
2861: switch (name[0]) {
2862:
2863: case ICMPV6CTL_STATS:
2864: return sysctl_rdstruct(oldp, oldlenp, newp,
2865: &icmp6stat, sizeof(icmp6stat));
2866: case ICMPV6CTL_ND6_DRLIST:
2867: case ICMPV6CTL_ND6_PRLIST:
2868: return nd6_sysctl(name[0], oldp, oldlenp, newp, newlen);
2869: default:
2870: if (name[0] < ICMPV6CTL_MAXID)
2871: return (sysctl_int_arr(icmpv6ctl_vars, name, namelen,
2872: oldp, oldlenp, newp, newlen));
2873: return ENOPROTOOPT;
2874: }
2875: /* NOTREACHED */
2876: }
CVSweb