Coverage Report

Created: 2026-08-13 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/radvd/interface.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 https://github.com/radvd-project/radvd/issues
12
 *
13
 */
14
15
#include "config.h"
16
#include "defaults.h"
17
#include "includes.h"
18
#include "radvd.h"
19
20
#define IFACE_SETUP_DELAY 1
21
22
void iface_init_defaults(struct Interface *iface)
23
0
{
24
0
  memset(iface, 0, sizeof(struct Interface));
25
26
0
  iface->state_info.changed = 1;
27
28
0
  iface->IgnoreIfMissing = DFLT_IgnoreIfMissing;
29
0
  iface->AdvSendAdvert = DFLT_AdvSendAdv;
30
0
  iface->MaxRtrAdvInterval = DFLT_MaxRtrAdvInterval;
31
0
  iface->AdvSourceLLAddress = DFLT_AdvSourceLLAddress;
32
0
  iface->RemoveAdvOnExit = DFLT_RemoveAdvOnExit;
33
0
  iface->MinDelayBetweenRAs = DFLT_MinDelayBetweenRAs;
34
0
  iface->MinRtrAdvInterval = -1;
35
0
  iface->UnicastOnly = DFLT_UnicastOnly;
36
0
  iface->UnrestrictedUnicast = DFLT_UnrestrictedUnicast;
37
0
  iface->AdvRASolicitedUnicast = DFLT_AdvRASolicitedUnicast;
38
39
0
  iface->ra_header_info.AdvDefaultPreference = DFLT_AdvDefaultPreference;
40
0
  iface->ra_header_info.AdvDefaultLifetime = -1;
41
0
  iface->ra_header_info.AdvReachableTime = DFLT_AdvReachableTime;
42
0
  iface->ra_header_info.AdvRetransTimer = DFLT_AdvRetransTimer;
43
0
  iface->ra_header_info.AdvCurHopLimit = DFLT_AdvCurHopLimit;
44
0
  iface->ra_header_info.AdvHomeAgentFlag = DFLT_AdvHomeAgentFlag;
45
0
  iface->ra_header_info.AdvSNACRouterFlag = DFLT_AdvSNACRouterFlag;
46
47
0
  iface->mipv6.AdvIntervalOpt = DFLT_AdvIntervalOpt;
48
0
  iface->mipv6.AdvHomeAgentInfo = DFLT_AdvHomeAgentInfo;
49
0
  iface->mipv6.HomeAgentPreference = DFLT_HomeAgentPreference;
50
0
  iface->mipv6.AdvMobRtrSupportFlag = DFLT_AdvMobRtrSupportFlag;
51
0
  iface->mipv6.HomeAgentLifetime = -1;
52
53
0
  iface->AdvLinkMTU = DFLT_AdvLinkMTU;
54
0
  iface->AdvRAMTU = DFLT_AdvRAMTU;
55
0
}
56
57
void touch_iface(struct Interface *iface)
58
0
{
59
0
  iface->state_info.changed = 1;
60
0
  iface->state_info.ready = 0;
61
0
  iface->state_info.racount = 0;
62
0
  reschedule_iface(iface, 0);
63
0
}
64
65
int setup_iface(int sock, struct Interface *iface)
66
25
{
67
25
  iface->state_info.changed = 0;
68
25
  iface->state_info.ready = 0;
69
70
  /* The device index must be setup first so we can search it later */
71
25
  if (update_device_index(iface) < 0) {
72
0
    return -1;
73
0
  }
74
75
  /* Check IFF_UP, IFF_RUNNING and IFF_MULTICAST */
76
25
  if (check_device(sock, iface) < 0) {
77
25
    return -2;
78
25
  }
79
80
  /* Set iface->max_mtu and iface hardware address */
81
0
  if (update_device_info(sock, iface) < 0) {
82
0
    return -3;
83
0
  }
84
85
  /* Make sure the settings in the config file for this interface are ok (this depends
86
   * on iface->max_mtu already being set). */
87
0
  if (check_iface(iface) < 0) {
88
0
    return -4;
89
0
  }
90
91
  /* Save the first link local address seen on the specified interface to
92
   * iface->props.if_addr and keep a list off all addrs in iface->props.if_addrs */
93
0
  if (setup_iface_addrs(iface) < 0) {
94
0
    return -5;
95
0
  }
96
97
  /* Check if we a usable RA source address */
98
0
  if (iface->props.if_addr_rasrc == NULL) {
99
0
    dlog(LOG_DEBUG, 5, "no configured AdvRASrcAddress present, skipping send");
100
0
    return -6;
101
0
  }
102
103
  /* join the allrouters multicast group so we get the solicitations */
104
0
  if (setup_allrouters_membership(sock, iface) < 0) {
105
0
    return -7;
106
0
  }
107
108
0
  iface->state_info.ready = 1;
109
110
0
  dlog(LOG_DEBUG, 4, "%s is ready", iface->props.name);
111
112
0
  return 0;
113
0
}
114
115
int cleanup_iface(int sock, struct Interface *iface)
116
0
{
117
  /* leave the allrouters multicast group */
118
0
  cleanup_allrouters_membership(sock, iface);
119
0
  return 0;
120
0
}
121
void prefix_init_defaults(struct AdvPrefix *prefix)
122
0
{
123
0
  memset(prefix, 0, sizeof(struct AdvPrefix));
124
125
0
  prefix->AdvOnLinkFlag = DFLT_AdvOnLinkFlag;
126
0
  prefix->AdvAutonomousFlag = DFLT_AdvAutonomousFlag;
127
0
  prefix->AdvRouterAddr = DFLT_AdvRouterAddr;
128
0
  prefix->AdvDHCPv6PDPreferredFlag = DFLT_AdvDHCPv6PDPreferredFlag;
129
0
  prefix->AdvValidLifetime = DFLT_AdvValidLifetime;
130
0
  prefix->AdvPreferredLifetime = DFLT_AdvPreferredLifetime;
131
0
  prefix->DeprecatePrefixFlag = DFLT_DeprecatePrefixFlag;
132
0
  prefix->DecrementLifetimesFlag = DFLT_DecrementLifetimesFlag;
133
134
0
  prefix->curr_validlft = prefix->AdvValidLifetime;
135
0
  prefix->curr_preferredlft = prefix->AdvPreferredLifetime;
136
0
}
137
138
void nat64prefix_init_defaults(struct NAT64Prefix *prefix, struct Interface *iface)
139
0
{
140
0
  memset(prefix, 0, sizeof(struct NAT64Prefix));
141
142
0
  prefix->AdvValidLifetime = min(DFLT_NAT64MaxValidLifetime, 3*(iface->MaxRtrAdvInterval));
143
144
0
  prefix->curr_validlft = prefix->AdvValidLifetime;
145
0
}
146
147
void route_init_defaults(struct AdvRoute *route, struct Interface *iface)
148
0
{
149
0
  memset(route, 0, sizeof(struct AdvRoute));
150
151
0
  route->AdvRouteLifetime = DFLT_AdvRouteLifetime(iface);
152
0
  route->AdvRoutePreference = DFLT_AdvRoutePreference;
153
0
  route->RemoveRouteFlag = DFLT_RemoveRouteFlag;
154
0
}
155
156
void rdnss_init_defaults(struct AdvRDNSS *rdnss, struct Interface *iface)
157
0
{
158
0
  memset(rdnss, 0, sizeof(struct AdvRDNSS));
159
160
0
  rdnss->AdvRDNSSLifetime = DFLT_AdvRDNSSLifetime(iface);
161
0
  rdnss->AdvRDNSSNumber = 0;
162
0
  rdnss->FlushRDNSSFlag = DFLT_FlushRDNSSFlag;
163
0
}
164
165
void dnssl_init_defaults(struct AdvDNSSL *dnssl, struct Interface *iface)
166
0
{
167
0
  memset(dnssl, 0, sizeof(struct AdvDNSSL));
168
169
0
  dnssl->AdvDNSSLLifetime = DFLT_AdvDNSSLLifetime(iface);
170
0
  dnssl->FlushDNSSLFlag = DFLT_FlushDNSSLFlag;
171
0
}
172
173
int check_iface(struct Interface *iface)
174
0
{
175
0
  int res = 0;
176
0
  int MIPv6 = 0;
177
0
  struct in6_addr zeroaddr;
178
0
  memset(&zeroaddr, 0, sizeof(zeroaddr));
179
180
  /* Check if we use Mobile IPv6 extensions */
181
0
  if (iface->ra_header_info.AdvHomeAgentFlag || iface->mipv6.AdvHomeAgentInfo || iface->mipv6.AdvIntervalOpt) {
182
0
    MIPv6 = 1;
183
0
    flog(LOG_INFO, "using Mobile IPv6 extensions");
184
0
  }
185
186
  /* Check forwarding on interface */
187
0
  if (check_ip6_iface_forwarding(iface->props.name) < 1) {
188
0
    flog(LOG_WARNING, "IPv6 forwarding on interface seems to be disabled, but continuing anyway");
189
0
  }
190
191
0
  struct AdvPrefix *prefix = iface->AdvPrefixList;
192
0
  while (!MIPv6 && prefix) {
193
0
    if (prefix->AdvRouterAddr) {
194
0
      MIPv6 = 1;
195
0
    }
196
0
    prefix = prefix->next;
197
0
  }
198
199
0
  if (iface->MinRtrAdvInterval < 0)
200
0
    iface->MinRtrAdvInterval = DFLT_MinRtrAdvInterval(iface);
201
202
0
  if ((iface->MinRtrAdvInterval < (MIPv6 ? MIN_MinRtrAdvInterval_MIPv6 : MIN_MinRtrAdvInterval)) ||
203
0
      (iface->MinRtrAdvInterval > MAX_MinRtrAdvInterval(iface))) {
204
0
    flog(LOG_ERR,
205
0
         "MinRtrAdvInterval for %s (%.2f) must be at least %.2f but no more than 3/4 of MaxRtrAdvInterval (%.2f)",
206
0
         iface->props.name, iface->MinRtrAdvInterval,
207
0
         MIPv6 ? MIN_MinRtrAdvInterval_MIPv6 : (int)MIN_MinRtrAdvInterval, MAX_MinRtrAdvInterval(iface));
208
0
    res = -1;
209
0
  }
210
211
0
  if ((iface->MaxRtrAdvInterval < (MIPv6 ? MIN_MaxRtrAdvInterval_MIPv6 : MIN_MaxRtrAdvInterval)) ||
212
0
      (iface->MaxRtrAdvInterval > MAX_MaxRtrAdvInterval)) {
213
0
    flog(LOG_ERR, "MaxRtrAdvInterval for %s (%.2f) must be between %.2f and %d", iface->props.name,
214
0
         iface->MaxRtrAdvInterval, MIPv6 ? MIN_MaxRtrAdvInterval_MIPv6 : (int)MIN_MaxRtrAdvInterval,
215
0
         MAX_MaxRtrAdvInterval);
216
0
    res = -1;
217
0
  }
218
219
0
  if (iface->MinDelayBetweenRAs < (MIPv6 ? MIN_DELAY_BETWEEN_RAS_MIPv6 : MIN_DELAY_BETWEEN_RAS)) {
220
0
    flog(LOG_ERR, "MinDelayBetweenRAs for %s (%.2f) must be at least %.2f", iface->props.name,
221
0
         iface->MinDelayBetweenRAs, MIPv6 ? MIN_DELAY_BETWEEN_RAS_MIPv6 : MIN_DELAY_BETWEEN_RAS);
222
0
    res = -1;
223
0
  }
224
225
0
  if ((iface->AdvLinkMTU != 0) && ((iface->AdvLinkMTU < MIN_AdvLinkMTU) ||
226
0
           (iface->sllao.if_maxmtu != -1 && (iface->AdvLinkMTU > iface->sllao.if_maxmtu)))) {
227
0
    flog(LOG_ERR, "AdvLinkMTU for %s (%u) must be zero or between %u and %u", iface->props.name, iface->AdvLinkMTU,
228
0
         MIN_AdvLinkMTU, iface->sllao.if_maxmtu);
229
0
    res = -1;
230
0
  }
231
232
0
  if (iface->ra_header_info.AdvReachableTime > MAX_AdvReachableTime) {
233
0
    flog(LOG_ERR, "AdvReachableTime for %s (%u) must not be greater than %u", iface->props.name,
234
0
         iface->ra_header_info.AdvReachableTime, MAX_AdvReachableTime);
235
0
    res = -1;
236
0
  }
237
238
0
  if (iface->ra_header_info.AdvDefaultLifetime < 0)
239
0
    iface->ra_header_info.AdvDefaultLifetime = DFLT_AdvDefaultLifetime(iface);
240
241
0
  if ((iface->ra_header_info.AdvDefaultLifetime != 0) &&
242
0
      ((iface->ra_header_info.AdvDefaultLifetime > MAX_AdvDefaultLifetime) ||
243
0
       (iface->ra_header_info.AdvDefaultLifetime < MIN_AdvDefaultLifetime(iface)))) {
244
0
    flog(LOG_ERR, "AdvDefaultLifetime for %s (%u) must be zero or between %u and %u", iface->props.name,
245
0
         iface->ra_header_info.AdvDefaultLifetime, (int)MIN_AdvDefaultLifetime(iface), MAX_AdvDefaultLifetime);
246
0
    res = -1;
247
0
  }
248
249
  /* Mobile IPv6 ext */
250
0
  if (iface->mipv6.HomeAgentLifetime < 0)
251
0
    iface->mipv6.HomeAgentLifetime = DFLT_HomeAgentLifetime(iface);
252
253
  /* Mobile IPv6 ext */
254
0
  if (iface->mipv6.AdvHomeAgentInfo) {
255
0
    if ((iface->mipv6.HomeAgentLifetime > MAX_HomeAgentLifetime) ||
256
0
        (iface->mipv6.HomeAgentLifetime < MIN_HomeAgentLifetime)) {
257
0
      flog(LOG_ERR, "HomeAgentLifetime for %s (%u) must be between %u and %u", iface->props.name,
258
0
           iface->mipv6.HomeAgentLifetime, MIN_HomeAgentLifetime, MAX_HomeAgentLifetime);
259
0
      res = -1;
260
0
    }
261
0
  }
262
263
  /* Mobile IPv6 ext */
264
0
  if (iface->mipv6.AdvHomeAgentInfo && !(iface->ra_header_info.AdvHomeAgentFlag)) {
265
0
    flog(LOG_ERR, "AdvHomeAgentFlag for %s must be set with HomeAgentInfo", iface->props.name);
266
0
    res = -1;
267
0
  }
268
0
  if (iface->mipv6.AdvMobRtrSupportFlag && !(iface->mipv6.AdvHomeAgentInfo)) {
269
0
    flog(LOG_ERR, "AdvHomeAgentInfo for %s must be set with AdvMobRtrSupportFlag", iface->props.name);
270
0
    res = -1;
271
0
  }
272
273
  /* XXX: need this? prefix = iface->AdvPrefixList; */
274
275
0
  while (prefix) {
276
0
    if (prefix->PrefixLen > MAX_PrefixLen) {
277
0
      flog(LOG_ERR, "invalid prefix length (%u) for %s", prefix->PrefixLen, iface->props.name);
278
0
      res = -1;
279
0
    }
280
281
0
    if (prefix->AdvPreferredLifetime > prefix->AdvValidLifetime) {
282
0
      flog(LOG_ERR, "AdvValidLifetime for %s (%u) must be "
283
0
              "greater than or equal to AdvPreferredLifetime for",
284
0
           iface->props.name, prefix->AdvValidLifetime);
285
0
      res = -1;
286
0
    }
287
288
0
    prefix = prefix->next;
289
0
  }
290
291
0
  struct AdvRoute *route = iface->AdvRouteList;
292
0
  while (route) {
293
0
    if (route->PrefixLen > MAX_PrefixLen) {
294
0
      flog(LOG_ERR, "invalid route prefix length (%u) for %s", route->PrefixLen, iface->props.name);
295
0
      res = -1;
296
0
    }
297
298
    /* For the default route 0::/0, we need to explicitly check the
299
     * lifetime against the AdvDefaultLifetime value.
300
     *
301
     * If exactly one of the two has a zero value, then nodes processing
302
     * the RA may have a flap in their default route.
303
     *
304
     * AdvDefaultLifetime == 0 && route.AdvRouteLifetime > 0:
305
     * - default route is deleted and then re-added.
306
     * AdvDefaultLifetime > 0 && route.AdvRouteLifetime == 0:
307
     * - default route is added and then deleted.
308
     */
309
0
    if (IN6_IS_ADDR_UNSPECIFIED(&(route->Prefix))) {
310
0
      int route_zerolife = (route->AdvRouteLifetime == 0);
311
0
      int defaultroute_zerolife = (iface->ra_header_info.AdvDefaultLifetime == 0);
312
0
      if (route_zerolife ^ defaultroute_zerolife) {
313
0
        flog(
314
0
            LOG_ERR,
315
0
            "route 0::/0 lifetime (%u) conflicts with AdvDefaultLifetime (%u), default routes will flap!",
316
0
            route->AdvRouteLifetime, iface->ra_header_info.AdvDefaultLifetime);
317
        // res = -1; // In some future version, abort on this configuration error.
318
0
      }
319
0
    }
320
321
0
    route = route->next;
322
0
  }
323
324
0
  return res;
325
0
}
326
327
struct Interface *find_iface_by_index(struct Interface *iface, int index)
328
594
{
329
594
  for (; iface; iface = iface->next) {
330
594
    if (iface->props.if_index == index) {
331
594
      return iface;
332
594
    }
333
594
  }
334
335
0
  return 0;
336
594
}
337
338
struct Interface *find_iface_by_name(struct Interface *iface, const char *name)
339
0
{
340
0
  if (!name) {
341
0
    return 0;
342
0
  }
343
344
0
  for (; iface; iface = iface->next) {
345
0
    if (strcmp(iface->props.name, name) == 0) {
346
0
      return iface;
347
0
    }
348
0
  }
349
350
0
  return 0;
351
0
}
352
353
struct Interface *find_iface_by_time(struct Interface *iface)
354
0
{
355
0
  if (!iface) {
356
0
    return 0;
357
0
  }
358
359
0
  int timeout = next_time_msec(iface);
360
0
  struct Interface *next = iface;
361
362
0
  for (iface = iface->next; iface; iface = iface->next) {
363
0
    int t = next_time_msec(iface);
364
0
    if (timeout > t) {
365
0
      timeout = t;
366
0
      next = iface;
367
0
    }
368
0
  }
369
370
0
  return next;
371
0
}
372
373
void reschedule_iface(struct Interface *iface, double next)
374
25
{
375
#ifdef HAVE_NETLINK
376
  if (!iface->state_info.changed && !iface->state_info.ready) {
377
    next = 10 * iface->MaxRtrAdvInterval;
378
  } else if (next == 0) {
379
    next = IFACE_SETUP_DELAY;
380
  } else
381
#endif
382
25
      if (iface->state_info.racount < MAX_INITIAL_RTR_ADVERTISEMENTS) {
383
25
    next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, iface->MaxRtrAdvInterval);
384
25
  }
