Coverage Report

Created: 2026-05-30 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
//////////////////////////////////////////////////////////////////////////////