1 |
27 |
unneback |
//==========================================================================
|
2 |
|
|
//
|
3 |
|
|
// src/sys/netinet6/in6_src.c
|
4 |
|
|
//
|
5 |
|
|
//==========================================================================
|
6 |
|
|
//####BSDCOPYRIGHTBEGIN####
|
7 |
|
|
//
|
8 |
|
|
// -------------------------------------------
|
9 |
|
|
//
|
10 |
|
|
// Portions of this software may have been derived from OpenBSD,
|
11 |
|
|
// FreeBSD or other sources, and are covered by the appropriate
|
12 |
|
|
// copyright disclaimers included herein.
|
13 |
|
|
//
|
14 |
|
|
// Portions created by Red Hat are
|
15 |
|
|
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
|
16 |
|
|
//
|
17 |
|
|
// -------------------------------------------
|
18 |
|
|
//
|
19 |
|
|
//####BSDCOPYRIGHTEND####
|
20 |
|
|
//==========================================================================
|
21 |
|
|
|
22 |
|
|
/* $KAME: in6_src.c,v 1.96 2001/12/24 10:39:29 jinmei Exp $ */
|
23 |
|
|
|
24 |
|
|
/*
|
25 |
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
26 |
|
|
* All rights reserved.
|
27 |
|
|
*
|
28 |
|
|
* Redistribution and use in source and binary forms, with or without
|
29 |
|
|
* modification, are permitted provided that the following conditions
|
30 |
|
|
* are met:
|
31 |
|
|
* 1. Redistributions of source code must retain the above copyright
|
32 |
|
|
* notice, this list of conditions and the following disclaimer.
|
33 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
34 |
|
|
* notice, this list of conditions and the following disclaimer in the
|
35 |
|
|
* documentation and/or other materials provided with the distribution.
|
36 |
|
|
* 3. Neither the name of the project nor the names of its contributors
|
37 |
|
|
* may be used to endorse or promote products derived from this software
|
38 |
|
|
* without specific prior written permission.
|
39 |
|
|
*
|
40 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
41 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
42 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
43 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
44 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
45 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
46 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
47 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
48 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
49 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
50 |
|
|
* SUCH DAMAGE.
|
51 |
|
|
*/
|
52 |
|
|
|
53 |
|
|
/*
|
54 |
|
|
* Copyright (c) 1982, 1986, 1991, 1993
|
55 |
|
|
* The Regents of the University of California. All rights reserved.
|
56 |
|
|
*
|
57 |
|
|
* Redistribution and use in source and binary forms, with or without
|
58 |
|
|
* modification, are permitted provided that the following conditions
|
59 |
|
|
* are met:
|
60 |
|
|
* 1. Redistributions of source code must retain the above copyright
|
61 |
|
|
* notice, this list of conditions and the following disclaimer.
|
62 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
63 |
|
|
* notice, this list of conditions and the following disclaimer in the
|
64 |
|
|
* documentation and/or other materials provided with the distribution.
|
65 |
|
|
* 3. All advertising materials mentioning features or use of this software
|
66 |
|
|
* must display the following acknowledgement:
|
67 |
|
|
* This product includes software developed by the University of
|
68 |
|
|
* California, Berkeley and its contributors.
|
69 |
|
|
* 4. Neither the name of the University nor the names of its contributors
|
70 |
|
|
* may be used to endorse or promote products derived from this software
|
71 |
|
|
* without specific prior written permission.
|
72 |
|
|
*
|
73 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
74 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
75 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
76 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
77 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
78 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
79 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
80 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
81 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
82 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
83 |
|
|
* SUCH DAMAGE.
|
84 |
|
|
*
|
85 |
|
|
* @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
|
86 |
|
|
*/
|
87 |
|
|
|
88 |
|
|
#include <sys/param.h>
|
89 |
|
|
#include <sys/malloc.h>
|
90 |
|
|
#include <sys/mbuf.h>
|
91 |
|
|
#include <sys/protosw.h>
|
92 |
|
|
#include <sys/socket.h>
|
93 |
|
|
#include <sys/socketvar.h>
|
94 |
|
|
#include <sys/sockio.h>
|
95 |
|
|
#include <sys/errno.h>
|
96 |
|
|
|
97 |
|
|
#include <net/if.h>
|
98 |
|
|
#include <net/route.h>
|
99 |
|
|
|
100 |
|
|
#include <netinet/in.h>
|
101 |
|
|
#include <netinet/in_var.h>
|
102 |
|
|
#include <netinet/in_systm.h>
|
103 |
|
|
#include <netinet/ip.h>
|
104 |
|
|
#include <netinet/in_pcb.h>
|
105 |
|
|
#include <netinet6/in6_var.h>
|
106 |
|
|
#include <netinet/ip6.h>
|
107 |
|
|
#include <netinet6/ip6_var.h>
|
108 |
|
|
#include <netinet6/in6_pcb.h>
|
109 |
|
|
#include <netinet6/nd6.h>
|
110 |
|
|
#include <netinet6/scope6_var.h>
|
111 |
|
|
|
112 |
|
|
#ifdef MIP6
|
113 |
|
|
#include <netinet6/mip6.h>
|
114 |
|
|
#endif /* MIP6 */
|
115 |
|
|
|
116 |
|
|
#if defined(__NetBSD__)
|
117 |
|
|
extern struct ifnet loif[NLOOP];
|
118 |
|
|
#endif
|
119 |
|
|
|
120 |
|
|
#define ADDR_LABEL_NOTAPP (-1)
|
121 |
|
|
struct in6_addrpolicy defaultaddrpolicy;
|
122 |
|
|
|
123 |
|
|
int ip6_prefer_tempaddr = 0;
|
124 |
|
|
|
125 |
|
|
#ifdef NEW_STRUCT_ROUTE
|
126 |
|
|
static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
|
127 |
|
|
struct ip6_moptions *,
|
128 |
|
|
struct route *ro,
|
129 |
|
|
struct ifnet **));
|
130 |
|
|
#else
|
131 |
|
|
static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
|
132 |
|
|
struct ip6_moptions *,
|
133 |
|
|
struct route_in6 *ro,
|
134 |
|
|
struct ifnet **));
|
135 |
|
|
#endif
|
136 |
|
|
|
137 |
|
|
static struct in6_addrpolicy *lookup_addrsel_policy __P((struct sockaddr_in6 *));
|
138 |
|
|
|
139 |
|
|
static void init_policy_queue __P((void));
|
140 |
|
|
static int add_addrsel_policyent __P((struct in6_addrpolicy *));
|
141 |
|
|
static int delete_addrsel_policyent __P((struct in6_addrpolicy *));
|
142 |
|
|
static struct in6_addrpolicy *match_addrsel_policy __P((struct sockaddr_in6 *));
|
143 |
|
|
|
144 |
|
|
/*
|
145 |
|
|
* Return an IPv6 address, which is the most appropriate for a given
|
146 |
|
|
* destination and user specified options.
|
147 |
|
|
* If necessary, this function lookups the routing table and returns
|
148 |
|
|
* an entry to the caller for later use.
|
149 |
|
|
*/
|
150 |
|
|
#define REPLACE(r) do {\
|
151 |
|
|
if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \
|
152 |
|
|
sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \
|
153 |
|
|
ip6stat.ip6s_sources_rule[(r)]++; \
|
154 |
|
|
/* printf("in6_selectsrc: replace %s with %s by %d\n", ia_best ? ip6_sprintf(&ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(&ia->ia_addr.sin6_addr), (r)); */ \
|
155 |
|
|
goto replace; \
|
156 |
|
|
} while(0)
|
157 |
|
|
#define NEXT(r) do {\
|
158 |
|
|
if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \
|
159 |
|
|
sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \
|
160 |
|
|
ip6stat.ip6s_sources_rule[(r)]++; \
|
161 |
|
|
/* printf("in6_selectsrc: keep %s against %s by %d\n", ia_best ? ip6_sprintf(&ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(&ia->ia_addr.sin6_addr), (r)); */ \
|
162 |
|
|
goto next; /* XXX: we can't use 'continue' here */ \
|
163 |
|
|
} while(0)
|
164 |
|
|
#define BREAK(r) do { \
|
165 |
|
|
if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \
|
166 |
|
|
sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \
|
167 |
|
|
ip6stat.ip6s_sources_rule[(r)]++; \
|
168 |
|
|
goto out; /* XXX: we can't use 'break' here */ \
|
169 |
|
|
} while(0)
|
170 |
|
|
|
171 |
|
|
struct in6_addr *
|
172 |
|
|
in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
173 |
|
|
struct ip6_moptions *mopts, struct route *ro,
|
174 |
|
|
struct ifnet **ifpp, struct in6_addr *laddr,
|
175 |
|
|
int *errorp)
|
176 |
|
|
{
|
177 |
|
|
struct in6_addr *dst;
|
178 |
|
|
struct ifnet *ifp = NULL;
|
179 |
|
|
struct in6_ifaddr *ia = NULL, *ia_best = NULL;
|
180 |
|
|
struct in6_pktinfo *pi = NULL;
|
181 |
|
|
int dst_scope = -1, best_scope = -1, best_matchlen = -1;
|
182 |
|
|
struct in6_addrpolicy *dst_policy = NULL, *best_policy = NULL;
|
183 |
|
|
#ifdef MIP6
|
184 |
|
|
struct hif_softc *sc;
|
185 |
|
|
#ifdef MIP6_ALLOW_COA_FALLBACK
|
186 |
|
|
struct mip6_bu *mbu_dst;
|
187 |
|
|
u_int8_t coafallback = 0;
|
188 |
|
|
#endif
|
189 |
|
|
#endif
|
190 |
|
|
|
191 |
|
|
dst = &dstsock->sin6_addr;
|
192 |
|
|
*errorp = 0;
|
193 |
|
|
if (ifpp)
|
194 |
|
|
*ifpp = NULL;
|
195 |
|
|
|
196 |
|
|
/*
|
197 |
|
|
* If the source address is explicitly specified by the caller,
|
198 |
|
|
* check if the requested source address is indeed a unicast address
|
199 |
|
|
* assigned to the node, and can be used as the packet's source
|
200 |
|
|
* address. If everything is okay, use the address as source.
|
201 |
|
|
*/
|
202 |
|
|
if (opts && (pi = opts->ip6po_pktinfo) &&
|
203 |
|
|
!IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
|
204 |
|
|
struct sockaddr_in6 srcsock;
|
205 |
|
|
struct in6_ifaddr *ia6;
|
206 |
|
|
|
207 |
|
|
/* get the outgoing interface */
|
208 |
|
|
if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp))
|
209 |
|
|
!= 0) {
|
210 |
|
|
return(NULL);
|
211 |
|
|
}
|
212 |
|
|
|
213 |
|
|
/*
|
214 |
|
|
* determine the appropriate zone id of the source based on
|
215 |
|
|
* the zone of the destination and the outgoing interface.
|
216 |
|
|
*/
|
217 |
|
|
bzero(&srcsock, sizeof(srcsock));
|
218 |
|
|
srcsock.sin6_family = AF_INET6;
|
219 |
|
|
srcsock.sin6_len = sizeof(srcsock);
|
220 |
|
|
srcsock.sin6_addr = pi->ipi6_addr;
|
221 |
|
|
if (ifp) {
|
222 |
|
|
int64_t zone;
|
223 |
|
|
|
224 |
|
|
zone = in6_addr2zoneid(ifp, &pi->ipi6_addr);
|
225 |
|
|
if (zone < 0) { /* XXX: this should not happen */
|
226 |
|
|
*errorp = EINVAL;
|
227 |
|
|
return(NULL);
|
228 |
|
|
}
|
229 |
|
|
srcsock.sin6_scope_id = zone;
|
230 |
|
|
}
|
231 |
|
|
if ((*errorp = in6_embedscope(&srcsock.sin6_addr, &srcsock))
|
232 |
|
|
!= 0) {
|
233 |
|
|
return(NULL);
|
234 |
|
|
}
|
235 |
|
|
#ifndef SCOPEDROUTING
|
236 |
|
|
srcsock.sin6_scope_id = 0; /* XXX: ifa_ifwithaddr expects 0 */
|
237 |
|
|
#endif
|
238 |
|
|
ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(&srcsock));
|
239 |
|
|
if (ia6 == NULL ||
|
240 |
|
|
(ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
|
241 |
|
|
*errorp = EADDRNOTAVAIL;
|
242 |
|
|
return(NULL);
|
243 |
|
|
}
|
244 |
|
|
pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
|
245 |
|
|
if (*ifpp)
|
246 |
|
|
*ifpp = ifp;
|
247 |
|
|
return(&pi->ipi6_addr);
|
248 |
|
|
}
|
249 |
|
|
|
250 |
|
|
/*
|
251 |
|
|
* Otherwise, if the socket has already bound the source, just use it.
|
252 |
|
|
*/
|
253 |
|
|
if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
|
254 |
|
|
return(laddr);
|
255 |
|
|
|
256 |
|
|
/*
|
257 |
|
|
* If the address is not specified, choose the best one based on
|
258 |
|
|
* the outgoing interface and the destination address.
|
259 |
|
|
*/
|
260 |
|
|
/* get the outgoing interface */
|
261 |
|
|
if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
|
262 |
|
|
return(NULL);
|
263 |
|
|
|
264 |
|
|
#ifdef MIP6
|
265 |
|
|
#ifdef MIP6_ALLOW_COA_FALLBACK
|
266 |
|
|
for (sc = TAILQ_FIRST(&hif_softc_list);
|
267 |
|
|
sc;
|
268 |
|
|
sc = TAILQ_NEXT(sc, hif_entry)) {
|
269 |
|
|
mbu_dst = mip6_bu_list_find_withpaddr(&sc->hif_bu_list, dst);
|
270 |
|
|
if (mbu_dst != NULL)
|
271 |
|
|
coafallback = mbu_dst->mbu_coafallback;
|
272 |
|
|
}
|
273 |
|
|
#endif /* MIP6_ALLOW_COA_FALLBACK */
|
274 |
|
|
#endif /* MIP6 */
|
275 |
|
|
|
276 |
|
|
#ifdef DIAGNOSTIC
|
277 |
|
|
if (ifp == NULL) /* this should not happen */
|
278 |
|
|
panic("in6_selectsrc: NULL ifp");
|
279 |
|
|
#endif
|
280 |
|
|
for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
|
281 |
|
|
int new_scope = -1, new_matchlen = -1;
|
282 |
|
|
struct in6_addrpolicy *new_policy = NULL;
|
283 |
|
|
int64_t srczone, dstzone;
|
284 |
|
|
struct ifnet *ifp1 = ia->ia_ifp;
|
285 |
|
|
|
286 |
|
|
/*
|
287 |
|
|
* We'll never take an address that breaks the scope zone
|
288 |
|
|
* of the destination. We also skip an address if its zone
|
289 |
|
|
* does not contain the outgoing interface.
|
290 |
|
|
* XXX: we should probably use sin6_scope_id here.
|
291 |
|
|
*/
|
292 |
|
|
if ((dstzone = in6_addr2zoneid(ifp1, dst)) < 0 ||
|
293 |
|
|
dstzone != in6_addr2zoneid(ifp, dst)) {
|
294 |
|
|
continue;
|
295 |
|
|
}
|
296 |
|
|
if ((srczone = in6_addr2zoneid(ifp1, &ia->ia_addr.sin6_addr))
|
297 |
|
|
< 0 ||
|
298 |
|
|
srczone != in6_addr2zoneid(ifp, &ia->ia_addr.sin6_addr)) {
|
299 |
|
|
continue;
|
300 |
|
|
}
|
301 |
|
|
|
302 |
|
|
/* avoid unusable addresses */
|
303 |
|
|
if ((ia->ia6_flags &
|
304 |
|
|
(IN6_IFF_NOTREADY | IN6_IFF_ANYCAST | IN6_IFF_DETACHED))) {
|
305 |
|
|
continue;
|
306 |
|
|
}
|
307 |
|
|
if (!ip6_use_deprecated && IFA6_IS_DEPRECATED(ia))
|
308 |
|
|
continue;
|
309 |
|
|
|
310 |
|
|
/* Rule 1: Prefer same address */
|
311 |
|
|
if (IN6_ARE_ADDR_EQUAL(dst, &ia->ia_addr.sin6_addr)) {
|
312 |
|
|
ia_best = ia;
|
313 |
|
|
BREAK(1); /* there should be no better candidate */
|
314 |
|
|
}
|
315 |
|
|
|
316 |
|
|
if (ia_best == NULL)
|
317 |
|
|
REPLACE(0);
|
318 |
|
|
|
319 |
|
|
/* Rule 2: Prefer appropriate scope */
|
320 |
|
|
if (dst_scope < 0)
|
321 |
|
|
dst_scope = in6_addrscope(dst);
|
322 |
|
|
new_scope = in6_addrscope(&ia->ia_addr.sin6_addr);
|
323 |
|
|
if (IN6_ARE_SCOPE_CMP(best_scope, new_scope) < 0) {
|
324 |
|
|
if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0)
|
325 |
|
|
REPLACE(2);
|
326 |
|
|
NEXT(2);
|
327 |
|
|
} else if (IN6_ARE_SCOPE_CMP(new_scope, best_scope) < 0) {
|
328 |
|
|
if (IN6_ARE_SCOPE_CMP(new_scope, dst_scope) < 0)
|
329 |
|
|
NEXT(2);
|
330 |
|
|
REPLACE(2);
|
331 |
|
|
}
|
332 |
|
|
|
333 |
|
|
/*
|
334 |
|
|
* Rule 3: Avoid deprecated addresses. Note that the case of
|
335 |
|
|
* !ip6_use_deprecated is already rejected above.
|
336 |
|
|
*/
|
337 |
|
|
if (!IFA6_IS_DEPRECATED(ia_best) && IFA6_IS_DEPRECATED(ia))
|
338 |
|
|
NEXT(3);
|
339 |
|
|
if (IFA6_IS_DEPRECATED(ia_best) && !IFA6_IS_DEPRECATED(ia))
|
340 |
|
|
REPLACE(3);
|
341 |
|
|
|
342 |
|
|
/* Rule 4: Prefer home addresses */
|
343 |
|
|
/*
|
344 |
|
|
* XXX: This is a TODO. We should probably merge the MIP6
|
345 |
|
|
* case above.
|
346 |
|
|
*/
|
347 |
|
|
#ifdef MIP6
|
348 |
|
|
/*
|
349 |
|
|
* If SA is simultaneously a home address and care-of address
|
350 |
|
|
* and SB is not, then prefer SA. Similarly, if SB is
|
351 |
|
|
* simultaneously a home address and care-of address and SA is
|
352 |
|
|
* not, then prefer SB.
|
353 |
|
|
*/
|
354 |
|
|
{
|
355 |
|
|
struct mip6_bu *mbu_ia_best = NULL, *mbu_ia = NULL;
|
356 |
|
|
|
357 |
|
|
if (ia_best->ia6_flags & IN6_IFF_HOME) {
|
358 |
|
|
/*
|
359 |
|
|
* find a binding update entry for ia_best.
|
360 |
|
|
*/
|
361 |
|
|
for (sc = TAILQ_FIRST(&hif_softc_list);
|
362 |
|
|
sc;
|
363 |
|
|
sc = TAILQ_NEXT(sc, hif_entry)) {
|
364 |
|
|
mbu_ia_best = mip6_bu_list_find_home_registration(
|
365 |
|
|
&sc->hif_bu_list,
|
366 |
|
|
&ia->ia_addr.sin6_addr);
|
367 |
|
|
if (mbu_ia_best)
|
368 |
|
|
break;
|
369 |
|
|
}
|
370 |
|
|
}
|
371 |
|
|
if (ia->ia6_flags & IN6_IFF_HOME) {
|
372 |
|
|
/*
|
373 |
|
|
* find a binding update entry for ia.
|
374 |
|
|
*/
|
375 |
|
|
for (sc = TAILQ_FIRST(&hif_softc_list);
|
376 |
|
|
sc;
|
377 |
|
|
sc = TAILQ_NEXT(sc, hif_entry)) {
|
378 |
|
|
mbu_ia = mip6_bu_list_find_home_registration(
|
379 |
|
|
&sc->hif_bu_list,
|
380 |
|
|
&ia->ia_addr.sin6_addr);
|
381 |
|
|
if (mbu_ia)
|
382 |
|
|
break;
|
383 |
|
|
}
|
384 |
|
|
}
|
385 |
|
|
/*
|
386 |
|
|
* if the binding update entry for a certain address
|
387 |
|
|
* exists and its registration status is
|
388 |
|
|
* MIP6_BU_REG_STATE_NOTREG, the address is a home
|
389 |
|
|
* address and a care of addres simultaneously.
|
390 |
|
|
*/
|
391 |
|
|
if ((mbu_ia_best &&
|
392 |
|
|
(mbu_ia_best->mbu_reg_state
|
393 |
|
|
== MIP6_BU_REG_STATE_NOTREG))
|
394 |
|
|
&&
|
395 |
|
|
!(mbu_ia &&
|
396 |
|
|
(mbu_ia->mbu_reg_state
|
397 |
|
|
== MIP6_BU_REG_STATE_NOTREG))) {
|
398 |
|
|
NEXT(4);
|
399 |
|
|
}
|
400 |
|
|
if (!(mbu_ia_best &&
|
401 |
|
|
(mbu_ia_best->mbu_reg_state
|
402 |
|
|
== MIP6_BU_REG_STATE_NOTREG))
|
403 |
|
|
&&
|
404 |
|
|
(mbu_ia &&
|
405 |
|
|
(mbu_ia->mbu_reg_state
|
406 |
|
|
== MIP6_BU_REG_STATE_NOTREG))) {
|
407 |
|
|
REPLACE(4);
|
408 |
|
|
}
|
409 |
|
|
}
|
410 |
|
|
#ifdef MIP6_ALLOW_COA_FALLBACK
|
411 |
|
|
if (coafallback) {
|
412 |
|
|
/*
|
413 |
|
|
* if the peer doesn't recognize a home
|
414 |
|
|
* address destination option, we will use a
|
415 |
|
|
* CoA as a source address instead of a home
|
416 |
|
|
* address we have registered before. Though
|
417 |
|
|
* this behavior may arouse a mip6 beleiver's
|
418 |
|
|
* anger, is very useful in the current
|
419 |
|
|
* transition period that many hosts don't
|
420 |
|
|
* recognize a home address destination
|
421 |
|
|
* option...
|
422 |
|
|
*/
|
423 |
|
|
if ((ia_best->ia6_flags & IN6_IFF_HOME) == 0 &&
|
424 |
|
|
(ia->ia6_flags & IN6_IFF_HOME) != 0) {
|
425 |
|
|
/* XXX will break stat! */
|
426 |
|
|
NEXT(0);
|
427 |
|
|
}
|
428 |
|
|
if ((ia_best->ia6_flags & IN6_IFF_HOME) != 0 &&
|
429 |
|
|
(ia->ia6_flags & IN6_IFF_HOME) == 0) {
|
430 |
|
|
/* XXX will break stat! */
|
431 |
|
|
REPLACE(0);
|
432 |
|
|
}
|
433 |
|
|
} else
|
434 |
|
|
#endif
|
435 |
|
|
{
|
436 |
|
|
/*
|
437 |
|
|
* If SA is just a home address and SB is just
|
438 |
|
|
* a care-of address, then prefer
|
439 |
|
|
* SA. Similarly, if SB is just a home address
|
440 |
|
|
* and SA is just a care-of address, then
|
441 |
|
|
* prefer SB.
|
442 |
|
|
*/
|
443 |
|
|
if ((ia_best->ia6_flags & IN6_IFF_HOME) != 0 &&
|
444 |
|
|
(ia->ia6_flags & IN6_IFF_HOME) == 0) {
|
445 |
|
|
NEXT(4);
|
446 |
|
|
}
|
447 |
|
|
if ((ia_best->ia6_flags & IN6_IFF_HOME) == 0 &&
|
448 |
|
|
(ia->ia6_flags & IN6_IFF_HOME) != 0) {
|
449 |
|
|
REPLACE(4);
|
450 |
|
|
}
|
451 |
|
|
}
|
452 |
|
|
#endif /* MIP6 */
|
453 |
|
|
|
454 |
|
|
/* Rule 5: Prefer outgoing interface */
|
455 |
|
|
if (ia_best->ia_ifp == ifp && ia->ia_ifp != ifp)
|
456 |
|
|
NEXT(5);
|
457 |
|
|
if (ia_best->ia_ifp != ifp && ia->ia_ifp == ifp)
|
458 |
|
|
REPLACE(5);
|
459 |
|
|
|
460 |
|
|
/*
|
461 |
|
|
* Rule 6: Prefer matching label
|
462 |
|
|
* Note that best_policy should be non-NULL here.
|
463 |
|
|
*/
|
464 |
|
|
if (dst_policy == NULL)
|
465 |
|
|
dst_policy = lookup_addrsel_policy(dstsock);
|
466 |
|
|
if (dst_policy->label != ADDR_LABEL_NOTAPP) {
|
467 |
|
|
new_policy = lookup_addrsel_policy(&ia->ia_addr);
|
468 |
|
|
if (dst_policy->label == best_policy->label &&
|
469 |
|
|
dst_policy->label != new_policy->label)
|
470 |
|
|
NEXT(6);
|
471 |
|
|
if (dst_policy->label != best_policy->label &&
|
472 |
|
|
dst_policy->label == new_policy->label)
|
473 |
|
|
REPLACE(6);
|
474 |
|
|
}
|
475 |
|
|
|
476 |
|
|
/*
|
477 |
|
|
* Rule 7: Prefer public addresses.
|
478 |
|
|
* We allow users to reverse the logic by configuring
|
479 |
|
|
* a sysctl variable, so that privacy conscious users can
|
480 |
|
|
* always prefer temporary addresses.
|
481 |
|
|
*/
|
482 |
|
|
if (!(ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&
|
483 |
|
|
(ia->ia6_flags & IN6_IFF_TEMPORARY)) {
|
484 |
|
|
if (ip6_prefer_tempaddr)
|
485 |
|
|
REPLACE(7);
|
486 |
|
|
else
|
487 |
|
|
NEXT(7);
|
488 |
|
|
}
|
489 |
|
|
if ((ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&
|
490 |
|
|
!(ia->ia6_flags & IN6_IFF_TEMPORARY)) {
|
491 |
|
|
if (ip6_prefer_tempaddr)
|
492 |
|
|
NEXT(7);
|
493 |
|
|
else
|
494 |
|
|
REPLACE(7);
|
495 |
|
|
}
|
496 |
|
|
|
497 |
|
|
/*
|
498 |
|
|
* Rule 8: prefer addresses on alive interfaces.
|
499 |
|
|
* This is a KAME specific rule.
|
500 |
|
|
*/
|
501 |
|
|
if ((ia_best->ia_ifp->if_flags & IFF_UP) &&
|
502 |
|
|
!(ia->ia_ifp->if_flags & IFF_UP))
|
503 |
|
|
NEXT(8);
|
504 |
|
|
if (!(ia_best->ia_ifp->if_flags & IFF_UP) &&
|
505 |
|
|
(ia->ia_ifp->if_flags & IFF_UP))
|
506 |
|
|
REPLACE(8);
|
507 |
|
|
|
508 |
|
|
/*
|
509 |
|
|
* Rule 9: prefer addresses on "preferred" interfaces.
|
510 |
|
|
* This is a KAME specific rule.
|
511 |
|
|
*/
|
512 |
|
|
#define NDI_BEST (nd_ifinfo[ia_best->ia_ifp->if_index])
|
513 |
|
|
#define NDI_NEW (nd_ifinfo[ia->ia_ifp->if_index])
|
514 |
|
|
if ((NDI_BEST.flags & ND6_IFF_PREFER_SOURCE) &&
|
515 |
|
|
!(NDI_NEW.flags & ND6_IFF_PREFER_SOURCE))
|
516 |
|
|
NEXT(9);
|
517 |
|
|
if (!(NDI_BEST.flags & ND6_IFF_PREFER_SOURCE) &&
|
518 |
|
|
(NDI_NEW.flags & ND6_IFF_PREFER_SOURCE))
|
519 |
|
|
REPLACE(9);
|
520 |
|
|
#undef NDI_BEST
|
521 |
|
|
#undef NDI_NEW
|
522 |
|
|
|
523 |
|
|
/*
|
524 |
|
|
* Rule 14: Use longest matching prefix.
|
525 |
|
|
* Note: in the address selection draft, this rule is
|
526 |
|
|
* documented as "Rule 8". However, since it is also
|
527 |
|
|
* documented that this rule can be overridden, we assign
|
528 |
|
|
* a large number so that it is easy to assign smaller numbers
|
529 |
|
|
* to more preferred rules.
|
530 |
|
|
*/
|
531 |
|
|
new_matchlen = in6_matchlen(&ia->ia_addr.sin6_addr, dst);
|
532 |
|
|
if (best_matchlen < new_matchlen)
|
533 |
|
|
REPLACE(14);
|
534 |
|
|
if (new_matchlen < best_matchlen)
|
535 |
|
|
NEXT(14);
|
536 |
|
|
|
537 |
|
|
/* Rule 15 is reserved. */
|
538 |
|
|
|
539 |
|
|
/*
|
540 |
|
|
* Last resort: just keep the current candidate.
|
541 |
|
|
* Or, do we need more rules?
|
542 |
|
|
*/
|
543 |
|
|
continue;
|
544 |
|
|
|
545 |
|
|
replace:
|
546 |
|
|
ia_best = ia;
|
547 |
|
|
best_scope = (new_scope >= 0 ? new_scope :
|
548 |
|
|
in6_addrscope(&ia_best->ia_addr.sin6_addr));
|
549 |
|
|
best_policy = (new_policy ? new_policy :
|
550 |
|
|
lookup_addrsel_policy(&ia_best->ia_addr));
|
551 |
|
|
best_matchlen = (new_matchlen >= 0 ? new_matchlen :
|
552 |
|
|
in6_matchlen(&ia_best->ia_addr.sin6_addr,
|
553 |
|
|
dst));
|
554 |
|
|
|
555 |
|
|
next:
|
556 |
|
|
continue;
|
557 |
|
|
|
558 |
|
|
out:
|
559 |
|
|
break;
|
560 |
|
|
}
|
561 |
|
|
|
562 |
|
|
if ((ia = ia_best) == NULL) {
|
563 |
|
|
*errorp = EADDRNOTAVAIL;
|
564 |
|
|
return(NULL);
|
565 |
|
|
}
|
566 |
|
|
|
567 |
|
|
if (ifpp)
|
568 |
|
|
*ifpp = ifp;
|
569 |
|
|
return(&ia->ia_addr.sin6_addr);
|
570 |
|
|
}
|
571 |
|
|
#undef REPLACE
|
572 |
|
|
#undef BREAK
|
573 |
|
|
#undef NEXT
|
574 |
|
|
|
575 |
|
|
static int
|
576 |
|
|
in6_selectif(dstsock, opts, mopts, ro, retifp)
|
577 |
|
|
struct sockaddr_in6 *dstsock;
|
578 |
|
|
struct ip6_pktopts *opts;
|
579 |
|
|
struct ip6_moptions *mopts;
|
580 |
|
|
#ifdef NEW_STRUCT_ROUTE
|
581 |
|
|
struct route *ro;
|
582 |
|
|
#else
|
583 |
|
|
struct route_in6 *ro;
|
584 |
|
|
#endif
|
585 |
|
|
struct ifnet **retifp;
|
586 |
|
|
{
|
587 |
|
|
int error, clone;
|
588 |
|
|
struct rtentry *rt = NULL;
|
589 |
|
|
|
590 |
|
|
clone = IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) ? 0 : 1;
|
591 |
|
|
if ((error = in6_selectroute(dstsock, opts, mopts, ro, retifp,
|
592 |
|
|
&rt, clone)) != 0) {
|
593 |
|
|
return(error);
|
594 |
|
|
}
|
595 |
|
|
/*
|
596 |
|
|
* Adjust the "outgoing" interface. If we're going to loop the packet
|
597 |
|
|
* back to ourselves, the ifp would be the loopback interface.
|
598 |
|
|
* However, we'd rather know the interface associated to the
|
599 |
|
|
* destination address (which should probably be one of our own
|
600 |
|
|
* addresses.)
|
601 |
|
|
*/
|
602 |
|
|
if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp)
|
603 |
|
|
*retifp = rt->rt_ifa->ifa_ifp;
|
604 |
|
|
|
605 |
|
|
return(0);
|
606 |
|
|
}
|
607 |
|
|
|
608 |
|
|
int
|
609 |
|
|
in6_selectroute(dstsock, opts, mopts, ro, retifp, retrt, clone)
|
610 |
|
|
struct sockaddr_in6 *dstsock;
|
611 |
|
|
struct ip6_pktopts *opts;
|
612 |
|
|
struct ip6_moptions *mopts;
|
613 |
|
|
#ifdef NEW_STRUCT_ROUTE
|
614 |
|
|
struct route *ro;
|
615 |
|
|
#else
|
616 |
|
|
struct route_in6 *ro;
|
617 |
|
|
#endif
|
618 |
|
|
struct ifnet **retifp;
|
619 |
|
|
struct rtentry **retrt;
|
620 |
|
|
int clone; /* meaningful only for bsdi and freebsd. */
|
621 |
|
|
{
|
622 |
|
|
int error = 0;
|
623 |
|
|
struct ifnet *ifp = NULL;
|
624 |
|
|
struct rtentry *rt = NULL;
|
625 |
|
|
struct sockaddr_in6 *sin6_next;
|
626 |
|
|
struct in6_pktinfo *pi = NULL;
|
627 |
|
|
struct in6_addr *dst = &dstsock->sin6_addr;
|
628 |
|
|
|
629 |
|
|
/* If the caller specify the outgoing interface explicitly, use it. */
|
630 |
|
|
if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
|
631 |
|
|
/* XXX boundary check is assumed to be already done. */
|
632 |
|
|
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
|
633 |
|
|
ifp = ifnet_byindex(pi->ipi6_ifindex);
|
634 |
|
|
#else
|
635 |
|
|
ifp = ifindex2ifnet[pi->ipi6_ifindex];
|
636 |
|
|
#endif
|
637 |
|
|
if (ifp != NULL &&
|
638 |
|
|
(retrt == NULL || IN6_IS_ADDR_MULTICAST(dst))) {
|
639 |
|
|
/*
|
640 |
|
|
* we do not have to check nor get the route for
|
641 |
|
|
* multicast.
|
642 |
|
|
*/
|
643 |
|
|
goto done;
|
644 |
|
|
} else
|
645 |
|
|
goto getroute;
|
646 |
|
|
}
|
647 |
|
|
|
648 |
|
|
/*
|
649 |
|
|
* If the destination address is a multicast address and the outgoing
|
650 |
|
|
* interface for the address is specified by the caller, use it.
|
651 |
|
|
*/
|
652 |
|
|
if (IN6_IS_ADDR_MULTICAST(dst) &&
|
653 |
|
|
mopts != NULL && (ifp = mopts->im6o_multicast_ifp) != NULL) {
|
654 |
|
|
goto done; /* we do not need a route for multicast. */
|
655 |
|
|
}
|
656 |
|
|
|
657 |
|
|
getroute:
|
658 |
|
|
/*
|
659 |
|
|
* If the next hop address for the packet is specified by the caller,
|
660 |
|
|
* use it as the gateway.
|
661 |
|
|
*/
|
662 |
|
|
if (opts && opts->ip6po_nexthop) {
|
663 |
|
|
#ifdef NEW_STRUCT_ROUTE
|
664 |
|
|
struct route *ron;
|
665 |
|
|
#else
|
666 |
|
|
struct route_in6 *ron;
|
667 |
|
|
#endif
|
668 |
|
|
|
669 |
|
|
sin6_next = satosin6(opts->ip6po_nexthop);
|
670 |
|
|
|
671 |
|
|
/* at this moment, we only support AF_INET6 next hops */
|
672 |
|
|
if (sin6_next->sin6_family != AF_INET6) {
|
673 |
|
|
error = EAFNOSUPPORT; /* or should we proceed? */
|
674 |
|
|
goto done;
|
675 |
|
|
}
|
676 |
|
|
|
677 |
|
|
/*
|
678 |
|
|
* If the next hop is an IPv6 address, then the node identified
|
679 |
|
|
* by that address must be a neighbor of the sending host.
|
680 |
|
|
*/
|
681 |
|
|
ron = &opts->ip6po_nextroute;
|
682 |
|
|
if ((ron->ro_rt &&
|
683 |
|
|
(ron->ro_rt->rt_flags & (RTF_UP | RTF_LLINFO)) !=
|
684 |
|
|
(RTF_UP | RTF_LLINFO)) ||
|
685 |
|
|
!SA6_ARE_ADDR_EQUAL(satosin6(&ron->ro_dst), sin6_next)) {
|
686 |
|
|
if (ron->ro_rt) {
|
687 |
|
|
RTFREE(ron->ro_rt);
|
688 |
|
|
ron->ro_rt = NULL;
|
689 |
|
|
}
|
690 |
|
|
*satosin6(&ron->ro_dst) = *sin6_next;
|
691 |
|
|
}
|
692 |
|
|
if (ron->ro_rt == NULL) {
|
693 |
|
|
rtalloc((struct route *)ron); /* multi path case? */
|
694 |
|
|
if (ron->ro_rt == NULL ||
|
695 |
|
|
!(ron->ro_rt->rt_flags & RTF_LLINFO)) {
|
696 |
|
|
if (ron->ro_rt) {
|
697 |
|
|
RTFREE(ron->ro_rt);
|
698 |
|
|
ron->ro_rt = NULL;
|
699 |
|
|
}
|
700 |
|
|
error = EHOSTUNREACH;
|
701 |
|
|
goto done;
|
702 |
|
|
}
|
703 |
|
|
}
|
704 |
|
|
rt = ron->ro_rt;
|
705 |
|
|
ifp = rt->rt_ifp;
|
706 |
|
|
|
707 |
|
|
/*
|
708 |
|
|
* When cloning is required, try to allocate a route to the
|
709 |
|
|
* destination so that the caller can store path MTU
|
710 |
|
|
* information.
|
711 |
|
|
*/
|
712 |
|
|
if (!clone)
|
713 |
|
|
goto done;
|
714 |
|
|
}
|
715 |
|
|
|
716 |
|
|
/*
|
717 |
|
|
* Use a cached route if it exists and is valid, else try to allocate
|
718 |
|
|
* a new one.
|
719 |
|
|
*/
|
720 |
|
|
if (ro) {
|
721 |
|
|
int newroute = 0;
|
722 |
|
|
|
723 |
|
|
if (ro->ro_rt &&
|
724 |
|
|
(!(ro->ro_rt->rt_flags & RTF_UP) ||
|
725 |
|
|
!IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,
|
726 |
|
|
dst))) {
|
727 |
|
|
RTFREE(ro->ro_rt);
|
728 |
|
|
ro->ro_rt = (struct rtentry *)NULL;
|
729 |
|
|
}
|
730 |
|
|
if (ro->ro_rt == (struct rtentry *)NULL) {
|
731 |
|
|
struct sockaddr_in6 *sa6;
|
732 |
|
|
|
733 |
|
|
/* No route yet, so try to acquire one */
|
734 |
|
|
newroute = 1;
|
735 |
|
|
bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
|
736 |
|
|
sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
|
737 |
|
|
sa6->sin6_family = AF_INET6;
|
738 |
|
|
sa6->sin6_len = sizeof(struct sockaddr_in6);
|
739 |
|
|
sa6->sin6_addr = *dst;
|
740 |
|
|
#ifdef SCOPEDROUTING
|
741 |
|
|
sa6->sin6_scope_id = dstsock->sin6_scope_id;
|
742 |
|
|
#endif
|
743 |
|
|
if (clone) {
|
744 |
|
|
#ifdef __bsdi__
|
745 |
|
|
rtcalloc((struct route *)ro);
|
746 |
|
|
#else /* !bsdi */
|
747 |
|
|
#ifdef RADIX_MPATH
|
748 |
|
|
rtalloc_mpath((struct route *)ro,
|
749 |
|
|
ntohl(dstsock->sin6_addr.s6_addr32[3]));
|
750 |
|
|
#else
|
751 |
|
|
rtalloc((struct route *)ro);
|
752 |
|
|
#endif /* RADIX_MPATH */
|
753 |
|
|
#endif /* bsdi */
|
754 |
|
|
} else {
|
755 |
|
|
#ifdef __FreeBSD__
|
756 |
|
|
ro->ro_rt = rtalloc1(&((struct route *)ro)
|
757 |
|
|
->ro_dst, (int)NULL, 0UL);
|
758 |
|
|
#else
|
759 |
|
|
#ifdef RADIX_MPATH
|
760 |
|
|
rtalloc_mpath((struct route *)ro,
|
761 |
|
|
ntohl(dstsock->sin6_addr.s6_addr32[3]));
|
762 |
|
|
#else
|
763 |
|
|
ro->ro_rt = rtalloc1(&((struct route *)ro)
|
764 |
|
|
->ro_dst, NULL);
|
765 |
|
|
#endif /* RADIX_MPATH */
|
766 |
|
|
#endif /* __FreeBSD__ */
|
767 |
|
|
}
|
768 |
|
|
}
|
769 |
|
|
|
770 |
|
|
/*
|
771 |
|
|
* do not care about the result if we have the nexthop
|
772 |
|
|
* explicitly specified.
|
773 |
|
|
*/
|
774 |
|
|
if (opts && opts->ip6po_nexthop)
|
775 |
|
|
goto done;
|
776 |
|
|
|
777 |
|
|
if (ro->ro_rt) {
|
778 |
|
|
ifp = ro->ro_rt->rt_ifp;
|
779 |
|
|
|
780 |
|
|
if (ifp == NULL) { /* can this really happen? */
|
781 |
|
|
RTFREE(ro->ro_rt);
|
782 |
|
|
ro->ro_rt = NULL;
|
783 |
|
|
}
|
784 |
|
|
}
|
785 |
|
|
if (ro->ro_rt == NULL)
|
786 |
|
|
error = EHOSTUNREACH;
|
787 |
|
|
rt = ro->ro_rt;
|
788 |
|
|
|
789 |
|
|
/*
|
790 |
|
|
* Check if the outgoing interface conflicts with
|
791 |
|
|
* the interface specified by ipi6_ifindex (if specified).
|
792 |
|
|
* Note that loopback interface is always okay.
|
793 |
|
|
* (this may happen when we are sending a packet to one of
|
794 |
|
|
* our own addresses.)
|
795 |
|
|
*/
|
796 |
|
|
if (opts && opts->ip6po_pktinfo
|
797 |
|
|
&& opts->ip6po_pktinfo->ipi6_ifindex) {
|
798 |
|
|
if (!(ifp->if_flags & IFF_LOOPBACK) &&
|
799 |
|
|
ifp->if_index !=
|
800 |
|
|
opts->ip6po_pktinfo->ipi6_ifindex) {
|
801 |
|
|
error = EHOSTUNREACH;
|
802 |
|
|
goto done;
|
803 |
|
|
}
|
804 |
|
|
}
|
805 |
|
|
}
|
806 |
|
|
|
807 |
|
|
done:
|
808 |
|
|
if (error == EHOSTUNREACH)
|
809 |
|
|
ip6stat.ip6s_noroute++;
|
810 |
|
|
|
811 |
|
|
if (retifp != NULL)
|
812 |
|
|
*retifp = ifp;
|
813 |
|
|
if (retrt != NULL)
|
814 |
|
|
*retrt = rt; /* rt may be NULL */
|
815 |
|
|
|
816 |
|
|
return(error);
|
817 |
|
|
}
|
818 |
|
|
|
819 |
|
|
/*
|
820 |
|
|
* Default hop limit selection. The precedence is as follows:
|
821 |
|
|
* 1. Hoplimit value specified via ioctl.
|
822 |
|
|
* 2. (If the outgoing interface is detected) the current
|
823 |
|
|
* hop limit of the interface specified by router advertisement.
|
824 |
|
|
* 3. The system default hoplimit.
|
825 |
|
|
*/
|
826 |
|
|
#ifdef HAVE_NRL_INPCB
|
827 |
|
|
#define in6pcb inpcb
|
828 |
|
|
#define in6p_hops inp_hops
|
829 |
|
|
#endif
|
830 |
|
|
int
|
831 |
|
|
in6_selecthlim(struct in6pcb *in6p, struct ifnet *ifp)
|
832 |
|
|
{
|
833 |
|
|
if (in6p && in6p->in6p_hops >= 0)
|
834 |
|
|
return(in6p->in6p_hops);
|
835 |
|
|
else if (ifp)
|
836 |
|
|
return(nd_ifinfo[ifp->if_index].chlim);
|
837 |
|
|
else
|
838 |
|
|
return(ip6_defhlim);
|
839 |
|
|
}
|
840 |
|
|
#ifdef HAVE_NRL_INPCB
|
841 |
|
|
#undef in6pcb
|
842 |
|
|
#undef in6p_hops
|
843 |
|
|
#endif
|
844 |
|
|
|
845 |
|
|
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__)
|
846 |
|
|
/*
|
847 |
|
|
* Find an empty port and set it to the specified PCB.
|
848 |
|
|
*/
|
849 |
|
|
#ifdef HAVE_NRL_INPCB /* XXX: I really hate such ugly macros...(jinmei) */
|
850 |
|
|
#define in6pcb inpcb
|
851 |
|
|
#define in6p_socket inp_socket
|
852 |
|
|
#define in6p_lport inp_lport
|
853 |
|
|
#define in6p_head inp_head
|
854 |
|
|
#define in6p_flags inp_flags
|
855 |
|
|
#define IN6PLOOKUP_WILDCARD INPLOOKUP_WILDCARD
|
856 |
|
|
#endif
|
857 |
|
|
int
|
858 |
|
|
in6_pcbsetport(struct in6_addr *laddr, struct in6pcb *in6p)
|
859 |
|
|
{
|
860 |
|
|
struct socket *so = in6p->in6p_socket;
|
861 |
|
|
struct in6pcb *head = in6p->in6p_head;
|
862 |
|
|
u_int16_t last_port, lport = 0;
|
863 |
|
|
int wild = 0;
|
864 |
|
|
void *t;
|
865 |
|
|
u_int16_t min, max;
|
866 |
|
|
|
867 |
|
|
/* XXX: this is redundant when called from in6_pcbbind */
|
868 |
|
|
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
|
869 |
|
|
((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
|
870 |
|
|
(so->so_options & SO_ACCEPTCONN) == 0))
|
871 |
|
|
wild = IN6PLOOKUP_WILDCARD;
|
872 |
|
|
|
873 |
|
|
if (in6p->in6p_flags & IN6P_LOWPORT) {
|
874 |
|
|
min = ip6_lowportmin;
|
875 |
|
|
max = ip6_lowportmax;
|
876 |
|
|
} else {
|
877 |
|
|
min = ip6_anonportmin;
|
878 |
|
|
max = ip6_anonportmax;
|
879 |
|
|
}
|
880 |
|
|
|
881 |
|
|
/* value out of range */
|
882 |
|
|
if (head->in6p_lport < min)
|
883 |
|
|
head->in6p_lport = min;
|
884 |
|
|
else if (head->in6p_lport > max)
|
885 |
|
|
head->in6p_lport = min;
|
886 |
|
|
last_port = head->in6p_lport;
|
887 |
|
|
goto startover; /*to randomize*/
|
888 |
|
|
for (;;) {
|
889 |
|
|
lport = htons(head->in6p_lport);
|
890 |
|
|
if (IN6_IS_ADDR_V4MAPPED(laddr)) {
|
891 |
|
|
#ifdef HAVE_NRL_INPCB
|
892 |
|
|
#ifdef INPLOOKUP_WILDCARD6
|
893 |
|
|
wild &= ~INPLOOKUP_WILDCARD6;
|
894 |
|
|
#endif
|
895 |
|
|
#endif
|
896 |
|
|
#if 0
|
897 |
|
|
t = in_pcblookup_bind(&tcbtable,
|
898 |
|
|
(struct in_addr *)&in6p->in6p_laddr.s6_addr32[3],
|
899 |
|
|
lport);
|
900 |
|
|
#else
|
901 |
|
|
t = NULL;
|
902 |
|
|
#endif
|
903 |
|
|
} else {
|
904 |
|
|
#ifdef HAVE_NRL_INPCB
|
905 |
|
|
#ifdef INPLOOKUP_WILDCARD4
|
906 |
|
|
wild &= ~INPLOOKUP_WILDCARD4;
|
907 |
|
|
#endif
|
908 |
|
|
/* XXX: ugly cast... */
|
909 |
|
|
t = in_pcblookup(head, (struct in_addr *)&zeroin6_addr,
|
910 |
|
|
0, (struct in_addr *)laddr,
|
911 |
|
|
lport, wild | INPLOOKUP_IPV6);
|
912 |
|
|
#else
|
913 |
|
|
t = in6_pcblookup(head, &zeroin6_addr, 0, laddr,
|
914 |
|
|
lport, wild);
|
915 |
|
|
#endif
|
916 |
|
|
}
|
917 |
|
|
if (t == 0)
|
918 |
|
|
break;
|
919 |
|
|
startover:
|
920 |
|
|
if (head->in6p_lport >= max)
|
921 |
|
|
head->in6p_lport = min;
|
922 |
|
|
else
|
923 |
|
|
head->in6p_lport++;
|
924 |
|
|
if (head->in6p_lport == last_port)
|
925 |
|
|
return (EADDRINUSE);
|
926 |
|
|
}
|
927 |
|
|
|
928 |
|
|
in6p->in6p_lport = lport;
|
929 |
|
|
return(0); /* success */
|
930 |
|
|
}
|
931 |
|
|
#ifdef HAVE_NRL_INPCB
|
932 |
|
|
#undef in6pcb
|
933 |
|
|
#undef in6p_socket
|
934 |
|
|
#undef in6p_lport
|
935 |
|
|
#undef in6p_head
|
936 |
|
|
#undef in6p_flags
|
937 |
|
|
#undef IN6PLOOKUP_WILDCARD
|
938 |
|
|
#endif
|
939 |
|
|
#endif /* !FreeBSD3 && !OpenBSD*/
|
940 |
|
|
|
941 |
|
|
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
|
942 |
|
|
/*
|
943 |
|
|
* XXX: this is borrowed from in6_pcbbind(). If possible, we should
|
944 |
|
|
* share this function by all *bsd*...
|
945 |
|
|
*/
|
946 |
|
|
int
|
947 |
|
|
in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct proc *p)
|
948 |
|
|
{
|
949 |
|
|
struct socket *so = inp->inp_socket;
|
950 |
|
|
u_int16_t lport = 0, first, last, *lastport;
|
951 |
|
|
int count, wild = 0;
|
952 |
|
|
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
|
953 |
|
|
|
954 |
|
|
/* XXX: this is redundant when called from in6_pcbbind */
|
955 |
|
|
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
|
956 |
|
|
wild = INPLOOKUP_WILDCARD;
|
957 |
|
|
|
958 |
|
|
inp->inp_flags |= INP_ANONPORT;
|
959 |
|
|
|
960 |
|
|
if (inp->inp_flags & INP_HIGHPORT) {
|
961 |
|
|
first = ipport_hifirstauto; /* sysctl */
|
962 |
|
|
last = ipport_hilastauto;
|
963 |
|
|
lastport = &pcbinfo->lasthi;
|
964 |
|
|
} else if (inp->inp_flags & INP_LOWPORT) {
|
965 |
|
|
first = ipport_lowfirstauto; /* 1023 */
|
966 |
|
|
last = ipport_lowlastauto; /* 600 */
|
967 |
|
|
lastport = &pcbinfo->lastlow;
|
968 |
|
|
} else {
|
969 |
|
|
first = ipport_firstauto; /* sysctl */
|
970 |
|
|
last = ipport_lastauto;
|
971 |
|
|
lastport = &pcbinfo->lastport;
|
972 |
|
|
}
|
973 |
|
|
/*
|
974 |
|
|
* Simple check to ensure all ports are not used up causing
|
975 |
|
|
* a deadlock here.
|
976 |
|
|
*
|
977 |
|
|
* We split the two cases (up and down) so that the direction
|
978 |
|
|
* is not being tested on each round of the loop.
|
979 |
|
|
*/
|
980 |
|
|
if (first > last) {
|
981 |
|
|
/*
|
982 |
|
|
* counting down
|
983 |
|
|
*/
|
984 |
|
|
count = first - last;
|
985 |
|
|
|
986 |
|
|
do {
|
987 |
|
|
if (count-- < 0) { /* completely used? */
|
988 |
|
|
/*
|
989 |
|
|
* Undo any address bind that may have
|
990 |
|
|
* occurred above.
|
991 |
|
|
*/
|
992 |
|
|
inp->in6p_laddr = in6addr_any;
|
993 |
|
|
return (EAGAIN);
|
994 |
|
|
}
|
995 |
|
|
--*lastport;
|
996 |
|
|
if (*lastport > first || *lastport < last)
|
997 |
|
|
*lastport = first;
|
998 |
|
|
lport = htons(*lastport);
|
999 |
|
|
} while (in6_pcblookup_local(pcbinfo,
|
1000 |
|
|
&inp->in6p_laddr, lport, wild));
|
1001 |
|
|
} else {
|
1002 |
|
|
/*
|
1003 |
|
|
* counting up
|
1004 |
|
|
*/
|
1005 |
|
|
count = last - first;
|
1006 |
|
|
|
1007 |
|
|
do {
|
1008 |
|
|
if (count-- < 0) { /* completely used? */
|
1009 |
|
|
/*
|
1010 |
|
|
* Undo any address bind that may have
|
1011 |
|
|
* occurred above.
|
1012 |
|
|
*/
|
1013 |
|
|
inp->in6p_laddr = in6addr_any;
|
1014 |
|
|
return (EAGAIN);
|
1015 |
|
|
}
|
1016 |
|
|
++*lastport;
|
1017 |
|
|
if (*lastport < first || *lastport > last)
|
1018 |
|
|
*lastport = first;
|
1019 |
|
|
lport = htons(*lastport);
|
1020 |
|
|
} while (in6_pcblookup_local(pcbinfo,
|
1021 |
|
|
&inp->in6p_laddr, lport, wild));
|
1022 |
|
|
}
|
1023 |
|
|
|
1024 |
|
|
inp->inp_lport = lport;
|
1025 |
|
|
if (in_pcbinshash(inp) != 0) {
|
1026 |
|
|
inp->in6p_laddr = in6addr_any;
|
1027 |
|
|
inp->inp_lport = 0;
|
1028 |
|
|
return (EAGAIN);
|
1029 |
|
|
}
|
1030 |
|
|
|
1031 |
|
|
return(0);
|
1032 |
|
|
}
|
1033 |
|
|
#endif
|
1034 |
|
|
|
1035 |
|
|
/*
|
1036 |
|
|
* Generate kernel-internal form (scopeid embedded into s6_addr16[1]).
|
1037 |
|
|
* If the address scope of is interface-local or link-local, embed the
|
1038 |
|
|
* interface index in the address.
|
1039 |
|
|
*
|
1040 |
|
|
* This function should be nuked in the future, when we get rid of embedded
|
1041 |
|
|
* scopeid thing.
|
1042 |
|
|
*/
|
1043 |
|
|
int
|
1044 |
|
|
in6_embedscope(in6, sin6)
|
1045 |
|
|
struct in6_addr *in6;
|
1046 |
|
|
const struct sockaddr_in6 *sin6;
|
1047 |
|
|
{
|
1048 |
|
|
#ifdef SCOPEDROUTING
|
1049 |
|
|
/*
|
1050 |
|
|
* XXX: the SCOPEDROUTING code path is NOT expected to work at this
|
1051 |
|
|
* moment (20011112). We added this just in case.
|
1052 |
|
|
*/
|
1053 |
|
|
return(0); /* do nothing */
|
1054 |
|
|
#else
|
1055 |
|
|
struct ifnet *ifp;
|
1056 |
|
|
u_int32_t zoneid = sin6->sin6_scope_id;
|
1057 |
|
|
|
1058 |
|
|
*in6 = sin6->sin6_addr;
|
1059 |
|
|
|
1060 |
|
|
/*
|
1061 |
|
|
* don't try to read sin6->sin6_addr beyond here, since the caller may
|
1062 |
|
|
* ask us to overwrite existing sockaddr_in6
|
1063 |
|
|
*/
|
1064 |
|
|
|
1065 |
|
|
if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
|
1066 |
|
|
/* KAME assumption: link id == interface id */
|
1067 |
|
|
if (zoneid) {
|
1068 |
|
|
if (if_index < zoneid)
|
1069 |
|
|
return(ENXIO); /* XXX EINVAL? */
|
1070 |
|
|
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
|
1071 |
|
|
ifp = ifnet_byindex(zoneid);
|
1072 |
|
|
#else
|
1073 |
|
|
ifp = ifindex2ifnet[zoneid];
|
1074 |
|
|
#endif
|
1075 |
|
|
if (ifp == NULL) /* XXX: this can happen for some OS */
|
1076 |
|
|
return(ENXIO);
|
1077 |
|
|
|
1078 |
|
|
/* XXX assignment to 16bit from 32bit variable */
|
1079 |
|
|
in6->s6_addr16[1] = htons(zoneid & 0xffff);
|
1080 |
|
|
}
|
1081 |
|
|
}
|
1082 |
|
|
|
1083 |
|
|
return 0;
|
1084 |
|
|
#endif
|
1085 |
|
|
}
|
1086 |
|
|
|
1087 |
|
|
/*
|
1088 |
|
|
* generate standard sockaddr_in6 from embedded form.
|
1089 |
|
|
* touches sin6_addr and sin6_scope_id only.
|
1090 |
|
|
*
|
1091 |
|
|
* this function should be nuked in the future, when we get rid of
|
1092 |
|
|
* embedded scopeid thing.
|
1093 |
|
|
*/
|
1094 |
|
|
int
|
1095 |
|
|
in6_recoverscope(sin6, in6, ifp)
|
1096 |
|
|
struct sockaddr_in6 *sin6;
|
1097 |
|
|
const struct in6_addr *in6;
|
1098 |
|
|
struct ifnet *ifp;
|
1099 |
|
|
{
|
1100 |
|
|
u_int32_t zoneid;
|
1101 |
|
|
|
1102 |
|
|
sin6->sin6_addr = *in6;
|
1103 |
|
|
|
1104 |
|
|
/*
|
1105 |
|
|
* don't try to read *in6 beyond here, since the caller may
|
1106 |
|
|
* ask us to overwrite existing sockaddr_in6
|
1107 |
|
|
*/
|
1108 |
|
|
|
1109 |
|
|
sin6->sin6_scope_id = 0;
|
1110 |
|
|
if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
|
1111 |
|
|
/*
|
1112 |
|
|
* KAME assumption: link id == interface id
|
1113 |
|
|
*/
|
1114 |
|
|
zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
|
1115 |
|
|
if (zoneid) {
|
1116 |
|
|
/* sanity check */
|
1117 |
|
|
if (zoneid < 0 || if_index < zoneid)
|
1118 |
|
|
return ENXIO;
|
1119 |
|
|
if (ifp && ifp->if_index != zoneid)
|
1120 |
|
|
return ENXIO;
|
1121 |
|
|
sin6->sin6_addr.s6_addr16[1] = 0;
|
1122 |
|
|
sin6->sin6_scope_id = zoneid;
|
1123 |
|
|
}
|
1124 |
|
|
}
|
1125 |
|
|
|
1126 |
|
|
return 0;
|
1127 |
|
|
}
|
1128 |
|
|
|
1129 |
|
|
/*
|
1130 |
|
|
* just clear the embedded scope identifer.
|
1131 |
|
|
* XXX: currently used for bsdi4 only as a supplement function.
|
1132 |
|
|
*/
|
1133 |
|
|
void
|
1134 |
|
|
in6_clearscope(addr)
|
1135 |
|
|
struct in6_addr *addr;
|
1136 |
|
|
{
|
1137 |
|
|
if (IN6_IS_SCOPE_LINKLOCAL(addr) || IN6_IS_ADDR_MC_INTFACELOCAL(addr))
|
1138 |
|
|
addr->s6_addr16[1] = 0;
|
1139 |
|
|
}
|
1140 |
|
|
|
1141 |
|
|
void
|
1142 |
|
|
addrsel_policy_init()
|
1143 |
|
|
{
|
1144 |
|
|
init_policy_queue();
|
1145 |
|
|
|
1146 |
|
|
/* initialize the "last resort" policy */
|
1147 |
|
|
bzero(&defaultaddrpolicy, sizeof(defaultaddrpolicy));
|
1148 |
|
|
defaultaddrpolicy.label = ADDR_LABEL_NOTAPP;
|
1149 |
|
|
}
|
1150 |
|
|
|
1151 |
|
|
static struct in6_addrpolicy *
|
1152 |
|
|
lookup_addrsel_policy(key)
|
1153 |
|
|
struct sockaddr_in6 *key;
|
1154 |
|
|
{
|
1155 |
|
|
struct in6_addrpolicy *match = NULL;
|
1156 |
|
|
|
1157 |
|
|
match = match_addrsel_policy(key);
|
1158 |
|
|
|
1159 |
|
|
if (match == NULL)
|
1160 |
|
|
match = &defaultaddrpolicy;
|
1161 |
|
|
else
|
1162 |
|
|
match->use++;
|
1163 |
|
|
|
1164 |
|
|
return(match);
|
1165 |
|
|
}
|
1166 |
|
|
|
1167 |
|
|
|
1168 |
|
|
int
|
1169 |
|
|
in6_src_ioctl(cmd, data)
|
1170 |
|
|
u_long cmd;
|
1171 |
|
|
caddr_t data;
|
1172 |
|
|
{
|
1173 |
|
|
int i;
|
1174 |
|
|
struct in6_addrpolicy ent0;
|
1175 |
|
|
|
1176 |
|
|
if (cmd != SIOCAADDRCTL_POLICY && cmd != SIOCDADDRCTL_POLICY)
|
1177 |
|
|
return(EOPNOTSUPP); /* check for safety */
|
1178 |
|
|
|
1179 |
|
|
ent0 = *(struct in6_addrpolicy *)data;
|
1180 |
|
|
|
1181 |
|
|
if (ent0.label == ADDR_LABEL_NOTAPP)
|
1182 |
|
|
return(EINVAL);
|
1183 |
|
|
/* check if the prefix mask is consecutive. */
|
1184 |
|
|
if (in6_mask2len(&ent0.addrmask.sin6_addr, NULL) < 0)
|
1185 |
|
|
return(EINVAL);
|
1186 |
|
|
/* clear trailing garbages (if any) of the prefix address. */
|
1187 |
|
|
for (i = 0; i < 4; i++) {
|
1188 |
|
|
ent0.addr.sin6_addr.s6_addr32[i] &=
|
1189 |
|
|
ent0.addrmask.sin6_addr.s6_addr32[i];
|
1190 |
|
|
}
|
1191 |
|
|
ent0.use = 0;
|
1192 |
|
|
|
1193 |
|
|
switch (cmd) {
|
1194 |
|
|
case SIOCAADDRCTL_POLICY:
|
1195 |
|
|
return(add_addrsel_policyent(&ent0));
|
1196 |
|
|
case SIOCDADDRCTL_POLICY:
|
1197 |
|
|
return(delete_addrsel_policyent(&ent0));
|
1198 |
|
|
}
|
1199 |
|
|
|
1200 |
|
|
return(0); /* XXX: compromise compilers */
|
1201 |
|
|
}
|
1202 |
|
|
|
1203 |
|
|
/*
|
1204 |
|
|
* The followings are implementation of the policy table using a
|
1205 |
|
|
* simple tail queue.
|
1206 |
|
|
* XXX such details should be hidden.
|
1207 |
|
|
* XXX implementation using binary tree should be more efficient.
|
1208 |
|
|
*/
|
1209 |
|
|
struct addrsel_policyent {
|
1210 |
|
|
TAILQ_ENTRY(addrsel_policyent) ape_entry;
|
1211 |
|
|
struct in6_addrpolicy ape_policy;
|
1212 |
|
|
};
|
1213 |
|
|
|
1214 |
|
|
TAILQ_HEAD(addrsel_policyhead, addrsel_policyent);
|
1215 |
|
|
|
1216 |
|
|
struct addrsel_policyhead addrsel_policytab;
|
1217 |
|
|
|
1218 |
|
|
static void
|
1219 |
|
|
init_policy_queue()
|
1220 |
|
|
{
|
1221 |
|
|
TAILQ_INIT(&addrsel_policytab);
|
1222 |
|
|
}
|
1223 |
|
|
|
1224 |
|
|
static int
|
1225 |
|
|
add_addrsel_policyent(newpolicy)
|
1226 |
|
|
struct in6_addrpolicy *newpolicy;
|
1227 |
|
|
{
|
1228 |
|
|
struct addrsel_policyent *new, *pol;
|
1229 |
|
|
|
1230 |
|
|
/* duplication check */
|
1231 |
|
|
for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
|
1232 |
|
|
pol = TAILQ_NEXT(pol, ape_entry)) {
|
1233 |
|
|
if (SA6_ARE_ADDR_EQUAL(&newpolicy->addr,
|
1234 |
|
|
&pol->ape_policy.addr) &&
|
1235 |
|
|
SA6_ARE_ADDR_EQUAL(&newpolicy->addrmask,
|
1236 |
|
|
&pol->ape_policy.addrmask)) {
|
1237 |
|
|
return(EEXIST); /* or override it? */
|
1238 |
|
|
}
|
1239 |
|
|
}
|
1240 |
|
|
|
1241 |
|
|
MALLOC(new, struct addrsel_policyent *, sizeof(*new), M_IFADDR,
|
1242 |
|
|
M_WAITOK);
|
1243 |
|
|
bzero(new, sizeof(*new));
|
1244 |
|
|
|
1245 |
|
|
/* XXX: should validate entry */
|
1246 |
|
|
new->ape_policy = *newpolicy;
|
1247 |
|
|
|
1248 |
|
|
TAILQ_INSERT_TAIL(&addrsel_policytab, new, ape_entry);
|
1249 |
|
|
|
1250 |
|
|
return(0);
|
1251 |
|
|
}
|
1252 |
|
|
|
1253 |
|
|
static int
|
1254 |
|
|
delete_addrsel_policyent(key)
|
1255 |
|
|
struct in6_addrpolicy *key;
|
1256 |
|
|
{
|
1257 |
|
|
struct addrsel_policyent *pol;
|
1258 |
|
|
|
1259 |
|
|
/* search for the entry in the table */
|
1260 |
|
|
for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
|
1261 |
|
|
pol = TAILQ_NEXT(pol, ape_entry)) {
|
1262 |
|
|
if (SA6_ARE_ADDR_EQUAL(&key->addr, &pol->ape_policy.addr) &&
|
1263 |
|
|
SA6_ARE_ADDR_EQUAL(&key->addrmask,
|
1264 |
|
|
&pol->ape_policy.addrmask)) {
|
1265 |
|
|
break;
|
1266 |
|
|
}
|
1267 |
|
|
}
|
1268 |
|
|
if (pol == NULL)
|
1269 |
|
|
return(ESRCH);
|
1270 |
|
|
|
1271 |
|
|
TAILQ_REMOVE(&addrsel_policytab, pol, ape_entry);
|
1272 |
|
|
|
1273 |
|
|
return(0);
|
1274 |
|
|
}
|
1275 |
|
|
|
1276 |
|
|
void
|
1277 |
|
|
_show_addrsel_policy(void)
|
1278 |
|
|
{
|
1279 |
|
|
struct addrsel_policyent *pol;
|
1280 |
|
|
|
1281 |
|
|
log(LOG_ADDR, "IPv6 address policy table\n");
|
1282 |
|
|
for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
|
1283 |
|
|
pol = TAILQ_NEXT(pol, ape_entry)) {
|
1284 |
|
|
log(LOG_ADDR, "Addr: \n");
|
1285 |
|
|
log_dump(LOG_ADDR, &pol->ape_policy.addr, 16);
|
1286 |
|
|
log(LOG_ADDR, "Mask:\n");
|
1287 |
|
|
log_dump(LOG_ADDR, &pol->ape_policy.addrmask, 16);
|
1288 |
|
|
}
|
1289 |
|
|
}
|
1290 |
|
|
|
1291 |
|
|
static struct in6_addrpolicy *
|
1292 |
|
|
match_addrsel_policy(key)
|
1293 |
|
|
struct sockaddr_in6 *key;
|
1294 |
|
|
{
|
1295 |
|
|
struct addrsel_policyent *pent;
|
1296 |
|
|
struct in6_addrpolicy *bestpol = NULL, *pol;
|
1297 |
|
|
int matchlen, bestmatchlen = -1;
|
1298 |
|
|
u_char *mp, *ep, *k, *p, m;
|
1299 |
|
|
|
1300 |
|
|
for (pent = TAILQ_FIRST(&addrsel_policytab); pent;
|
1301 |
|
|
pent = TAILQ_NEXT(pent, ape_entry)) {
|
1302 |
|
|
matchlen = 0;
|
1303 |
|
|
|
1304 |
|
|
pol = &pent->ape_policy;
|
1305 |
|
|
mp = (u_char *)&pol->addrmask.sin6_addr;
|
1306 |
|
|
ep = mp + 16; /* XXX: scope field? */
|
1307 |
|
|
k = (u_char *)&key->sin6_addr;
|
1308 |
|
|
p = (u_char *)&pol->addr.sin6_addr;
|
1309 |
|
|
for (; mp < ep && *mp; mp++, k++, p++) {
|
1310 |
|
|
m = *mp;
|
1311 |
|
|
if ((*k & m) != *p)
|
1312 |
|
|
goto next; /* not match */
|
1313 |
|
|
if (m == 0xff) /* short cut for a typical case */
|
1314 |
|
|
matchlen += 8;
|
1315 |
|
|
else {
|
1316 |
|
|
while(m >= 0x80) {
|
1317 |
|
|
matchlen++;
|
1318 |
|
|
m <<= 1;
|
1319 |
|
|
}
|
1320 |
|
|
}
|
1321 |
|
|
}
|
1322 |
|
|
|
1323 |
|
|
/* matched. check if this is better than the current best. */
|
1324 |
|
|
if (bestpol == NULL ||
|
1325 |
|
|
matchlen > bestmatchlen) {
|
1326 |
|
|
bestpol = pol;
|
1327 |
|
|
bestmatchlen = matchlen;
|
1328 |
|
|
}
|
1329 |
|
|
|
1330 |
|
|
next:
|
1331 |
|
|
continue;
|
1332 |
|
|
}
|
1333 |
|
|
|
1334 |
|
|
return(bestpol);
|
1335 |
|
|
}
|