385
386
25
  dlog(LOG_DEBUG, 5, "%s next scheduled RA in %g second(s)", iface->props.name, next);
387
388
25
  iface->times.next_multicast = next_timespec(next);
389
25
}
390
391
void for_each_iface(struct Interface *ifaces, void (*foo)(struct Interface *, void *), void *data)
392
0
{
393
0
  for (; ifaces; ifaces = ifaces->next) {
394
0
    foo(ifaces, data);
395
0
  }
396
0
}
397
398
static void free_iface_list(struct Interface *iface)
399
606
{
400
606
  while (iface) {
401
0
    struct Interface *next_iface = iface->next;
402
403
0
    dlog(LOG_DEBUG, 4, "freeing interface %s", iface->props.name);
404
405
0
    struct AdvPrefix *prefix = iface->AdvPrefixList;
406
0
    while (prefix) {
407
0
      struct AdvPrefix *next_prefix = prefix->next;
408
409
0
      free(prefix);
410
0
      prefix = next_prefix;
411
0
    }
412
413
0
    struct AdvRoute *route = iface->AdvRouteList;
414
0
    while (route) {
415
0
      struct AdvRoute *next_route = route->next;
416
417
0
      free(route);
418
0
      route = next_route;
419
0
    }
420
421
0
    struct AdvRDNSS *rdnss = iface->AdvRDNSSList;
422
0
    while (rdnss) {
423
0
      struct AdvRDNSS *next_rdnss = rdnss->next;
424
425
0
      free(rdnss->AdvRDNSSAddr);
426
0
      free(rdnss);
427
0
      rdnss = next_rdnss;
428
0
    }
429
430
0
    struct AdvDNSSL *dnssl = iface->AdvDNSSLList;
431
0
    while (dnssl) {
432
0
      struct AdvDNSSL *next_dnssl = dnssl->next;
433
434
0
      for (int i = 0; i < dnssl->AdvDNSSLNumber; i++)
435
0
        free(dnssl->AdvDNSSLSuffixes[i]);
436
0
      free(dnssl->AdvDNSSLSuffixes);
437
0
      free(dnssl);
438
439
0
      dnssl = next_dnssl;
440
0
    }
441
442
0
    struct AutogenIgnorePrefix *ignore_prefixes = iface->IgnorePrefixList;
443
0
    while (ignore_prefixes) {
444
0
      struct AutogenIgnorePrefix *next_ignore_prefix = ignore_prefixes->next;
445
446
0
      free(ignore_prefixes);
447
0
      ignore_prefixes = next_ignore_prefix;
448
0
    }
449
450
0
    struct Clients *clients = iface->ClientList;
451
0
    while (clients) {
452
0
      struct Clients *next_client = clients->next;
453
454
0
      free(clients);
455
0
      clients = next_client;
456
0
    }
457
458
0
    free(iface->props.if_addrs);
459
460
0
    free(iface->AdvCaptivePortalAPI);
461
462
0
    free(iface);
463
0
    iface = next_iface;
464
0
  }
465
606
}
466
467
void free_ifaces(struct Interface *ifaces)
468
606
{
469
606
  dlog(LOG_DEBUG, 3, "Freeing Interfaces");
470
471
606
  free_iface_list(ifaces);
472
606
}