| @@ -1,2109 +1,2126 @@ | | | @@ -1,2109 +1,2126 @@ |
1 | /* $NetBSD: icmp6.c,v 1.108 2005/01/17 10:16:07 itojun Exp $ */ | | 1 | /* $NetBSD: icmp6.c,v 1.108.8.1 2008/10/03 09:21:02 jdc Exp $ */ |
2 | /* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */ | | 2 | /* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | | 5 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | | 9 | * modification, are permitted provided that the following conditions |
10 | * are met: | | 10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | | 14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. | | 15 | * documentation and/or other materials provided with the distribution. |
16 | * 3. Neither the name of the project nor the names of its contributors | | 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 | | 17 | * may be used to endorse or promote products derived from this software |
18 | * without specific prior written permission. | | 18 | * without specific prior written permission. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | | 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 | | 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | | 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 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 | | 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 | | 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 | | 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 | * SUCH DAMAGE. | | 30 | * SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | /* | | 33 | /* |
34 | * Copyright (c) 1982, 1986, 1988, 1993 | | 34 | * Copyright (c) 1982, 1986, 1988, 1993 |
35 | * The Regents of the University of California. All rights reserved. | | 35 | * The Regents of the University of California. All rights reserved. |
36 | * | | 36 | * |
37 | * Redistribution and use in source and binary forms, with or without | | 37 | * Redistribution and use in source and binary forms, with or without |
38 | * modification, are permitted provided that the following conditions | | 38 | * modification, are permitted provided that the following conditions |
39 | * are met: | | 39 | * are met: |
40 | * 1. Redistributions of source code must retain the above copyright | | 40 | * 1. Redistributions of source code must retain the above copyright |
41 | * notice, this list of conditions and the following disclaimer. | | 41 | * notice, this list of conditions and the following disclaimer. |
42 | * 2. Redistributions in binary form must reproduce the above copyright | | 42 | * 2. Redistributions in binary form must reproduce the above copyright |
43 | * notice, this list of conditions and the following disclaimer in the | | 43 | * notice, this list of conditions and the following disclaimer in the |
44 | * documentation and/or other materials provided with the distribution. | | 44 | * documentation and/or other materials provided with the distribution. |
45 | * 3. Neither the name of the University nor the names of its contributors | | 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 | | 46 | * may be used to endorse or promote products derived from this software |
47 | * without specific prior written permission. | | 47 | * without specific prior written permission. |
48 | * | | 48 | * |
49 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 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 | | 50 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
51 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 51 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
53 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 53 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
54 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 54 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
55 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 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 | | 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 | | 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 | | 58 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
59 | * SUCH DAMAGE. | | 59 | * SUCH DAMAGE. |
60 | * | | 60 | * |
61 | * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 | | 61 | * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 |
62 | */ | | 62 | */ |
63 | | | 63 | |
64 | #include <sys/cdefs.h> | | 64 | #include <sys/cdefs.h> |
65 | __KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.108 2005/01/17 10:16:07 itojun Exp $"); | | 65 | __KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.108.8.1 2008/10/03 09:21:02 jdc Exp $"); |
66 | | | 66 | |
67 | #include "opt_inet.h" | | 67 | #include "opt_inet.h" |
68 | #include "opt_ipsec.h" | | 68 | #include "opt_ipsec.h" |
69 | | | 69 | |
70 | #include <sys/param.h> | | 70 | #include <sys/param.h> |
71 | #include <sys/systm.h> | | 71 | #include <sys/systm.h> |
72 | #include <sys/malloc.h> | | 72 | #include <sys/malloc.h> |
73 | #include <sys/mbuf.h> | | 73 | #include <sys/mbuf.h> |
74 | #include <sys/protosw.h> | | 74 | #include <sys/protosw.h> |
75 | #include <sys/socket.h> | | 75 | #include <sys/socket.h> |
76 | #include <sys/socketvar.h> | | 76 | #include <sys/socketvar.h> |
77 | #include <sys/time.h> | | 77 | #include <sys/time.h> |
78 | #include <sys/kernel.h> | | 78 | #include <sys/kernel.h> |
79 | #include <sys/syslog.h> | | 79 | #include <sys/syslog.h> |
80 | #include <sys/domain.h> | | 80 | #include <sys/domain.h> |
81 | #include <sys/sysctl.h> | | 81 | #include <sys/sysctl.h> |
82 | | | 82 | |
83 | #include <net/if.h> | | 83 | #include <net/if.h> |
84 | #include <net/route.h> | | 84 | #include <net/route.h> |
85 | #include <net/if_dl.h> | | 85 | #include <net/if_dl.h> |
86 | #include <net/if_types.h> | | 86 | #include <net/if_types.h> |
87 | | | 87 | |
88 | #include <netinet/in.h> | | 88 | #include <netinet/in.h> |
89 | #include <netinet/in_var.h> | | 89 | #include <netinet/in_var.h> |
90 | #include <netinet/ip6.h> | | 90 | #include <netinet/ip6.h> |
91 | #include <netinet6/ip6_var.h> | | 91 | #include <netinet6/ip6_var.h> |
92 | #include <netinet/icmp6.h> | | 92 | #include <netinet/icmp6.h> |
93 | #include <netinet6/mld6_var.h> | | 93 | #include <netinet6/mld6_var.h> |
94 | #include <netinet6/in6_pcb.h> | | 94 | #include <netinet6/in6_pcb.h> |
95 | #include <netinet6/nd6.h> | | 95 | #include <netinet6/nd6.h> |
96 | #include <netinet6/in6_ifattach.h> | | 96 | #include <netinet6/in6_ifattach.h> |
97 | #include <netinet6/ip6protosw.h> | | 97 | #include <netinet6/ip6protosw.h> |
98 | | | 98 | |
99 | #ifdef IPSEC | | 99 | #ifdef IPSEC |
100 | #include <netinet6/ipsec.h> | | 100 | #include <netinet6/ipsec.h> |
101 | #include <netkey/key.h> | | 101 | #include <netkey/key.h> |
102 | #endif | | 102 | #endif |
103 | | | 103 | |
104 | #include "faith.h" | | 104 | #include "faith.h" |
105 | #if defined(NFAITH) && 0 < NFAITH | | 105 | #if defined(NFAITH) && 0 < NFAITH |
106 | #include <net/if_faith.h> | | 106 | #include <net/if_faith.h> |
107 | #endif | | 107 | #endif |
108 | | | 108 | |
109 | #include <net/net_osdep.h> | | 109 | #include <net/net_osdep.h> |
110 | | | 110 | |
111 | extern struct domain inet6domain; | | 111 | extern struct domain inet6domain; |
112 | | | 112 | |
113 | struct icmp6stat icmp6stat; | | 113 | struct icmp6stat icmp6stat; |
114 | | | 114 | |
115 | extern struct inpcbtable raw6cbtable; | | 115 | extern struct inpcbtable raw6cbtable; |
116 | extern int icmp6errppslim; | | 116 | extern int icmp6errppslim; |
117 | static int icmp6errpps_count = 0; | | 117 | static int icmp6errpps_count = 0; |
118 | static struct timeval icmp6errppslim_last; | | 118 | static struct timeval icmp6errppslim_last; |
119 | extern int icmp6_nodeinfo; | | 119 | extern int icmp6_nodeinfo; |
120 | | | 120 | |
121 | /* | | 121 | /* |
122 | * List of callbacks to notify when Path MTU changes are made. | | 122 | * List of callbacks to notify when Path MTU changes are made. |
123 | */ | | 123 | */ |
124 | struct icmp6_mtudisc_callback { | | 124 | struct icmp6_mtudisc_callback { |
125 | LIST_ENTRY(icmp6_mtudisc_callback) mc_list; | | 125 | LIST_ENTRY(icmp6_mtudisc_callback) mc_list; |
126 | void (*mc_func) __P((struct in6_addr *)); | | 126 | void (*mc_func) __P((struct in6_addr *)); |
127 | }; | | 127 | }; |
128 | | | 128 | |
129 | LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks = | | 129 | LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks = |
130 | LIST_HEAD_INITIALIZER(&icmp6_mtudisc_callbacks); | | 130 | LIST_HEAD_INITIALIZER(&icmp6_mtudisc_callbacks); |
131 | | | 131 | |
132 | static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL; | | 132 | static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL; |
133 | extern int pmtu_expire; | | 133 | extern int pmtu_expire; |
134 | | | 134 | |
135 | /* XXX do these values make any sense? */ | | 135 | /* XXX do these values make any sense? */ |
136 | static int icmp6_mtudisc_hiwat = 1280; | | 136 | static int icmp6_mtudisc_hiwat = 1280; |
137 | static int icmp6_mtudisc_lowat = 256; | | 137 | static int icmp6_mtudisc_lowat = 256; |
138 | | | 138 | |
139 | /* | | 139 | /* |
140 | * keep track of # of redirect routes. | | 140 | * keep track of # of redirect routes. |
141 | */ | | 141 | */ |
142 | static struct rttimer_queue *icmp6_redirect_timeout_q = NULL; | | 142 | static struct rttimer_queue *icmp6_redirect_timeout_q = NULL; |
143 | | | 143 | |
144 | /* XXX experimental, turned off */ | | 144 | /* XXX experimental, turned off */ |
145 | static int icmp6_redirect_hiwat = -1; | | 145 | static int icmp6_redirect_hiwat = -1; |
146 | static int icmp6_redirect_lowat = -1; | | 146 | static int icmp6_redirect_lowat = -1; |
147 | | | 147 | |
148 | static void icmp6_errcount __P((struct icmp6errstat *, int, int)); | | 148 | static void icmp6_errcount __P((struct icmp6errstat *, int, int)); |
149 | static int icmp6_rip6_input __P((struct mbuf **, int)); | | 149 | static int icmp6_rip6_input __P((struct mbuf **, int)); |
150 | static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int)); | | 150 | static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int)); |
151 | static const char *icmp6_redirect_diag __P((struct in6_addr *, | | 151 | static const char *icmp6_redirect_diag __P((struct in6_addr *, |
152 | struct in6_addr *, struct in6_addr *)); | | 152 | struct in6_addr *, struct in6_addr *)); |
153 | static struct mbuf *ni6_input __P((struct mbuf *, int)); | | 153 | static struct mbuf *ni6_input __P((struct mbuf *, int)); |
154 | static struct mbuf *ni6_nametodns __P((const char *, int, int)); | | 154 | static struct mbuf *ni6_nametodns __P((const char *, int, int)); |
155 | static int ni6_dnsmatch __P((const char *, int, const char *, int)); | | 155 | static int ni6_dnsmatch __P((const char *, int, const char *, int)); |
156 | static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *, | | 156 | static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *, |
157 | struct ifnet **, char *)); | | 157 | struct ifnet **, char *)); |
158 | static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, | | 158 | static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, |
159 | struct ifnet *, int)); | | 159 | struct ifnet *, int)); |
160 | static int icmp6_notify_error __P((struct mbuf *, int, int, int)); | | 160 | static int icmp6_notify_error __P((struct mbuf *, int, int, int)); |
161 | static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *)); | | 161 | static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *)); |
162 | static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *)); | | 162 | static void icmp6_mtudisc_timeout __P((struct rtentry *, struct rttimer *)); |
163 | static void icmp6_redirect_timeout __P((struct rtentry *, struct rttimer *)); | | 163 | static void icmp6_redirect_timeout __P((struct rtentry *, struct rttimer *)); |
164 | | | 164 | |
165 | void | | 165 | void |
166 | icmp6_init() | | 166 | icmp6_init() |
167 | { | | 167 | { |
168 | mld6_init(); | | 168 | mld6_init(); |
169 | icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire); | | 169 | icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire); |
170 | icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout); | | 170 | icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout); |
171 | } | | 171 | } |
172 | | | 172 | |
173 | static void | | 173 | static void |
174 | icmp6_errcount(stat, type, code) | | 174 | icmp6_errcount(stat, type, code) |
175 | struct icmp6errstat *stat; | | 175 | struct icmp6errstat *stat; |
176 | int type, code; | | 176 | int type, code; |
177 | { | | 177 | { |
178 | switch (type) { | | 178 | switch (type) { |
179 | case ICMP6_DST_UNREACH: | | 179 | case ICMP6_DST_UNREACH: |
180 | switch (code) { | | 180 | switch (code) { |
181 | case ICMP6_DST_UNREACH_NOROUTE: | | 181 | case ICMP6_DST_UNREACH_NOROUTE: |
182 | stat->icp6errs_dst_unreach_noroute++; | | 182 | stat->icp6errs_dst_unreach_noroute++; |
183 | return; | | 183 | return; |
184 | case ICMP6_DST_UNREACH_ADMIN: | | 184 | case ICMP6_DST_UNREACH_ADMIN: |
185 | stat->icp6errs_dst_unreach_admin++; | | 185 | stat->icp6errs_dst_unreach_admin++; |
186 | return; | | 186 | return; |
187 | case ICMP6_DST_UNREACH_BEYONDSCOPE: | | 187 | case ICMP6_DST_UNREACH_BEYONDSCOPE: |
188 | stat->icp6errs_dst_unreach_beyondscope++; | | 188 | stat->icp6errs_dst_unreach_beyondscope++; |
189 | return; | | 189 | return; |
190 | case ICMP6_DST_UNREACH_ADDR: | | 190 | case ICMP6_DST_UNREACH_ADDR: |
191 | stat->icp6errs_dst_unreach_addr++; | | 191 | stat->icp6errs_dst_unreach_addr++; |
192 | return; | | 192 | return; |
193 | case ICMP6_DST_UNREACH_NOPORT: | | 193 | case ICMP6_DST_UNREACH_NOPORT: |
194 | stat->icp6errs_dst_unreach_noport++; | | 194 | stat->icp6errs_dst_unreach_noport++; |
195 | return; | | 195 | return; |
196 | } | | 196 | } |
197 | break; | | 197 | break; |
198 | case ICMP6_PACKET_TOO_BIG: | | 198 | case ICMP6_PACKET_TOO_BIG: |
199 | stat->icp6errs_packet_too_big++; | | 199 | stat->icp6errs_packet_too_big++; |
200 | return; | | 200 | return; |
201 | case ICMP6_TIME_EXCEEDED: | | 201 | case ICMP6_TIME_EXCEEDED: |
202 | switch (code) { | | 202 | switch (code) { |
203 | case ICMP6_TIME_EXCEED_TRANSIT: | | 203 | case ICMP6_TIME_EXCEED_TRANSIT: |
204 | stat->icp6errs_time_exceed_transit++; | | 204 | stat->icp6errs_time_exceed_transit++; |
205 | return; | | 205 | return; |
206 | case ICMP6_TIME_EXCEED_REASSEMBLY: | | 206 | case ICMP6_TIME_EXCEED_REASSEMBLY: |
207 | stat->icp6errs_time_exceed_reassembly++; | | 207 | stat->icp6errs_time_exceed_reassembly++; |
208 | return; | | 208 | return; |
209 | } | | 209 | } |
210 | break; | | 210 | break; |
211 | case ICMP6_PARAM_PROB: | | 211 | case ICMP6_PARAM_PROB: |
212 | switch (code) { | | 212 | switch (code) { |
213 | case ICMP6_PARAMPROB_HEADER: | | 213 | case ICMP6_PARAMPROB_HEADER: |
214 | stat->icp6errs_paramprob_header++; | | 214 | stat->icp6errs_paramprob_header++; |
215 | return; | | 215 | return; |
216 | case ICMP6_PARAMPROB_NEXTHEADER: | | 216 | case ICMP6_PARAMPROB_NEXTHEADER: |
217 | stat->icp6errs_paramprob_nextheader++; | | 217 | stat->icp6errs_paramprob_nextheader++; |
218 | return; | | 218 | return; |
219 | case ICMP6_PARAMPROB_OPTION: | | 219 | case ICMP6_PARAMPROB_OPTION: |
220 | stat->icp6errs_paramprob_option++; | | 220 | stat->icp6errs_paramprob_option++; |
221 | return; | | 221 | return; |
222 | } | | 222 | } |
223 | break; | | 223 | break; |
224 | case ND_REDIRECT: | | 224 | case ND_REDIRECT: |
225 | stat->icp6errs_redirect++; | | 225 | stat->icp6errs_redirect++; |
226 | return; | | 226 | return; |
227 | } | | 227 | } |
228 | stat->icp6errs_unknown++; | | 228 | stat->icp6errs_unknown++; |
229 | } | | 229 | } |
230 | | | 230 | |
231 | /* | | 231 | /* |
232 | * Register a Path MTU Discovery callback. | | 232 | * Register a Path MTU Discovery callback. |
233 | */ | | 233 | */ |
234 | void | | 234 | void |
235 | icmp6_mtudisc_callback_register(func) | | 235 | icmp6_mtudisc_callback_register(func) |
236 | void (*func) __P((struct in6_addr *)); | | 236 | void (*func) __P((struct in6_addr *)); |
237 | { | | 237 | { |
238 | struct icmp6_mtudisc_callback *mc; | | 238 | struct icmp6_mtudisc_callback *mc; |
239 | | | 239 | |
240 | for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL; | | 240 | for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL; |
241 | mc = LIST_NEXT(mc, mc_list)) { | | 241 | mc = LIST_NEXT(mc, mc_list)) { |
242 | if (mc->mc_func == func) | | 242 | if (mc->mc_func == func) |
243 | return; | | 243 | return; |
244 | } | | 244 | } |
245 | | | 245 | |
246 | mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT); | | 246 | mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT); |
247 | if (mc == NULL) | | 247 | if (mc == NULL) |
248 | panic("icmp6_mtudisc_callback_register"); | | 248 | panic("icmp6_mtudisc_callback_register"); |
249 | | | 249 | |
250 | mc->mc_func = func; | | 250 | mc->mc_func = func; |
251 | LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list); | | 251 | LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list); |
252 | } | | 252 | } |
253 | | | 253 | |
254 | /* | | 254 | /* |
255 | * Generate an error packet of type error in response to bad IP6 packet. | | 255 | * Generate an error packet of type error in response to bad IP6 packet. |
256 | */ | | 256 | */ |
257 | void | | 257 | void |
258 | icmp6_error(m, type, code, param) | | 258 | icmp6_error(m, type, code, param) |
259 | struct mbuf *m; | | 259 | struct mbuf *m; |
260 | int type, code, param; | | 260 | int type, code, param; |
261 | { | | 261 | { |
262 | struct ip6_hdr *oip6, *nip6; | | 262 | struct ip6_hdr *oip6, *nip6; |
263 | struct icmp6_hdr *icmp6; | | 263 | struct icmp6_hdr *icmp6; |
264 | u_int preplen; | | 264 | u_int preplen; |
265 | int off; | | 265 | int off; |
266 | int nxt; | | 266 | int nxt; |
267 | | | 267 | |
268 | icmp6stat.icp6s_error++; | | 268 | icmp6stat.icp6s_error++; |
269 | | | 269 | |
270 | /* count per-type-code statistics */ | | 270 | /* count per-type-code statistics */ |
271 | icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code); | | 271 | icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code); |
272 | | | 272 | |
273 | if (m->m_flags & M_DECRYPTED) { | | 273 | if (m->m_flags & M_DECRYPTED) { |
274 | icmp6stat.icp6s_canterror++; | | 274 | icmp6stat.icp6s_canterror++; |
275 | goto freeit; | | 275 | goto freeit; |
276 | } | | 276 | } |
277 | | | 277 | |
278 | if (m->m_len < sizeof(struct ip6_hdr)) { | | 278 | if (m->m_len < sizeof(struct ip6_hdr)) { |
279 | m = m_pullup(m, sizeof(struct ip6_hdr)); | | 279 | m = m_pullup(m, sizeof(struct ip6_hdr)); |
280 | if (m == NULL) | | 280 | if (m == NULL) |
281 | return; | | 281 | return; |
282 | } | | 282 | } |
283 | oip6 = mtod(m, struct ip6_hdr *); | | 283 | oip6 = mtod(m, struct ip6_hdr *); |
284 | | | 284 | |
285 | /* | | 285 | /* |
286 | * If the destination address of the erroneous packet is a multicast | | 286 | * If the destination address of the erroneous packet is a multicast |
287 | * address, or the packet was sent using link-layer multicast, | | 287 | * address, or the packet was sent using link-layer multicast, |
288 | * we should basically suppress sending an error (RFC 2463, Section | | 288 | * we should basically suppress sending an error (RFC 2463, Section |
289 | * 2.4). | | 289 | * 2.4). |
290 | * We have two exceptions (the item e.2 in that section): | | 290 | * We have two exceptions (the item e.2 in that section): |
291 | * - the Pakcet Too Big message can be sent for path MTU discovery. | | 291 | * - the Pakcet Too Big message can be sent for path MTU discovery. |
292 | * - the Parameter Problem Message that can be allowed an icmp6 error | | 292 | * - the Parameter Problem Message that can be allowed an icmp6 error |
293 | * in the option type field. This check has been done in | | 293 | * in the option type field. This check has been done in |
294 | * ip6_unknown_opt(), so we can just check the type and code. | | 294 | * ip6_unknown_opt(), so we can just check the type and code. |
295 | */ | | 295 | */ |
296 | if ((m->m_flags & (M_BCAST|M_MCAST) || | | 296 | if ((m->m_flags & (M_BCAST|M_MCAST) || |
297 | IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) && | | 297 | IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) && |
298 | (type != ICMP6_PACKET_TOO_BIG && | | 298 | (type != ICMP6_PACKET_TOO_BIG && |
299 | (type != ICMP6_PARAM_PROB || | | 299 | (type != ICMP6_PARAM_PROB || |
300 | code != ICMP6_PARAMPROB_OPTION))) | | 300 | code != ICMP6_PARAMPROB_OPTION))) |
301 | goto freeit; | | 301 | goto freeit; |
302 | | | 302 | |
303 | /* | | 303 | /* |
304 | * RFC 2463, 2.4 (e.5): source address check. | | 304 | * RFC 2463, 2.4 (e.5): source address check. |
305 | * XXX: the case of anycast source? | | 305 | * XXX: the case of anycast source? |
306 | */ | | 306 | */ |
307 | if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) || | | 307 | if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) || |
308 | IN6_IS_ADDR_MULTICAST(&oip6->ip6_src)) | | 308 | IN6_IS_ADDR_MULTICAST(&oip6->ip6_src)) |
309 | goto freeit; | | 309 | goto freeit; |
310 | | | 310 | |
311 | /* | | 311 | /* |
312 | * If we are about to send ICMPv6 against ICMPv6 error/redirect, | | 312 | * If we are about to send ICMPv6 against ICMPv6 error/redirect, |
313 | * don't do it. | | 313 | * don't do it. |
314 | */ | | 314 | */ |
315 | nxt = -1; | | 315 | nxt = -1; |
316 | off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); | | 316 | off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); |
317 | if (off >= 0 && nxt == IPPROTO_ICMPV6) { | | 317 | if (off >= 0 && nxt == IPPROTO_ICMPV6) { |
318 | struct icmp6_hdr *icp; | | 318 | struct icmp6_hdr *icp; |
319 | | | 319 | |
320 | IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off, | | 320 | IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off, |
321 | sizeof(*icp)); | | 321 | sizeof(*icp)); |
322 | if (icp == NULL) { | | 322 | if (icp == NULL) { |
323 | icmp6stat.icp6s_tooshort++; | | 323 | icmp6stat.icp6s_tooshort++; |
324 | return; | | 324 | return; |
325 | } | | 325 | } |
326 | if (icp->icmp6_type < ICMP6_ECHO_REQUEST || | | 326 | if (icp->icmp6_type < ICMP6_ECHO_REQUEST || |
327 | icp->icmp6_type == ND_REDIRECT) { | | 327 | icp->icmp6_type == ND_REDIRECT) { |
328 | /* | | 328 | /* |
329 | * ICMPv6 error | | 329 | * ICMPv6 error |
330 | * Special case: for redirect (which is | | 330 | * Special case: for redirect (which is |
331 | * informational) we must not send icmp6 error. | | 331 | * informational) we must not send icmp6 error. |
332 | */ | | 332 | */ |
333 | icmp6stat.icp6s_canterror++; | | 333 | icmp6stat.icp6s_canterror++; |
334 | goto freeit; | | 334 | goto freeit; |
335 | } else { | | 335 | } else { |
336 | /* ICMPv6 informational - send the error */ | | 336 | /* ICMPv6 informational - send the error */ |
337 | } | | 337 | } |
338 | } | | 338 | } |
339 | #if 0 /* controversial */ | | 339 | #if 0 /* controversial */ |
340 | else if (off >= 0 && nxt == IPPROTO_ESP) { | | 340 | else if (off >= 0 && nxt == IPPROTO_ESP) { |
341 | /* | | 341 | /* |
342 | * It could be ICMPv6 error inside ESP. Take a safer side, | | 342 | * It could be ICMPv6 error inside ESP. Take a safer side, |
343 | * don't respond. | | 343 | * don't respond. |
344 | */ | | 344 | */ |
345 | icmp6stat.icp6s_canterror++; | | 345 | icmp6stat.icp6s_canterror++; |
346 | goto freeit; | | 346 | goto freeit; |
347 | } | | 347 | } |
348 | #endif | | 348 | #endif |
349 | else { | | 349 | else { |
350 | /* non-ICMPv6 - send the error */ | | 350 | /* non-ICMPv6 - send the error */ |
351 | } | | 351 | } |
352 | | | 352 | |
353 | oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */ | | 353 | oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */ |
354 | | | 354 | |
355 | /* Finally, do rate limitation check. */ | | 355 | /* Finally, do rate limitation check. */ |
356 | if (icmp6_ratelimit(&oip6->ip6_src, type, code)) { | | 356 | if (icmp6_ratelimit(&oip6->ip6_src, type, code)) { |
357 | icmp6stat.icp6s_toofreq++; | | 357 | icmp6stat.icp6s_toofreq++; |
358 | goto freeit; | | 358 | goto freeit; |
359 | } | | 359 | } |
360 | | | 360 | |
361 | /* | | 361 | /* |
362 | * OK, ICMP6 can be generated. | | 362 | * OK, ICMP6 can be generated. |
363 | */ | | 363 | */ |
364 | | | 364 | |
365 | if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN) | | 365 | if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN) |
366 | m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len); | | 366 | m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len); |
367 | | | 367 | |
368 | preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); | | 368 | preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); |
369 | M_PREPEND(m, preplen, M_DONTWAIT); | | 369 | M_PREPEND(m, preplen, M_DONTWAIT); |
370 | if (m && m->m_len < preplen) | | 370 | if (m && m->m_len < preplen) |
371 | m = m_pullup(m, preplen); | | 371 | m = m_pullup(m, preplen); |
372 | if (m == NULL) { | | 372 | if (m == NULL) { |
373 | nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__)); | | 373 | nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__)); |
374 | return; | | 374 | return; |
375 | } | | 375 | } |
376 | | | 376 | |
377 | nip6 = mtod(m, struct ip6_hdr *); | | 377 | nip6 = mtod(m, struct ip6_hdr *); |
378 | nip6->ip6_src = oip6->ip6_src; | | 378 | nip6->ip6_src = oip6->ip6_src; |
379 | nip6->ip6_dst = oip6->ip6_dst; | | 379 | nip6->ip6_dst = oip6->ip6_dst; |
380 | | | 380 | |
381 | if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src)) | | 381 | if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src)) |
382 | oip6->ip6_src.s6_addr16[1] = 0; | | 382 | oip6->ip6_src.s6_addr16[1] = 0; |
383 | if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst)) | | 383 | if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst)) |
384 | oip6->ip6_dst.s6_addr16[1] = 0; | | 384 | oip6->ip6_dst.s6_addr16[1] = 0; |
385 | | | 385 | |
386 | icmp6 = (struct icmp6_hdr *)(nip6 + 1); | | 386 | icmp6 = (struct icmp6_hdr *)(nip6 + 1); |
387 | icmp6->icmp6_type = type; | | 387 | icmp6->icmp6_type = type; |
388 | icmp6->icmp6_code = code; | | 388 | icmp6->icmp6_code = code; |
389 | icmp6->icmp6_pptr = htonl((u_int32_t)param); | | 389 | icmp6->icmp6_pptr = htonl((u_int32_t)param); |
390 | | | 390 | |
391 | /* | | 391 | /* |
392 | * icmp6_reflect() is designed to be in the input path. | | 392 | * icmp6_reflect() is designed to be in the input path. |
393 | * icmp6_error() can be called from both input and outut path, | | 393 | * icmp6_error() can be called from both input and outut path, |
394 | * and if we are in output path rcvif could contain bogus value. | | 394 | * and if we are in output path rcvif could contain bogus value. |
395 | * clear m->m_pkthdr.rcvif for safety, we should have enough scope | | 395 | * clear m->m_pkthdr.rcvif for safety, we should have enough scope |
396 | * information in ip header (nip6). | | 396 | * information in ip header (nip6). |
397 | */ | | 397 | */ |
398 | m->m_pkthdr.rcvif = NULL; | | 398 | m->m_pkthdr.rcvif = NULL; |
399 | | | 399 | |
400 | icmp6stat.icp6s_outhist[type]++; | | 400 | icmp6stat.icp6s_outhist[type]++; |
401 | icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */ | | 401 | icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */ |
402 | | | 402 | |
403 | return; | | 403 | return; |
404 | | | 404 | |
405 | freeit: | | 405 | freeit: |
406 | /* | | 406 | /* |
407 | * If we can't tell wheter or not we can generate ICMP6, free it. | | 407 | * If we can't tell wheter or not we can generate ICMP6, free it. |
408 | */ | | 408 | */ |
409 | m_freem(m); | | 409 | m_freem(m); |
410 | } | | 410 | } |
411 | | | 411 | |
412 | /* | | 412 | /* |
413 | * Process a received ICMP6 message. | | 413 | * Process a received ICMP6 message. |
414 | */ | | 414 | */ |
415 | int | | 415 | int |
416 | icmp6_input(mp, offp, proto) | | 416 | icmp6_input(mp, offp, proto) |
417 | struct mbuf **mp; | | 417 | struct mbuf **mp; |
418 | int *offp, proto; | | 418 | int *offp, proto; |
419 | { | | 419 | { |
420 | struct mbuf *m = *mp, *n; | | 420 | struct mbuf *m = *mp, *n; |
421 | struct ip6_hdr *ip6, *nip6; | | 421 | struct ip6_hdr *ip6, *nip6; |
422 | struct icmp6_hdr *icmp6, *nicmp6; | | 422 | struct icmp6_hdr *icmp6, *nicmp6; |
423 | int off = *offp; | | 423 | int off = *offp; |
424 | int icmp6len = m->m_pkthdr.len - *offp; | | 424 | int icmp6len = m->m_pkthdr.len - *offp; |
425 | int code, sum, noff; | | 425 | int code, sum, noff; |
426 | | | 426 | |
427 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg); | | 427 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg); |
428 | | | 428 | |
429 | /* | | 429 | /* |
430 | * Locate icmp6 structure in mbuf, and check | | 430 | * Locate icmp6 structure in mbuf, and check |
431 | * that not corrupted and of at least minimum length | | 431 | * that not corrupted and of at least minimum length |
432 | */ | | 432 | */ |
433 | | | 433 | |
434 | ip6 = mtod(m, struct ip6_hdr *); | | 434 | ip6 = mtod(m, struct ip6_hdr *); |
435 | if (icmp6len < sizeof(struct icmp6_hdr)) { | | 435 | if (icmp6len < sizeof(struct icmp6_hdr)) { |
436 | icmp6stat.icp6s_tooshort++; | | 436 | icmp6stat.icp6s_tooshort++; |
437 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error); | | 437 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error); |
438 | goto freeit; | | 438 | goto freeit; |
439 | } | | 439 | } |
440 | | | 440 | |
441 | /* | | 441 | /* |
442 | * calculate the checksum | | 442 | * calculate the checksum |
443 | */ | | 443 | */ |
444 | IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6)); | | 444 | IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6)); |
445 | if (icmp6 == NULL) { | | 445 | if (icmp6 == NULL) { |
446 | icmp6stat.icp6s_tooshort++; | | 446 | icmp6stat.icp6s_tooshort++; |
447 | /* m is invalid */ | | 447 | /* m is invalid */ |
448 | /*icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);*/ | | 448 | /*icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);*/ |
449 | return IPPROTO_DONE; | | 449 | return IPPROTO_DONE; |
450 | } | | 450 | } |
451 | KASSERT(IP6_HDR_ALIGNED_P(icmp6)); | | 451 | KASSERT(IP6_HDR_ALIGNED_P(icmp6)); |
452 | code = icmp6->icmp6_code; | | 452 | code = icmp6->icmp6_code; |
453 | | | 453 | |
454 | if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) { | | 454 | if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) { |
455 | nd6log((LOG_ERR, | | 455 | nd6log((LOG_ERR, |
456 | "ICMP6 checksum error(%d|%x) %s\n", | | 456 | "ICMP6 checksum error(%d|%x) %s\n", |
457 | icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src))); | | 457 | icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src))); |
458 | icmp6stat.icp6s_checksum++; | | 458 | icmp6stat.icp6s_checksum++; |
459 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error); | | 459 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error); |
460 | goto freeit; | | 460 | goto freeit; |
461 | } | | 461 | } |
462 | | | 462 | |
463 | #if defined(NFAITH) && 0 < NFAITH | | 463 | #if defined(NFAITH) && 0 < NFAITH |
464 | if (faithprefix(&ip6->ip6_dst)) { | | 464 | if (faithprefix(&ip6->ip6_dst)) { |
465 | /* | | 465 | /* |
466 | * Deliver very specific ICMP6 type only. | | 466 | * Deliver very specific ICMP6 type only. |
467 | * This is important to deilver TOOBIG. Otherwise PMTUD | | 467 | * This is important to deilver TOOBIG. Otherwise PMTUD |
468 | * will not work. | | 468 | * will not work. |
469 | */ | | 469 | */ |
470 | switch (icmp6->icmp6_type) { | | 470 | switch (icmp6->icmp6_type) { |
471 | case ICMP6_DST_UNREACH: | | 471 | case ICMP6_DST_UNREACH: |
472 | case ICMP6_PACKET_TOO_BIG: | | 472 | case ICMP6_PACKET_TOO_BIG: |
473 | case ICMP6_TIME_EXCEEDED: | | 473 | case ICMP6_TIME_EXCEEDED: |
474 | break; | | 474 | break; |
475 | default: | | 475 | default: |
476 | goto freeit; | | 476 | goto freeit; |
477 | } | | 477 | } |
478 | } | | 478 | } |
479 | #endif | | 479 | #endif |
480 | | | 480 | |
481 | icmp6stat.icp6s_inhist[icmp6->icmp6_type]++; | | 481 | icmp6stat.icp6s_inhist[icmp6->icmp6_type]++; |
482 | | | 482 | |
483 | switch (icmp6->icmp6_type) { | | 483 | switch (icmp6->icmp6_type) { |
484 | case ICMP6_DST_UNREACH: | | 484 | case ICMP6_DST_UNREACH: |
485 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach); | | 485 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach); |
486 | switch (code) { | | 486 | switch (code) { |
487 | case ICMP6_DST_UNREACH_NOROUTE: | | 487 | case ICMP6_DST_UNREACH_NOROUTE: |
488 | code = PRC_UNREACH_NET; | | 488 | code = PRC_UNREACH_NET; |
489 | break; | | 489 | break; |
490 | case ICMP6_DST_UNREACH_ADMIN: | | 490 | case ICMP6_DST_UNREACH_ADMIN: |
491 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib); | | 491 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib); |
492 | code = PRC_UNREACH_PROTOCOL; /* is this a good code? */ | | 492 | code = PRC_UNREACH_PROTOCOL; /* is this a good code? */ |
493 | break; | | 493 | break; |
494 | case ICMP6_DST_UNREACH_ADDR: | | 494 | case ICMP6_DST_UNREACH_ADDR: |
495 | code = PRC_HOSTDEAD; | | 495 | code = PRC_HOSTDEAD; |
496 | break; | | 496 | break; |
497 | #ifdef COMPAT_RFC1885 | | 497 | #ifdef COMPAT_RFC1885 |
498 | case ICMP6_DST_UNREACH_NOTNEIGHBOR: | | 498 | case ICMP6_DST_UNREACH_NOTNEIGHBOR: |
499 | code = PRC_UNREACH_SRCFAIL; | | 499 | code = PRC_UNREACH_SRCFAIL; |
500 | break; | | 500 | break; |
501 | #else | | 501 | #else |
502 | case ICMP6_DST_UNREACH_BEYONDSCOPE: | | 502 | case ICMP6_DST_UNREACH_BEYONDSCOPE: |
503 | /* I mean "source address was incorrect." */ | | 503 | /* I mean "source address was incorrect." */ |
504 | code = PRC_UNREACH_NET; | | 504 | code = PRC_UNREACH_NET; |
505 | break; | | 505 | break; |
506 | #endif | | 506 | #endif |
507 | case ICMP6_DST_UNREACH_NOPORT: | | 507 | case ICMP6_DST_UNREACH_NOPORT: |
508 | code = PRC_UNREACH_PORT; | | 508 | code = PRC_UNREACH_PORT; |
509 | break; | | 509 | break; |
510 | default: | | 510 | default: |
511 | goto badcode; | | 511 | goto badcode; |
512 | } | | 512 | } |
513 | goto deliver; | | 513 | goto deliver; |
514 | | | 514 | |
515 | case ICMP6_PACKET_TOO_BIG: | | 515 | case ICMP6_PACKET_TOO_BIG: |
516 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig); | | 516 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig); |
517 | | | 517 | |
| | | 518 | /* |
| | | 519 | * MTU is checked in icmp6_mtudisc. |
| | | 520 | */ |
518 | code = PRC_MSGSIZE; | | 521 | code = PRC_MSGSIZE; |
519 | | | 522 | |
520 | /* | | 523 | /* |
521 | * Updating the path MTU will be done after examining | | 524 | * Updating the path MTU will be done after examining |
522 | * intermediate extension headers. | | 525 | * intermediate extension headers. |
523 | */ | | 526 | */ |
524 | goto deliver; | | 527 | goto deliver; |
525 | | | 528 | |
526 | case ICMP6_TIME_EXCEEDED: | | 529 | case ICMP6_TIME_EXCEEDED: |
527 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed); | | 530 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed); |
528 | switch (code) { | | 531 | switch (code) { |
529 | case ICMP6_TIME_EXCEED_TRANSIT: | | 532 | case ICMP6_TIME_EXCEED_TRANSIT: |
530 | code = PRC_TIMXCEED_INTRANS; | | 533 | code = PRC_TIMXCEED_INTRANS; |
531 | break; | | 534 | break; |
532 | case ICMP6_TIME_EXCEED_REASSEMBLY: | | 535 | case ICMP6_TIME_EXCEED_REASSEMBLY: |
533 | code = PRC_TIMXCEED_REASS; | | 536 | code = PRC_TIMXCEED_REASS; |
534 | break; | | 537 | break; |
535 | default: | | 538 | default: |
536 | goto badcode; | | 539 | goto badcode; |
537 | } | | 540 | } |
538 | goto deliver; | | 541 | goto deliver; |
539 | | | 542 | |
540 | case ICMP6_PARAM_PROB: | | 543 | case ICMP6_PARAM_PROB: |
541 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob); | | 544 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob); |
542 | switch (code) { | | 545 | switch (code) { |
543 | case ICMP6_PARAMPROB_NEXTHEADER: | | 546 | case ICMP6_PARAMPROB_NEXTHEADER: |
544 | code = PRC_UNREACH_PROTOCOL; | | 547 | code = PRC_UNREACH_PROTOCOL; |
545 | break; | | 548 | break; |
546 | case ICMP6_PARAMPROB_HEADER: | | 549 | case ICMP6_PARAMPROB_HEADER: |
547 | case ICMP6_PARAMPROB_OPTION: | | 550 | case ICMP6_PARAMPROB_OPTION: |
548 | code = PRC_PARAMPROB; | | 551 | code = PRC_PARAMPROB; |
549 | break; | | 552 | break; |
550 | default: | | 553 | default: |
551 | goto badcode; | | 554 | goto badcode; |
552 | } | | 555 | } |
553 | goto deliver; | | 556 | goto deliver; |
554 | | | 557 | |
555 | case ICMP6_ECHO_REQUEST: | | 558 | case ICMP6_ECHO_REQUEST: |
556 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo); | | 559 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo); |
557 | if (code != 0) | | 560 | if (code != 0) |
558 | goto badcode; | | 561 | goto badcode; |
559 | /* | | 562 | /* |
560 | * Copy mbuf to send to two data paths: userland socket(s), | | 563 | * Copy mbuf to send to two data paths: userland socket(s), |
561 | * and to the querier (echo reply). | | 564 | * and to the querier (echo reply). |
562 | * m: a copy for socket, n: a copy for querier | | 565 | * m: a copy for socket, n: a copy for querier |
563 | */ | | 566 | */ |
564 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { | | 567 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { |
565 | /* Give up local */ | | 568 | /* Give up local */ |
566 | n = m; | | 569 | n = m; |
567 | m = NULL; | | 570 | m = NULL; |
568 | goto deliverecho; | | 571 | goto deliverecho; |
569 | } | | 572 | } |
570 | /* | | 573 | /* |
571 | * If the first mbuf is shared, or the first mbuf is too short, | | 574 | * If the first mbuf is shared, or the first mbuf is too short, |
572 | * copy the first part of the data into a fresh mbuf. | | 575 | * copy the first part of the data into a fresh mbuf. |
573 | * Otherwise, we will wrongly overwrite both copies. | | 576 | * Otherwise, we will wrongly overwrite both copies. |
574 | */ | | 577 | */ |
575 | if ((n->m_flags & M_EXT) != 0 || | | 578 | if ((n->m_flags & M_EXT) != 0 || |
576 | n->m_len < off + sizeof(struct icmp6_hdr)) { | | 579 | n->m_len < off + sizeof(struct icmp6_hdr)) { |
577 | struct mbuf *n0 = n; | | 580 | struct mbuf *n0 = n; |
578 | const int maxlen = sizeof(*nip6) + sizeof(*nicmp6); | | 581 | const int maxlen = sizeof(*nip6) + sizeof(*nicmp6); |
579 | | | 582 | |
580 | /* | | 583 | /* |
581 | * Prepare an internal mbuf. m_pullup() doesn't | | 584 | * Prepare an internal mbuf. m_pullup() doesn't |
582 | * always copy the length we specified. | | 585 | * always copy the length we specified. |
583 | */ | | 586 | */ |
584 | if (maxlen >= MCLBYTES) { | | 587 | if (maxlen >= MCLBYTES) { |
585 | /* Give up remote */ | | 588 | /* Give up remote */ |
586 | m_freem(n0); | | 589 | m_freem(n0); |
587 | break; | | 590 | break; |
588 | } | | 591 | } |
589 | MGETHDR(n, M_DONTWAIT, n0->m_type); | | 592 | MGETHDR(n, M_DONTWAIT, n0->m_type); |
590 | if (n && maxlen >= MHLEN) { | | 593 | if (n && maxlen >= MHLEN) { |
591 | MCLGET(n, M_DONTWAIT); | | 594 | MCLGET(n, M_DONTWAIT); |
592 | if ((n->m_flags & M_EXT) == 0) { | | 595 | if ((n->m_flags & M_EXT) == 0) { |
593 | m_free(n); | | 596 | m_free(n); |
594 | n = NULL; | | 597 | n = NULL; |
595 | } | | 598 | } |
596 | } | | 599 | } |
597 | if (n == NULL) { | | 600 | if (n == NULL) { |
598 | /* Give up local */ | | 601 | /* Give up local */ |
599 | m_freem(n0); | | 602 | m_freem(n0); |
600 | n = m; | | 603 | n = m; |
601 | m = NULL; | | 604 | m = NULL; |
602 | goto deliverecho; | | 605 | goto deliverecho; |
603 | } | | 606 | } |
604 | M_COPY_PKTHDR(n, n0); | | 607 | M_COPY_PKTHDR(n, n0); |
605 | /* | | 608 | /* |
606 | * Copy IPv6 and ICMPv6 only. | | 609 | * Copy IPv6 and ICMPv6 only. |
607 | */ | | 610 | */ |
608 | nip6 = mtod(n, struct ip6_hdr *); | | 611 | nip6 = mtod(n, struct ip6_hdr *); |
609 | bcopy(ip6, nip6, sizeof(struct ip6_hdr)); | | 612 | bcopy(ip6, nip6, sizeof(struct ip6_hdr)); |
610 | nicmp6 = (struct icmp6_hdr *)(nip6 + 1); | | 613 | nicmp6 = (struct icmp6_hdr *)(nip6 + 1); |
611 | bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr)); | | 614 | bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr)); |
612 | noff = sizeof(struct ip6_hdr); | | 615 | noff = sizeof(struct ip6_hdr); |
613 | n->m_len = noff + sizeof(struct icmp6_hdr); | | 616 | n->m_len = noff + sizeof(struct icmp6_hdr); |
614 | /* | | 617 | /* |
615 | * Adjust mbuf. ip6_plen will be adjusted in | | 618 | * Adjust mbuf. ip6_plen will be adjusted in |
616 | * ip6_output(). | | 619 | * ip6_output(). |
617 | * n->m_pkthdr.len == n0->m_pkthdr.len at this point. | | 620 | * n->m_pkthdr.len == n0->m_pkthdr.len at this point. |
618 | */ | | 621 | */ |
619 | n->m_pkthdr.len += noff + sizeof(struct icmp6_hdr); | | 622 | n->m_pkthdr.len += noff + sizeof(struct icmp6_hdr); |
620 | n->m_pkthdr.len -= (off + sizeof(struct icmp6_hdr)); | | 623 | n->m_pkthdr.len -= (off + sizeof(struct icmp6_hdr)); |
621 | m_adj(n0, off + sizeof(struct icmp6_hdr)); | | 624 | m_adj(n0, off + sizeof(struct icmp6_hdr)); |
622 | n->m_next = n0; | | 625 | n->m_next = n0; |
623 | n0->m_flags &= ~M_PKTHDR; | | 626 | n0->m_flags &= ~M_PKTHDR; |
624 | } else { | | 627 | } else { |
625 | deliverecho: | | 628 | deliverecho: |
626 | nip6 = mtod(n, struct ip6_hdr *); | | 629 | nip6 = mtod(n, struct ip6_hdr *); |
627 | nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off); | | 630 | nicmp6 = (struct icmp6_hdr *)((caddr_t)nip6 + off); |
628 | noff = off; | | 631 | noff = off; |
629 | } | | 632 | } |
630 | nicmp6->icmp6_type = ICMP6_ECHO_REPLY; | | 633 | nicmp6->icmp6_type = ICMP6_ECHO_REPLY; |
631 | nicmp6->icmp6_code = 0; | | 634 | nicmp6->icmp6_code = 0; |
632 | if (n) { | | 635 | if (n) { |
633 | icmp6stat.icp6s_reflect++; | | 636 | icmp6stat.icp6s_reflect++; |
634 | icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++; | | 637 | icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++; |
635 | icmp6_reflect(n, noff); | | 638 | icmp6_reflect(n, noff); |
636 | } | | 639 | } |
637 | if (!m) | | 640 | if (!m) |
638 | goto freeit; | | 641 | goto freeit; |
639 | break; | | 642 | break; |
640 | | | 643 | |
641 | case ICMP6_ECHO_REPLY: | | 644 | case ICMP6_ECHO_REPLY: |
642 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply); | | 645 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply); |
643 | if (code != 0) | | 646 | if (code != 0) |
644 | goto badcode; | | 647 | goto badcode; |
645 | break; | | 648 | break; |
646 | | | 649 | |
647 | case MLD_LISTENER_QUERY: | | 650 | case MLD_LISTENER_QUERY: |
648 | case MLD_LISTENER_REPORT: | | 651 | case MLD_LISTENER_REPORT: |
649 | if (icmp6len < sizeof(struct mld_hdr)) | | 652 | if (icmp6len < sizeof(struct mld_hdr)) |
650 | goto badlen; | | 653 | goto badlen; |
651 | if (icmp6->icmp6_type == MLD_LISTENER_QUERY) /* XXX: ugly... */ | | 654 | if (icmp6->icmp6_type == MLD_LISTENER_QUERY) /* XXX: ugly... */ |
652 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery); | | 655 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery); |
653 | else | | 656 | else |
654 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport); | | 657 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport); |
655 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { | | 658 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { |
656 | /* give up local */ | | 659 | /* give up local */ |
657 | mld6_input(m, off); | | 660 | mld6_input(m, off); |
658 | m = NULL; | | 661 | m = NULL; |
659 | goto freeit; | | 662 | goto freeit; |
660 | } | | 663 | } |
661 | mld6_input(n, off); | | 664 | mld6_input(n, off); |
662 | /* m stays. */ | | 665 | /* m stays. */ |
663 | break; | | 666 | break; |
664 | | | 667 | |
665 | case MLD_LISTENER_DONE: | | 668 | case MLD_LISTENER_DONE: |
666 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone); | | 669 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone); |
667 | if (icmp6len < sizeof(struct mld_hdr)) /* necessary? */ | | 670 | if (icmp6len < sizeof(struct mld_hdr)) /* necessary? */ |
668 | goto badlen; | | 671 | goto badlen; |
669 | break; /* nothing to be done in kernel */ | | 672 | break; /* nothing to be done in kernel */ |
670 | | | 673 | |
671 | case MLD_MTRACE_RESP: | | 674 | case MLD_MTRACE_RESP: |
672 | case MLD_MTRACE: | | 675 | case MLD_MTRACE: |
673 | /* XXX: these two are experimental. not officially defined. */ | | 676 | /* XXX: these two are experimental. not officially defined. */ |
674 | /* XXX: per-interface statistics? */ | | 677 | /* XXX: per-interface statistics? */ |
675 | break; /* just pass it to applications */ | | 678 | break; /* just pass it to applications */ |
676 | | | 679 | |
677 | case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */ | | 680 | case ICMP6_WRUREQUEST: /* ICMP6_FQDN_QUERY */ |
678 | { | | 681 | { |
679 | enum { WRU, FQDN } mode; | | 682 | enum { WRU, FQDN } mode; |
680 | | | 683 | |
681 | if (!icmp6_nodeinfo) | | 684 | if (!icmp6_nodeinfo) |
682 | break; | | 685 | break; |
683 | | | 686 | |
684 | if (icmp6len == sizeof(struct icmp6_hdr) + 4) | | 687 | if (icmp6len == sizeof(struct icmp6_hdr) + 4) |
685 | mode = WRU; | | 688 | mode = WRU; |
686 | else if (icmp6len >= sizeof(struct icmp6_nodeinfo)) | | 689 | else if (icmp6len >= sizeof(struct icmp6_nodeinfo)) |
687 | mode = FQDN; | | 690 | mode = FQDN; |
688 | else | | 691 | else |
689 | goto badlen; | | 692 | goto badlen; |
690 | | | 693 | |
691 | if (mode == FQDN) { | | 694 | if (mode == FQDN) { |
692 | n = m_copym(m, 0, M_COPYALL, M_DONTWAIT); | | 695 | n = m_copym(m, 0, M_COPYALL, M_DONTWAIT); |
693 | if (n) | | 696 | if (n) |
694 | n = ni6_input(n, off); | | 697 | n = ni6_input(n, off); |
695 | /* XXX meaningless if n == NULL */ | | 698 | /* XXX meaningless if n == NULL */ |
696 | noff = sizeof(struct ip6_hdr); | | 699 | noff = sizeof(struct ip6_hdr); |
697 | } else { | | 700 | } else { |
698 | u_char *p; | | 701 | u_char *p; |
699 | int maxlen, maxhlen; | | 702 | int maxlen, maxhlen; |
700 | | | 703 | |
701 | if ((icmp6_nodeinfo & 5) != 5) | | 704 | if ((icmp6_nodeinfo & 5) != 5) |
702 | break; | | 705 | break; |
703 | | | 706 | |
704 | if (code != 0) | | 707 | if (code != 0) |
705 | goto badcode; | | 708 | goto badcode; |
706 | maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4; | | 709 | maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4; |
707 | if (maxlen >= MCLBYTES) { | | 710 | if (maxlen >= MCLBYTES) { |
708 | /* Give up remote */ | | 711 | /* Give up remote */ |
709 | break; | | 712 | break; |
710 | } | | 713 | } |
711 | MGETHDR(n, M_DONTWAIT, m->m_type); | | 714 | MGETHDR(n, M_DONTWAIT, m->m_type); |
712 | if (n && maxlen > MHLEN) { | | 715 | if (n && maxlen > MHLEN) { |
713 | MCLGET(n, M_DONTWAIT); | | 716 | MCLGET(n, M_DONTWAIT); |
714 | if ((n->m_flags & M_EXT) == 0) { | | 717 | if ((n->m_flags & M_EXT) == 0) { |
715 | m_free(n); | | 718 | m_free(n); |
716 | n = NULL; | | 719 | n = NULL; |
717 | } | | 720 | } |
718 | } | | 721 | } |
719 | if (n == NULL) { | | 722 | if (n == NULL) { |
720 | /* Give up remote */ | | 723 | /* Give up remote */ |
721 | break; | | 724 | break; |
722 | } | | 725 | } |
723 | n->m_pkthdr.rcvif = NULL; | | 726 | n->m_pkthdr.rcvif = NULL; |
724 | n->m_len = 0; | | 727 | n->m_len = 0; |
725 | maxhlen = M_TRAILINGSPACE(n) - maxlen; | | 728 | maxhlen = M_TRAILINGSPACE(n) - maxlen; |
726 | if (maxhlen > hostnamelen) | | 729 | if (maxhlen > hostnamelen) |
727 | maxhlen = hostnamelen; | | 730 | maxhlen = hostnamelen; |
728 | /* | | 731 | /* |
729 | * Copy IPv6 and ICMPv6 only. | | 732 | * Copy IPv6 and ICMPv6 only. |
730 | */ | | 733 | */ |
731 | nip6 = mtod(n, struct ip6_hdr *); | | 734 | nip6 = mtod(n, struct ip6_hdr *); |
732 | bcopy(ip6, nip6, sizeof(struct ip6_hdr)); | | 735 | bcopy(ip6, nip6, sizeof(struct ip6_hdr)); |
733 | nicmp6 = (struct icmp6_hdr *)(nip6 + 1); | | 736 | nicmp6 = (struct icmp6_hdr *)(nip6 + 1); |
734 | bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr)); | | 737 | bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr)); |
735 | p = (u_char *)(nicmp6 + 1); | | 738 | p = (u_char *)(nicmp6 + 1); |
736 | bzero(p, 4); | | 739 | bzero(p, 4); |
737 | bcopy(hostname, p + 4, maxhlen); /* meaningless TTL */ | | 740 | bcopy(hostname, p + 4, maxhlen); /* meaningless TTL */ |
738 | noff = sizeof(struct ip6_hdr); | | 741 | noff = sizeof(struct ip6_hdr); |
739 | M_COPY_PKTHDR(n, m); /* just for rcvif */ | | 742 | M_COPY_PKTHDR(n, m); /* just for rcvif */ |
740 | n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + | | 743 | n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + |
741 | sizeof(struct icmp6_hdr) + 4 + maxhlen; | | 744 | sizeof(struct icmp6_hdr) + 4 + maxhlen; |
742 | nicmp6->icmp6_type = ICMP6_WRUREPLY; | | 745 | nicmp6->icmp6_type = ICMP6_WRUREPLY; |
743 | nicmp6->icmp6_code = 0; | | 746 | nicmp6->icmp6_code = 0; |
744 | } | | 747 | } |
745 | #undef hostnamelen | | 748 | #undef hostnamelen |
746 | if (n) { | | 749 | if (n) { |
747 | icmp6stat.icp6s_reflect++; | | 750 | icmp6stat.icp6s_reflect++; |
748 | icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++; | | 751 | icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++; |
749 | icmp6_reflect(n, noff); | | 752 | icmp6_reflect(n, noff); |
750 | } | | 753 | } |
751 | break; | | 754 | break; |
752 | } | | 755 | } |
753 | | | 756 | |
754 | case ICMP6_WRUREPLY: | | 757 | case ICMP6_WRUREPLY: |
755 | if (code != 0) | | 758 | if (code != 0) |
756 | goto badcode; | | 759 | goto badcode; |
757 | break; | | 760 | break; |
758 | | | 761 | |
759 | case ND_ROUTER_SOLICIT: | | 762 | case ND_ROUTER_SOLICIT: |
760 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit); | | 763 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit); |
761 | if (code != 0) | | 764 | if (code != 0) |
762 | goto badcode; | | 765 | goto badcode; |
763 | if (icmp6len < sizeof(struct nd_router_solicit)) | | 766 | if (icmp6len < sizeof(struct nd_router_solicit)) |
764 | goto badlen; | | 767 | goto badlen; |
765 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { | | 768 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { |
766 | /* give up local */ | | 769 | /* give up local */ |
767 | nd6_rs_input(m, off, icmp6len); | | 770 | nd6_rs_input(m, off, icmp6len); |
768 | m = NULL; | | 771 | m = NULL; |
769 | goto freeit; | | 772 | goto freeit; |
770 | } | | 773 | } |
771 | nd6_rs_input(n, off, icmp6len); | | 774 | nd6_rs_input(n, off, icmp6len); |
772 | /* m stays. */ | | 775 | /* m stays. */ |
773 | break; | | 776 | break; |
774 | | | 777 | |
775 | case ND_ROUTER_ADVERT: | | 778 | case ND_ROUTER_ADVERT: |
776 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert); | | 779 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert); |
777 | if (code != 0) | | 780 | if (code != 0) |
778 | goto badcode; | | 781 | goto badcode; |
779 | if (icmp6len < sizeof(struct nd_router_advert)) | | 782 | if (icmp6len < sizeof(struct nd_router_advert)) |
780 | goto badlen; | | 783 | goto badlen; |
781 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { | | 784 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { |
782 | /* give up local */ | | 785 | /* give up local */ |
783 | nd6_ra_input(m, off, icmp6len); | | 786 | nd6_ra_input(m, off, icmp6len); |
784 | m = NULL; | | 787 | m = NULL; |
785 | goto freeit; | | 788 | goto freeit; |
786 | } | | 789 | } |
787 | nd6_ra_input(n, off, icmp6len); | | 790 | nd6_ra_input(n, off, icmp6len); |
788 | /* m stays. */ | | 791 | /* m stays. */ |
789 | break; | | 792 | break; |
790 | | | 793 | |
791 | case ND_NEIGHBOR_SOLICIT: | | 794 | case ND_NEIGHBOR_SOLICIT: |
792 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit); | | 795 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit); |
793 | if (code != 0) | | 796 | if (code != 0) |
794 | goto badcode; | | 797 | goto badcode; |
795 | if (icmp6len < sizeof(struct nd_neighbor_solicit)) | | 798 | if (icmp6len < sizeof(struct nd_neighbor_solicit)) |
796 | goto badlen; | | 799 | goto badlen; |
797 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { | | 800 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { |
798 | /* give up local */ | | 801 | /* give up local */ |
799 | nd6_ns_input(m, off, icmp6len); | | 802 | nd6_ns_input(m, off, icmp6len); |
800 | m = NULL; | | 803 | m = NULL; |
801 | goto freeit; | | 804 | goto freeit; |
802 | } | | 805 | } |
803 | nd6_ns_input(n, off, icmp6len); | | 806 | nd6_ns_input(n, off, icmp6len); |
804 | /* m stays. */ | | 807 | /* m stays. */ |
805 | break; | | 808 | break; |
806 | | | 809 | |
807 | case ND_NEIGHBOR_ADVERT: | | 810 | case ND_NEIGHBOR_ADVERT: |
808 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert); | | 811 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert); |
809 | if (code != 0) | | 812 | if (code != 0) |
810 | goto badcode; | | 813 | goto badcode; |
811 | if (icmp6len < sizeof(struct nd_neighbor_advert)) | | 814 | if (icmp6len < sizeof(struct nd_neighbor_advert)) |
812 | goto badlen; | | 815 | goto badlen; |
813 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { | | 816 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { |
814 | /* give up local */ | | 817 | /* give up local */ |
815 | nd6_na_input(m, off, icmp6len); | | 818 | nd6_na_input(m, off, icmp6len); |
816 | m = NULL; | | 819 | m = NULL; |
817 | goto freeit; | | 820 | goto freeit; |
818 | } | | 821 | } |
819 | nd6_na_input(n, off, icmp6len); | | 822 | nd6_na_input(n, off, icmp6len); |
820 | /* m stays. */ | | 823 | /* m stays. */ |
821 | break; | | 824 | break; |
822 | | | 825 | |
823 | case ND_REDIRECT: | | 826 | case ND_REDIRECT: |
824 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect); | | 827 | icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect); |
825 | if (code != 0) | | 828 | if (code != 0) |
826 | goto badcode; | | 829 | goto badcode; |
827 | if (icmp6len < sizeof(struct nd_redirect)) | | 830 | if (icmp6len < sizeof(struct nd_redirect)) |
828 | goto badlen; | | 831 | goto badlen; |
829 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { | | 832 | if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { |
830 | /* give up local */ | | 833 | /* give up local */ |
831 | icmp6_redirect_input(m, off); | | 834 | icmp6_redirect_input(m, off); |
832 | m = NULL; | | 835 | m = NULL; |
833 | goto freeit; | | 836 | goto freeit; |
834 | } | | 837 | } |
835 | icmp6_redirect_input(n, off); | | 838 | icmp6_redirect_input(n, off); |
836 | /* m stays. */ | | 839 | /* m stays. */ |
837 | break; | | 840 | break; |
838 | | | 841 | |
839 | case ICMP6_ROUTER_RENUMBERING: | | 842 | case ICMP6_ROUTER_RENUMBERING: |
840 | if (code != ICMP6_ROUTER_RENUMBERING_COMMAND && | | 843 | if (code != ICMP6_ROUTER_RENUMBERING_COMMAND && |
841 | code != ICMP6_ROUTER_RENUMBERING_RESULT) | | 844 | code != ICMP6_ROUTER_RENUMBERING_RESULT) |
842 | goto badcode; | | 845 | goto badcode; |
843 | if (icmp6len < sizeof(struct icmp6_router_renum)) | | 846 | if (icmp6len < sizeof(struct icmp6_router_renum)) |
844 | goto badlen; | | 847 | goto badlen; |
845 | break; | | 848 | break; |
846 | | | 849 | |
847 | default: | | 850 | default: |
848 | nd6log((LOG_DEBUG, | | 851 | nd6log((LOG_DEBUG, |
849 | "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n", | | 852 | "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n", |
850 | icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src), | | 853 | icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src), |
851 | ip6_sprintf(&ip6->ip6_dst), | | 854 | ip6_sprintf(&ip6->ip6_dst), |
852 | m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0)); | | 855 | m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0)); |
853 | if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) { | | 856 | if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) { |
854 | /* ICMPv6 error: MUST deliver it by spec... */ | | 857 | /* ICMPv6 error: MUST deliver it by spec... */ |
855 | code = PRC_NCMDS; | | 858 | code = PRC_NCMDS; |
856 | /* deliver */ | | 859 | /* deliver */ |
857 | } else { | | 860 | } else { |
858 | /* ICMPv6 informational: MUST not deliver */ | | 861 | /* ICMPv6 informational: MUST not deliver */ |
859 | break; | | 862 | break; |
860 | } | | 863 | } |
861 | deliver: | | 864 | deliver: |
862 | if (icmp6_notify_error(m, off, icmp6len, code)) { | | 865 | if (icmp6_notify_error(m, off, icmp6len, code)) { |
863 | /* In this case, m should've been freed. */ | | 866 | /* In this case, m should've been freed. */ |
864 | return (IPPROTO_DONE); | | 867 | return (IPPROTO_DONE); |
865 | } | | 868 | } |
866 | break; | | 869 | break; |
867 | | | 870 | |
868 | badcode: | | 871 | badcode: |
869 | icmp6stat.icp6s_badcode++; | | 872 | icmp6stat.icp6s_badcode++; |
870 | break; | | 873 | break; |
871 | | | 874 | |
872 | badlen: | | 875 | badlen: |
873 | icmp6stat.icp6s_badlen++; | | 876 | icmp6stat.icp6s_badlen++; |
874 | break; | | 877 | break; |
875 | } | | 878 | } |
876 | | | 879 | |
877 | /* deliver the packet to appropriate sockets */ | | 880 | /* deliver the packet to appropriate sockets */ |
878 | icmp6_rip6_input(&m, *offp); | | 881 | icmp6_rip6_input(&m, *offp); |
879 | | | 882 | |
880 | return IPPROTO_DONE; | | 883 | return IPPROTO_DONE; |
881 | | | 884 | |
882 | freeit: | | 885 | freeit: |
883 | m_freem(m); | | 886 | m_freem(m); |
884 | return IPPROTO_DONE; | | 887 | return IPPROTO_DONE; |
885 | } | | 888 | } |
886 | | | 889 | |
887 | static int | | 890 | static int |
888 | icmp6_notify_error(m, off, icmp6len, code) | | 891 | icmp6_notify_error(m, off, icmp6len, code) |
889 | struct mbuf *m; | | 892 | struct mbuf *m; |
890 | int off, icmp6len; | | 893 | int off, icmp6len; |
891 | { | | 894 | { |
892 | struct icmp6_hdr *icmp6; | | 895 | struct icmp6_hdr *icmp6; |
893 | struct ip6_hdr *eip6; | | 896 | struct ip6_hdr *eip6; |
894 | u_int32_t notifymtu; | | 897 | u_int32_t notifymtu; |
895 | struct sockaddr_in6 icmp6src, icmp6dst; | | 898 | struct sockaddr_in6 icmp6src, icmp6dst; |
896 | | | 899 | |
897 | if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { | | 900 | if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { |
898 | icmp6stat.icp6s_tooshort++; | | 901 | icmp6stat.icp6s_tooshort++; |
899 | goto freeit; | | 902 | goto freeit; |
900 | } | | 903 | } |
901 | IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, | | 904 | IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, |
902 | sizeof(*icmp6) + sizeof(struct ip6_hdr)); | | 905 | sizeof(*icmp6) + sizeof(struct ip6_hdr)); |
903 | if (icmp6 == NULL) { | | 906 | if (icmp6 == NULL) { |
904 | icmp6stat.icp6s_tooshort++; | | 907 | icmp6stat.icp6s_tooshort++; |
905 | return (-1); | | 908 | return (-1); |
906 | } | | 909 | } |
907 | eip6 = (struct ip6_hdr *)(icmp6 + 1); | | 910 | eip6 = (struct ip6_hdr *)(icmp6 + 1); |
908 | | | 911 | |
909 | /* Detect the upper level protocol */ | | 912 | /* Detect the upper level protocol */ |
910 | { | | 913 | { |
911 | void (*ctlfunc) __P((int, struct sockaddr *, void *)); | | 914 | void (*ctlfunc) __P((int, struct sockaddr *, void *)); |
912 | u_int8_t nxt = eip6->ip6_nxt; | | 915 | u_int8_t nxt = eip6->ip6_nxt; |
913 | int eoff = off + sizeof(struct icmp6_hdr) + | | 916 | int eoff = off + sizeof(struct icmp6_hdr) + |
914 | sizeof(struct ip6_hdr); | | 917 | sizeof(struct ip6_hdr); |
915 | struct ip6ctlparam ip6cp; | | 918 | struct ip6ctlparam ip6cp; |
916 | struct in6_addr *finaldst = NULL; | | 919 | struct in6_addr *finaldst = NULL; |
917 | int icmp6type = icmp6->icmp6_type; | | 920 | int icmp6type = icmp6->icmp6_type; |
918 | struct ip6_frag *fh; | | 921 | struct ip6_frag *fh; |
919 | struct ip6_rthdr *rth; | | 922 | struct ip6_rthdr *rth; |
920 | struct ip6_rthdr0 *rth0; | | 923 | struct ip6_rthdr0 *rth0; |
921 | int rthlen; | | 924 | int rthlen; |
922 | | | 925 | |
923 | while (1) { /* XXX: should avoid infinite loop explicitly? */ | | 926 | while (1) { /* XXX: should avoid infinite loop explicitly? */ |
924 | struct ip6_ext *eh; | | 927 | struct ip6_ext *eh; |
925 | | | 928 | |
926 | switch (nxt) { | | 929 | switch (nxt) { |
927 | case IPPROTO_HOPOPTS: | | 930 | case IPPROTO_HOPOPTS: |
928 | case IPPROTO_DSTOPTS: | | 931 | case IPPROTO_DSTOPTS: |
929 | case IPPROTO_AH: | | 932 | case IPPROTO_AH: |
930 | IP6_EXTHDR_GET(eh, struct ip6_ext *, m, | | 933 | IP6_EXTHDR_GET(eh, struct ip6_ext *, m, |
931 | eoff, sizeof(*eh)); | | 934 | eoff, sizeof(*eh)); |
932 | if (eh == NULL) { | | 935 | if (eh == NULL) { |
933 | icmp6stat.icp6s_tooshort++; | | 936 | icmp6stat.icp6s_tooshort++; |
934 | return (-1); | | 937 | return (-1); |
935 | } | | 938 | } |
936 | | | 939 | |
937 | if (nxt == IPPROTO_AH) | | 940 | if (nxt == IPPROTO_AH) |
938 | eoff += (eh->ip6e_len + 2) << 2; | | 941 | eoff += (eh->ip6e_len + 2) << 2; |
939 | else | | 942 | else |
940 | eoff += (eh->ip6e_len + 1) << 3; | | 943 | eoff += (eh->ip6e_len + 1) << 3; |
941 | nxt = eh->ip6e_nxt; | | 944 | nxt = eh->ip6e_nxt; |
942 | break; | | 945 | break; |
943 | case IPPROTO_ROUTING: | | 946 | case IPPROTO_ROUTING: |
944 | /* | | 947 | /* |
945 | * When the erroneous packet contains a | | 948 | * When the erroneous packet contains a |
946 | * routing header, we should examine the | | 949 | * routing header, we should examine the |
947 | * header to determine the final destination. | | 950 | * header to determine the final destination. |
948 | * Otherwise, we can't properly update | | 951 | * Otherwise, we can't properly update |
949 | * information that depends on the final | | 952 | * information that depends on the final |
950 | * destination (e.g. path MTU). | | 953 | * destination (e.g. path MTU). |
951 | */ | | 954 | */ |
952 | IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m, | | 955 | IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m, |
953 | eoff, sizeof(*rth)); | | 956 | eoff, sizeof(*rth)); |
954 | if (rth == NULL) { | | 957 | if (rth == NULL) { |
955 | icmp6stat.icp6s_tooshort++; | | 958 | icmp6stat.icp6s_tooshort++; |
956 | return (-1); | | 959 | return (-1); |
957 | } | | 960 | } |
958 | rthlen = (rth->ip6r_len + 1) << 3; | | 961 | rthlen = (rth->ip6r_len + 1) << 3; |
959 | /* | | 962 | /* |
960 | * XXX: currently there is no | | 963 | * XXX: currently there is no |
961 | * officially defined type other | | 964 | * officially defined type other |
962 | * than type-0. | | 965 | * than type-0. |
963 | * Note that if the segment left field | | 966 | * Note that if the segment left field |
964 | * is 0, all intermediate hops must | | 967 | * is 0, all intermediate hops must |
965 | * have been passed. | | 968 | * have been passed. |
966 | */ | | 969 | */ |
967 | if (rth->ip6r_segleft && | | 970 | if (rth->ip6r_segleft && |
968 | rth->ip6r_type == IPV6_RTHDR_TYPE_0) { | | 971 | rth->ip6r_type == IPV6_RTHDR_TYPE_0) { |
969 | int hops; | | 972 | int hops; |
970 | | | 973 | |
971 | IP6_EXTHDR_GET(rth0, | | 974 | IP6_EXTHDR_GET(rth0, |
972 | struct ip6_rthdr0 *, m, | | 975 | struct ip6_rthdr0 *, m, |
973 | eoff, rthlen); | | 976 | eoff, rthlen); |
974 | if (rth0 == NULL) { | | 977 | if (rth0 == NULL) { |
975 | icmp6stat.icp6s_tooshort++; | | 978 | icmp6stat.icp6s_tooshort++; |
976 | return (-1); | | 979 | return (-1); |
977 | } | | 980 | } |
978 | /* just ignore a bogus header */ | | 981 | /* just ignore a bogus header */ |
979 | if ((rth0->ip6r0_len % 2) == 0 && | | 982 | if ((rth0->ip6r0_len % 2) == 0 && |
980 | (hops = rth0->ip6r0_len/2)) | | 983 | (hops = rth0->ip6r0_len/2)) |
981 | finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1); | | 984 | finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1); |
982 | } | | 985 | } |
983 | eoff += rthlen; | | 986 | eoff += rthlen; |
984 | nxt = rth->ip6r_nxt; | | 987 | nxt = rth->ip6r_nxt; |
985 | break; | | 988 | break; |
986 | case IPPROTO_FRAGMENT: | | 989 | case IPPROTO_FRAGMENT: |
987 | IP6_EXTHDR_GET(fh, struct ip6_frag *, m, | | 990 | IP6_EXTHDR_GET(fh, struct ip6_frag *, m, |
988 | eoff, sizeof(*fh)); | | 991 | eoff, sizeof(*fh)); |
989 | if (fh == NULL) { | | 992 | if (fh == NULL) { |
990 | icmp6stat.icp6s_tooshort++; | | 993 | icmp6stat.icp6s_tooshort++; |
991 | return (-1); | | 994 | return (-1); |
992 | } | | 995 | } |
993 | /* | | 996 | /* |
994 | * Data after a fragment header is meaningless | | 997 | * Data after a fragment header is meaningless |
995 | * unless it is the first fragment, but | | 998 | * unless it is the first fragment, but |
996 | * we'll go to the notify label for path MTU | | 999 | * we'll go to the notify label for path MTU |
997 | * discovery. | | 1000 | * discovery. |
998 | */ | | 1001 | */ |
999 | if (fh->ip6f_offlg & IP6F_OFF_MASK) | | 1002 | if (fh->ip6f_offlg & IP6F_OFF_MASK) |
1000 | goto notify; | | 1003 | goto notify; |
1001 | | | 1004 | |
1002 | eoff += sizeof(struct ip6_frag); | | 1005 | eoff += sizeof(struct ip6_frag); |
1003 | nxt = fh->ip6f_nxt; | | 1006 | nxt = fh->ip6f_nxt; |
1004 | break; | | 1007 | break; |
1005 | default: | | 1008 | default: |
1006 | /* | | 1009 | /* |
1007 | * This case includes ESP and the No Next | | 1010 | * This case includes ESP and the No Next |
1008 | * Header. In such cases going to the notify | | 1011 | * Header. In such cases going to the notify |
1009 | * label does not have any meaning | | 1012 | * label does not have any meaning |
1010 | * (i.e. ctlfunc will be NULL), but we go | | 1013 | * (i.e. ctlfunc will be NULL), but we go |
1011 | * anyway since we might have to update | | 1014 | * anyway since we might have to update |
1012 | * path MTU information. | | 1015 | * path MTU information. |
1013 | */ | | 1016 | */ |
1014 | goto notify; | | 1017 | goto notify; |
1015 | } | | 1018 | } |
1016 | } | | 1019 | } |
1017 | notify: | | 1020 | notify: |
1018 | IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, | | 1021 | IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, |
1019 | sizeof(*icmp6) + sizeof(struct ip6_hdr)); | | 1022 | sizeof(*icmp6) + sizeof(struct ip6_hdr)); |
1020 | if (icmp6 == NULL) { | | 1023 | if (icmp6 == NULL) { |
1021 | icmp6stat.icp6s_tooshort++; | | 1024 | icmp6stat.icp6s_tooshort++; |
1022 | return (-1); | | 1025 | return (-1); |
1023 | } | | 1026 | } |
1024 | | | 1027 | |
1025 | eip6 = (struct ip6_hdr *)(icmp6 + 1); | | 1028 | eip6 = (struct ip6_hdr *)(icmp6 + 1); |
1026 | bzero(&icmp6dst, sizeof(icmp6dst)); | | 1029 | bzero(&icmp6dst, sizeof(icmp6dst)); |
1027 | icmp6dst.sin6_len = sizeof(struct sockaddr_in6); | | 1030 | icmp6dst.sin6_len = sizeof(struct sockaddr_in6); |
1028 | icmp6dst.sin6_family = AF_INET6; | | 1031 | icmp6dst.sin6_family = AF_INET6; |
1029 | if (finaldst == NULL) | | 1032 | if (finaldst == NULL) |
1030 | icmp6dst.sin6_addr = eip6->ip6_dst; | | 1033 | icmp6dst.sin6_addr = eip6->ip6_dst; |
1031 | else | | 1034 | else |
1032 | icmp6dst.sin6_addr = *finaldst; | | 1035 | icmp6dst.sin6_addr = *finaldst; |
1033 | icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, | | 1036 | icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, |
1034 | &icmp6dst.sin6_addr); | | 1037 | &icmp6dst.sin6_addr); |
1035 | #ifndef SCOPEDROUTING | | 1038 | #ifndef SCOPEDROUTING |
1036 | if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst, | | 1039 | if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst, |
1037 | NULL, NULL)) { | | 1040 | NULL, NULL)) { |
1038 | /* should be impossbile */ | | 1041 | /* should be impossbile */ |
1039 | nd6log((LOG_DEBUG, | | 1042 | nd6log((LOG_DEBUG, |
1040 | "icmp6_notify_error: in6_embedscope failed\n")); | | 1043 | "icmp6_notify_error: in6_embedscope failed\n")); |
1041 | goto freeit; | | 1044 | goto freeit; |
1042 | } | | 1045 | } |
1043 | #endif | | 1046 | #endif |
1044 | | | 1047 | |
1045 | /* | | 1048 | /* |
1046 | * retrieve parameters from the inner IPv6 header, and convert | | 1049 | * retrieve parameters from the inner IPv6 header, and convert |
1047 | * them into sockaddr structures. | | 1050 | * them into sockaddr structures. |
1048 | */ | | 1051 | */ |
1049 | bzero(&icmp6src, sizeof(icmp6src)); | | 1052 | bzero(&icmp6src, sizeof(icmp6src)); |
1050 | icmp6src.sin6_len = sizeof(struct sockaddr_in6); | | 1053 | icmp6src.sin6_len = sizeof(struct sockaddr_in6); |
1051 | icmp6src.sin6_family = AF_INET6; | | 1054 | icmp6src.sin6_family = AF_INET6; |
1052 | icmp6src.sin6_addr = eip6->ip6_src; | | 1055 | icmp6src.sin6_addr = eip6->ip6_src; |
1053 | icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, | | 1056 | icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif, |
1054 | &icmp6src.sin6_addr); | | 1057 | &icmp6src.sin6_addr); |
1055 | #ifndef SCOPEDROUTING | | 1058 | #ifndef SCOPEDROUTING |
1056 | if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src, | | 1059 | if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src, |
1057 | NULL, NULL)) { | | 1060 | NULL, NULL)) { |
1058 | /* should be impossbile */ | | 1061 | /* should be impossbile */ |
1059 | nd6log((LOG_DEBUG, | | 1062 | nd6log((LOG_DEBUG, |
1060 | "icmp6_notify_error: in6_embedscope failed\n")); | | 1063 | "icmp6_notify_error: in6_embedscope failed\n")); |
1061 | goto freeit; | | 1064 | goto freeit; |
1062 | } | | 1065 | } |
1063 | #endif | | 1066 | #endif |
1064 | icmp6src.sin6_flowinfo = | | 1067 | icmp6src.sin6_flowinfo = |
1065 | (eip6->ip6_flow & IPV6_FLOWLABEL_MASK); | | 1068 | (eip6->ip6_flow & IPV6_FLOWLABEL_MASK); |
1066 | | | 1069 | |
1067 | if (finaldst == NULL) | | 1070 | if (finaldst == NULL) |
1068 | finaldst = &eip6->ip6_dst; | | 1071 | finaldst = &eip6->ip6_dst; |
1069 | ip6cp.ip6c_m = m; | | 1072 | ip6cp.ip6c_m = m; |
1070 | ip6cp.ip6c_icmp6 = icmp6; | | 1073 | ip6cp.ip6c_icmp6 = icmp6; |
1071 | ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); | | 1074 | ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1); |
1072 | ip6cp.ip6c_off = eoff; | | 1075 | ip6cp.ip6c_off = eoff; |
1073 | ip6cp.ip6c_finaldst = finaldst; | | 1076 | ip6cp.ip6c_finaldst = finaldst; |
1074 | ip6cp.ip6c_src = &icmp6src; | | 1077 | ip6cp.ip6c_src = &icmp6src; |
1075 | ip6cp.ip6c_nxt = nxt; | | 1078 | ip6cp.ip6c_nxt = nxt; |
1076 | | | 1079 | |
1077 | if (icmp6type == ICMP6_PACKET_TOO_BIG) { | | 1080 | if (icmp6type == ICMP6_PACKET_TOO_BIG) { |
1078 | notifymtu = ntohl(icmp6->icmp6_mtu); | | 1081 | notifymtu = ntohl(icmp6->icmp6_mtu); |
1079 | ip6cp.ip6c_cmdarg = (void *)¬ifymtu; | | 1082 | ip6cp.ip6c_cmdarg = (void *)¬ifymtu; |
1080 | } | | 1083 | } |
1081 | | | 1084 | |
1082 | ctlfunc = (void (*) __P((int, struct sockaddr *, void *))) | | 1085 | ctlfunc = (void (*) __P((int, struct sockaddr *, void *))) |
1083 | (inet6sw[ip6_protox[nxt]].pr_ctlinput); | | 1086 | (inet6sw[ip6_protox[nxt]].pr_ctlinput); |
1084 | if (ctlfunc) { | | 1087 | if (ctlfunc) { |
1085 | (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst, | | 1088 | (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst, |
1086 | &ip6cp); | | 1089 | &ip6cp); |
1087 | } | | 1090 | } |
1088 | } | | 1091 | } |
1089 | return (0); | | 1092 | return (0); |
1090 | | | 1093 | |
1091 | freeit: | | 1094 | freeit: |
1092 | m_freem(m); | | 1095 | m_freem(m); |
1093 | return (-1); | | 1096 | return (-1); |
1094 | } | | 1097 | } |
1095 | | | 1098 | |
1096 | void | | 1099 | void |
1097 | icmp6_mtudisc_update(ip6cp, validated) | | 1100 | icmp6_mtudisc_update(ip6cp, validated) |
1098 | struct ip6ctlparam *ip6cp; | | 1101 | struct ip6ctlparam *ip6cp; |
1099 | int validated; | | 1102 | int validated; |
1100 | { | | 1103 | { |
1101 | unsigned long rtcount; | | 1104 | unsigned long rtcount; |
1102 | struct icmp6_mtudisc_callback *mc; | | 1105 | struct icmp6_mtudisc_callback *mc; |
1103 | struct in6_addr *dst = ip6cp->ip6c_finaldst; | | 1106 | struct in6_addr *dst = ip6cp->ip6c_finaldst; |
1104 | struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6; | | 1107 | struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6; |
1105 | struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */ | | 1108 | struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */ |
1106 | u_int mtu = ntohl(icmp6->icmp6_mtu); | | 1109 | u_int mtu = ntohl(icmp6->icmp6_mtu); |
1107 | struct rtentry *rt = NULL; | | 1110 | struct rtentry *rt = NULL; |
1108 | struct sockaddr_in6 sin6; | | 1111 | struct sockaddr_in6 sin6; |
1109 | | | 1112 | |
1110 | /* | | 1113 | /* |
| | | 1114 | * The MTU should not be less than the minimal IPv6 MTU except for the |
| | | 1115 | * hack in ip6_output/ip6_setpmtu where we always include a frag header. |
| | | 1116 | * In that one case, the MTU might be less than 1280. |
| | | 1117 | */ |
| | | 1118 | if (__predict_false(mtu < IPV6_MMTU - sizeof(struct ip6_frag))) { |
| | | 1119 | /* is the mtu even sane? */ |
| | | 1120 | if (mtu < sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + 8) |
| | | 1121 | return; |
| | | 1122 | if (!validated) |
| | | 1123 | return; |
| | | 1124 | mtu = IPV6_MMTU - sizeof(struct ip6_frag); |
| | | 1125 | } |
| | | 1126 | |
| | | 1127 | /* |
1111 | * allow non-validated cases if memory is plenty, to make traffic | | 1128 | * allow non-validated cases if memory is plenty, to make traffic |
1112 | * from non-connected pcb happy. | | 1129 | * from non-connected pcb happy. |
1113 | */ | | 1130 | */ |
1114 | rtcount = rt_timer_count(icmp6_mtudisc_timeout_q); | | 1131 | rtcount = rt_timer_count(icmp6_mtudisc_timeout_q); |
1115 | if (validated) { | | 1132 | if (validated) { |
1116 | if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat) | | 1133 | if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat) |
1117 | return; | | 1134 | return; |
1118 | else if (0 <= icmp6_mtudisc_lowat && | | 1135 | else if (0 <= icmp6_mtudisc_lowat && |
1119 | rtcount > icmp6_mtudisc_lowat) { | | 1136 | rtcount > icmp6_mtudisc_lowat) { |
1120 | /* | | 1137 | /* |
1121 | * XXX nuke a victim, install the new one. | | 1138 | * XXX nuke a victim, install the new one. |
1122 | */ | | 1139 | */ |
1123 | } | | 1140 | } |
1124 | } else { | | 1141 | } else { |
1125 | if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat) | | 1142 | if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat) |
1126 | return; | | 1143 | return; |
1127 | } | | 1144 | } |
1128 | | | 1145 | |
1129 | bzero(&sin6, sizeof(sin6)); | | 1146 | bzero(&sin6, sizeof(sin6)); |
1130 | sin6.sin6_family = PF_INET6; | | 1147 | sin6.sin6_family = PF_INET6; |
1131 | sin6.sin6_len = sizeof(struct sockaddr_in6); | | 1148 | sin6.sin6_len = sizeof(struct sockaddr_in6); |
1132 | sin6.sin6_addr = *dst; | | 1149 | sin6.sin6_addr = *dst; |
1133 | /* XXX normally, this won't happen */ | | 1150 | /* XXX normally, this won't happen */ |
1134 | if (IN6_IS_ADDR_LINKLOCAL(dst)) { | | 1151 | if (IN6_IS_ADDR_LINKLOCAL(dst)) { |
1135 | sin6.sin6_addr.s6_addr16[1] = | | 1152 | sin6.sin6_addr.s6_addr16[1] = |
1136 | htons(m->m_pkthdr.rcvif->if_index); | | 1153 | htons(m->m_pkthdr.rcvif->if_index); |
1137 | } | | 1154 | } |
1138 | /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */ | | 1155 | /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */ |
1139 | rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6); | | 1156 | rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6); |
1140 | | | 1157 | |
1141 | if (rt && (rt->rt_flags & RTF_HOST) && | | 1158 | if (rt && (rt->rt_flags & RTF_HOST) && |
1142 | !(rt->rt_rmx.rmx_locks & RTV_MTU) && | | 1159 | !(rt->rt_rmx.rmx_locks & RTV_MTU) && |
1143 | (rt->rt_rmx.rmx_mtu > mtu || rt->rt_rmx.rmx_mtu == 0)) { | | 1160 | (rt->rt_rmx.rmx_mtu > mtu || rt->rt_rmx.rmx_mtu == 0)) { |
1144 | if (mtu < IN6_LINKMTU(rt->rt_ifp)) { | | 1161 | if (mtu < IN6_LINKMTU(rt->rt_ifp)) { |
1145 | icmp6stat.icp6s_pmtuchg++; | | 1162 | icmp6stat.icp6s_pmtuchg++; |
1146 | rt->rt_rmx.rmx_mtu = mtu; | | 1163 | rt->rt_rmx.rmx_mtu = mtu; |
1147 | } | | 1164 | } |
1148 | } | | 1165 | } |
1149 | if (rt) { /* XXX: need braces to avoid conflict with else in RTFREE. */ | | 1166 | if (rt) { /* XXX: need braces to avoid conflict with else in RTFREE. */ |
1150 | RTFREE(rt); | | 1167 | RTFREE(rt); |
1151 | } | | 1168 | } |
1152 | | | 1169 | |
1153 | /* | | 1170 | /* |
1154 | * Notify protocols that the MTU for this destination | | 1171 | * Notify protocols that the MTU for this destination |
1155 | * has changed. | | 1172 | * has changed. |
1156 | */ | | 1173 | */ |
1157 | for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL; | | 1174 | for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL; |
1158 | mc = LIST_NEXT(mc, mc_list)) | | 1175 | mc = LIST_NEXT(mc, mc_list)) |
1159 | (*mc->mc_func)(&sin6.sin6_addr); | | 1176 | (*mc->mc_func)(&sin6.sin6_addr); |
1160 | } | | 1177 | } |
1161 | | | 1178 | |
1162 | /* | | 1179 | /* |
1163 | * Process a Node Information Query packet, based on | | 1180 | * Process a Node Information Query packet, based on |
1164 | * draft-ietf-ipngwg-icmp-name-lookups-07. | | 1181 | * draft-ietf-ipngwg-icmp-name-lookups-07. |
1165 | * | | 1182 | * |
1166 | * Spec incompatibilities: | | 1183 | * Spec incompatibilities: |
1167 | * - IPv6 Subject address handling | | 1184 | * - IPv6 Subject address handling |
1168 | * - IPv4 Subject address handling support missing | | 1185 | * - IPv4 Subject address handling support missing |
1169 | * - Proxy reply (answer even if it's not for me) | | 1186 | * - Proxy reply (answer even if it's not for me) |
1170 | * - joins NI group address at in6_ifattach() time only, does not cope | | 1187 | * - joins NI group address at in6_ifattach() time only, does not cope |
1171 | * with hostname changes by sethostname(3) | | 1188 | * with hostname changes by sethostname(3) |
1172 | */ | | 1189 | */ |
1173 | #ifndef offsetof /* XXX */ | | 1190 | #ifndef offsetof /* XXX */ |
1174 | #define offsetof(type, member) ((size_t)(&((type *)0)->member)) | | 1191 | #define offsetof(type, member) ((size_t)(&((type *)0)->member)) |
1175 | #endif | | 1192 | #endif |
1176 | static struct mbuf * | | 1193 | static struct mbuf * |
1177 | ni6_input(m, off) | | 1194 | ni6_input(m, off) |
1178 | struct mbuf *m; | | 1195 | struct mbuf *m; |
1179 | int off; | | 1196 | int off; |
1180 | { | | 1197 | { |
1181 | struct icmp6_nodeinfo *ni6, *nni6; | | 1198 | struct icmp6_nodeinfo *ni6, *nni6; |
1182 | struct mbuf *n = NULL; | | 1199 | struct mbuf *n = NULL; |
1183 | u_int16_t qtype; | | 1200 | u_int16_t qtype; |
1184 | int subjlen; | | 1201 | int subjlen; |
1185 | int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo); | | 1202 | int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo); |
1186 | struct ni_reply_fqdn *fqdn; | | 1203 | struct ni_reply_fqdn *fqdn; |
1187 | int addrs; /* for NI_QTYPE_NODEADDR */ | | 1204 | int addrs; /* for NI_QTYPE_NODEADDR */ |
1188 | struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */ | | 1205 | struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */ |
1189 | struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */ | | 1206 | struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */ |
1190 | struct ip6_hdr *ip6; | | 1207 | struct ip6_hdr *ip6; |
1191 | int oldfqdn = 0; /* if 1, return pascal string (03 draft) */ | | 1208 | int oldfqdn = 0; /* if 1, return pascal string (03 draft) */ |
1192 | char *subj = NULL; | | 1209 | char *subj = NULL; |
1193 | | | 1210 | |
1194 | ip6 = mtod(m, struct ip6_hdr *); | | 1211 | ip6 = mtod(m, struct ip6_hdr *); |
1195 | IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6)); | | 1212 | IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6)); |
1196 | if (ni6 == NULL) { | | 1213 | if (ni6 == NULL) { |
1197 | /* m is already reclaimed */ | | 1214 | /* m is already reclaimed */ |
1198 | return NULL; | | 1215 | return NULL; |
1199 | } | | 1216 | } |
1200 | | | 1217 | |
1201 | /* | | 1218 | /* |
1202 | * Validate IPv6 destination address. | | 1219 | * Validate IPv6 destination address. |
1203 | * | | 1220 | * |
1204 | * The Responder must discard the Query without further processing | | 1221 | * The Responder must discard the Query without further processing |
1205 | * unless it is one of the Responder's unicast or anycast addresses, or | | 1222 | * unless it is one of the Responder's unicast or anycast addresses, or |
1206 | * a link-local scope multicast address which the Responder has joined. | | 1223 | * a link-local scope multicast address which the Responder has joined. |
1207 | * [icmp-name-lookups-07, Section 4.] | | 1224 | * [icmp-name-lookups-07, Section 4.] |
1208 | */ | | 1225 | */ |
1209 | bzero(&sin6, sizeof(sin6)); | | 1226 | bzero(&sin6, sizeof(sin6)); |
1210 | sin6.sin6_family = AF_INET6; | | 1227 | sin6.sin6_family = AF_INET6; |
1211 | sin6.sin6_len = sizeof(struct sockaddr_in6); | | 1228 | sin6.sin6_len = sizeof(struct sockaddr_in6); |
1212 | bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); | | 1229 | bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); |
1213 | /* XXX scopeid */ | | 1230 | /* XXX scopeid */ |
1214 | if (ifa_ifwithaddr((struct sockaddr *)&sin6)) | | 1231 | if (ifa_ifwithaddr((struct sockaddr *)&sin6)) |
1215 | ; /* unicast/anycast, fine */ | | 1232 | ; /* unicast/anycast, fine */ |
1216 | else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) | | 1233 | else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) |
1217 | ; /* link-local multicast, fine */ | | 1234 | ; /* link-local multicast, fine */ |
1218 | else | | 1235 | else |
1219 | goto bad; | | 1236 | goto bad; |
1220 | | | 1237 | |
1221 | /* validate query Subject field. */ | | 1238 | /* validate query Subject field. */ |
1222 | qtype = ntohs(ni6->ni_qtype); | | 1239 | qtype = ntohs(ni6->ni_qtype); |
1223 | subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo); | | 1240 | subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo); |
1224 | switch (qtype) { | | 1241 | switch (qtype) { |
1225 | case NI_QTYPE_NOOP: | | 1242 | case NI_QTYPE_NOOP: |
1226 | case NI_QTYPE_SUPTYPES: | | 1243 | case NI_QTYPE_SUPTYPES: |
1227 | /* 07 draft */ | | 1244 | /* 07 draft */ |
1228 | if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0) | | 1245 | if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0) |
1229 | break; | | 1246 | break; |
1230 | /* FALLTHROUGH */ | | 1247 | /* FALLTHROUGH */ |
1231 | case NI_QTYPE_FQDN: | | 1248 | case NI_QTYPE_FQDN: |
1232 | case NI_QTYPE_NODEADDR: | | 1249 | case NI_QTYPE_NODEADDR: |
1233 | switch (ni6->ni_code) { | | 1250 | switch (ni6->ni_code) { |
1234 | case ICMP6_NI_SUBJ_IPV6: | | 1251 | case ICMP6_NI_SUBJ_IPV6: |
1235 | #if ICMP6_NI_SUBJ_IPV6 != 0 | | 1252 | #if ICMP6_NI_SUBJ_IPV6 != 0 |
1236 | case 0: | | 1253 | case 0: |
1237 | #endif | | 1254 | #endif |
1238 | /* | | 1255 | /* |
1239 | * backward compatibility - try to accept 03 draft | | 1256 | * backward compatibility - try to accept 03 draft |
1240 | * format, where no Subject is present. | | 1257 | * format, where no Subject is present. |
1241 | */ | | 1258 | */ |
1242 | if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 && | | 1259 | if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 && |
1243 | subjlen == 0) { | | 1260 | subjlen == 0) { |
1244 | oldfqdn++; | | 1261 | oldfqdn++; |
1245 | break; | | 1262 | break; |
1246 | } | | 1263 | } |
1247 | #if ICMP6_NI_SUBJ_IPV6 != 0 | | 1264 | #if ICMP6_NI_SUBJ_IPV6 != 0 |
1248 | if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6) | | 1265 | if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6) |
1249 | goto bad; | | 1266 | goto bad; |
1250 | #endif | | 1267 | #endif |
1251 | | | 1268 | |
1252 | if (subjlen != sizeof(sin6.sin6_addr)) | | 1269 | if (subjlen != sizeof(sin6.sin6_addr)) |
1253 | goto bad; | | 1270 | goto bad; |
1254 | | | 1271 | |
1255 | /* | | 1272 | /* |
1256 | * Validate Subject address. | | 1273 | * Validate Subject address. |
1257 | * | | 1274 | * |
1258 | * Not sure what exactly "address belongs to the node" | | 1275 | * Not sure what exactly "address belongs to the node" |
1259 | * means in the spec, is it just unicast, or what? | | 1276 | * means in the spec, is it just unicast, or what? |
1260 | * | | 1277 | * |
1261 | * At this moment we consider Subject address as | | 1278 | * At this moment we consider Subject address as |
1262 | * "belong to the node" if the Subject address equals | | 1279 | * "belong to the node" if the Subject address equals |
1263 | * to the IPv6 destination address; validation for | | 1280 | * to the IPv6 destination address; validation for |
1264 | * IPv6 destination address should have done enough | | 1281 | * IPv6 destination address should have done enough |
1265 | * check for us. | | 1282 | * check for us. |
1266 | * | | 1283 | * |
1267 | * We do not do proxy at this moment. | | 1284 | * We do not do proxy at this moment. |
1268 | */ | | 1285 | */ |
1269 | /* m_pulldown instead of copy? */ | | 1286 | /* m_pulldown instead of copy? */ |
1270 | m_copydata(m, off + sizeof(struct icmp6_nodeinfo), | | 1287 | m_copydata(m, off + sizeof(struct icmp6_nodeinfo), |
1271 | subjlen, (caddr_t)&sin6.sin6_addr); | | 1288 | subjlen, (caddr_t)&sin6.sin6_addr); |
1272 | /* XXX kame scope hack */ | | 1289 | /* XXX kame scope hack */ |
1273 | if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) { | | 1290 | if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) { |
1274 | if ((m->m_flags & M_PKTHDR) != 0 && | | 1291 | if ((m->m_flags & M_PKTHDR) != 0 && |
1275 | m->m_pkthdr.rcvif) { | | 1292 | m->m_pkthdr.rcvif) { |
1276 | sin6.sin6_addr.s6_addr16[1] = | | 1293 | sin6.sin6_addr.s6_addr16[1] = |
1277 | htons(m->m_pkthdr.rcvif->if_index); | | 1294 | htons(m->m_pkthdr.rcvif->if_index); |
1278 | } | | 1295 | } |
1279 | } | | 1296 | } |
1280 | subj = (char *)&sin6; | | 1297 | subj = (char *)&sin6; |
1281 | if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6.sin6_addr)) | | 1298 | if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6.sin6_addr)) |
1282 | break; | | 1299 | break; |
1283 | | | 1300 | |
1284 | /* | | 1301 | /* |
1285 | * XXX if we are to allow other cases, we should really | | 1302 | * XXX if we are to allow other cases, we should really |
1286 | * be careful about scope here. | | 1303 | * be careful about scope here. |
1287 | * basically, we should disallow queries toward IPv6 | | 1304 | * basically, we should disallow queries toward IPv6 |
1288 | * destination X with subject Y, if scope(X) > scope(Y). | | 1305 | * destination X with subject Y, if scope(X) > scope(Y). |
1289 | * if we allow scope(X) > scope(Y), it will result in | | 1306 | * if we allow scope(X) > scope(Y), it will result in |
1290 | * information leakage across scope boundary. | | 1307 | * information leakage across scope boundary. |
1291 | */ | | 1308 | */ |
1292 | goto bad; | | 1309 | goto bad; |
1293 | | | 1310 | |
1294 | case ICMP6_NI_SUBJ_FQDN: | | 1311 | case ICMP6_NI_SUBJ_FQDN: |
1295 | /* | | 1312 | /* |
1296 | * Validate Subject name with gethostname(3). | | 1313 | * Validate Subject name with gethostname(3). |
1297 | * | | 1314 | * |
1298 | * The behavior may need some debate, since: | | 1315 | * The behavior may need some debate, since: |
1299 | * - we are not sure if the node has FQDN as | | 1316 | * - we are not sure if the node has FQDN as |
1300 | * hostname (returned by gethostname(3)). | | 1317 | * hostname (returned by gethostname(3)). |
1301 | * - the code does wildcard match for truncated names. | | 1318 | * - the code does wildcard match for truncated names. |
1302 | * however, we are not sure if we want to perform | | 1319 | * however, we are not sure if we want to perform |
1303 | * wildcard match, if gethostname(3) side has | | 1320 | * wildcard match, if gethostname(3) side has |
1304 | * truncated hostname. | | 1321 | * truncated hostname. |
1305 | */ | | 1322 | */ |
1306 | n = ni6_nametodns(hostname, hostnamelen, 0); | | 1323 | n = ni6_nametodns(hostname, hostnamelen, 0); |
1307 | if (!n || n->m_next || n->m_len == 0) | | 1324 | if (!n || n->m_next || n->m_len == 0) |
1308 | goto bad; | | 1325 | goto bad; |
1309 | IP6_EXTHDR_GET(subj, char *, m, | | 1326 | IP6_EXTHDR_GET(subj, char *, m, |
1310 | off + sizeof(struct icmp6_nodeinfo), subjlen); | | 1327 | off + sizeof(struct icmp6_nodeinfo), subjlen); |
1311 | if (subj == NULL) | | 1328 | if (subj == NULL) |
1312 | goto bad; | | 1329 | goto bad; |
1313 | if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *), | | 1330 | if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *), |
1314 | n->m_len)) { | | 1331 | n->m_len)) { |
1315 | goto bad; | | 1332 | goto bad; |
1316 | } | | 1333 | } |
1317 | m_freem(n); | | 1334 | m_freem(n); |
1318 | n = NULL; | | 1335 | n = NULL; |
1319 | break; | | 1336 | break; |
1320 | | | 1337 | |
1321 | case ICMP6_NI_SUBJ_IPV4: /* XXX: to be implemented? */ | | 1338 | case ICMP6_NI_SUBJ_IPV4: /* XXX: to be implemented? */ |
1322 | default: | | 1339 | default: |
1323 | goto bad; | | 1340 | goto bad; |
1324 | } | | 1341 | } |
1325 | break; | | 1342 | break; |
1326 | } | | 1343 | } |
1327 | | | 1344 | |
1328 | /* refuse based on configuration. XXX ICMP6_NI_REFUSED? */ | | 1345 | /* refuse based on configuration. XXX ICMP6_NI_REFUSED? */ |
1329 | switch (qtype) { | | 1346 | switch (qtype) { |
1330 | case NI_QTYPE_FQDN: | | 1347 | case NI_QTYPE_FQDN: |
1331 | if ((icmp6_nodeinfo & 1) == 0) | | 1348 | if ((icmp6_nodeinfo & 1) == 0) |
1332 | goto bad; | | 1349 | goto bad; |
1333 | break; | | 1350 | break; |
1334 | case NI_QTYPE_NODEADDR: | | 1351 | case NI_QTYPE_NODEADDR: |
1335 | if ((icmp6_nodeinfo & 2) == 0) | | 1352 | if ((icmp6_nodeinfo & 2) == 0) |
1336 | goto bad; | | 1353 | goto bad; |
1337 | break; | | 1354 | break; |
1338 | } | | 1355 | } |
1339 | | | 1356 | |
1340 | /* guess reply length */ | | 1357 | /* guess reply length */ |
1341 | switch (qtype) { | | 1358 | switch (qtype) { |
1342 | case NI_QTYPE_NOOP: | | 1359 | case NI_QTYPE_NOOP: |
1343 | break; /* no reply data */ | | 1360 | break; /* no reply data */ |
1344 | case NI_QTYPE_SUPTYPES: | | 1361 | case NI_QTYPE_SUPTYPES: |
1345 | replylen += sizeof(u_int32_t); | | 1362 | replylen += sizeof(u_int32_t); |
1346 | break; | | 1363 | break; |
1347 | case NI_QTYPE_FQDN: | | 1364 | case NI_QTYPE_FQDN: |
1348 | /* XXX will append an mbuf */ | | 1365 | /* XXX will append an mbuf */ |
1349 | replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); | | 1366 | replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); |
1350 | break; | | 1367 | break; |
1351 | case NI_QTYPE_NODEADDR: | | 1368 | case NI_QTYPE_NODEADDR: |
1352 | addrs = ni6_addrs(ni6, m, &ifp, subj); | | 1369 | addrs = ni6_addrs(ni6, m, &ifp, subj); |
1353 | if ((replylen += addrs * (sizeof(struct in6_addr) + | | 1370 | if ((replylen += addrs * (sizeof(struct in6_addr) + |
1354 | sizeof(u_int32_t))) > MCLBYTES) | | 1371 | sizeof(u_int32_t))) > MCLBYTES) |
1355 | replylen = MCLBYTES; /* XXX: will truncate pkt later */ | | 1372 | replylen = MCLBYTES; /* XXX: will truncate pkt later */ |
1356 | break; | | 1373 | break; |
1357 | default: | | 1374 | default: |
1358 | /* | | 1375 | /* |
1359 | * XXX: We must return a reply with the ICMP6 code | | 1376 | * XXX: We must return a reply with the ICMP6 code |
1360 | * `unknown Qtype' in this case. However we regard the case | | 1377 | * `unknown Qtype' in this case. However we regard the case |
1361 | * as an FQDN query for backward compatibility. | | 1378 | * as an FQDN query for backward compatibility. |
1362 | * Older versions set a random value to this field, | | 1379 | * Older versions set a random value to this field, |
1363 | * so it rarely varies in the defined qtypes. | | 1380 | * so it rarely varies in the defined qtypes. |
1364 | * But the mechanism is not reliable... | | 1381 | * But the mechanism is not reliable... |
1365 | * maybe we should obsolete older versions. | | 1382 | * maybe we should obsolete older versions. |
1366 | */ | | 1383 | */ |
1367 | qtype = NI_QTYPE_FQDN; | | 1384 | qtype = NI_QTYPE_FQDN; |
1368 | /* XXX will append an mbuf */ | | 1385 | /* XXX will append an mbuf */ |
1369 | replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); | | 1386 | replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); |
1370 | oldfqdn++; | | 1387 | oldfqdn++; |
1371 | break; | | 1388 | break; |
1372 | } | | 1389 | } |
1373 | | | 1390 | |
1374 | /* allocate an mbuf to reply. */ | | 1391 | /* allocate an mbuf to reply. */ |
1375 | MGETHDR(n, M_DONTWAIT, m->m_type); | | 1392 | MGETHDR(n, M_DONTWAIT, m->m_type); |
1376 | if (n == NULL) { | | 1393 | if (n == NULL) { |
1377 | m_freem(m); | | 1394 | m_freem(m); |
1378 | return (NULL); | | 1395 | return (NULL); |
1379 | } | | 1396 | } |
1380 | M_COPY_PKTHDR(n, m); /* just for rcvif */ | | 1397 | M_COPY_PKTHDR(n, m); /* just for rcvif */ |
1381 | if (replylen > MHLEN) { | | 1398 | if (replylen > MHLEN) { |
1382 | if (replylen > MCLBYTES) { | | 1399 | if (replylen > MCLBYTES) { |
1383 | /* | | 1400 | /* |
1384 | * XXX: should we try to allocate more? But MCLBYTES | | 1401 | * XXX: should we try to allocate more? But MCLBYTES |
1385 | * is probably much larger than IPV6_MMTU... | | 1402 | * is probably much larger than IPV6_MMTU... |
1386 | */ | | 1403 | */ |
1387 | goto bad; | | 1404 | goto bad; |
1388 | } | | 1405 | } |
1389 | MCLGET(n, M_DONTWAIT); | | 1406 | MCLGET(n, M_DONTWAIT); |
1390 | if ((n->m_flags & M_EXT) == 0) { | | 1407 | if ((n->m_flags & M_EXT) == 0) { |
1391 | goto bad; | | 1408 | goto bad; |
1392 | } | | 1409 | } |
1393 | } | | 1410 | } |
1394 | n->m_pkthdr.len = n->m_len = replylen; | | 1411 | n->m_pkthdr.len = n->m_len = replylen; |
1395 | | | 1412 | |
1396 | /* copy mbuf header and IPv6 + Node Information base headers */ | | 1413 | /* copy mbuf header and IPv6 + Node Information base headers */ |
1397 | bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr)); | | 1414 | bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr)); |
1398 | nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1); | | 1415 | nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1); |
1399 | bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo)); | | 1416 | bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo)); |
1400 | | | 1417 | |
1401 | /* qtype dependent procedure */ | | 1418 | /* qtype dependent procedure */ |
1402 | switch (qtype) { | | 1419 | switch (qtype) { |
1403 | case NI_QTYPE_NOOP: | | 1420 | case NI_QTYPE_NOOP: |
1404 | nni6->ni_code = ICMP6_NI_SUCCESS; | | 1421 | nni6->ni_code = ICMP6_NI_SUCCESS; |
1405 | nni6->ni_flags = 0; | | 1422 | nni6->ni_flags = 0; |
1406 | break; | | 1423 | break; |
1407 | case NI_QTYPE_SUPTYPES: | | 1424 | case NI_QTYPE_SUPTYPES: |
1408 | { | | 1425 | { |
1409 | u_int32_t v; | | 1426 | u_int32_t v; |
1410 | nni6->ni_code = ICMP6_NI_SUCCESS; | | 1427 | nni6->ni_code = ICMP6_NI_SUCCESS; |
1411 | nni6->ni_flags = htons(0x0000); /* raw bitmap */ | | 1428 | nni6->ni_flags = htons(0x0000); /* raw bitmap */ |
1412 | /* supports NOOP, SUPTYPES, FQDN, and NODEADDR */ | | 1429 | /* supports NOOP, SUPTYPES, FQDN, and NODEADDR */ |
1413 | v = (u_int32_t)htonl(0x0000000f); | | 1430 | v = (u_int32_t)htonl(0x0000000f); |
1414 | bcopy(&v, nni6 + 1, sizeof(u_int32_t)); | | 1431 | bcopy(&v, nni6 + 1, sizeof(u_int32_t)); |
1415 | break; | | 1432 | break; |
1416 | } | | 1433 | } |
1417 | case NI_QTYPE_FQDN: | | 1434 | case NI_QTYPE_FQDN: |
1418 | nni6->ni_code = ICMP6_NI_SUCCESS; | | 1435 | nni6->ni_code = ICMP6_NI_SUCCESS; |
1419 | fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) + | | 1436 | fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) + |
1420 | sizeof(struct ip6_hdr) + | | 1437 | sizeof(struct ip6_hdr) + |
1421 | sizeof(struct icmp6_nodeinfo)); | | 1438 | sizeof(struct icmp6_nodeinfo)); |
1422 | nni6->ni_flags = 0; /* XXX: meaningless TTL */ | | 1439 | nni6->ni_flags = 0; /* XXX: meaningless TTL */ |
1423 | fqdn->ni_fqdn_ttl = 0; /* ditto. */ | | 1440 | fqdn->ni_fqdn_ttl = 0; /* ditto. */ |
1424 | /* | | 1441 | /* |
1425 | * XXX do we really have FQDN in variable "hostname"? | | 1442 | * XXX do we really have FQDN in variable "hostname"? |
1426 | */ | | 1443 | */ |
1427 | n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn); | | 1444 | n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn); |
1428 | if (n->m_next == NULL) | | 1445 | if (n->m_next == NULL) |
1429 | goto bad; | | 1446 | goto bad; |
1430 | /* XXX we assume that n->m_next is not a chain */ | | 1447 | /* XXX we assume that n->m_next is not a chain */ |
1431 | if (n->m_next->m_next != NULL) | | 1448 | if (n->m_next->m_next != NULL) |
1432 | goto bad; | | 1449 | goto bad; |
1433 | n->m_pkthdr.len += n->m_next->m_len; | | 1450 | n->m_pkthdr.len += n->m_next->m_len; |
1434 | break; | | 1451 | break; |
1435 | case NI_QTYPE_NODEADDR: | | 1452 | case NI_QTYPE_NODEADDR: |
1436 | { | | 1453 | { |
1437 | int lenlim, copied; | | 1454 | int lenlim, copied; |
1438 | | | 1455 | |
1439 | nni6->ni_code = ICMP6_NI_SUCCESS; | | 1456 | nni6->ni_code = ICMP6_NI_SUCCESS; |
1440 | n->m_pkthdr.len = n->m_len = | | 1457 | n->m_pkthdr.len = n->m_len = |
1441 | sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo); | | 1458 | sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo); |
1442 | lenlim = M_TRAILINGSPACE(n); | | 1459 | lenlim = M_TRAILINGSPACE(n); |
1443 | copied = ni6_store_addrs(ni6, nni6, ifp, lenlim); | | 1460 | copied = ni6_store_addrs(ni6, nni6, ifp, lenlim); |
1444 | /* XXX: reset mbuf length */ | | 1461 | /* XXX: reset mbuf length */ |
1445 | n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + | | 1462 | n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) + |
1446 | sizeof(struct icmp6_nodeinfo) + copied; | | 1463 | sizeof(struct icmp6_nodeinfo) + copied; |
1447 | break; | | 1464 | break; |
1448 | } | | 1465 | } |
1449 | default: | | 1466 | default: |
1450 | break; /* XXX impossible! */ | | 1467 | break; /* XXX impossible! */ |
1451 | } | | 1468 | } |
1452 | | | 1469 | |
1453 | nni6->ni_type = ICMP6_NI_REPLY; | | 1470 | nni6->ni_type = ICMP6_NI_REPLY; |
1454 | m_freem(m); | | 1471 | m_freem(m); |
1455 | return (n); | | 1472 | return (n); |
1456 | | | 1473 | |
1457 | bad: | | 1474 | bad: |
1458 | m_freem(m); | | 1475 | m_freem(m); |
1459 | if (n) | | 1476 | if (n) |
1460 | m_freem(n); | | 1477 | m_freem(n); |
1461 | return (NULL); | | 1478 | return (NULL); |
1462 | } | | 1479 | } |
1463 | #undef hostnamelen | | 1480 | #undef hostnamelen |
1464 | | | 1481 | |
1465 | #define isupper(x) ('A' <= (x) && (x) <= 'Z') | | 1482 | #define isupper(x) ('A' <= (x) && (x) <= 'Z') |
1466 | #define isalpha(x) (('A' <= (x) && (x) <= 'Z') || ('a' <= (x) && (x) <= 'z')) | | 1483 | #define isalpha(x) (('A' <= (x) && (x) <= 'Z') || ('a' <= (x) && (x) <= 'z')) |
1467 | #define isalnum(x) (isalpha(x) || ('0' <= (x) && (x) <= '9')) | | 1484 | #define isalnum(x) (isalpha(x) || ('0' <= (x) && (x) <= '9')) |
1468 | #define tolower(x) (isupper(x) ? (x) + 'a' - 'A' : (x)) | | 1485 | #define tolower(x) (isupper(x) ? (x) + 'a' - 'A' : (x)) |
1469 | | | 1486 | |
1470 | /* | | 1487 | /* |
1471 | * make a mbuf with DNS-encoded string. no compression support. | | 1488 | * make a mbuf with DNS-encoded string. no compression support. |
1472 | * | | 1489 | * |
1473 | * XXX names with less than 2 dots (like "foo" or "foo.section") will be | | 1490 | * XXX names with less than 2 dots (like "foo" or "foo.section") will be |
1474 | * treated as truncated name (two \0 at the end). this is a wild guess. | | 1491 | * treated as truncated name (two \0 at the end). this is a wild guess. |
1475 | */ | | 1492 | */ |
1476 | static struct mbuf * | | 1493 | static struct mbuf * |
1477 | ni6_nametodns(name, namelen, old) | | 1494 | ni6_nametodns(name, namelen, old) |
1478 | const char *name; | | 1495 | const char *name; |
1479 | int namelen; | | 1496 | int namelen; |
1480 | int old; /* return pascal string if non-zero */ | | 1497 | int old; /* return pascal string if non-zero */ |
1481 | { | | 1498 | { |
1482 | struct mbuf *m; | | 1499 | struct mbuf *m; |
1483 | char *cp, *ep; | | 1500 | char *cp, *ep; |
1484 | const char *p, *q; | | 1501 | const char *p, *q; |
1485 | int i, len, nterm; | | 1502 | int i, len, nterm; |
1486 | | | 1503 | |
1487 | if (old) | | 1504 | if (old) |
1488 | len = namelen + 1; | | 1505 | len = namelen + 1; |
1489 | else | | 1506 | else |
1490 | len = MCLBYTES; | | 1507 | len = MCLBYTES; |
1491 | | | 1508 | |
1492 | /* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */ | | 1509 | /* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */ |
1493 | MGET(m, M_DONTWAIT, MT_DATA); | | 1510 | MGET(m, M_DONTWAIT, MT_DATA); |
1494 | if (m && len > MLEN) { | | 1511 | if (m && len > MLEN) { |
1495 | MCLGET(m, M_DONTWAIT); | | 1512 | MCLGET(m, M_DONTWAIT); |
1496 | if ((m->m_flags & M_EXT) == 0) | | 1513 | if ((m->m_flags & M_EXT) == 0) |
1497 | goto fail; | | 1514 | goto fail; |
1498 | } | | 1515 | } |
1499 | if (!m) | | 1516 | if (!m) |
1500 | goto fail; | | 1517 | goto fail; |
1501 | m->m_next = NULL; | | 1518 | m->m_next = NULL; |
1502 | | | 1519 | |
1503 | if (old) { | | 1520 | if (old) { |
1504 | m->m_len = len; | | 1521 | m->m_len = len; |
1505 | *mtod(m, char *) = namelen; | | 1522 | *mtod(m, char *) = namelen; |
1506 | bcopy(name, mtod(m, char *) + 1, namelen); | | 1523 | bcopy(name, mtod(m, char *) + 1, namelen); |
1507 | return m; | | 1524 | return m; |
1508 | } else { | | 1525 | } else { |
1509 | m->m_len = 0; | | 1526 | m->m_len = 0; |
1510 | cp = mtod(m, char *); | | 1527 | cp = mtod(m, char *); |
1511 | ep = mtod(m, char *) + M_TRAILINGSPACE(m); | | 1528 | ep = mtod(m, char *) + M_TRAILINGSPACE(m); |
1512 | | | 1529 | |
1513 | /* if not certain about my name, return empty buffer */ | | 1530 | /* if not certain about my name, return empty buffer */ |
1514 | if (namelen == 0) | | 1531 | if (namelen == 0) |
1515 | return m; | | 1532 | return m; |
1516 | | | 1533 | |
1517 | /* | | 1534 | /* |
1518 | * guess if it looks like shortened hostname, or FQDN. | | 1535 | * guess if it looks like shortened hostname, or FQDN. |
1519 | * shortened hostname needs two trailing "\0". | | 1536 | * shortened hostname needs two trailing "\0". |
1520 | */ | | 1537 | */ |
1521 | i = 0; | | 1538 | i = 0; |
1522 | for (p = name; p < name + namelen; p++) { | | 1539 | for (p = name; p < name + namelen; p++) { |
1523 | if (*p && *p == '.') | | 1540 | if (*p && *p == '.') |
1524 | i++; | | 1541 | i++; |
1525 | } | | 1542 | } |
1526 | if (i < 2) | | 1543 | if (i < 2) |
1527 | nterm = 2; | | 1544 | nterm = 2; |
1528 | else | | 1545 | else |
1529 | nterm = 1; | | 1546 | nterm = 1; |
1530 | | | 1547 | |
1531 | p = name; | | 1548 | p = name; |
1532 | while (cp < ep && p < name + namelen) { | | 1549 | while (cp < ep && p < name + namelen) { |
1533 | i = 0; | | 1550 | i = 0; |
1534 | for (q = p; q < name + namelen && *q && *q != '.'; q++) | | 1551 | for (q = p; q < name + namelen && *q && *q != '.'; q++) |
1535 | i++; | | 1552 | i++; |
1536 | /* result does not fit into mbuf */ | | 1553 | /* result does not fit into mbuf */ |
1537 | if (cp + i + 1 >= ep) | | 1554 | if (cp + i + 1 >= ep) |
1538 | goto fail; | | 1555 | goto fail; |
1539 | /* | | 1556 | /* |
1540 | * DNS label length restriction, RFC1035 page 8. | | 1557 | * DNS label length restriction, RFC1035 page 8. |
1541 | * "i == 0" case is included here to avoid returning | | 1558 | * "i == 0" case is included here to avoid returning |
1542 | * 0-length label on "foo..bar". | | 1559 | * 0-length label on "foo..bar". |
1543 | */ | | 1560 | */ |
1544 | if (i <= 0 || i >= 64) | | 1561 | if (i <= 0 || i >= 64) |
1545 | goto fail; | | 1562 | goto fail; |
1546 | *cp++ = i; | | 1563 | *cp++ = i; |
1547 | if (!isalpha(p[0]) || !isalnum(p[i - 1])) | | 1564 | if (!isalpha(p[0]) || !isalnum(p[i - 1])) |
1548 | goto fail; | | 1565 | goto fail; |
1549 | while (i > 0) { | | 1566 | while (i > 0) { |
1550 | if (!isalnum(*p) && *p != '-') | | 1567 | if (!isalnum(*p) && *p != '-') |
1551 | goto fail; | | 1568 | goto fail; |
1552 | if (isupper(*p)) { | | 1569 | if (isupper(*p)) { |
1553 | *cp++ = tolower(*p); | | 1570 | *cp++ = tolower(*p); |
1554 | p++; | | 1571 | p++; |
1555 | } else | | 1572 | } else |
1556 | *cp++ = *p++; | | 1573 | *cp++ = *p++; |
1557 | i--; | | 1574 | i--; |
1558 | } | | 1575 | } |
1559 | p = q; | | 1576 | p = q; |
1560 | if (p < name + namelen && *p == '.') | | 1577 | if (p < name + namelen && *p == '.') |
1561 | p++; | | 1578 | p++; |
1562 | } | | 1579 | } |
1563 | /* termination */ | | 1580 | /* termination */ |
1564 | if (cp + nterm >= ep) | | 1581 | if (cp + nterm >= ep) |
1565 | goto fail; | | 1582 | goto fail; |
1566 | while (nterm-- > 0) | | 1583 | while (nterm-- > 0) |
1567 | *cp++ = '\0'; | | 1584 | *cp++ = '\0'; |
1568 | m->m_len = cp - mtod(m, char *); | | 1585 | m->m_len = cp - mtod(m, char *); |
1569 | return m; | | 1586 | return m; |
1570 | } | | 1587 | } |
1571 | | | 1588 | |
1572 | panic("should not reach here"); | | 1589 | panic("should not reach here"); |
1573 | /* NOTREACHED */ | | 1590 | /* NOTREACHED */ |
1574 | | | 1591 | |
1575 | fail: | | 1592 | fail: |
1576 | if (m) | | 1593 | if (m) |
1577 | m_freem(m); | | 1594 | m_freem(m); |
1578 | return NULL; | | 1595 | return NULL; |
1579 | } | | 1596 | } |
1580 | | | 1597 | |
1581 | /* | | 1598 | /* |
1582 | * check if two DNS-encoded string matches. takes care of truncated | | 1599 | * check if two DNS-encoded string matches. takes care of truncated |
1583 | * form (with \0\0 at the end). no compression support. | | 1600 | * form (with \0\0 at the end). no compression support. |
1584 | * XXX upper/lowercase match (see RFC2065) | | 1601 | * XXX upper/lowercase match (see RFC2065) |
1585 | */ | | 1602 | */ |
1586 | static int | | 1603 | static int |
1587 | ni6_dnsmatch(a, alen, b, blen) | | 1604 | ni6_dnsmatch(a, alen, b, blen) |
1588 | const char *a; | | 1605 | const char *a; |
1589 | int alen; | | 1606 | int alen; |
1590 | const char *b; | | 1607 | const char *b; |
1591 | int blen; | | 1608 | int blen; |
1592 | { | | 1609 | { |
1593 | const char *a0, *b0; | | 1610 | const char *a0, *b0; |
1594 | int l; | | 1611 | int l; |
1595 | | | 1612 | |
1596 | /* simplest case - need validation? */ | | 1613 | /* simplest case - need validation? */ |
1597 | if (alen == blen && bcmp(a, b, alen) == 0) | | 1614 | if (alen == blen && bcmp(a, b, alen) == 0) |
1598 | return 1; | | 1615 | return 1; |
1599 | | | 1616 | |
1600 | a0 = a; | | 1617 | a0 = a; |
1601 | b0 = b; | | 1618 | b0 = b; |
1602 | | | 1619 | |
1603 | /* termination is mandatory */ | | 1620 | /* termination is mandatory */ |
1604 | if (alen < 2 || blen < 2) | | 1621 | if (alen < 2 || blen < 2) |
1605 | return 0; | | 1622 | return 0; |
1606 | if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0') | | 1623 | if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0') |
1607 | return 0; | | 1624 | return 0; |
1608 | alen--; | | 1625 | alen--; |
1609 | blen--; | | 1626 | blen--; |
1610 | | | 1627 | |
1611 | while (a - a0 < alen && b - b0 < blen) { | | 1628 | while (a - a0 < alen && b - b0 < blen) { |
1612 | if (a - a0 + 1 > alen || b - b0 + 1 > blen) | | 1629 | if (a - a0 + 1 > alen || b - b0 + 1 > blen) |
1613 | return 0; | | 1630 | return 0; |
1614 | | | 1631 | |
1615 | if ((signed char)a[0] < 0 || (signed char)b[0] < 0) | | 1632 | if ((signed char)a[0] < 0 || (signed char)b[0] < 0) |
1616 | return 0; | | 1633 | return 0; |
1617 | /* we don't support compression yet */ | | 1634 | /* we don't support compression yet */ |
1618 | if (a[0] >= 64 || b[0] >= 64) | | 1635 | if (a[0] >= 64 || b[0] >= 64) |
1619 | return 0; | | 1636 | return 0; |
1620 | | | 1637 | |
1621 | /* truncated case */ | | 1638 | /* truncated case */ |
1622 | if (a[0] == 0 && a - a0 == alen - 1) | | 1639 | if (a[0] == 0 && a - a0 == alen - 1) |
1623 | return 1; | | 1640 | return 1; |
1624 | if (b[0] == 0 && b - b0 == blen - 1) | | 1641 | if (b[0] == 0 && b - b0 == blen - 1) |
1625 | return 1; | | 1642 | return 1; |
1626 | if (a[0] == 0 || b[0] == 0) | | 1643 | if (a[0] == 0 || b[0] == 0) |
1627 | return 0; | | 1644 | return 0; |
1628 | | | 1645 | |
1629 | if (a[0] != b[0]) | | 1646 | if (a[0] != b[0]) |
1630 | return 0; | | 1647 | return 0; |
1631 | l = a[0]; | | 1648 | l = a[0]; |
1632 | if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen) | | 1649 | if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen) |
1633 | return 0; | | 1650 | return 0; |
1634 | if (bcmp(a + 1, b + 1, l) != 0) | | 1651 | if (bcmp(a + 1, b + 1, l) != 0) |
1635 | return 0; | | 1652 | return 0; |
1636 | | | 1653 | |
1637 | a += 1 + l; | | 1654 | a += 1 + l; |
1638 | b += 1 + l; | | 1655 | b += 1 + l; |
1639 | } | | 1656 | } |
1640 | | | 1657 | |
1641 | if (a - a0 == alen && b - b0 == blen) | | 1658 | if (a - a0 == alen && b - b0 == blen) |
1642 | return 1; | | 1659 | return 1; |
1643 | else | | 1660 | else |
1644 | return 0; | | 1661 | return 0; |
1645 | } | | 1662 | } |
1646 | | | 1663 | |
1647 | /* | | 1664 | /* |
1648 | * calculate the number of addresses to be returned in the node info reply. | | 1665 | * calculate the number of addresses to be returned in the node info reply. |
1649 | */ | | 1666 | */ |
1650 | static int | | 1667 | static int |
1651 | ni6_addrs(ni6, m, ifpp, subj) | | 1668 | ni6_addrs(ni6, m, ifpp, subj) |
1652 | struct icmp6_nodeinfo *ni6; | | 1669 | struct icmp6_nodeinfo *ni6; |
1653 | struct mbuf *m; | | 1670 | struct mbuf *m; |
1654 | struct ifnet **ifpp; | | 1671 | struct ifnet **ifpp; |
1655 | char *subj; | | 1672 | char *subj; |
1656 | { | | 1673 | { |
1657 | struct ifnet *ifp; | | 1674 | struct ifnet *ifp; |
1658 | struct in6_ifaddr *ifa6; | | 1675 | struct in6_ifaddr *ifa6; |
1659 | struct ifaddr *ifa; | | 1676 | struct ifaddr *ifa; |
1660 | struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */ | | 1677 | struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */ |
1661 | int addrs = 0, addrsofif, iffound = 0; | | 1678 | int addrs = 0, addrsofif, iffound = 0; |
1662 | int niflags = ni6->ni_flags; | | 1679 | int niflags = ni6->ni_flags; |
1663 | | | 1680 | |
1664 | if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) { | | 1681 | if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) { |
1665 | switch (ni6->ni_code) { | | 1682 | switch (ni6->ni_code) { |
1666 | case ICMP6_NI_SUBJ_IPV6: | | 1683 | case ICMP6_NI_SUBJ_IPV6: |
1667 | if (subj == NULL) /* must be impossible... */ | | 1684 | if (subj == NULL) /* must be impossible... */ |
1668 | return (0); | | 1685 | return (0); |
1669 | subj_ip6 = (struct sockaddr_in6 *)subj; | | 1686 | subj_ip6 = (struct sockaddr_in6 *)subj; |
1670 | break; | | 1687 | break; |
1671 | default: | | 1688 | default: |
1672 | /* | | 1689 | /* |
1673 | * XXX: we only support IPv6 subject address for | | 1690 | * XXX: we only support IPv6 subject address for |
1674 | * this Qtype. | | 1691 | * this Qtype. |
1675 | */ | | 1692 | */ |
1676 | return (0); | | 1693 | return (0); |
1677 | } | | 1694 | } |
1678 | } | | 1695 | } |
1679 | | | 1696 | |
1680 | for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) | | 1697 | for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) |
1681 | { | | 1698 | { |
1682 | addrsofif = 0; | | 1699 | addrsofif = 0; |
1683 | for (ifa = ifp->if_addrlist.tqh_first; ifa; | | 1700 | for (ifa = ifp->if_addrlist.tqh_first; ifa; |
1684 | ifa = ifa->ifa_list.tqe_next) | | 1701 | ifa = ifa->ifa_list.tqe_next) |
1685 | { | | 1702 | { |
1686 | if (ifa->ifa_addr->sa_family != AF_INET6) | | 1703 | if (ifa->ifa_addr->sa_family != AF_INET6) |
1687 | continue; | | 1704 | continue; |
1688 | ifa6 = (struct in6_ifaddr *)ifa; | | 1705 | ifa6 = (struct in6_ifaddr *)ifa; |
1689 | | | 1706 | |
1690 | if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 && | | 1707 | if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 && |
1691 | IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr, | | 1708 | IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr, |
1692 | &ifa6->ia_addr.sin6_addr)) | | 1709 | &ifa6->ia_addr.sin6_addr)) |
1693 | iffound = 1; | | 1710 | iffound = 1; |
1694 | | | 1711 | |
1695 | /* | | 1712 | /* |
1696 | * IPv4-mapped addresses can only be returned by a | | 1713 | * IPv4-mapped addresses can only be returned by a |
1697 | * Node Information proxy, since they represent | | 1714 | * Node Information proxy, since they represent |
1698 | * addresses of IPv4-only nodes, which perforce do | | 1715 | * addresses of IPv4-only nodes, which perforce do |
1699 | * not implement this protocol. | | 1716 | * not implement this protocol. |
1700 | * [icmp-name-lookups-07, Section 5.4] | | 1717 | * [icmp-name-lookups-07, Section 5.4] |
1701 | * So we don't support NI_NODEADDR_FLAG_COMPAT in | | 1718 | * So we don't support NI_NODEADDR_FLAG_COMPAT in |
1702 | * this function at this moment. | | 1719 | * this function at this moment. |
1703 | */ | | 1720 | */ |
1704 | | | 1721 | |
1705 | /* What do we have to do about ::1? */ | | 1722 | /* What do we have to do about ::1? */ |
1706 | switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) { | | 1723 | switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) { |
1707 | case IPV6_ADDR_SCOPE_LINKLOCAL: | | 1724 | case IPV6_ADDR_SCOPE_LINKLOCAL: |
1708 | if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) | | 1725 | if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) |
1709 | continue; | | 1726 | continue; |
1710 | break; | | 1727 | break; |
1711 | case IPV6_ADDR_SCOPE_SITELOCAL: | | 1728 | case IPV6_ADDR_SCOPE_SITELOCAL: |
1712 | if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) | | 1729 | if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) |
1713 | continue; | | 1730 | continue; |
1714 | break; | | 1731 | break; |
1715 | case IPV6_ADDR_SCOPE_GLOBAL: | | 1732 | case IPV6_ADDR_SCOPE_GLOBAL: |
1716 | if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) | | 1733 | if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) |
1717 | continue; | | 1734 | continue; |
1718 | break; | | 1735 | break; |
1719 | default: | | 1736 | default: |
1720 | continue; | | 1737 | continue; |
1721 | } | | 1738 | } |
1722 | | | 1739 | |
1723 | /* | | 1740 | /* |
1724 | * check if anycast is okay. | | 1741 | * check if anycast is okay. |
1725 | * XXX: just experimental. not in the spec. | | 1742 | * XXX: just experimental. not in the spec. |
1726 | */ | | 1743 | */ |
1727 | if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && | | 1744 | if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && |
1728 | (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) | | 1745 | (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) |
1729 | continue; /* we need only unicast addresses */ | | 1746 | continue; /* we need only unicast addresses */ |
1730 | | | 1747 | |
1731 | addrsofif++; /* count the address */ | | 1748 | addrsofif++; /* count the address */ |
1732 | } | | 1749 | } |
1733 | if (iffound) { | | 1750 | if (iffound) { |
1734 | *ifpp = ifp; | | 1751 | *ifpp = ifp; |
1735 | return (addrsofif); | | 1752 | return (addrsofif); |
1736 | } | | 1753 | } |
1737 | | | 1754 | |
1738 | addrs += addrsofif; | | 1755 | addrs += addrsofif; |
1739 | } | | 1756 | } |
1740 | | | 1757 | |
1741 | return (addrs); | | 1758 | return (addrs); |
1742 | } | | 1759 | } |
1743 | | | 1760 | |
1744 | static int | | 1761 | static int |
1745 | ni6_store_addrs(ni6, nni6, ifp0, resid) | | 1762 | ni6_store_addrs(ni6, nni6, ifp0, resid) |
1746 | struct icmp6_nodeinfo *ni6, *nni6; | | 1763 | struct icmp6_nodeinfo *ni6, *nni6; |
1747 | struct ifnet *ifp0; | | 1764 | struct ifnet *ifp0; |
1748 | int resid; | | 1765 | int resid; |
1749 | { | | 1766 | { |
1750 | struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); | | 1767 | struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); |
1751 | struct in6_ifaddr *ifa6; | | 1768 | struct in6_ifaddr *ifa6; |
1752 | struct ifaddr *ifa; | | 1769 | struct ifaddr *ifa; |
1753 | struct ifnet *ifp_dep = NULL; | | 1770 | struct ifnet *ifp_dep = NULL; |
1754 | int copied = 0, allow_deprecated = 0; | | 1771 | int copied = 0, allow_deprecated = 0; |
1755 | u_char *cp = (u_char *)(nni6 + 1); | | 1772 | u_char *cp = (u_char *)(nni6 + 1); |
1756 | int niflags = ni6->ni_flags; | | 1773 | int niflags = ni6->ni_flags; |
1757 | u_int32_t ltime; | | 1774 | u_int32_t ltime; |
1758 | | | 1775 | |
1759 | if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL)) | | 1776 | if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL)) |
1760 | return (0); /* needless to copy */ | | 1777 | return (0); /* needless to copy */ |
1761 | | | 1778 | |
1762 | again: | | 1779 | again: |
1763 | | | 1780 | |
1764 | for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) | | 1781 | for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) |
1765 | { | | 1782 | { |
1766 | for (ifa = ifp->if_addrlist.tqh_first; ifa; | | 1783 | for (ifa = ifp->if_addrlist.tqh_first; ifa; |
1767 | ifa = ifa->ifa_list.tqe_next) | | 1784 | ifa = ifa->ifa_list.tqe_next) |
1768 | { | | 1785 | { |
1769 | if (ifa->ifa_addr->sa_family != AF_INET6) | | 1786 | if (ifa->ifa_addr->sa_family != AF_INET6) |
1770 | continue; | | 1787 | continue; |
1771 | ifa6 = (struct in6_ifaddr *)ifa; | | 1788 | ifa6 = (struct in6_ifaddr *)ifa; |
1772 | | | 1789 | |
1773 | if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 && | | 1790 | if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 && |
1774 | allow_deprecated == 0) { | | 1791 | allow_deprecated == 0) { |
1775 | /* | | 1792 | /* |
1776 | * prefererred address should be put before | | 1793 | * prefererred address should be put before |
1777 | * deprecated addresses. | | 1794 | * deprecated addresses. |
1778 | */ | | 1795 | */ |
1779 | | | 1796 | |
1780 | /* record the interface for later search */ | | 1797 | /* record the interface for later search */ |
1781 | if (ifp_dep == NULL) | | 1798 | if (ifp_dep == NULL) |
1782 | ifp_dep = ifp; | | 1799 | ifp_dep = ifp; |
1783 | | | 1800 | |
1784 | continue; | | 1801 | continue; |
1785 | } | | 1802 | } |
1786 | else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 && | | 1803 | else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 && |
1787 | allow_deprecated != 0) | | 1804 | allow_deprecated != 0) |
1788 | continue; /* we now collect deprecated addrs */ | | 1805 | continue; /* we now collect deprecated addrs */ |
1789 | | | 1806 | |
1790 | /* What do we have to do about ::1? */ | | 1807 | /* What do we have to do about ::1? */ |
1791 | switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) { | | 1808 | switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) { |
1792 | case IPV6_ADDR_SCOPE_LINKLOCAL: | | 1809 | case IPV6_ADDR_SCOPE_LINKLOCAL: |
1793 | if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) | | 1810 | if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0) |
1794 | continue; | | 1811 | continue; |
1795 | break; | | 1812 | break; |
1796 | case IPV6_ADDR_SCOPE_SITELOCAL: | | 1813 | case IPV6_ADDR_SCOPE_SITELOCAL: |
1797 | if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) | | 1814 | if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0) |
1798 | continue; | | 1815 | continue; |
1799 | break; | | 1816 | break; |
1800 | case IPV6_ADDR_SCOPE_GLOBAL: | | 1817 | case IPV6_ADDR_SCOPE_GLOBAL: |
1801 | if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) | | 1818 | if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0) |
1802 | continue; | | 1819 | continue; |
1803 | break; | | 1820 | break; |
1804 | default: | | 1821 | default: |
1805 | continue; | | 1822 | continue; |
1806 | } | | 1823 | } |
1807 | | | 1824 | |
1808 | /* | | 1825 | /* |
1809 | * check if anycast is okay. | | 1826 | * check if anycast is okay. |
1810 | * XXX: just experimental. not in the spec. | | 1827 | * XXX: just experimental. not in the spec. |
1811 | */ | | 1828 | */ |
1812 | if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && | | 1829 | if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && |
1813 | (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) | | 1830 | (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) |
1814 | continue; | | 1831 | continue; |
1815 | | | 1832 | |
1816 | /* now we can copy the address */ | | 1833 | /* now we can copy the address */ |
1817 | if (resid < sizeof(struct in6_addr) + | | 1834 | if (resid < sizeof(struct in6_addr) + |
1818 | sizeof(u_int32_t)) { | | 1835 | sizeof(u_int32_t)) { |
1819 | /* | | 1836 | /* |
1820 | * We give up much more copy. | | 1837 | * We give up much more copy. |
1821 | * Set the truncate flag and return. | | 1838 | * Set the truncate flag and return. |
1822 | */ | | 1839 | */ |
1823 | nni6->ni_flags |= | | 1840 | nni6->ni_flags |= |
1824 | NI_NODEADDR_FLAG_TRUNCATE; | | 1841 | NI_NODEADDR_FLAG_TRUNCATE; |
1825 | return (copied); | | 1842 | return (copied); |
1826 | } | | 1843 | } |
1827 | | | 1844 | |
1828 | /* | | 1845 | /* |
1829 | * Set the TTL of the address. | | 1846 | * Set the TTL of the address. |
1830 | * The TTL value should be one of the following | | 1847 | * The TTL value should be one of the following |
1831 | * according to the specification: | | 1848 | * according to the specification: |
1832 | * | | 1849 | * |
1833 | * 1. The remaining lifetime of a DHCP lease on the | | 1850 | * 1. The remaining lifetime of a DHCP lease on the |
1834 | * address, or | | 1851 | * address, or |
1835 | * 2. The remaining Valid Lifetime of a prefix from | | 1852 | * 2. The remaining Valid Lifetime of a prefix from |
1836 | * which the address was derived through Stateless | | 1853 | * which the address was derived through Stateless |
1837 | * Autoconfiguration. | | 1854 | * Autoconfiguration. |
1838 | * | | 1855 | * |
1839 | * Note that we currently do not support stateful | | 1856 | * Note that we currently do not support stateful |
1840 | * address configuration by DHCPv6, so the former | | 1857 | * address configuration by DHCPv6, so the former |
1841 | * case can't happen. | | 1858 | * case can't happen. |
1842 | * | | 1859 | * |
1843 | * TTL must be 2^31 > TTL >= 0. | | 1860 | * TTL must be 2^31 > TTL >= 0. |
1844 | */ | | 1861 | */ |
1845 | if (ifa6->ia6_lifetime.ia6t_expire == 0) | | 1862 | if (ifa6->ia6_lifetime.ia6t_expire == 0) |
1846 | ltime = ND6_INFINITE_LIFETIME; | | 1863 | ltime = ND6_INFINITE_LIFETIME; |
1847 | else { | | 1864 | else { |
1848 | if (ifa6->ia6_lifetime.ia6t_expire > | | 1865 | if (ifa6->ia6_lifetime.ia6t_expire > |
1849 | time.tv_sec) | | 1866 | time.tv_sec) |
1850 | ltime = ifa6->ia6_lifetime.ia6t_expire - time.tv_sec; | | 1867 | ltime = ifa6->ia6_lifetime.ia6t_expire - time.tv_sec; |
1851 | else | | 1868 | else |
1852 | ltime = 0; | | 1869 | ltime = 0; |
1853 | } | | 1870 | } |
1854 | if (ltime > 0x7fffffff) | | 1871 | if (ltime > 0x7fffffff) |
1855 | ltime = 0x7fffffff; | | 1872 | ltime = 0x7fffffff; |
1856 | ltime = htonl(ltime); | | 1873 | ltime = htonl(ltime); |
1857 | | | 1874 | |
1858 | bcopy(<ime, cp, sizeof(u_int32_t)); | | 1875 | bcopy(<ime, cp, sizeof(u_int32_t)); |
1859 | cp += sizeof(u_int32_t); | | 1876 | cp += sizeof(u_int32_t); |
1860 | | | 1877 | |
1861 | /* copy the address itself */ | | 1878 | /* copy the address itself */ |
1862 | bcopy(&ifa6->ia_addr.sin6_addr, cp, | | 1879 | bcopy(&ifa6->ia_addr.sin6_addr, cp, |
1863 | sizeof(struct in6_addr)); | | 1880 | sizeof(struct in6_addr)); |
1864 | /* XXX: KAME link-local hack; remove ifindex */ | | 1881 | /* XXX: KAME link-local hack; remove ifindex */ |
1865 | if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) | | 1882 | if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) |
1866 | ((struct in6_addr *)cp)->s6_addr16[1] = 0; | | 1883 | ((struct in6_addr *)cp)->s6_addr16[1] = 0; |
1867 | cp += sizeof(struct in6_addr); | | 1884 | cp += sizeof(struct in6_addr); |
1868 | | | 1885 | |
1869 | resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t)); | | 1886 | resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t)); |
1870 | copied += (sizeof(struct in6_addr) + | | 1887 | copied += (sizeof(struct in6_addr) + |
1871 | sizeof(u_int32_t)); | | 1888 | sizeof(u_int32_t)); |
1872 | } | | 1889 | } |
1873 | if (ifp0) /* we need search only on the specified IF */ | | 1890 | if (ifp0) /* we need search only on the specified IF */ |
1874 | break; | | 1891 | break; |
1875 | } | | 1892 | } |
1876 | | | 1893 | |
1877 | if (allow_deprecated == 0 && ifp_dep != NULL) { | | 1894 | if (allow_deprecated == 0 && ifp_dep != NULL) { |
1878 | ifp = ifp_dep; | | 1895 | ifp = ifp_dep; |
1879 | allow_deprecated = 1; | | 1896 | allow_deprecated = 1; |
1880 | | | 1897 | |
1881 | goto again; | | 1898 | goto again; |
1882 | } | | 1899 | } |
1883 | | | 1900 | |
1884 | return (copied); | | 1901 | return (copied); |
1885 | } | | 1902 | } |
1886 | | | 1903 | |
1887 | /* | | 1904 | /* |
1888 | * XXX almost dup'ed code with rip6_input. | | 1905 | * XXX almost dup'ed code with rip6_input. |
1889 | */ | | 1906 | */ |
1890 | static int | | 1907 | static int |
1891 | icmp6_rip6_input(mp, off) | | 1908 | icmp6_rip6_input(mp, off) |
1892 | struct mbuf **mp; | | 1909 | struct mbuf **mp; |
1893 | int off; | | 1910 | int off; |
1894 | { | | 1911 | { |
1895 | struct mbuf *m = *mp; | | 1912 | struct mbuf *m = *mp; |
1896 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | | 1913 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
1897 | struct inpcb_hdr *inph; | | 1914 | struct inpcb_hdr *inph; |
1898 | struct in6pcb *in6p; | | 1915 | struct in6pcb *in6p; |
1899 | struct in6pcb *last = NULL; | | 1916 | struct in6pcb *last = NULL; |
1900 | struct sockaddr_in6 rip6src; | | 1917 | struct sockaddr_in6 rip6src; |
1901 | struct icmp6_hdr *icmp6; | | 1918 | struct icmp6_hdr *icmp6; |
1902 | struct mbuf *opts = NULL; | | 1919 | struct mbuf *opts = NULL; |
1903 | | | 1920 | |
1904 | IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6)); | | 1921 | IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6)); |
1905 | if (icmp6 == NULL) { | | 1922 | if (icmp6 == NULL) { |
1906 | /* m is already reclaimed */ | | 1923 | /* m is already reclaimed */ |
1907 | return IPPROTO_DONE; | | 1924 | return IPPROTO_DONE; |
1908 | } | | 1925 | } |
1909 | | | 1926 | |
1910 | bzero(&rip6src, sizeof(rip6src)); | | 1927 | bzero(&rip6src, sizeof(rip6src)); |
1911 | rip6src.sin6_len = sizeof(struct sockaddr_in6); | | 1928 | rip6src.sin6_len = sizeof(struct sockaddr_in6); |
1912 | rip6src.sin6_family = AF_INET6; | | 1929 | rip6src.sin6_family = AF_INET6; |
1913 | /* KAME hack: recover scopeid */ | | 1930 | /* KAME hack: recover scopeid */ |
1914 | (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif); | | 1931 | (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif); |
1915 | | | 1932 | |
1916 | CIRCLEQ_FOREACH(inph, &raw6cbtable.inpt_queue, inph_queue) { | | 1933 | CIRCLEQ_FOREACH(inph, &raw6cbtable.inpt_queue, inph_queue) { |
1917 | in6p = (struct in6pcb *)inph; | | 1934 | in6p = (struct in6pcb *)inph; |
1918 | if (in6p->in6p_af != AF_INET6) | | 1935 | if (in6p->in6p_af != AF_INET6) |
1919 | continue; | | 1936 | continue; |
1920 | if (in6p->in6p_ip6.ip6_nxt != IPPROTO_ICMPV6) | | 1937 | if (in6p->in6p_ip6.ip6_nxt != IPPROTO_ICMPV6) |
1921 | continue; | | 1938 | continue; |
1922 | if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && | | 1939 | if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && |
1923 | !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) | | 1940 | !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) |
1924 | continue; | | 1941 | continue; |
1925 | if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && | | 1942 | if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && |
1926 | !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) | | 1943 | !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) |
1927 | continue; | | 1944 | continue; |
1928 | if (in6p->in6p_icmp6filt | | 1945 | if (in6p->in6p_icmp6filt |
1929 | && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type, | | 1946 | && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type, |
1930 | in6p->in6p_icmp6filt)) | | 1947 | in6p->in6p_icmp6filt)) |
1931 | continue; | | 1948 | continue; |
1932 | if (last) { | | 1949 | if (last) { |
1933 | struct mbuf *n; | | 1950 | struct mbuf *n; |
1934 | if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { | | 1951 | if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { |
1935 | if (last->in6p_flags & IN6P_CONTROLOPTS) | | 1952 | if (last->in6p_flags & IN6P_CONTROLOPTS) |
1936 | ip6_savecontrol(last, &opts, ip6, n); | | 1953 | ip6_savecontrol(last, &opts, ip6, n); |
1937 | /* strip intermediate headers */ | | 1954 | /* strip intermediate headers */ |
1938 | m_adj(n, off); | | 1955 | m_adj(n, off); |
1939 | if (sbappendaddr(&last->in6p_socket->so_rcv, | | 1956 | if (sbappendaddr(&last->in6p_socket->so_rcv, |
1940 | (struct sockaddr *)&rip6src, | | 1957 | (struct sockaddr *)&rip6src, |
1941 | n, opts) == 0) { | | 1958 | n, opts) == 0) { |
1942 | /* should notify about lost packet */ | | 1959 | /* should notify about lost packet */ |
1943 | m_freem(n); | | 1960 | m_freem(n); |
1944 | if (opts) | | 1961 | if (opts) |
1945 | m_freem(opts); | | 1962 | m_freem(opts); |
1946 | } else | | 1963 | } else |
1947 | sorwakeup(last->in6p_socket); | | 1964 | sorwakeup(last->in6p_socket); |
1948 | opts = NULL; | | 1965 | opts = NULL; |
1949 | } | | 1966 | } |
1950 | } | | 1967 | } |
1951 | last = in6p; | | 1968 | last = in6p; |
1952 | } | | 1969 | } |
1953 | if (last) { | | 1970 | if (last) { |
1954 | if (last->in6p_flags & IN6P_CONTROLOPTS) | | 1971 | if (last->in6p_flags & IN6P_CONTROLOPTS) |
1955 | ip6_savecontrol(last, &opts, ip6, m); | | 1972 | ip6_savecontrol(last, &opts, ip6, m); |
1956 | /* strip intermediate headers */ | | 1973 | /* strip intermediate headers */ |
1957 | m_adj(m, off); | | 1974 | m_adj(m, off); |
1958 | if (sbappendaddr(&last->in6p_socket->so_rcv, | | 1975 | if (sbappendaddr(&last->in6p_socket->so_rcv, |
1959 | (struct sockaddr *)&rip6src, m, opts) == 0) { | | 1976 | (struct sockaddr *)&rip6src, m, opts) == 0) { |
1960 | m_freem(m); | | 1977 | m_freem(m); |
1961 | if (opts) | | 1978 | if (opts) |
1962 | m_freem(opts); | | 1979 | m_freem(opts); |
1963 | } else | | 1980 | } else |
1964 | sorwakeup(last->in6p_socket); | | 1981 | sorwakeup(last->in6p_socket); |
1965 | } else { | | 1982 | } else { |
1966 | m_freem(m); | | 1983 | m_freem(m); |
1967 | ip6stat.ip6s_delivered--; | | 1984 | ip6stat.ip6s_delivered--; |
1968 | } | | 1985 | } |
1969 | return IPPROTO_DONE; | | 1986 | return IPPROTO_DONE; |
1970 | } | | 1987 | } |
1971 | | | 1988 | |
1972 | /* | | 1989 | /* |
1973 | * Reflect the ip6 packet back to the source. | | 1990 | * Reflect the ip6 packet back to the source. |
1974 | * OFF points to the icmp6 header, counted from the top of the mbuf. | | 1991 | * OFF points to the icmp6 header, counted from the top of the mbuf. |
1975 | * | | 1992 | * |
1976 | * Note: RFC 1885 required that an echo reply should be truncated if it | | 1993 | * Note: RFC 1885 required that an echo reply should be truncated if it |
1977 | * did not fit in with (return) path MTU, and KAME code supported the | | 1994 | * did not fit in with (return) path MTU, and KAME code supported the |
1978 | * behavior. However, as a clarification after the RFC, this limitation | | 1995 | * behavior. However, as a clarification after the RFC, this limitation |
1979 | * was removed in a revised version of the spec, RFC 2463. We had kept the | | 1996 | * was removed in a revised version of the spec, RFC 2463. We had kept the |
1980 | * old behavior, with a (non-default) ifdef block, while the new version of | | 1997 | * old behavior, with a (non-default) ifdef block, while the new version of |
1981 | * the spec was an internet-draft status, and even after the new RFC was | | 1998 | * the spec was an internet-draft status, and even after the new RFC was |
1982 | * published. But it would rather make sense to clean the obsoleted part | | 1999 | * published. But it would rather make sense to clean the obsoleted part |
1983 | * up, and to make the code simpler at this stage. | | 2000 | * up, and to make the code simpler at this stage. |
1984 | */ | | 2001 | */ |
1985 | void | | 2002 | void |
1986 | icmp6_reflect(m, off) | | 2003 | icmp6_reflect(m, off) |
1987 | struct mbuf *m; | | 2004 | struct mbuf *m; |
1988 | size_t off; | | 2005 | size_t off; |
1989 | { | | 2006 | { |
1990 | struct ip6_hdr *ip6; | | 2007 | struct ip6_hdr *ip6; |
1991 | struct icmp6_hdr *icmp6; | | 2008 | struct icmp6_hdr *icmp6; |
1992 | struct in6_ifaddr *ia; | | 2009 | struct in6_ifaddr *ia; |
1993 | struct in6_addr t, *src = 0; | | 2010 | struct in6_addr t, *src = 0; |
1994 | int plen; | | 2011 | int plen; |
1995 | int type, code; | | 2012 | int type, code; |
1996 | struct ifnet *outif = NULL; | | 2013 | struct ifnet *outif = NULL; |
1997 | struct sockaddr_in6 sa6_src, sa6_dst; | | 2014 | struct sockaddr_in6 sa6_src, sa6_dst; |
1998 | | | 2015 | |
1999 | /* too short to reflect */ | | 2016 | /* too short to reflect */ |
2000 | if (off < sizeof(struct ip6_hdr)) { | | 2017 | if (off < sizeof(struct ip6_hdr)) { |
2001 | nd6log((LOG_DEBUG, | | 2018 | nd6log((LOG_DEBUG, |
2002 | "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n", | | 2019 | "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n", |
2003 | (u_long)off, (u_long)sizeof(struct ip6_hdr), | | 2020 | (u_long)off, (u_long)sizeof(struct ip6_hdr), |
2004 | __FILE__, __LINE__)); | | 2021 | __FILE__, __LINE__)); |
2005 | goto bad; | | 2022 | goto bad; |
2006 | } | | 2023 | } |
2007 | | | 2024 | |
2008 | /* | | 2025 | /* |
2009 | * If there are extra headers between IPv6 and ICMPv6, strip | | 2026 | * If there are extra headers between IPv6 and ICMPv6, strip |
2010 | * off that header first. | | 2027 | * off that header first. |
2011 | */ | | 2028 | */ |
2012 | #ifdef DIAGNOSTIC | | 2029 | #ifdef DIAGNOSTIC |
2013 | if (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) > MHLEN) | | 2030 | if (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) > MHLEN) |
2014 | panic("assumption failed in icmp6_reflect"); | | 2031 | panic("assumption failed in icmp6_reflect"); |
2015 | #endif | | 2032 | #endif |
2016 | if (off > sizeof(struct ip6_hdr)) { | | 2033 | if (off > sizeof(struct ip6_hdr)) { |
2017 | size_t l; | | 2034 | size_t l; |
2018 | struct ip6_hdr nip6; | | 2035 | struct ip6_hdr nip6; |
2019 | | | 2036 | |
2020 | l = off - sizeof(struct ip6_hdr); | | 2037 | l = off - sizeof(struct ip6_hdr); |
2021 | m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6); | | 2038 | m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6); |
2022 | m_adj(m, l); | | 2039 | m_adj(m, l); |
2023 | l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); | | 2040 | l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); |
2024 | if (m->m_len < l) { | | 2041 | if (m->m_len < l) { |
2025 | if ((m = m_pullup(m, l)) == NULL) | | 2042 | if ((m = m_pullup(m, l)) == NULL) |
2026 | return; | | 2043 | return; |
2027 | } | | 2044 | } |
2028 | bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6)); | | 2045 | bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6)); |
2029 | } else /* off == sizeof(struct ip6_hdr) */ { | | 2046 | } else /* off == sizeof(struct ip6_hdr) */ { |
2030 | size_t l; | | 2047 | size_t l; |
2031 | l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); | | 2048 | l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr); |
2032 | if (m->m_len < l) { | | 2049 | if (m->m_len < l) { |
2033 | if ((m = m_pullup(m, l)) == NULL) | | 2050 | if ((m = m_pullup(m, l)) == NULL) |
2034 | return; | | 2051 | return; |
2035 | } | | 2052 | } |
2036 | } | | 2053 | } |
2037 | plen = m->m_pkthdr.len - sizeof(struct ip6_hdr); | | 2054 | plen = m->m_pkthdr.len - sizeof(struct ip6_hdr); |
2038 | ip6 = mtod(m, struct ip6_hdr *); | | 2055 | ip6 = mtod(m, struct ip6_hdr *); |
2039 | ip6->ip6_nxt = IPPROTO_ICMPV6; | | 2056 | ip6->ip6_nxt = IPPROTO_ICMPV6; |
2040 | icmp6 = (struct icmp6_hdr *)(ip6 + 1); | | 2057 | icmp6 = (struct icmp6_hdr *)(ip6 + 1); |
2041 | type = icmp6->icmp6_type; /* keep type for statistics */ | | 2058 | type = icmp6->icmp6_type; /* keep type for statistics */ |
2042 | code = icmp6->icmp6_code; /* ditto. */ | | 2059 | code = icmp6->icmp6_code; /* ditto. */ |
2043 | | | 2060 | |
2044 | t = ip6->ip6_dst; | | 2061 | t = ip6->ip6_dst; |
2045 | /* | | 2062 | /* |
2046 | * ip6_input() drops a packet if its src is multicast. | | 2063 | * ip6_input() drops a packet if its src is multicast. |
2047 | * So, the src is never multicast. | | 2064 | * So, the src is never multicast. |
2048 | */ | | 2065 | */ |
2049 | ip6->ip6_dst = ip6->ip6_src; | | 2066 | ip6->ip6_dst = ip6->ip6_src; |
2050 | | | 2067 | |
2051 | /* | | 2068 | /* |
2052 | * XXX: make sure to embed scope zone information, using | | 2069 | * XXX: make sure to embed scope zone information, using |
2053 | * already embedded IDs or the received interface (if any). | | 2070 | * already embedded IDs or the received interface (if any). |
2054 | * Note that rcvif may be NULL. | | 2071 | * Note that rcvif may be NULL. |
2055 | * TODO: scoped routing case (XXX). | | 2072 | * TODO: scoped routing case (XXX). |
2056 | */ | | 2073 | */ |
2057 | bzero(&sa6_src, sizeof(sa6_src)); | | 2074 | bzero(&sa6_src, sizeof(sa6_src)); |
2058 | sa6_src.sin6_family = AF_INET6; | | 2075 | sa6_src.sin6_family = AF_INET6; |
2059 | sa6_src.sin6_len = sizeof(sa6_src); | | 2076 | sa6_src.sin6_len = sizeof(sa6_src); |
2060 | sa6_src.sin6_addr = ip6->ip6_dst; | | 2077 | sa6_src.sin6_addr = ip6->ip6_dst; |
2061 | in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif); | | 2078 | in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif); |
2062 | in6_embedscope(&sa6_src.sin6_addr, &sa6_src, NULL, NULL); | | 2079 | in6_embedscope(&sa6_src.sin6_addr, &sa6_src, NULL, NULL); |
2063 | ip6->ip6_dst = sa6_src.sin6_addr; | | 2080 | ip6->ip6_dst = sa6_src.sin6_addr; |
2064 | | | 2081 | |
2065 | bzero(&sa6_dst, sizeof(sa6_dst)); | | 2082 | bzero(&sa6_dst, sizeof(sa6_dst)); |
2066 | sa6_dst.sin6_family = AF_INET6; | | 2083 | sa6_dst.sin6_family = AF_INET6; |
2067 | sa6_dst.sin6_len = sizeof(sa6_dst); | | 2084 | sa6_dst.sin6_len = sizeof(sa6_dst); |
2068 | sa6_dst.sin6_addr = t; | | 2085 | sa6_dst.sin6_addr = t; |
2069 | in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif); | | 2086 | in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif); |
2070 | in6_embedscope(&t, &sa6_dst, NULL, NULL); | | 2087 | in6_embedscope(&t, &sa6_dst, NULL, NULL); |
2071 | | | 2088 | |
2072 | /* | | 2089 | /* |
2073 | * If the incoming packet was addressed directly to us (i.e. unicast), | | 2090 | * If the incoming packet was addressed directly to us (i.e. unicast), |
2074 | * use dst as the src for the reply. | | 2091 | * use dst as the src for the reply. |
2075 | * The IN6_IFF_NOTREADY case would be VERY rare, but is possible | | 2092 | * The IN6_IFF_NOTREADY case would be VERY rare, but is possible |
2076 | * (for example) when we encounter an error while forwarding procedure | | 2093 | * (for example) when we encounter an error while forwarding procedure |
2077 | * destined to a duplicated address of ours. | | 2094 | * destined to a duplicated address of ours. |
2078 | */ | | 2095 | */ |
2079 | for (ia = in6_ifaddr; ia; ia = ia->ia_next) | | 2096 | for (ia = in6_ifaddr; ia; ia = ia->ia_next) |
2080 | if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) && | | 2097 | if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) && |
2081 | (ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) { | | 2098 | (ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) { |
2082 | src = &t; | | 2099 | src = &t; |
2083 | break; | | 2100 | break; |
2084 | } | | 2101 | } |
2085 | if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) { | | 2102 | if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) { |
2086 | /* | | 2103 | /* |
2087 | * This is the case if the dst is our link-local address | | 2104 | * This is the case if the dst is our link-local address |
2088 | * and the sender is also ourselves. | | 2105 | * and the sender is also ourselves. |
2089 | */ | | 2106 | */ |
2090 | src = &t; | | 2107 | src = &t; |
2091 | } | | 2108 | } |
2092 | | | 2109 | |
2093 | if (src == 0) { | | 2110 | if (src == 0) { |
2094 | int e; | | 2111 | int e; |
2095 | struct route_in6 ro; | | 2112 | struct route_in6 ro; |
2096 | | | 2113 | |
2097 | /* | | 2114 | /* |
2098 | * This case matches to multicasts, our anycast, or unicasts | | 2115 | * This case matches to multicasts, our anycast, or unicasts |
2099 | * that we do not own. Select a source address based on the | | 2116 | * that we do not own. Select a source address based on the |
2100 | * source address of the erroneous packet. | | 2117 | * source address of the erroneous packet. |
2101 | */ | | 2118 | */ |
2102 | bzero(&ro, sizeof(ro)); | | 2119 | bzero(&ro, sizeof(ro)); |
2103 | src = in6_selectsrc(&sa6_src, NULL, NULL, &ro, NULL, &e); | | 2120 | src = in6_selectsrc(&sa6_src, NULL, NULL, &ro, NULL, &e); |
2104 | if (ro.ro_rt) { /* XXX: see comments in icmp6_mtudisc_update */ | | 2121 | if (ro.ro_rt) { /* XXX: see comments in icmp6_mtudisc_update */ |
2105 | RTFREE(ro.ro_rt); /* XXX: we could use this */ | | 2122 | RTFREE(ro.ro_rt); /* XXX: we could use this */ |
2106 | } | | 2123 | } |
2107 | if (src == NULL) { | | 2124 | if (src == NULL) { |
2108 | nd6log((LOG_DEBUG, | | 2125 | nd6log((LOG_DEBUG, |
2109 | "icmp6_reflect: source can't be determined: " | | 2126 | "icmp6_reflect: source can't be determined: " |