Coverage Report

Created: 2025-07-18 07:03

/src/bind9/lib/isc/netaddr.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <inttypes.h>
17
#include <stdbool.h>
18
#include <stdio.h>
19
20
#include <isc/buffer.h>
21
#include <isc/net.h>
22
#include <isc/netaddr.h>
23
#include <isc/sockaddr.h>
24
#include <isc/string.h>
25
#include <isc/util.h>
26
27
bool
28
0
isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
29
0
  REQUIRE(a != NULL && b != NULL);
30
31
0
  if (a->family != b->family) {
32
0
    return false;
33
0
  }
34
35
0
  if (a->zone != b->zone) {
36
0
    return false;
37
0
  }
38
39
0
  switch (a->family) {
40
0
  case AF_INET:
41
0
    if (a->type.in.s_addr != b->type.in.s_addr) {
42
0
      return false;
43
0
    }
44
0
    break;
45
0
  case AF_INET6:
46
0
    if (memcmp(&a->type.in6, &b->type.in6, sizeof(a->type.in6)) !=
47
0
          0 ||
48
0
        a->zone != b->zone)
49
0
    {
50
0
      return false;
51
0
    }
52
0
    break;
53
0
  default:
54
0
    return false;
55
0
  }
56
0
  return true;
57
0
}
58
59
bool
60
isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
61
0
         unsigned int prefixlen) {
62
0
  const unsigned char *pa = NULL, *pb = NULL;
63
0
  unsigned int ipabytes = 0; /* Length of whole IP address in bytes */
64
0
  unsigned int nbytes;     /* Number of significant whole bytes */
65
0
  unsigned int nbits;    /* Number of significant leftover bits */
66
67
0
  REQUIRE(a != NULL && b != NULL);
68
69
0
  if (a->family != b->family) {
70
0
    return false;
71
0
  }
72
73
0
  if (a->zone != b->zone && b->zone != 0) {
74
0
    return false;
75
0
  }
76
77
0
  switch (a->family) {
78
0
  case AF_INET:
79
0
    pa = (const unsigned char *)&a->type.in;
80
0
    pb = (const unsigned char *)&b->type.in;
81
0
    ipabytes = 4;
82
0
    break;
83
0
  case AF_INET6:
84
0
    pa = (const unsigned char *)&a->type.in6;
85
0
    pb = (const unsigned char *)&b->type.in6;
86
0
    ipabytes = 16;
87
0
    break;
88
0
  default:
89
0
    return false;
90
0
  }
91
92
  /*
93
   * Don't crash if we get a pattern like 10.0.0.1/9999999.
94
   */
95
0
  if (prefixlen > ipabytes * 8) {
96
0
    prefixlen = ipabytes * 8;
97
0
  }
98
99
0
  nbytes = prefixlen / 8;
100
0
  nbits = prefixlen % 8;
101
102
0
  if (nbytes > 0) {
103
0
    if (memcmp(pa, pb, nbytes) != 0) {
104
0
      return false;
105
0
    }
106
0
  }
107
0
  if (nbits > 0) {
108
0
    unsigned int bytea, byteb, mask;
109
0
    INSIST(nbytes < ipabytes);
110
0
    INSIST(nbits < 8);
111
0
    bytea = pa[nbytes];
112
0
    byteb = pb[nbytes];
113
0
    mask = (0xFF << (8 - nbits)) & 0xFF;
114
0
    if ((bytea & mask) != (byteb & mask)) {
115
0
      return false;
116
0
    }
117
0
  }
118
0
  return true;
119
0
}
120
121
isc_result_t
122
0
isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
123
0
  char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
124
0
  char zbuf[sizeof("%4294967295")];
125
0
  unsigned int alen;
126
0
  int zlen;
127
0
  const char *r;
128
0
  const void *type;
129
130
0
  REQUIRE(netaddr != NULL);
131
132
0
  switch (netaddr->family) {
133
0
  case AF_INET:
134
0
    type = &netaddr->type.in;
135
0
    break;
136
0
  case AF_INET6:
137
0
    type = &netaddr->type.in6;
138
0
    break;
139
0
  default:
140
0
    return ISC_R_FAILURE;
141
0
  }
142
0
  r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
143
0
  if (r == NULL) {
144
0
    return ISC_R_FAILURE;
145
0
  }
146
147
0
  alen = strlen(abuf);
148
0
  INSIST(alen < sizeof(abuf));
149
150
0
  zlen = 0;
151
0
  if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
152
0
    zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
153
0
    if (zlen < 0) {
154
0
      return ISC_R_FAILURE;
155
0
    }
156
0
    INSIST((unsigned int)zlen < sizeof(zbuf));
157
0
  }
158
159
0
  if (alen + zlen > isc_buffer_availablelength(target)) {
160
0
    return ISC_R_NOSPACE;
161
0
  }
