Coverage Report

Created: 2026-03-15 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/radvd/util.c
Line
Count
Source
1
/*
2
 *
3
 *   Authors:
4
 *    Lars Fenneberg    <lf@elemental.net>
5
 *
6
 *   This software is Copyright 1996,1997 by the above mentioned author(s),
7
 *   All Rights Reserved.
8
 *
9
 *   The license which is distributed with this software in the file COPYRIGHT
10
 *   applies to this software. If your distribution is missing this file, you
11
 *   may request it from <reubenhwk@gmail.com>.
12
 *
13
 */
14
15
#include "config.h"
16
#include "includes.h"
17
#include "radvd.h"
18
19
#ifdef UNIT_TEST
20
#include "test/util.c"
21
#endif
22
23
struct safe_buffer *new_safe_buffer(void)
24
0
{
25
0
  struct safe_buffer *sb = malloc(sizeof(struct safe_buffer));
26
0
  *sb = SAFE_BUFFER_INIT;
27
0
  sb->should_free = 1;
28
0
  return sb;
29
0
}
30
31
void safe_buffer_free(struct safe_buffer *sb)
32
0
{
33
0
  if (sb && sb->buffer) {
34
0
    free(sb->buffer);
35
0
    sb->buffer = NULL;
36
0
  }
37
38
0
  if (sb && sb->should_free) {
39
0
    free(sb);
40
0
    sb = NULL;
41
0
  }
42
0
}
43
44
/**
45
 * Requests that the safe_buffer capacity be least n bytes in size.
46
 *
47
 * If n is greater than the current capacity, the function causes the container
48
 * to reallocate its storage increasing its capacity to n (or greater).
49
 *
50
 * In all other cases, the function call does not cause a reallocation and the
51
 * capacity is not affected.
52
 *
53
 * @param sb safe_buffer to enlarge
54
 * @param b Minimum capacity for the safe_buffer.
55
 */
56
void safe_buffer_resize(struct safe_buffer *sb, size_t n)
57
0
{
58
0
  const int blocksize = 1 << 6; // MUST BE POWER OF 2.
59
0
  if (sb->allocated < n) {
60
0
    if (n % blocksize > 0) {
61
0
      n |= (blocksize - 1); // Set all the low bits
62
0
      n++;
63
0
    }
64
0
    if (n > 64 * 1024) {
65
0
      flog(LOG_ERR, "Requested buffer too large for any possible IPv6 ND, even with jumbogram.  Exiting.");
66
0
      exit(1);
67
0
    }
68
0
    sb->allocated = n;
69
0
    sb->buffer = realloc(sb->buffer, sb->allocated);
70
0
  }
71
0
}
72
73
size_t safe_buffer_pad(struct safe_buffer *sb, size_t count)
74
0
{
75
0
  safe_buffer_resize(sb, sb->used + count);
76
0
  memset(&sb->buffer[sb->used], (uint8_t)0, count);
77
0
  sb->used += count;
78
0
  return count;
79
0
}
80
81
size_t safe_buffer_append(struct safe_buffer *sb, void const *v, size_t count)
82
0
{
83
0
  if (sb) {
84
0
    unsigned const char *m = (unsigned const char *)v;
85
0
    safe_buffer_resize(sb, sb->used + count);
86
0
    memcpy(&sb->buffer[sb->used], m, count);
87
0
    sb->used += count;
88
0
  }
89
90
0
  return count;
91
0
}
92
93
/**
94
 * Create a new safe_buffer_list
95
 *
96
 * @return new safe_buffer_list, with a safe_buffer on the heap.
97
 */
98
struct safe_buffer_list *new_safe_buffer_list(void)
99
0
{
100
0
  struct safe_buffer_list *sbl = malloc(sizeof(struct safe_buffer_list));
101
0
  sbl->sb = new_safe_buffer();
102
0
  sbl->next = NULL;
103
0
  return sbl;
104
0
}
105
106
/**
107
 * Ensure list tail has an empty buffer ready to accept data.
108
 *
109
 * If the present element is empty of data, just return it.
110
 * Otherwise return a new safe_buffer_list ready to accept data.
111
 *
112
 * @param sbl safe_buffer_list.
113
 * @return new tail of list.
114
 */
115
struct safe_buffer_list *safe_buffer_list_append(struct safe_buffer_list *sbl)
116
0
{
117
  // Only allocate a new entry if this one has bytes in it.
118
0
  if (sbl->sb && sbl->sb->used > 0) {
119
0
    struct safe_buffer_list *next = new_safe_buffer_list();
120
0
    sbl->next = next;
121
0
    sbl = next;
122
0
  }
123
0
  return sbl;
124
0
}
125
126
/**
127
 * Convert an entire safe_buffer_list to a single safe_buffer.
128
 *
129
 * @param sbl safe_buffer_list source.
130
 * @param sb  safe_buffer destination.
131
 */
132
void safe_buffer_list_to_safe_buffer(struct safe_buffer_list *sbl, struct safe_buffer *sb)
133
0
{
134
0
  struct safe_buffer_list *cur;
135
0
  for (cur = sbl; cur; cur = cur->next) {
136
0
    if (cur->sb)
137
0
      safe_buffer_append(sb, cur->sb->buffer, cur->sb->used);
138
0
  }
139
0
}
140
141
/**
142
 * Free all memory used by a safe_buffer_list
143
 *
144
 * @param sbl safe_buffer_list to free.
145
 */
