/src/coturn/src/client/ns_turn_ioaddr.c
Line | Count | Source |
1 | | /* |
2 | | * SPDX-License-Identifier: BSD-3-Clause |
3 | | * |
4 | | * https://opensource.org/license/bsd-3-clause |
5 | | * |
6 | | * Copyright (C) 2011, 2012, 2013 Citrix Systems |
7 | | * |
8 | | * All rights reserved. |
9 | | * |
10 | | * Redistribution and use in source and binary forms, with or without |
11 | | * modification, are permitted provided that the following conditions |
12 | | * are met: |
13 | | * 1. Redistributions of source code must retain the above copyright |
14 | | * notice, this list of conditions and the following disclaimer. |
15 | | * 2. Redistributions in binary form must reproduce the above copyright |
16 | | * notice, this list of conditions and the following disclaimer in the |
17 | | * documentation and/or other materials provided with the distribution. |
18 | | * 3. Neither the name of the project nor the names of its contributors |
19 | | * may be used to endorse or promote products derived from this software |
20 | | * without specific prior written permission. |
21 | | * |
22 | | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
23 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
26 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | | * SUCH DAMAGE. |
33 | | */ |
34 | | |
35 | | #include "ns_turn_ioaddr.h" |
36 | | |
37 | | #include "ns_turn_defs.h" // for nswap16, nswap32, STRCPY |
38 | | |
39 | | #include <stdio.h> // for snprintf, fprintf, stderr |
40 | | #include <stdlib.h> // for atoi, malloc, realloc, free |
41 | | #include <string.h> // for memcpy, strncpy, memset, NULL, memcmp, strstr |
42 | | |
43 | | #if defined(__unix__) || defined(unix) || defined(__APPLE__) |
44 | | #include <netdb.h> |
45 | | #endif |
46 | | |
47 | 27.6k | void addr_set_any(ioa_addr *addr) { |
48 | 27.6k | if (addr) { |
49 | 27.6k | memset(addr, 0, sizeof(ioa_addr)); |
50 | 27.6k | } |
51 | 27.6k | } |
52 | | |
53 | 0 | int addr_any(const ioa_addr *addr) { |
54 | |
|
55 | 0 | if (!addr) { |
56 | 0 | return 1; |
57 | 0 | } |
58 | | |
59 | 0 | if (addr->ss.sa_family == AF_INET) { |
60 | 0 | return ((addr->s4.sin_addr.s_addr == 0) && (addr->s4.sin_port == 0)); |
61 | 0 | } else if (addr->ss.sa_family == AF_INET6) { |
62 | 0 | if (addr->s6.sin6_port != 0) { |
63 | 0 | return 0; |
64 | 0 | } else { |
65 | 0 | size_t i; |
66 | 0 | for (i = 0; i < sizeof(addr->s6.sin6_addr); i++) { |
67 | 0 | if (((const char *)&(addr->s6.sin6_addr))[i]) { |
68 | 0 | return 0; |
69 | 0 | } |
70 | 0 | } |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | 0 | return 1; |
75 | 0 | } |
76 | | |
77 | 15.6k | int addr_any_no_port(const ioa_addr *addr) { |
78 | 15.6k | if (!addr) { |
79 | 0 | return 1; |
80 | 0 | } |
81 | | |
82 | 15.6k | if (addr->ss.sa_family == AF_INET) { |
83 | 8.48k | return (addr->s4.sin_addr.s_addr == 0); |
84 | 8.48k | } else if (addr->ss.sa_family == AF_INET6) { |
85 | 7.14k | size_t i; |
86 | 8.04k | for (i = 0; i < sizeof(addr->s6.sin6_addr); i++) { |
87 | 8.04k | if (((const char *)(&(addr->s6.sin6_addr)))[i]) { |
88 | 7.14k | return 0; |
89 | 7.14k | } |
90 | 8.04k | } |
91 | 7.14k | } |
92 | | |
93 | 0 | return 1; |
94 | 15.6k | } |
95 | | |
96 | 0 | uint32_t hash_int32(uint32_t a) { |
97 | 0 | a = a ^ (a >> 4); |
98 | 0 | a = (a ^ 0xdeadbeef) + (a << 5); |
99 | 0 | a = a ^ (a >> 11); |
100 | 0 | return a; |
101 | 0 | } |
102 | | |
103 | 0 | uint64_t hash_int64(uint64_t a) { |
104 | 0 | a = a ^ (a >> 4); |
105 | 0 | a = (a ^ 0xdeadbeefdeadbeefLL) + (a << 5); |
106 | 0 | a = a ^ (a >> 11); |
107 | 0 | return a; |
108 | 0 | } |
109 | | |
110 | 0 | uint32_t addr_hash(const ioa_addr *addr) { |
111 | 0 | if (!addr) { |
112 | 0 | return 0; |
113 | 0 | } |
114 | | |
115 | 0 | uint32_t ret = 0; |
116 | 0 | if (addr->ss.sa_family == AF_INET) { |
117 | 0 | ret = hash_int32(addr->s4.sin_addr.s_addr + addr->s4.sin_port); |
118 | 0 | } else { |
119 | 0 | uint64_t a[2]; |
120 | 0 | memcpy(&a, &(addr->s6.sin6_addr), sizeof(a)); |
121 | 0 | ret = (uint32_t)((hash_int64(a[0]) << 3) + (hash_int64(a[1] + addr->s6.sin6_port))); |
122 | 0 | } |
123 | 0 | return ret; |
124 | 0 | } |
125 | | |
126 | 0 | uint32_t addr_hash_no_port(const ioa_addr *addr) { |
127 | 0 | if (!addr) { |
128 | 0 | return 0; |
129 | 0 | } |
130 | | |
131 | 0 | uint32_t ret = 0; |
132 | 0 | if (addr->ss.sa_family == AF_INET) { |
133 | 0 | ret = hash_int32(addr->s4.sin_addr.s_addr); |
134 | 0 | } else { |
135 | 0 | uint64_t a[2]; |
136 | 0 | memcpy(&a, &(addr->s6.sin6_addr), sizeof(a)); |
137 | 0 | ret = (uint32_t)((hash_int64(a[0]) << 3) + (hash_int64(a[1]))); |
138 | 0 | } |
139 | 0 | return ret; |
140 | 0 | } |
141 | | |
142 | | /* addr_cpy is now defined as static inline in ns_turn_ioaddr.h. */ |
143 | | |
144 | 0 | void addr_cpy4(ioa_addr *dst, const struct sockaddr_in *src) { |
145 | 0 | if (src && dst) { |
146 | 0 | memcpy(dst, src, sizeof(struct sockaddr_in)); |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | 0 | void addr_cpy6(ioa_addr *dst, const struct sockaddr_in6 *src) { |
151 | 0 | if (src && dst) { |
152 | 0 | memcpy(dst, src, sizeof(struct sockaddr_in6)); |
153 | 0 | } |
154 | 0 | } |
155 | | |
156 | 0 | int addr_eq(const ioa_addr *a1, const ioa_addr *a2) { |
157 | |
|
158 | 0 | if (!a1) { |
159 | 0 | return (!a2); |
160 | 0 | } else if (!a2) { |
161 | 0 | return (!a1); |
162 | 0 | } |
163 | | |
164 | 0 | if (a1->ss.sa_family == a2->ss.sa_family) { |
165 | 0 | if (a1->ss.sa_family == AF_INET && a1->s4.sin_port == a2->s4.sin_port) { |
166 | 0 | if ((int)a1->s4.sin_addr.s_addr == (int)a2->s4.sin_addr.s_addr) { |
167 | 0 | return 1; |
168 | 0 | } |
169 | 0 | } else if (a1->ss.sa_family == AF_INET6 && a1->s6.sin6_port == a2->s6.sin6_port) { |
170 | 0 | if (memcmp(&(a1->s6.sin6_addr), &(a2->s6.sin6_addr), sizeof(struct in6_addr)) == 0) { |
171 | 0 | return 1; |
172 | 0 | } |
173 | 0 | } |
174 | 0 | } |
175 | | |
176 | 0 | return 0; |
177 | 0 | } |
178 | | |
179 | 44.4k | int addr_eq_no_port(const ioa_addr *a1, const ioa_addr *a2) { |
180 | | |
181 | 44.4k | if (!a1) { |
182 | 0 | return (!a2); |
183 | 44.4k | } else if (!a2) { |
184 | 0 | return (!a1); |
185 | 0 | } |
186 | | |
187 | 44.4k | if (a1->ss.sa_family == a2->ss.sa_family) { |
188 | 21.3k | if (a1->ss.sa_family == AF_INET) { |
189 | 10.8k | if ((int)a1->s4.sin_addr.s_addr == (int)a2->s4.sin_addr.s_addr) { |
190 | 24 | return 1; |
191 | 24 | } |
192 | 10.8k | } else if (a1->ss.sa_family == AF_INET6) { |
193 | 10.4k | if (memcmp(&(a1->s6.sin6_addr), &(a2->s6.sin6_addr), sizeof(struct in6_addr)) == 0) { |
194 | 0 | return 1; |
195 | 0 | } |
196 | 10.4k | } |
197 | 21.3k | } |
198 | 44.4k | return 0; |
199 | 44.4k | } |
200 | | |
201 | 12 | int make_ioa_addr(const uint8_t *saddr0, uint16_t port, ioa_addr *addr) { |
202 | | |
203 | 12 | if (!saddr0 || !addr) { |
204 | 0 | return -1; |
205 | 0 | } |
206 | | |
207 | 12 | char ssaddr[257]; |
208 | 12 | STRCPY(ssaddr, saddr0); |
209 | | |
210 | 12 | char *saddr = ssaddr; |
211 | 12 | while (*saddr == ' ') { |
212 | 0 | ++saddr; |
213 | 0 | } |
214 | | |
215 | 12 | size_t len = strlen(saddr); |
216 | 12 | while (len > 0) { |
217 | 12 | if (saddr[len - 1] == ' ') { |
218 | 0 | saddr[len - 1] = 0; |
219 | 0 | --len; |
220 | 12 | } else { |
221 | 12 | break; |
222 | 12 | } |
223 | 12 | } |
224 | | |
225 | 12 | memset(addr, 0, sizeof(ioa_addr)); |
226 | 12 | if ((len == 0) || (inet_pton(AF_INET, saddr, &addr->s4.sin_addr) == 1)) { |
227 | 6 | addr->s4.sin_family = AF_INET; |
228 | | #if defined(TURN_HAS_SIN_LEN) /* tested when configured */ |
229 | | addr->s4.sin_len = sizeof(struct sockaddr_in); |
230 | | #endif |
231 | 6 | addr->s4.sin_port = nswap16(port); |
232 | 6 | } else if (inet_pton(AF_INET6, saddr, &addr->s6.sin6_addr) == 1) { |
233 | 6 | addr->s6.sin6_family = AF_INET6; |
234 | | #if defined(SIN6_LEN) /* this define is required by IPv6 if used */ |
235 | | addr->s6.sin6_len = sizeof(struct sockaddr_in6); |
236 | | #endif |
237 | 6 | addr->s6.sin6_port = nswap16(port); |
238 | 6 | } else { |
239 | 0 | struct addrinfo addr_hints; |
240 | 0 | struct addrinfo *addr_result = NULL; |
241 | 0 | int err; |
242 | |
|
243 | 0 | memset(&addr_hints, 0, sizeof(struct addrinfo)); |
244 | 0 | addr_hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ |
245 | 0 | addr_hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ |
246 | 0 | addr_hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ |
247 | 0 | addr_hints.ai_protocol = 0; /* Any protocol */ |
248 | 0 | addr_hints.ai_canonname = NULL; |
249 | 0 | addr_hints.ai_addr = NULL; |
250 | 0 | addr_hints.ai_next = NULL; |
251 | |
|
252 | 0 | err = getaddrinfo(saddr, NULL, &addr_hints, &addr_result); |
253 | 0 | if ((err != 0) || (!addr_result)) { |
254 | 0 | fprintf(stderr, "error resolving '%s' hostname: %s\n", saddr, gai_strerror(err)); |
255 | 0 | return -1; |
256 | 0 | } |
257 | | |
258 | 0 | int family = AF_INET; |
259 | 0 | struct addrinfo *addr_result_orig = addr_result; |
260 | 0 | int found = 0; |
261 | |
|
262 | 0 | beg_af: |
263 | |
|
264 | 0 | while (addr_result) { |
265 | |
|
266 | 0 | if (addr_result->ai_family == family) { |
267 | 0 | if (addr_result->ai_family == AF_INET) { |
268 | 0 | memcpy(addr, addr_result->ai_addr, addr_result->ai_addrlen); |
269 | 0 | addr->s4.sin_port = nswap16(port); |
270 | | #if defined(TURN_HAS_SIN_LEN) /* tested when configured */ |
271 | | addr->s4.sin_len = sizeof(struct sockaddr_in); |
272 | | #endif |
273 | 0 | found = 1; |
274 | 0 | break; |
275 | 0 | } else if (addr_result->ai_family == AF_INET6) { |
276 | 0 | memcpy(addr, addr_result->ai_addr, addr_result->ai_addrlen); |
277 | 0 | addr->s6.sin6_port = nswap16(port); |
278 | | #if defined(SIN6_LEN) /* this define is required by IPv6 if used */ |
279 | | addr->s6.sin6_len = sizeof(struct sockaddr_in6); |
280 | | #endif |
281 | 0 | found = 1; |
282 | 0 | break; |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | 0 | addr_result = addr_result->ai_next; |
287 | 0 | } |
288 | |
|
289 | 0 | if (!found && family == AF_INET) { |
290 | 0 | family = AF_INET6; |
291 | 0 | addr_result = addr_result_orig; |
292 | 0 | goto beg_af; |
293 | 0 | } |
294 | | |
295 | 0 | freeaddrinfo(addr_result_orig); |
296 | 0 | } |
297 | | |
298 | 12 | return 0; |
299 | 12 | } |
300 | | |
301 | 0 | static char *get_addr_string_and_port(char *s0, uint16_t *port) { |
302 | 0 | char *s = s0; |
303 | 0 | while (*s && (*s == ' ')) { |
304 | 0 | ++s; |
305 | 0 | } |
306 | 0 | if (*s == '[') { |
307 | 0 | ++s; |
308 | 0 | char *tail = strstr(s, "]"); |
309 | 0 | if (tail) { |
310 | 0 | *tail = 0; |
311 | 0 | ++tail; |
312 | 0 | while (*tail && (*tail == ' ')) { |
313 | 0 | ++tail; |
314 | 0 | } |
315 | 0 | if (*tail == ':') { |
316 | 0 | ++tail; |
317 | 0 | *port = atoi(tail); |
318 | 0 | return s; |
319 | 0 | } else if (*tail == 0) { |
320 | 0 | *port = 0; |
321 | 0 | return s; |
322 | 0 | } |
323 | 0 | } |
324 | 0 | } else { |
325 | 0 | char *tail = strstr(s, ":"); |
326 | 0 | if (tail) { |
327 | 0 | *tail = 0; |
328 | 0 | ++tail; |
329 | 0 | *port = atoi(tail); |
330 | 0 | return s; |
331 | 0 | } else { |
332 | 0 | *port = 0; |
333 | 0 | return s; |
334 | 0 | } |
335 | 0 | } |
336 | 0 | return NULL; |
337 | 0 | } |
338 | | |
339 | 0 | int make_ioa_addr_from_full_string(const uint8_t *saddr, uint16_t default_port, ioa_addr *addr) { |
340 | 0 | if (!addr) { |
341 | 0 | return -1; |
342 | 0 | } |
343 | | |
344 | 0 | int ret = -1; |
345 | 0 | uint16_t port = 0; |
346 | 0 | char *s = strdup((const char *)saddr); |
347 | 0 | char *sa = get_addr_string_and_port(s, &port); |
348 | 0 | if (sa) { |
349 | 0 | if (port < 1) { |
350 | 0 | port = default_port; |
351 | 0 | } |
352 | 0 | ret = make_ioa_addr((uint8_t *)sa, port, addr); |
353 | 0 | } |
354 | 0 | free(s); |
355 | 0 | return ret; |
356 | 0 | } |
357 | | |
358 | 0 | int addr_to_string(const ioa_addr *addr, char *saddr) { |
359 | |
|
360 | 0 | if (addr && saddr) { |
361 | 0 | saddr[0] = '\0'; |
362 | 0 | char addrtmp[INET6_ADDRSTRLEN]; |
363 | |
|
364 | 0 | if (addr->ss.sa_family == AF_INET) { |
365 | 0 | inet_ntop(AF_INET, &addr->s4.sin_addr, addrtmp, INET_ADDRSTRLEN); |
366 | 0 | if (addr_get_port(addr) > 0) { |
367 | 0 | snprintf(saddr, MAX_IOA_ADDR_STRING, "%s:%d", addrtmp, addr_get_port(addr)); |
368 | 0 | } else { |
369 | 0 | snprintf(saddr, MAX_IOA_ADDR_STRING, "%s", addrtmp); |
370 | 0 | } |
371 | 0 | } else if (addr->ss.sa_family == AF_INET6) { |
372 | 0 | inet_ntop(AF_INET6, &addr->s6.sin6_addr, addrtmp, INET6_ADDRSTRLEN); |
373 | 0 | if (addr_get_port(addr) > 0) { |
374 | 0 | snprintf(saddr, MAX_IOA_ADDR_STRING, "[%s]:%d", addrtmp, addr_get_port(addr)); |
375 | 0 | } else { |
376 | 0 | snprintf(saddr, MAX_IOA_ADDR_STRING, "%s", addrtmp); |
377 | 0 | } |
378 | 0 | } else { |
379 | 0 | return -1; |
380 | 0 | } |
381 | | |
382 | 0 | return 0; |
383 | 0 | } |
384 | | |
385 | 0 | return -1; |
386 | 0 | } |
387 | | |
388 | 0 | int addr_to_string_no_port(const ioa_addr *addr, char *saddr) { |
389 | |
|
390 | 0 | if (addr && saddr) { |
391 | 0 | saddr[0] = '\0'; |
392 | 0 | if (addr->ss.sa_family == AF_INET) { |
393 | 0 | inet_ntop(AF_INET, &addr->s4.sin_addr, saddr, INET_ADDRSTRLEN); |
394 | 0 | } else if (addr->ss.sa_family == AF_INET6) { |
395 | 0 | inet_ntop(AF_INET6, &addr->s6.sin6_addr, saddr, INET6_ADDRSTRLEN); |
396 | 0 | } else { |
397 | 0 | return -1; |
398 | 0 | } |
399 | | |
400 | 0 | return 0; |
401 | 0 | } |
402 | | |
403 | 0 | return -1; |
404 | 0 | } |
405 | | |
406 | 1.83k | void addr_set_port(ioa_addr *addr, uint16_t port) { |
407 | 1.83k | if (addr) { |
408 | 1.83k | if (addr->s4.sin_family == AF_INET) { |
409 | 1.02k | addr->s4.sin_port = nswap16(port); |
410 | 1.02k | } else if (addr->s6.sin6_family == AF_INET6) { |
411 | 810 | addr->s6.sin6_port = nswap16(port); |
412 | 810 | } |
413 | 1.83k | } |
414 | 1.83k | } |
415 | | |
416 | 1.83k | uint16_t addr_get_port(const ioa_addr *addr) { |
417 | 1.83k | if (!addr) { |
418 | 0 | return 0; |
419 | 0 | } |
420 | | |
421 | 1.83k | if (addr->s4.sin_family == AF_INET) { |
422 | 1.83k | return nswap16(addr->s4.sin_port); |
423 | 1.83k | } else if (addr->s6.sin6_family == AF_INET6) { |
424 | 0 | return nswap16(addr->s6.sin6_port); |
425 | 0 | } |
426 | 0 | return 0; |
427 | 1.83k | } |
428 | | |
429 | | ///////////////////////////////////////////////////////////////////////////// |
430 | | |
431 | 0 | void ioa_addr_range_set(ioa_addr_range *range, const ioa_addr *addr_min, const ioa_addr *addr_max) { |
432 | 0 | if (range) { |
433 | 0 | if (addr_min) { |
434 | 0 | addr_cpy(&(range->min), addr_min); |
435 | 0 | } else { |
436 | 0 | addr_set_any(&(range->min)); |
437 | 0 | } |
438 | 0 | if (addr_max) { |
439 | 0 | addr_cpy(&(range->max), addr_max); |
440 | 0 | } else { |
441 | 0 | addr_set_any(&(range->max)); |
442 | 0 | } |
443 | 0 | } |
444 | 0 | } |
445 | | |
446 | 0 | int addr_less_eq(const ioa_addr *addr1, const ioa_addr *addr2) { |
447 | |
|
448 | 0 | if (!addr1) { |
449 | 0 | return 1; |
450 | 0 | } else if (!addr2) { |
451 | 0 | return 0; |
452 | 0 | } else { |
453 | 0 | if (addr1->ss.sa_family != addr2->ss.sa_family) { |
454 | 0 | return (addr1->ss.sa_family < addr2->ss.sa_family); |
455 | 0 | } else if (addr1->ss.sa_family == AF_INET) { |
456 | 0 | return ((uint32_t)nswap32(addr1->s4.sin_addr.s_addr) <= (uint32_t)nswap32(addr2->s4.sin_addr.s_addr)); |
457 | 0 | } else if (addr1->ss.sa_family == AF_INET6) { |
458 | 0 | int i; |
459 | 0 | for (i = 0; i < 16; i++) { |
460 | 0 | if ((uint8_t)(((const char *)&(addr1->s6.sin6_addr))[i]) > |
461 | 0 | (uint8_t)(((const char *)&(addr2->s6.sin6_addr))[i])) { |
462 | 0 | return 0; |
463 | 0 | } |
464 | 0 | } |
465 | 0 | return 1; |
466 | 0 | } else { |
467 | 0 | return 1; |
468 | 0 | } |
469 | 0 | } |
470 | 0 | } |
471 | | |
472 | 0 | int ioa_addr_in_range(const ioa_addr_range *range, const ioa_addr *addr) { |
473 | |
|
474 | 0 | if (range && addr) { |
475 | 0 | #if !defined(WINDOWS) |
476 | | /* If the range is AF_INET and addr is an IPv4-mapped IPv6 address |
477 | | * (::ffff:x.x.x.x), extract the embedded IPv4 so the comparison works. */ |
478 | 0 | ioa_addr addr4; |
479 | 0 | if (addr->ss.sa_family == AF_INET6) { |
480 | 0 | sa_family_t range_family = range->min.ss.sa_family; |
481 | 0 | if (range_family == 0) { |
482 | 0 | range_family = range->max.ss.sa_family; |
483 | 0 | } |
484 | 0 | if (range_family == AF_INET && IN6_IS_ADDR_V4MAPPED(&addr->s6.sin6_addr)) { |
485 | 0 | memset(&addr4, 0, sizeof(addr4)); |
486 | 0 | addr4.s4.sin_family = AF_INET; |
487 | 0 | memcpy(&addr4.s4.sin_addr, addr->s6.sin6_addr.s6_addr + 12, 4); |
488 | 0 | addr = &addr4; |
489 | 0 | } |
490 | 0 | } |
491 | 0 | #endif |
492 | 0 | if (addr_any(&(range->min)) || addr_less_eq(&(range->min), addr)) { |
493 | 0 | if (addr_any(&(range->max))) { |
494 | 0 | return 1; |
495 | 0 | } else { |
496 | 0 | return addr_less_eq(addr, &(range->max)); |
497 | 0 | } |
498 | 0 | } |
499 | 0 | } |
500 | | |
501 | 0 | return 0; |
502 | 0 | } |
503 | | |
504 | 0 | void ioa_addr_range_cpy(ioa_addr_range *dest, const ioa_addr_range *src) { |
505 | 0 | if (dest && src) { |
506 | 0 | addr_cpy(&(dest->min), &(src->min)); |
507 | 0 | addr_cpy(&(dest->max), &(src->max)); |
508 | 0 | } |
509 | 0 | } |
510 | | |
511 | | /////// Check whether this is a good address ////////////// |
512 | | |
513 | 0 | int ioa_addr_is_multicast(ioa_addr *addr) { |
514 | 0 | if (addr) { |
515 | 0 | if (addr->ss.sa_family == AF_INET) { |
516 | 0 | const uint8_t *u = ((const uint8_t *)&(addr->s4.sin_addr)); |
517 | 0 | return (u[0] > 223); |
518 | 0 | } else if (addr->ss.sa_family == AF_INET6) { |
519 | 0 | const uint8_t *u = ((const uint8_t *)&(addr->s6.sin6_addr)); |
520 | | /* IPv4-mapped IPv6: ::ffff:x.x.x.x — check embedded IPv4 multicast range */ |
521 | 0 | if (IN6_IS_ADDR_V4MAPPED(&addr->s6.sin6_addr)) { |
522 | 0 | return (u[12] > 223); |
523 | 0 | } |
524 | 0 | return (u[0] == 255); |
525 | 0 | } |
526 | 0 | } |
527 | 0 | return 0; |
528 | 0 | } |
529 | | |
530 | 0 | int ioa_addr_is_loopback(ioa_addr *addr) { |
531 | 0 | if (addr) { |
532 | 0 | if (addr->ss.sa_family == AF_INET) { |
533 | 0 | const uint8_t *u = ((const uint8_t *)&(addr->s4.sin_addr)); |
534 | 0 | return (u[0] == 127); |
535 | 0 | } else if (addr->ss.sa_family == AF_INET6) { |
536 | 0 | const uint8_t *u = ((const uint8_t *)&(addr->s6.sin6_addr)); |
537 | 0 | if (u[15] == 1) { |
538 | 0 | int i; |
539 | 0 | for (i = 0; i < 15; ++i) { |
540 | 0 | if (u[i]) { |
541 | 0 | return 0; |
542 | 0 | } |
543 | 0 | } |
544 | 0 | return 1; |
545 | 0 | } |
546 | | /* IPv4-mapped IPv6: ::ffff:x.x.x.x */ |
547 | 0 | if (IN6_IS_ADDR_V4MAPPED(&addr->s6.sin6_addr)) { |
548 | 0 | return (u[12] == 127); |
549 | 0 | } |
550 | 0 | } |
551 | 0 | } |
552 | 0 | return 0; |
553 | 0 | } |
554 | | |
555 | | /* |
556 | | To avoid a vulnerability this function checks whether the addr is in 0.0.0.0/8 or ::/128. |
557 | | Source from (INADDR_ANY) 0.0.0.0/32 and (in6addr_any) ::/128 routed to loopback on Linux systems for old BSD backward |
558 | | compatibility. https://github.com/torvalds/linux/blob/a2f5ea9e314ba6778f885c805c921e9362ec0420/net/ipv6/tcp_ipv6.c#L182 |
559 | | To avoid any trouble we match the whole 0.0.0.0/8 that defined in RFC6890 as local network "this". |
560 | | */ |
561 | 0 | int ioa_addr_is_zero(ioa_addr *addr) { |
562 | 0 | if (addr) { |
563 | 0 | if (addr->ss.sa_family == AF_INET) { |
564 | 0 | const uint8_t *u = ((const uint8_t *)&(addr->s4.sin_addr)); |
565 | 0 | return (u[0] == 0); |
566 | 0 | } else if (addr->ss.sa_family == AF_INET6) { |
567 | 0 | const uint8_t *u = ((const uint8_t *)&(addr->s6.sin6_addr)); |
568 | | /* IPv4-mapped IPv6: ::ffff:0.0.0.0 */ |
569 | 0 | if (IN6_IS_ADDR_V4MAPPED(&addr->s6.sin6_addr)) { |
570 | 0 | return (u[12] == 0 && u[13] == 0 && u[14] == 0 && u[15] == 0); |
571 | 0 | } |
572 | 0 | int i; |
573 | 0 | for (i = 0; i <= 15; ++i) { |
574 | 0 | if (u[i]) { |
575 | 0 | return 0; |
576 | 0 | } |
577 | 0 | } |
578 | 0 | return 1; |
579 | 0 | } |
580 | 0 | } |
581 | 0 | return 0; |
582 | 0 | } |
583 | | |
584 | | /////// Map "public" address to "private" address ////////////// |
585 | | |
586 | | // Must be called only in a single-threaded context, |
587 | | // before the program starts spawning threads: |
588 | | |
589 | | static ioa_addr **public_addrs = NULL; |
590 | | static ioa_addr **private_addrs = NULL; |
591 | | static size_t mcount = 0; |
592 | | static size_t msz = 0; |
593 | | |
594 | 6 | void ioa_addr_add_mapping(ioa_addr *apub, ioa_addr *apriv) { |
595 | 6 | const size_t new_size = msz + sizeof(ioa_addr *); |
596 | 6 | public_addrs = (ioa_addr **)realloc(public_addrs, new_size); |
597 | 6 | private_addrs = (ioa_addr **)realloc(private_addrs, new_size); |
598 | 6 | public_addrs[mcount] = (ioa_addr *)malloc(sizeof(ioa_addr)); |
599 | 6 | private_addrs[mcount] = (ioa_addr *)malloc(sizeof(ioa_addr)); |
600 | 6 | addr_cpy(public_addrs[mcount], apub); |
601 | 6 | addr_cpy(private_addrs[mcount], apriv); |
602 | 6 | ++mcount; |
603 | 6 | msz += sizeof(ioa_addr *); |
604 | 6 | } |
605 | | |
606 | 13.8k | void map_addr_from_public_to_private(const ioa_addr *public_addr, ioa_addr *private_addr) { |
607 | 13.8k | size_t i; |
608 | 41.4k | for (i = 0; i < mcount; ++i) { |
609 | 27.6k | if (addr_eq_no_port(public_addr, public_addrs[i])) { |
610 | 16 | addr_cpy(private_addr, private_addrs[i]); |
611 | 16 | addr_set_port(private_addr, addr_get_port(public_addr)); |
612 | 16 | return; |
613 | 16 | } |
614 | 27.6k | } |
615 | 13.7k | addr_cpy(private_addr, public_addr); |
616 | 13.7k | } |
617 | | |
618 | 8.41k | void map_addr_from_private_to_public(const ioa_addr *private_addr, ioa_addr *public_addr) { |
619 | 8.41k | size_t i; |
620 | 25.2k | for (i = 0; i < mcount; ++i) { |
621 | 16.8k | if (addr_eq_no_port(private_addr, private_addrs[i])) { |
622 | 8 | addr_cpy(public_addr, public_addrs[i]); |
623 | 8 | addr_set_port(public_addr, addr_get_port(private_addr)); |
624 | 8 | return; |
625 | 8 | } |
626 | 16.8k | } |
627 | 8.40k | addr_cpy(public_addr, private_addr); |
628 | 8.40k | } |
629 | | |
630 | | ////////////////////////////////////////////////////////////////////////////// |