BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file |
||
3 | * |
||
4 | * IPv6 address scopes, zones, and scoping policy. |
||
5 | * |
||
6 | * This header provides the means to implement support for IPv6 address scopes, |
||
7 | * as per RFC 4007. An address scope can be either global or more constrained. |
||
8 | * In lwIP, we say that an address "has a scope" or "is scoped" when its scope |
||
9 | * is constrained, in which case the address is meaningful only in a specific |
||
10 | * "zone." For unicast addresses, only link-local addresses have a scope; in |
||
11 | * that case, the scope is the link. For multicast addresses, there are various |
||
12 | * scopes defined by RFC 4007 and others. For any constrained scope, a system |
||
13 | * must establish a (potentially one-to-many) mapping between zones and local |
||
14 | * interfaces. For example, a link-local address is valid on only one link (its |
||
15 | * zone). That link may be attached to one or more local interfaces. The |
||
16 | * decisions on which scopes are constrained and the mapping between zones and |
||
17 | * interfaces is together what we refer to as the "scoping policy" - more on |
||
18 | * this in a bit. |
||
19 | * |
||
20 | * In lwIP, each IPv6 address has an associated zone index. This zone index may |
||
21 | * be set to "no zone" (IP6_NO_ZONE, 0) or an actual zone. We say that an |
||
22 | * address "has a zone" or "is zoned" when its zone index is *not* set to "no |
||
23 | * zone." In lwIP, in principle, each address should be "properly zoned," which |
||
24 | * means that if the address has a zone if and only if has a scope. As such, it |
||
25 | * is a rule that an unscoped (e.g., global) address must never have a zone. |
||
26 | * Even though one could argue that there is always one zone even for global |
||
27 | * scopes, this rule exists for implementation simplicity. Violation of the |
||
28 | * rule will trigger assertions or otherwise result in undesired behavior. |
||
29 | * |
||
30 | * Backward compatibility prevents us from requiring that applications always |
||
31 | * provide properly zoned addresses. We do enforce the rule that the in the |
||
32 | * lwIP link layer (everything below netif->output_ip6() and in particular ND6) |
||
33 | * *all* addresses are properly zoned. Thus, on the output paths down the |
||
34 | * stack, various places deal with the case of addresses that lack a zone. |
||
35 | * Some of them are best-effort for efficiency (e.g. the PCB bind and connect |
||
36 | * API calls' attempts to add missing zones); ultimately the IPv6 output |
||
37 | * handler (@ref ip6_output_if_src) will set a zone if necessary. |
||
38 | * |
||
39 | * Aside from dealing with scoped addresses lacking a zone, a proper IPv6 |
||
40 | * implementation must also ensure that a packet with a scoped source and/or |
||
41 | * destination address does not leave its zone. This is currently implemented |
||
42 | * in the input and forward functions. However, for output, these checks are |
||
43 | * deliberately omitted in order to keep the implementation lightweight. The |
||
44 | * routing algorithm in @ref ip6_route will take decisions such that it will |
||
45 | * not cause zone violations unless the application sets bad addresses, though. |
||
46 | * |
||
47 | * In terms of scoping policy, lwIP implements the default policy from RFC 4007 |
||
48 | * using macros in this file. This policy considers link-local unicast |
||
49 | * addresses and (only) interface-local and link-local multicast addresses as |
||
50 | * having a scope. For all these addresses, the zone is equal to the interface. |
||
51 | * As shown below in this file, it is possible to implement a custom policy. |
||
52 | */ |
||
53 | |||
54 | /* |
||
55 | * Copyright (c) 2017 The MINIX 3 Project. |
||
56 | * All rights reserved. |
||
57 | * |
||
58 | * Redistribution and use in source and binary forms, with or without modification, |
||
59 | * are permitted provided that the following conditions are met: |
||
60 | * |
||
61 | * 1. Redistributions of source code must retain the above copyright notice, |
||
62 | * this list of conditions and the following disclaimer. |
||
63 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
||
64 | * this list of conditions and the following disclaimer in the documentation |
||
65 | * and/or other materials provided with the distribution. |
||
66 | * 3. The name of the author may not be used to endorse or promote products |
||
67 | * derived from this software without specific prior written permission. |
||
68 | * |
||
69 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||
70 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
71 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||
72 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||
73 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
||
74 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
75 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
76 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
77 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
||
78 | * OF SUCH DAMAGE. |
||
79 | * |
||
80 | * This file is part of the lwIP TCP/IP stack. |
||
81 | * |
||
82 | * Author: David van Moolenbroek <david@minix3.org> |
||
83 | * |
||
84 | */ |
||
85 | #ifndef LWIP_HDR_IP6_ZONE_H |
||
86 | #define LWIP_HDR_IP6_ZONE_H |
||
87 | |||
88 | /** |
||
89 | * @defgroup ip6_zones IPv6 Zones |
||
90 | * @ingroup ip6 |
||
91 | * @{ |
||
92 | */ |
||
93 | |||
94 | #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ |
||
95 | |||
96 | /** Identifier for "no zone". */ |
||
97 | #define IP6_NO_ZONE 0 |
||
98 | |||
99 | #if LWIP_IPV6_SCOPES |
||
100 | |||
101 | /** Zone initializer for static IPv6 address initialization, including comma. */ |
||
102 | #define IPADDR6_ZONE_INIT , IP6_NO_ZONE |
||
103 | |||
104 | /** Return the zone index of the given IPv6 address; possibly "no zone". */ |
||
105 | #define ip6_addr_zone(ip6addr) ((ip6addr)->zone) |
||
106 | |||
107 | /** Does the given IPv6 address have a zone set? (0/1) */ |
||
108 | #define ip6_addr_has_zone(ip6addr) (ip6_addr_zone(ip6addr) != IP6_NO_ZONE) |
||
109 | |||
110 | /** Set the zone field of an IPv6 address to a particular value. */ |
||
111 | #define ip6_addr_set_zone(ip6addr, zone_idx) ((ip6addr)->zone = (zone_idx)) |
||
112 | |||
113 | /** Clear the zone field of an IPv6 address, setting it to "no zone". */ |
||
114 | #define ip6_addr_clear_zone(ip6addr) ((ip6addr)->zone = IP6_NO_ZONE) |
||
115 | |||
116 | /** Copy the zone field from the second IPv6 address to the first one. */ |
||
117 | #define ip6_addr_copy_zone(ip6addr1, ip6addr2) ((ip6addr1).zone = (ip6addr2).zone) |
||
118 | |||
119 | /** Is the zone field of the given IPv6 address equal to the given zone index? (0/1) */ |
||
120 | #define ip6_addr_equals_zone(ip6addr, zone_idx) ((ip6addr)->zone == (zone_idx)) |
||
121 | |||
122 | /** Are the zone fields of the given IPv6 addresses equal? (0/1) |
||
123 | * This macro must only be used on IPv6 addresses of the same scope. */ |
||
124 | #define ip6_addr_cmp_zone(ip6addr1, ip6addr2) ((ip6addr1)->zone == (ip6addr2)->zone) |
||
125 | |||
126 | /** Symbolic constants for the 'type' parameters in some of the macros. |
||
127 | * These exist for efficiency only, allowing the macros to avoid certain tests |
||
128 | * when the address is known not to be of a certain type. Dead code elimination |
||
129 | * will do the rest. IP6_MULTICAST is supported but currently not optimized. |
||
130 | * @see ip6_addr_has_scope, ip6_addr_assign_zone, ip6_addr_lacks_zone. |
||
131 | */ |
||
132 | enum lwip_ipv6_scope_type |
||
133 | { |
||
134 | /** Unknown */ |
||
135 | IP6_UNKNOWN = 0, |
||
136 | /** Unicast */ |
||
137 | IP6_UNICAST = 1, |
||
138 | /** Multicast */ |
||
139 | IP6_MULTICAST = 2 |
||
140 | }; |
||
141 | |||
142 | /** IPV6_CUSTOM_SCOPES: together, the following three macro definitions, |
||
143 | * @ref ip6_addr_has_scope, @ref ip6_addr_assign_zone, and |
||
144 | * @ref ip6_addr_test_zone, completely define the lwIP scoping policy. |
||
145 | * The definitions below implement the default policy from RFC 4007 Sec. 6. |
||
146 | * Should an implementation desire to implement a different policy, it can |
||
147 | * define IPV6_CUSTOM_SCOPES to 1 and supply its own definitions for the three |
||
148 | * macros instead. |
||
149 | */ |
||
150 | #ifndef IPV6_CUSTOM_SCOPES |
||
151 | #define IPV6_CUSTOM_SCOPES 0 |
||
152 | #endif /* !IPV6_CUSTOM_SCOPES */ |
||
153 | |||
154 | #if !IPV6_CUSTOM_SCOPES |
||
155 | |||
156 | /** |
||
157 | * Determine whether an IPv6 address has a constrained scope, and as such is |
||
158 | * meaningful only if accompanied by a zone index to identify the scope's zone. |
||
159 | * The given address type may be used to eliminate at compile time certain |
||
160 | * checks that will evaluate to false at run time anyway. |
||
161 | * |
||
162 | * This default implementation follows the default model of RFC 4007, where |
||
163 | * only interface-local and link-local scopes are defined. |
||
164 | * |
||
165 | * Even though the unicast loopback address does have an implied link-local |
||
166 | * scope, in this implementation it does not have an explicitly assigned zone |
||
167 | * index. As such it should not be tested for in this macro. |
||
168 | * |
||
169 | * @param ip6addr the IPv6 address (const); only its address part is examined. |
||
170 | * @param type address type; see @ref lwip_ipv6_scope_type. |
||
171 | * @return 1 if the address has a constrained scope, 0 if it does not. |
||
172 | */ |
||
173 | #define ip6_addr_has_scope(ip6addr, type) \ |
||
174 | (ip6_addr_islinklocal(ip6addr) || (((type) != IP6_UNICAST) && \ |
||
175 | (ip6_addr_ismulticast_iflocal(ip6addr) || \ |
||
176 | ip6_addr_ismulticast_linklocal(ip6addr)))) |
||
177 | |||
178 | /** |
||
179 | * Assign a zone index to an IPv6 address, based on a network interface. If the |
||
180 | * given address has a scope, the assigned zone index is that scope's zone of |
||
181 | * the given netif; otherwise, the assigned zone index is "no zone". |
||
182 | * |
||
183 | * This default implementation follows the default model of RFC 4007, where |
||
184 | * only interface-local and link-local scopes are defined, and the zone index |
||
185 | * of both of those scopes always equals the index of the network interface. |
||
186 | * As such, this default implementation need not distinguish between different |
||
187 | * constrained scopes when assigning the zone. |
||
188 | * |
||
189 | * @param ip6addr the IPv6 address; its address part is examined, and its zone |
||
190 | * index is assigned. |
||
191 | * @param type address type; see @ref lwip_ipv6_scope_type. |
||
192 | * @param netif the network interface (const). |
||
193 | */ |
||
194 | #define ip6_addr_assign_zone(ip6addr, type, netif) \ |
||
195 | (ip6_addr_set_zone((ip6addr), \ |
||
196 | ip6_addr_has_scope((ip6addr), (type)) ? netif_get_index(netif) : 0)) |
||
197 | |||
198 | /** |
||
199 | * Test whether an IPv6 address is "zone-compatible" with a network interface. |
||
200 | * That is, test whether the network interface is part of the zone associated |
||
201 | * with the address. For efficiency, this macro is only ever called if the |
||
202 | * given address is either scoped or zoned, and thus, it need not test this. |
||
203 | * If an address is scoped but not zoned, or zoned and not scoped, it is |
||
204 | * considered not zone-compatible with any netif. |
||
205 | * |
||
206 | * This default implementation follows the default model of RFC 4007, where |
||
207 | * only interface-local and link-local scopes are defined, and the zone index |
||
208 | * of both of those scopes always equals the index of the network interface. |
||
209 | * As such, there is always only one matching netif for a specific zone index, |
||
210 | * but all call sites of this macro currently support multiple matching netifs |
||
211 | * as well (at no additional expense in the common case). |
||
212 | * |
||
213 | * @param ip6addr the IPv6 address (const). |
||
214 | * @param netif the network interface (const). |
||
215 | * @return 1 if the address is scope-compatible with the netif, 0 if not. |
||
216 | */ |
||
217 | #define ip6_addr_test_zone(ip6addr, netif) \ |
||
218 | (ip6_addr_equals_zone((ip6addr), netif_get_index(netif))) |
||
219 | |||
220 | #endif /* !IPV6_CUSTOM_SCOPES */ |
||
221 | |||
222 | /** Does the given IPv6 address have a scope, and as such should also have a |
||
223 | * zone to be meaningful, but does not actually have a zone? (0/1) */ |
||
224 | #define ip6_addr_lacks_zone(ip6addr, type) \ |
||
225 | (!ip6_addr_has_zone(ip6addr) && ip6_addr_has_scope((ip6addr), (type))) |
||
226 | |||
227 | /** |
||
228 | * Try to select a zone for a scoped address that does not yet have a zone. |
||
229 | * Called from PCB bind and connect routines, for two reasons: 1) to save on |
||
230 | * this (relatively expensive) selection for every individual packet route |
||
231 | * operation and 2) to allow the application to obtain the selected zone from |
||
232 | * the PCB as is customary for e.g. getsockname/getpeername BSD socket calls. |
||
233 | * |
||
234 | * Ideally, callers would always supply a properly zoned address, in which case |
||
235 | * this function would not be needed. It exists both for compatibility with the |
||
236 | * BSD socket API (which accepts zoneless destination addresses) and for |
||
237 | * backward compatibility with pre-scoping lwIP code. |
||
238 | * |
||
239 | * It may be impossible to select a zone, e.g. if there are no netifs. In that |
||
240 | * case, the address's zone field will be left as is. |
||
241 | * |
||
242 | * @param dest the IPv6 address for which to select and set a zone. |
||
243 | * @param src source IPv6 address (const); may be equal to dest. |
||
244 | */ |
||
245 | #define ip6_addr_select_zone(dest, src) do { struct netif *selected_netif; \ |
||
246 | selected_netif = ip6_route((src), (dest)); \ |
||
247 | if (selected_netif != NULL) { \ |
||
248 | ip6_addr_assign_zone((dest), IP6_UNKNOWN, selected_netif); \ |
||
249 | } } while (0) |
||
250 | |||
251 | /** |
||
252 | * @} |
||
253 | */ |
||
254 | |||
255 | #else /* LWIP_IPV6_SCOPES */ |
||
256 | |||
257 | #define IPADDR6_ZONE_INIT |
||
258 | #define ip6_addr_zone(ip6addr) (IP6_NO_ZONE) |
||
259 | #define ip6_addr_has_zone(ip6addr) (0) |
||
260 | #define ip6_addr_set_zone(ip6addr, zone_idx) |
||
261 | #define ip6_addr_clear_zone(ip6addr) |
||
262 | #define ip6_addr_copy_zone(ip6addr1, ip6addr2) |
||
263 | #define ip6_addr_equals_zone(ip6addr, zone_idx) (1) |
||
264 | #define ip6_addr_cmp_zone(ip6addr1, ip6addr2) (1) |
||
265 | #define IPV6_CUSTOM_SCOPES 0 |
||
266 | #define ip6_addr_has_scope(ip6addr, type) (0) |
||
267 | #define ip6_addr_assign_zone(ip6addr, type, netif) |
||
268 | #define ip6_addr_test_zone(ip6addr, netif) (1) |
||
269 | #define ip6_addr_lacks_zone(ip6addr, type) (0) |
||
270 | #define ip6_addr_select_zone(ip6addr, src) |
||
271 | |||
272 | #endif /* LWIP_IPV6_SCOPES */ |
||
273 | |||
274 | #if LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG |
||
275 | |||
276 | /** Verify that the given IPv6 address is properly zoned. */ |
||
277 | #define IP6_ADDR_ZONECHECK(ip6addr) LWIP_ASSERT("IPv6 zone check failed", \ |
||
278 | ip6_addr_has_scope(ip6addr, IP6_UNKNOWN) == ip6_addr_has_zone(ip6addr)) |
||
279 | |||
280 | /** Verify that the given IPv6 address is properly zoned for the given netif. */ |
||
281 | #define IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif) LWIP_ASSERT("IPv6 netif zone check failed", \ |
||
282 | ip6_addr_has_scope(ip6addr, IP6_UNKNOWN) ? \ |
||
283 | (ip6_addr_has_zone(ip6addr) && \ |
||
284 | (((netif) == NULL) || ip6_addr_test_zone((ip6addr), (netif)))) : \ |
||
285 | !ip6_addr_has_zone(ip6addr)) |
||
286 | |||
287 | #else /* LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG */ |
||
288 | |||
289 | #define IP6_ADDR_ZONECHECK(ip6addr) |
||
290 | #define IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif) |
||
291 | |||
292 | #endif /* LWIP_IPV6_SCOPES && LWIP_IPV6_SCOPES_DEBUG */ |
||
293 | |||
294 | #endif /* LWIP_IPV6 */ |
||
295 | |||
296 | #endif /* LWIP_HDR_IP6_ADDR_H */ |