146
void safe_buffer_list_free(struct safe_buffer_list *sbl)
147
0
{
148
0
  struct safe_buffer_list *next;
149
0
  for (struct safe_buffer_list *current = sbl; current; current = next) {
150
0
    if (current->sb) {
151
0
      safe_buffer_free(current->sb);
152
0
      current->sb = NULL;
153
0
    }
154
0
    next = current->next;
155
0
    free(current);
156
0
  }
157
0
}
158
159
__attribute__((format(printf, 1, 2))) char *strdupf(char const *format, ...)
160
0
{
161
0
  va_list va;
162
0
  va_start(va, format);
163
0
  char *strp = 0;
164
0
  int rc = vasprintf(&strp, format, va);
165
0
  if (rc == -1 || !strp) {
166
0
    flog(LOG_ERR, "vasprintf failed: %s", strerror(errno));
167
0
    exit(-1);
168
0
  }
169
0
  va_end(va);
170
171
0
  return strp;
172
0
}
173
174
0
double rand_between(double lower, double upper) { return ((upper - lower) / (RAND_MAX + 1.0) * rand() + lower); }
175
176
/* This assumes that str is not null and str_size > 0 */
177
void addrtostr(struct in6_addr const *addr, char *str, size_t str_size)
178
0
{
179
0
  const char *res;
180
181
0
  res = inet_ntop(AF_INET6, (void const *)addr, str, str_size);
182
183
0
  if (res == NULL) {
184
0
    flog(LOG_ERR, "addrtostr: inet_ntop: %s", strerror(errno));
185
0
    strncpy(str, "[invalid address]", str_size);
186
0
    str[str_size - 1] = '\0';
187
0
  }
188
0
}
189
190
/* Check if an in6_addr exists in the rdnss list */
191
int check_rdnss_presence(struct AdvRDNSS *rdnss, struct in6_addr *addr)
192
0
{
193
0
  while (rdnss) {
194
0
    for (int i = 0; i < rdnss->AdvRDNSSNumber; i++) {
195
0
      if (!memcmp(&rdnss->AdvRDNSSAddr[i], addr, sizeof(struct in6_addr)))
196
0
        return 1; /* rdnss address found in the list */
197
0
    }
198
0
    rdnss = rdnss->next;
199
0
  }
200
0
  return 0;
201
0
}
202
203
/* Check if a suffix exists in the dnssl list */
204
int check_dnssl_presence(struct AdvDNSSL *dnssl, const char *suffix)
205
0
{
206
0
  while (dnssl) {
207
0
    for (int i = 0; i < dnssl->AdvDNSSLNumber; ++i) {
208
0
      if (0 == strcmp(dnssl->AdvDNSSLSuffixes[i], suffix))
209
0
        return 1; /* suffix found in the list */
210
0
    }
211
0
    dnssl = dnssl->next;
212
0
  }
213
0
  return 0;
214
0
}
215
216
/* Like read(), but retries in case of partial read */
217
ssize_t readn(int fd, void *buf, size_t count)
218
0
{
219
0
  size_t n = 0;
220
0
  while (count > 0) {
221
0
    int r = read(fd, buf, count);
222
0
    if (r < 0) {
223
0
      if (errno == EINTR)
224
0
        continue;
225
0
      return r;
226
0
    }
227
0
    if (r == 0)
228
0
      return n;
229
0
    buf = (char *)buf + r;
230
0
    count -= r;
231
0
    n += r;
232
0
  }
233
0
  return n;
234
0
}
235
236
/* Like write(), but retries in case of partial write */
237
ssize_t writen(int fd, const void *buf, size_t count)
238
0
{
239
0
  size_t n = 0;
240
0
  while (count > 0) {
241
0
    int r = write(fd, buf, count);
242
0
    if (r < 0) {
243
0
      if (errno == EINTR)
244
0
        continue;
245
0
      return r;
246
0
    }
247
0
    if (r == 0)
248
0
      return n;
249
0
    buf = (const char *)buf + r;
250
0
    count -= r;
251
0
    n += r;
252
0
  }
253
0
  return n;
254
0
}
255
256
int countbits(int b)
257
0
{
258
0
  int count;
259
260
0
  for (count = 0; b != 0; count++) {
261
0
    b &= b - 1; // this clears the LSB-most set bit
262
0
  }
263
264
0
  return (count);
265
0
}
266
267
int count_mask(struct sockaddr_in6 *m)
268
0
{
269
0
  struct in6_addr *in6 = &m->sin6_addr;
270
0
  int i;
271
0
  int count = 0;
272
273
0
  for (i = 0; i < 16; ++i) {
274
0
    count += countbits(in6->s6_addr[i]);
275
0
  }
276
0
  return count;
277
0
}
278
279
struct in6_addr get_prefix6(struct in6_addr const *addr, struct in6_addr const *mask)
280
0
{
281
0
  struct in6_addr prefix = *addr;
282
0
  int i = 0;
283
284
0
  for (; i < 16; ++i) {
285
0
    prefix.s6_addr[i] &= mask->s6_addr[i];
286
0
  }
287
288
0
  return prefix;
289
0
}