162
163
0
  isc_buffer_putmem(target, (unsigned char *)abuf, alen);
164
0
  isc_buffer_putmem(target, (unsigned char *)zbuf, (unsigned int)zlen);
165
166
0
  return ISC_R_SUCCESS;
167
0
}
168
169
void
170
0
isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
171
0
  isc_result_t result;
172
0
  isc_buffer_t buf;
173
174
0
  isc_buffer_init(&buf, array, size);
175
0
  result = isc_netaddr_totext(na, &buf);
176
177
0
  if (size == 0) {
178
0
    return;
179
0
  }
180
181
  /*
182
   * Null terminate.
183
   */
184
0
  if (result == ISC_R_SUCCESS) {
185
0
    if (isc_buffer_availablelength(&buf) >= 1) {
186
0
      isc_buffer_putuint8(&buf, 0);
187
0
    } else {
188
0
      result = ISC_R_NOSPACE;
189
0
    }
190
0
  }
191
192
0
  if (result != ISC_R_SUCCESS) {
193
0
    snprintf(array, size, "<unknown address, family %u>",
194
0
       na->family);
195
0
    array[size - 1] = '\0';
196
0
  }
197
0
}
198
199
isc_result_t
200
0
isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
201
0
  static const unsigned char zeros[16];
202
0
  unsigned int nbits, nbytes, ipbytes = 0;
203
0
  const unsigned char *p;
204
205
0
  switch (na->family) {
206
0
  case AF_INET:
207
0
    p = (const unsigned char *)&na->type.in;
208
0
    ipbytes = 4;
209
0
    if (prefixlen > 32) {
210
0
      return ISC_R_RANGE;
211
0
    }
212
0
    break;
213
0
  case AF_INET6:
214
0
    p = (const unsigned char *)&na->type.in6;
215
0
    ipbytes = 16;
216
0
    if (prefixlen > 128) {
217
0
      return ISC_R_RANGE;
218
0
    }
219
0
    break;
220
0
  default:
221
0
    return ISC_R_NOTIMPLEMENTED;
222
0
  }
223
0
  nbytes = prefixlen / 8;
224
0
  nbits = prefixlen % 8;
225
0
  if (nbits != 0) {
226
0
    INSIST(nbytes < ipbytes);
227
0
    if ((p[nbytes] & (0xff >> nbits)) != 0U) {
228
0
      return ISC_R_FAILURE;
229
0
    }
230
0
    nbytes++;
231
0
  }
232
0
  if (nbytes < ipbytes &&
233
0
      memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0)
234
0
  {
235
0
    return ISC_R_FAILURE;
236
0
  }
237
0
  return ISC_R_SUCCESS;
238
0
}
239
240
isc_result_t
241
0
isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
242
0
  unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i;
243
0
  const unsigned char *p;
244
245
0
  switch (s->family) {
246
0
  case AF_INET:
247
0
    p = (const unsigned char *)&s->type.in;
248
0
    ipbytes = 4;
249
0
    break;
250
0
  case AF_INET6:
251
0
    p = (const unsigned char *)&s->type.in6;
252
0
    ipbytes = 16;
253
0
    break;
254
0
  default:
255
0
    return ISC_R_NOTIMPLEMENTED;
256
0
  }
257
0
  for (i = 0; i < ipbytes; i++) {
258
0
    if (p[i] != 0xFF) {
259
0
      break;
260
0
    }
261
0
  }
262
0
  nbytes = i;
263
0
  if (i < ipbytes) {
264
0
    unsigned int c = p[nbytes];
265
0
    while ((c & 0x80) != 0 && nbits < 8) {
266
0
      c <<= 1;
267
0
      nbits++;
268
0
    }
269
0
    if ((c & 0xFF) != 0) {
270
0
      return ISC_R_MASKNONCONTIG;
271
0
    }
272
0
    i++;
273
0
  }
274
0
  for (; i < ipbytes; i++) {
275
0
    if (p[i] != 0) {
276
0
      return ISC_R_MASKNONCONTIG;
277
0
    }
278
0
  }
279
0
  *lenp = nbytes * 8 + nbits;
280
0
  return ISC_R_SUCCESS;
281
0
}
282
283
void
284
0
isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
285
0
  memset(netaddr, 0, sizeof(*netaddr));
286
0
  netaddr->family = AF_INET;
287
0
  netaddr->type.in = *ina;
288
0
}
289
290
void
291
0
isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
292
0
  memset(netaddr, 0, sizeof(*netaddr));
293
0
  netaddr->family = AF_INET6;
294
0
  netaddr->type.in6 = *ina6;
