Print this page
4596 Callers of ip_srcid_find_id() need to be more careful
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/inet/ip/ip_srcid.c
+++ new/usr/src/uts/common/inet/ip/ip_srcid.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 + *
25 + * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
24 26 */
25 27
26 28 /*
27 29 * This is used to support the hidden __sin6_src_id in the sockaddr_in6
28 30 * structure which is there to ensure that applications (such as UDP apps)
29 31 * which get an address from recvfrom and use that address in a sendto
30 32 * or connect will by default use the same source address in the "response"
31 33 * as the destination address in the "request" they received.
32 34 *
33 35 * This is built using some new functions (in IP - doing their own locking
34 36 * so they can be called from the transports) to map between integer IDs
35 37 * and in6_addr_t.
36 38 * The use applies to sockaddr_in6 - whether or not mapped addresses are used.
37 39 *
38 40 * This file contains the functions used by both IP and the transports
39 41 * to implement __sin6_src_id.
40 42 * The routines do their own locking since they are called from
41 43 * the transports (to map between a source id and an address)
42 44 * and from IP proper when IP addresses are added and removed.
43 45 *
44 46 * The routines handle both IPv4 and IPv6 with the IPv4 addresses represented
45 47 * as IPv4-mapped addresses.
46 48 */
47 49
48 50 #include <sys/types.h>
49 51 #include <sys/stream.h>
50 52 #include <sys/dlpi.h>
51 53 #include <sys/stropts.h>
52 54 #include <sys/sysmacros.h>
53 55 #include <sys/strsubr.h>
54 56 #include <sys/strlog.h>
55 57 #define _SUN_TPI_VERSION 2
56 58 #include <sys/tihdr.h>
57 59 #include <sys/xti_inet.h>
58 60 #include <sys/ddi.h>
59 61 #include <sys/cmn_err.h>
60 62 #include <sys/debug.h>
61 63 #include <sys/modctl.h>
62 64 #include <sys/atomic.h>
63 65 #include <sys/zone.h>
64 66
65 67 #include <sys/systm.h>
66 68 #include <sys/param.h>
67 69 #include <sys/kmem.h>
68 70 #include <sys/callb.h>
69 71 #include <sys/socket.h>
70 72 #include <sys/vtrace.h>
71 73 #include <sys/isa_defs.h>
72 74 #include <sys/kmem.h>
73 75 #include <net/if.h>
74 76 #include <net/if_arp.h>
75 77 #include <net/route.h>
76 78 #include <sys/sockio.h>
77 79 #include <netinet/in.h>
78 80 #include <net/if_dl.h>
79 81
80 82 #include <inet/common.h>
81 83 #include <inet/mi.h>
82 84 #include <inet/mib2.h>
83 85 #include <inet/nd.h>
84 86 #include <inet/arp.h>
85 87 #include <inet/snmpcom.h>
86 88
87 89 #include <netinet/igmp_var.h>
88 90 #include <netinet/ip6.h>
89 91 #include <netinet/icmp6.h>
90 92
91 93 #include <inet/ip.h>
92 94 #include <inet/ip6.h>
93 95 #include <inet/tcp.h>
94 96 #include <inet/ip_multi.h>
95 97 #include <inet/ip_if.h>
96 98 #include <inet/ip_ire.h>
97 99 #include <inet/ip_rts.h>
98 100 #include <inet/optcom.h>
99 101 #include <inet/ip_ndp.h>
100 102 #include <netinet/igmp.h>
101 103 #include <netinet/ip_mroute.h>
102 104 #include <inet/ipclassifier.h>
103 105
104 106 #include <sys/kmem.h>
105 107
106 108 static uint_t srcid_nextid(ip_stack_t *);
107 109 static srcid_map_t **srcid_lookup_addr(const in6_addr_t *addr,
108 110 zoneid_t zoneid, ip_stack_t *);
109 111 static srcid_map_t **srcid_lookup_id(uint_t id, ip_stack_t *);
110 112
111 113
112 114 /*
113 115 * Insert/add a new address to the map.
114 116 * Returns zero if ok; otherwise errno (e.g. for memory allocation failure).
115 117 */
116 118 int
117 119 ip_srcid_insert(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst)
118 120 {
119 121 srcid_map_t **smpp;
120 122 #ifdef DEBUG
121 123 char abuf[INET6_ADDRSTRLEN];
122 124
123 125 ip1dbg(("ip_srcid_insert(%s, %d)\n",
124 126 inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid));
125 127 #endif
126 128
127 129 rw_enter(&ipst->ips_srcid_lock, RW_WRITER);
128 130 smpp = srcid_lookup_addr(addr, zoneid, ipst);
129 131 if (*smpp != NULL) {
130 132 /* Already present - increment refcount */
131 133 (*smpp)->sm_refcnt++;
132 134 ASSERT((*smpp)->sm_refcnt != 0); /* wraparound */
133 135 rw_exit(&ipst->ips_srcid_lock);
134 136 return (0);
135 137 }
136 138 /* Insert new */
137 139 *smpp = kmem_alloc(sizeof (srcid_map_t), KM_NOSLEEP);
138 140 if (*smpp == NULL) {
139 141 rw_exit(&ipst->ips_srcid_lock);
140 142 return (ENOMEM);
141 143 }
142 144 (*smpp)->sm_next = NULL;
143 145 (*smpp)->sm_addr = *addr;
144 146 (*smpp)->sm_srcid = srcid_nextid(ipst);
145 147 (*smpp)->sm_refcnt = 1;
146 148 (*smpp)->sm_zoneid = zoneid;
147 149
148 150 rw_exit(&ipst->ips_srcid_lock);
149 151 return (0);
150 152 }
151 153
152 154 /*
153 155 * Remove an new address from the map.
154 156 * Returns zero if ok; otherwise errno (e.g. for nonexistent address).
155 157 */
156 158 int
157 159 ip_srcid_remove(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst)
158 160 {
159 161 srcid_map_t **smpp;
160 162 srcid_map_t *smp;
161 163 #ifdef DEBUG
162 164 char abuf[INET6_ADDRSTRLEN];
163 165
164 166 ip1dbg(("ip_srcid_remove(%s, %d)\n",
165 167 inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid));
166 168 #endif
167 169
168 170 rw_enter(&ipst->ips_srcid_lock, RW_WRITER);
169 171 smpp = srcid_lookup_addr(addr, zoneid, ipst);
170 172 smp = *smpp;
171 173 if (smp == NULL) {
172 174 /* Not preset */
173 175 rw_exit(&ipst->ips_srcid_lock);
174 176 return (ENOENT);
175 177 }
176 178
177 179 /* Decrement refcount */
178 180 ASSERT(smp->sm_refcnt != 0);
179 181 smp->sm_refcnt--;
180 182 if (smp->sm_refcnt != 0) {
181 183 rw_exit(&ipst->ips_srcid_lock);
182 184 return (0);
183 185 }
184 186 /* Remove entry */
185 187 *smpp = smp->sm_next;
186 188 rw_exit(&ipst->ips_srcid_lock);
187 189 smp->sm_next = NULL;
188 190 kmem_free(smp, sizeof (srcid_map_t));
189 191 return (0);
190 192 }
191 193
192 194 /*
193 195 * Map from an address to a source id.
194 196 * If the address is unknown return the unknown id (zero).
195 197 */
196 198 uint_t
197 199 ip_srcid_find_addr(const in6_addr_t *addr, zoneid_t zoneid,
198 200 netstack_t *ns)
199 201 {
200 202 srcid_map_t **smpp;
201 203 srcid_map_t *smp;
202 204 uint_t id;
203 205 ip_stack_t *ipst = ns->netstack_ip;
204 206
205 207 rw_enter(&ipst->ips_srcid_lock, RW_READER);
206 208 smpp = srcid_lookup_addr(addr, zoneid, ipst);
207 209 smp = *smpp;
208 210 if (smp == NULL) {
209 211 char abuf[INET6_ADDRSTRLEN];
210 212
211 213 /* Not present - could be broadcast or multicast address */
212 214 ip1dbg(("ip_srcid_find_addr: unknown %s in zone %d\n",
213 215 inet_ntop(AF_INET6, addr, abuf, sizeof (abuf)), zoneid));
214 216 id = 0;
215 217 } else {
|
↓ open down ↓ |
182 lines elided |
↑ open up ↑ |
216 218 ASSERT(smp->sm_refcnt != 0);
217 219 id = smp->sm_srcid;
218 220 }
219 221 rw_exit(&ipst->ips_srcid_lock);
220 222 return (id);
221 223 }
222 224
223 225 /*
224 226 * Map from a source id to an address.
225 227 * If the id is unknown return the unspecified address.
228 + *
229 + * For known IDs, check if the returned address is v4mapped or not, and
230 + * return B_TRUE if it matches the desired v4mapped state or not. This
231 + * prevents a broken app from requesting (via __sin6_src_id) a v4mapped
232 + * address for a v6 destination, or vice versa.
233 + *
234 + * "addr" will not be set if we return B_FALSE.
226 235 */
227 -void
236 +boolean_t
228 237 ip_srcid_find_id(uint_t id, in6_addr_t *addr, zoneid_t zoneid,
229 - netstack_t *ns)
238 + boolean_t v4mapped, netstack_t *ns)
230 239 {
231 240 srcid_map_t **smpp;
232 241 srcid_map_t *smp;
233 242 ip_stack_t *ipst = ns->netstack_ip;
243 + boolean_t rc;
234 244
235 245 rw_enter(&ipst->ips_srcid_lock, RW_READER);
236 246 smpp = srcid_lookup_id(id, ipst);
237 247 smp = *smpp;
238 248 if (smp == NULL || (smp->sm_zoneid != zoneid && zoneid != ALL_ZONES)) {
239 249 /* Not preset */
240 250 ip1dbg(("ip_srcid_find_id: unknown %u or in wrong zone\n", id));
241 251 *addr = ipv6_all_zeros;
252 + rc = B_TRUE;
242 253 } else {
243 254 ASSERT(smp->sm_refcnt != 0);
244 - *addr = smp->sm_addr;
255 + /*
256 + * The caller tells us if it expects a v4mapped address.
257 + * Use it, along with the property of "addr" to set the rc.
258 + */
259 + if (IN6_IS_ADDR_V4MAPPED(&smp->sm_addr))
260 + rc = v4mapped; /* We want a v4mapped address. */
261 + else
262 + rc = !v4mapped; /* We don't want a v4mapped address. */
263 +
264 + if (rc)
265 + *addr = smp->sm_addr;
266 +
245 267 }
246 268 rw_exit(&ipst->ips_srcid_lock);
269 + return (rc);
247 270 }
248 271
249 272 /* Assign the next available ID */
250 273 static uint_t
251 274 srcid_nextid(ip_stack_t *ipst)
252 275 {
253 276 uint_t id;
254 277 srcid_map_t **smpp;
255 278
256 279 ASSERT(rw_owner(&ipst->ips_srcid_lock) == curthread);
257 280
258 281 if (!ipst->ips_srcid_wrapped) {
259 282 id = ipst->ips_ip_src_id++;
260 283 if (ipst->ips_ip_src_id == 0)
261 284 ipst->ips_srcid_wrapped = B_TRUE;
262 285 return (id);
263 286 }
264 287 /* Once it wraps we search for an unused ID. */
265 288 for (id = 0; id < 0xffffffff; id++) {
266 289 smpp = srcid_lookup_id(id, ipst);
267 290 if (*smpp == NULL)
268 291 return (id);
269 292 }
270 293 panic("srcid_nextid: No free identifiers!");
271 294 /* NOTREACHED */
272 295 }
273 296
274 297 /*
275 298 * Lookup based on address.
276 299 * Always returns a non-null pointer.
277 300 * If found then *ptr will be the found object.
278 301 * Otherwise *ptr will be NULL and can be used to insert a new object.
279 302 */
280 303 static srcid_map_t **
281 304 srcid_lookup_addr(const in6_addr_t *addr, zoneid_t zoneid, ip_stack_t *ipst)
282 305 {
283 306 srcid_map_t **smpp;
284 307
285 308 ASSERT(RW_LOCK_HELD(&ipst->ips_srcid_lock));
286 309 smpp = &ipst->ips_srcid_head;
287 310 while (*smpp != NULL) {
288 311 if (IN6_ARE_ADDR_EQUAL(&(*smpp)->sm_addr, addr) &&
289 312 (zoneid == (*smpp)->sm_zoneid || zoneid == ALL_ZONES))
290 313 return (smpp);
291 314 smpp = &(*smpp)->sm_next;
292 315 }
293 316 return (smpp);
294 317 }
295 318
296 319 /*
297 320 * Lookup based on address.
298 321 * Always returns a non-null pointer.
299 322 * If found then *ptr will be the found object.
300 323 * Otherwise *ptr will be NULL and can be used to insert a new object.
301 324 */
302 325 static srcid_map_t **
303 326 srcid_lookup_id(uint_t id, ip_stack_t *ipst)
304 327 {
305 328 srcid_map_t **smpp;
306 329
307 330 ASSERT(RW_LOCK_HELD(&ipst->ips_srcid_lock));
308 331 smpp = &ipst->ips_srcid_head;
309 332 while (*smpp != NULL) {
310 333 if ((*smpp)->sm_srcid == id)
311 334 return (smpp);
312 335 smpp = &(*smpp)->sm_next;
313 336 }
314 337 return (smpp);
315 338 }
|
↓ open down ↓ |
59 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX