Coverage Report

Created: 2026-09-04 06:33

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
void dnr_init_defaults(struct AdvDNR *dnr, struct Interface *iface)
174
0
{
175
0
  memset(dnr, 0, sizeof(struct AdvDNR));
176
177
0
  dnr->AdvDNRPriority = DFLT_AdvDNRPriority;
178
0
  dnr->AdvDNRLifetime = DFLT_AdvDNRLifetime(iface);
179
0
  dnr->FlushDNRFlag = DFLT_FlushDNRFlag;
180
0
}
181
182
int check_iface(struct Interface *iface)
183
0
{
184
0
  int res = 0;
185
0
  int MIPv6 = 0;
186
0
  struct in6_addr zeroaddr;
187
0
  memset(&zeroaddr, 0, sizeof(zeroaddr));
188
189
  /* Check if we use Mobile IPv6 extensions */
190
0
  if (iface->ra_header_info.AdvHomeAgentFlag || iface->mipv6.AdvHomeAgentInfo || iface->mipv6.AdvIntervalOpt) {
191
0
    MIPv6 = 1;
192
0
    flog(LOG_INFO, "using Mobile IPv6 extensions");
193
0
  }
194
195
  /* Check forwarding on interface */
196
0
  if (check_ip6_iface_forwarding(iface->props.name) < 1) {
197
0
    flog(LOG_WARNING, "IPv6 forwarding on interface seems to be disabled, but continuing anyway");
198
0
  }
199
200
0
  struct AdvPrefix *prefix = iface->AdvPrefixList;
201
0
  while (!MIPv6 && prefix) {
202
0
    if (prefix->AdvRouterAddr) {
203
0
      MIPv6 = 1;
204
0
    }
205
0
    prefix = prefix->next;
206
0
  }
207
208
0
  if (iface->MinRtrAdvInterval < 0)
209
0
    iface->MinRtrAdvInterval = DFLT_MinRtrAdvInterval(iface);
210
211
0
  if ((iface->MinRtrAdvInterval < (MIPv6 ? MIN_MinRtrAdvInterval_MIPv6 : MIN_MinRtrAdvInterval)) ||
212
0
      (iface->MinRtrAdvInterval > MAX_MinRtrAdvInterval(iface))) {
213
0
    flog(LOG_ERR,
214
0
         "MinRtrAdvInterval for %s (%.2f) must be at least %.2f but no more than 3/4 of MaxRtrAdvInterval (%.2f)",
215
0
         iface->props.name, iface->MinRtrAdvInterval,
216
0
         MIPv6 ? MIN_MinRtrAdvInterval_MIPv6 : (int)MIN_MinRtrAdvInterval, MAX_MinRtrAdvInterval(iface));
217
0
    res = -1;
218
0
  }
219
220
0
  if ((iface->MaxRtrAdvInterval < (MIPv6 ? MIN_MaxRtrAdvInterval_MIPv6 : MIN_MaxRtrAdvInterval)) ||
221
0
      (iface->MaxRtrAdvInterval > MAX_MaxRtrAdvInterval)) {
222
0
    flog(LOG_ERR, "MaxRtrAdvInterval for %s (%.2f) must be between %.2f and %d", iface->props.name,
223
0
         iface->MaxRtrAdvInterval, MIPv6 ? MIN_MaxRtrAdvInterval_MIPv6 : (int)MIN_MaxRtrAdvInterval,
224
0
         MAX_MaxRtrAdvInterval);
225
0
    res = -1;
226
0
  }
227
228
0
  if (iface->MinDelayBetweenRAs < (MIPv6 ? MIN_DELAY_BETWEEN_RAS_MIPv6 : MIN_DELAY_BETWEEN_RAS)) {
229
0
    flog(LOG_ERR, "MinDelayBetweenRAs for %s (%.2f) must be at least %.2f", iface->props.name,
230
0
         iface->MinDelayBetweenRAs, MIPv6 ? MIN_DELAY_BETWEEN_RAS_MIPv6 : MIN_DELAY_BETWEEN_RAS);
231
0
    res = -1;
232
0
  }
233
234
0
  if ((iface->AdvLinkMTU != 0) && ((iface->AdvLinkMTU < MIN_AdvLinkMTU) ||
235
0
           (iface->sllao.if_maxmtu != -1 && (iface->AdvLinkMTU > iface->sllao.if_maxmtu)))) {
236
0
    flog(LOG_ERR, "AdvLinkMTU for %s (%u) must be zero or between %u and %u", iface->props.name, iface->AdvLinkMTU,
237
0
         MIN_AdvLinkMTU, iface->sllao.if_maxmtu);
238
0
    res = -1;
239
0
  }
240
241
0
  if (iface->ra_header_info.AdvReachableTime > MAX_AdvReachableTime) {
242
0
    flog(LOG_ERR, "AdvReachableTime for %s (%u) must not be greater than %u", iface->props.name,
243
0
         iface->ra_header_info.AdvReachableTime, MAX_AdvReachableTime);
244
0
    res = -1;
245
0
  }
246
247
0
  if (iface->ra_header_info.AdvDefaultLifetime < 0)
248
0
    iface->ra_header_info.AdvDefaultLifetime = DFLT_AdvDefaultLifetime(iface);
249
250
0
  if ((iface->ra_header_info.AdvDefaultLifetime != 0) &&
251
0
      ((iface->ra_header_info.AdvDefaultLifetime > MAX_AdvDefaultLifetime) ||
252
0
       (iface->ra_header_info.AdvDefaultLifetime < MIN_AdvDefaultLifetime(iface)))) {
253
0
    flog(LOG_ERR, "AdvDefaultLifetime for %s (%u) must be zero or between %u and %u", iface->props.name,
254
0
         iface->ra_header_info.AdvDefaultLifetime, (int)MIN_AdvDefaultLifetime(iface), MAX_AdvDefaultLifetime);
255
0
    res = -1;
256
0
  }
257
258
  /* Mobile IPv6 ext */
259
0
  if (iface->mipv6.HomeAgentLifetime < 0)
260
0
    iface->mipv6.HomeAgentLifetime = DFLT_HomeAgentLifetime(iface);
261
262
  /* Mobile IPv6 ext */
263
0
  if (iface->mipv6.AdvHomeAgentInfo) {
264
0
    if ((iface->mipv6.HomeAgentLifetime > MAX_HomeAgentLifetime) ||
265
0
        (iface->mipv6.HomeAgentLifetime < MIN_HomeAgentLifetime)) {
266
0
      flog(LOG_ERR, "HomeAgentLifetime for %s (%u) must be between %u and %u", iface->props.name,
267
0
           iface->mipv6.HomeAgentLifetime, MIN_HomeAgentLifetime, MAX_HomeAgentLifetime);
268
0
      res = -1;
269
0
    }
270
0
  }
271
272
  /* Mobile IPv6 ext */
273
0
  if (iface->mipv6.AdvHomeAgentInfo && !(iface->ra_header_info.AdvHomeAgentFlag)) {
274
0
    flog(LOG_ERR, "AdvHomeAgentFlag for %s must be set with HomeAgentInfo", iface->props.name);
275
0
    res = -1;
276
0
  }
277
0
  if (iface->mipv6.AdvMobRtrSupportFlag && !(iface->mipv6.AdvHomeAgentInfo)) {
278
0
    flog(LOG_ERR, "AdvHomeAgentInfo for %s must be set with AdvMobRtrSupportFlag", iface->props.name);
279
0
    res = -1;
280
0
  }
281
282
  /* XXX: need this? prefix = iface->AdvPrefixList; */
283
284
0
  while (prefix) {
285
0
    if (prefix->PrefixLen > MAX_PrefixLen) {
286
0
      flog(LOG_ERR, "invalid prefix length (%u) for %s", prefix->PrefixLen, iface->props.name);
287
0
      res = -1;
288
0
    }
289
290
0
    if (prefix->AdvPreferredLifetime > prefix->AdvValidLifetime) {
291
0
      flog(LOG_ERR, "AdvValidLifetime for %s (%u) must be "
292
0
              "greater than or equal to AdvPreferredLifetime for",
293
0
           iface->props.name, prefix->AdvValidLifetime);
294
0
      res = -1;
295
0
    }
296
297
0
    prefix = prefix->next;
298
0
  }
299
300
0
  struct AdvRoute *route = iface->AdvRouteList;
301
0
  while (route) {
302
0
    if (route->PrefixLen > MAX_PrefixLen) {
303
0
      flog(LOG_ERR, "invalid route prefix length (%u) for %s", route->PrefixLen, iface->props.name);
304
0
      res = -1;
305
0
    }
306
307
    /* For the default route 0::/0, we need to explicitly check the
308
     * lifetime against the AdvDefaultLifetime value.
309
     *
310
     * If exactly one of the two has a zero value, then nodes processing
311
     * the RA may have a flap in their default route.
312
     *
313
     * AdvDefaultLifetime == 0 && route.AdvRouteLifetime > 0:
314
     * - default route is deleted and then re-added.
315
     * AdvDefaultLifetime > 0 && route.AdvRouteLifetime == 0:
316
     * - default route is added and then deleted.
317
     */
318
0
    if (IN6_IS_ADDR_UNSPECIFIED(&(route->Prefix))) {
319
0
      int route_zerolife = (route->AdvRouteLifetime == 0);
320
0
      int defaultroute_zerolife = (iface->ra_header_info.AdvDefaultLifetime == 0);
321
0
      if (route_zerolife ^ defaultroute_zerolife) {
322
0
        flog(
323
0
            LOG_ERR,
324
0
            "route 0::/0 lifetime (%u) conflicts with AdvDefaultLifetime (%u), default routes will flap!",
325
0
            route->AdvRouteLifetime, iface->ra_header_info.AdvDefaultLifetime);
326
        // res = -1; // In some future version, abort on this configuration error.
327
0
      }
328
0
    }
329
330
0
    route = route->next;
331
0
  }
332
333
0
  return res;
334
0
}
335
336
struct Interface *find_iface_by_index(struct Interface *iface, int index)
337
603
{
338
603
  for (; iface; iface = iface->next) {
339
603
    if (iface->props.if_index == index) {
340
603
      return iface;
341
603
    }
342
603
  }
343
344
0
  return 0;
345
603
}
346
347
struct Interface *find_iface_by_name(struct Interface *iface, const char *name)
348
0
{
349
0
  if (!name) {
350
0
    return 0;
351
0
  }
352
353
0
  for (; iface; iface = iface->next) {
354
0
    if (strcmp(iface->props.name, name) == 0) {
355
0
      return iface;
356
0
    }
357
0
  }
358
359
0
  return 0;
360
0
}
361
362
struct Interface *find_iface_by_time(struct Interface *iface)
363
0
{
364
0
  if (!iface) {
365
0
    return 0;
366
0
  }
367
368
0
  int timeout = next_time_msec(iface);
369
0
  struct Interface *next = iface;
370
371
0
  for (iface = iface->next; iface; iface = iface->next) {
372
0
    int t = next_time_msec(iface);
373
0
    if (timeout > t) {
374
0
      timeout = t;
375
0
      next = iface;
376
0
    }
377
0
  }
378
379
0
  return next;
380
0
}
381
382
void reschedule_iface(struct Interface *iface, double next)
383
25
{
384
#ifdef HAVE_NETLINK
385
  if (!iface->state_info.changed && !iface->state_info.ready) {
386
    next = 10 * iface->MaxRtrAdvInterval;
387
  } else if (next == 0) {
388
    next = IFACE_SETUP_DELAY;
389
  } else
390
#endif
391
25
      if (iface->state_info.racount < MAX_INITIAL_RTR_ADVERTISEMENTS) {
392
25
    next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, iface->MaxRtrAdvInterval);
393
25
  }
