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