295
0
}
296
297
void
298
0
isc_netaddr_setzone(isc_netaddr_t *netaddr, uint32_t zone) {
299
  /* we currently only support AF_INET6. */
300
0
  REQUIRE(netaddr->family == AF_INET6);
301
302
0
  netaddr->zone = zone;
303
0
}
304
305
uint32_t
306
0
isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
307
0
  return netaddr->zone;
308
0
}
309
310
void
311
0
isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
312
0
  int family = s->type.sa.sa_family;
313
0
  t->family = family;
314
0
  switch (family) {
315
0
  case AF_INET:
316
0
    t->type.in = s->type.sin.sin_addr;
317
0
    t->zone = 0;
318
0
    break;
319
0
  case AF_INET6:
320
0
    memmove(&t->type.in6, &s->type.sin6.sin6_addr, 16);
321
0
    t->zone = s->type.sin6.sin6_scope_id;
322
0
    break;
323
0
  default:
324
0
    UNREACHABLE();
325
0
  }
326
0
}
327
328
void
329
0
isc_netaddr_any(isc_netaddr_t *netaddr) {
330
0
  memset(netaddr, 0, sizeof(*netaddr));
331
0
  netaddr->family = AF_INET;
332
0
  netaddr->type.in.s_addr = INADDR_ANY;
333
0
}
334
335
void
336
0
isc_netaddr_any6(isc_netaddr_t *netaddr) {
337
0
  memset(netaddr, 0, sizeof(*netaddr));
338
0
  netaddr->family = AF_INET6;
339
0
  netaddr->type.in6 = in6addr_any;
340
0
}
341
342
void
343
0
isc_netaddr_unspec(isc_netaddr_t *netaddr) {
344
0
  memset(netaddr, 0, sizeof(*netaddr));
345
0
  netaddr->family = AF_UNSPEC;
346
0
}
347
348
bool
349
0
isc_netaddr_ismulticast(const isc_netaddr_t *na) {
350
0
  switch (na->family) {
351
0
  case AF_INET:
352
0
    return ISC_IPADDR_ISMULTICAST(na->type.in.s_addr);
353
0
  case AF_INET6:
354
0
    return IN6_IS_ADDR_MULTICAST(&na->type.in6);
355
0
  default:
356
0
    return false; /* XXXMLG ? */
357
0
  }
358
0
}
359
360
bool
361
0
isc_netaddr_isexperimental(const isc_netaddr_t *na) {
362
0
  switch (na->family) {
363
0
  case AF_INET:
364
0
    return ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr);
365
0
  default:
366
0
    return false; /* XXXMLG ? */
367
0
  }
368
0
}
369
370
bool
371
0
isc_netaddr_islinklocal(const isc_netaddr_t *na) {
372
0
  switch (na->family) {
373
0
  case AF_INET:
374
0
    return false;
375
0
  case AF_INET6:
376
0
    return IN6_IS_ADDR_LINKLOCAL(&na->type.in6);
377
0
  default:
378
0
    return false;
379
0
  }
380
0
}
381
382
bool
383
0
isc_netaddr_issitelocal(const isc_netaddr_t *na) {
384
0
  switch (na->family) {
385
0
  case AF_INET:
386
0
    return false;
387
0
  case AF_INET6:
388
0
    return IN6_IS_ADDR_SITELOCAL(&na->type.in6);
389
0
  default:
390
0
    return false;
391
0
  }
392
0
}
393
394
#define ISC_IPADDR_ISNETZERO(i) \
395
0
  (((uint32_t)(i) & ISC__IPADDR(0xff000000)) == ISC__IPADDR(0x00000000))
396
397
bool
398
0
isc_netaddr_isnetzero(const isc_netaddr_t *na) {
399
0
  switch (na->family) {
400
0
  case AF_INET:
401
0
    return ISC_IPADDR_ISNETZERO(na->type.in.s_addr);
402
0
  case AF_INET6:
403
0
    return false;
404
0
  default:
405
0
    return false;
406
0
  }
407
0
}
408
409
void
410
0
isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
411
0
  isc_netaddr_t *src = UNCONST(s); /* Must come before
412
              IN6_IS_ADDR_V4MAPPED. */
413
414
0
  REQUIRE(s->family == AF_INET6);
415
0
  REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
416
417
0
  memset(t, 0, sizeof(*t));
418
0
  t->family = AF_INET;
419
0
  memmove(&t->type.in, (char *)&src->type.in6 + 12, 4);
420
0
  return;
421
0
}
422
423
bool
424
0
isc_netaddr_isloopback(const isc_netaddr_t *na) {
425
0
  switch (na->family) {
426
0
  case AF_INET:
427
0
    return (ntohl(na->type.in.s_addr) & 0xff000000U) == 0x7f000000U;
428
0
  case AF_INET6:
429
0
    return IN6_IS_ADDR_LOOPBACK(&na->type.in6);
430
0
  default:
431
0
    return false;
432
0
  }
433
0
}