Coverage Report

Created: 2026-05-29 06:57

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