394
395
25
  dlog(LOG_DEBUG, 5, "%s next scheduled RA in %g second(s)", iface->props.name, next);
396
397
25
  iface->times.next_multicast = next_timespec(next);
398
25
}
399
400
void for_each_iface(struct Interface *ifaces, void (*foo)(struct Interface *, void *), void *data)
401
0
{
402
0
  for (; ifaces; ifaces = ifaces->next) {
403
0
    foo(ifaces, data);
404
0
  }
405
0
}
406
407
static void free_iface_list(struct Interface *iface)
408
633
{
409
633
  while (iface) {
410
0
    struct Interface *next_iface = iface->next;
411
412
0
    dlog(LOG_DEBUG, 4, "freeing interface %s", iface->props.name);
413
414
0
    struct AdvPrefix *prefix = iface->AdvPrefixList;
415
0
    while (prefix) {
416
0
      struct AdvPrefix *next_prefix = prefix->next;
417
418
0
      free(prefix);
419
0
      prefix = next_prefix;
420
0
    }
421
422
0
    struct AdvRoute *route = iface->AdvRouteList;
423
0
    while (route) {
424
0
      struct AdvRoute *next_route = route->next;
425
426
0
      free(route);
427
0
      route = next_route;
428
0
    }
429
430
0
    struct AdvRDNSS *rdnss = iface->AdvRDNSSList;
431
0
    while (rdnss) {
432
0
      struct AdvRDNSS *next_rdnss = rdnss->next;
433
434
0
      free(rdnss->AdvRDNSSAddr);
435
0
      free(rdnss);
436
0
      rdnss = next_rdnss;
437
0
    }
438
439
0
    struct AdvDNSSL *dnssl = iface->AdvDNSSLList;
440
0
    while (dnssl) {
441
0
      struct AdvDNSSL *next_dnssl = dnssl->next;
442
443
0
      for (int i = 0; i < dnssl->AdvDNSSLNumber; i++)
444
0
        free(dnssl->AdvDNSSLSuffixes[i]);
445
0
      free(dnssl->AdvDNSSLSuffixes);
446
0
      free(dnssl);
447
448
0
      dnssl = next_dnssl;
449
0
    }
450
451
0
    struct AdvDNR *dnr = iface->AdvDNRList;
452
0
    while (dnr) {
453
0
      struct AdvDNR *next_dnr = dnr->next;
454
455
0
      free(dnr->AdvDNRAddrs);
456
0
      free(dnr->AdvDNRADN);
457
0
      free(dnr->AdvDNRSvcAlpn);
458
0
      free(dnr->AdvDNRSvcDohpath);
459
0
      free(dnr);
460
461
0
      dnr = next_dnr;
462
0
    }
463
464
0
    struct AutogenIgnorePrefix *ignore_prefixes = iface->IgnorePrefixList;
465
0
    while (ignore_prefixes) {
466
0
      struct AutogenIgnorePrefix *next_ignore_prefix = ignore_prefixes->next;
467
468
0
      free(ignore_prefixes);
469
0
      ignore_prefixes = next_ignore_prefix;
470
0
    }
471
472
0
    struct Clients *clients = iface->ClientList;
473
0
    while (clients) {
474
0
      struct Clients *next_client = clients->next;
475
476
0
      free(clients);
477
0
      clients = next_client;
478
0
    }
479
480
0
    free(iface->props.if_addrs);
481
482
0
    free(iface->AdvCaptivePortalAPI);
483
484
0
    free(iface);
485
0
    iface = next_iface;
486
0
  }
487
633
}
488
489
void free_ifaces(struct Interface *ifaces)
490
633
{
491
633
  dlog(LOG_DEBUG, 3, "Freeing Interfaces");
492
493
633
  free_iface_list(ifaces);
494
633
}