Coverage Report

Created: 2025-07-09 06:38

/src/dnsmasq/src/radv.c
Line
Count
Source (jump to first uncovered line)
1
/* dnsmasq is Copyright (c) 2000-2025 Simon Kelley
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 dated June, 1991, or
6
   (at your option) version 3 dated 29 June, 2007.
7
 
8
   This program is distributed in the hope that it will be useful,
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
   GNU General Public License for more details.
12
     
13
   You should have received a copy of the GNU General Public License
14
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
*/
16
17
18
/* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
19
   It therefore cannot use any DHCP buffer resources except outpacket, which is
20
   not used by DHCPv4 code. This code may also be called when DHCP 4 or 6 isn't
21
   active, so we ensure that outpacket is allocated here too */
22
23
#include "dnsmasq.h"
24
25
#ifdef HAVE_DHCP6
26
27
#include <netinet/icmp6.h>
28
29
struct ra_param {
30
  time_t now;
31
  int ind, managed, other, first, adv_router;
32
  char *if_name;
33
  struct dhcp_netid *tags;
34
  struct in6_addr link_local, link_global, ula;
35
  unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval, prio;
36
  struct dhcp_context *found_context;
37
};
38
39
struct search_param {
40
  time_t now; int iface;
41
  char name[IF_NAMESIZE+1];
42
};
43
44
struct alias_param {
45
  int iface;
46
  struct dhcp_bridge *bridge;
47
  int num_alias_ifs;
48
  int max_alias_ifs;
49
  int *alias_ifs;
50
};
51
52
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
53
static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest,
54
                    int send_iface);
55
static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm);
56
static int add_prefixes(struct in6_addr *local,  int prefix,
57
      int scope, int if_index, int flags, 
58
      unsigned int preferred, unsigned int valid, void *vparam);
59
static int iface_search(struct in6_addr *local,  int prefix,
60
      int scope, int if_index, int flags, 
61
      unsigned int prefered, unsigned int valid, void *vparam);
62
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
63
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
64
static unsigned int calc_lifetime(struct ra_interface *ra);
65
static unsigned int calc_interval(struct ra_interface *ra);
66
static unsigned int calc_prio(struct ra_interface *ra);
67
static struct ra_interface *find_iface_param(char *iface);
68
69
static int hop_limit;
70
71
void ra_init(time_t now)
72
0
{
73
0
  struct icmp6_filter filter;
74
0
  int fd;
75
0
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
76
0
  int class = IPTOS_CLASS_CS6;
77
0
#endif
78
0
  int val = 255; /* radvd uses this value */
79
0
  socklen_t len = sizeof(int);
80
0
  struct dhcp_context *context;
81
  
82
  /* ensure this is around even if we're not doing DHCPv6 */
83
0
  expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
84
 
85
  /* See if we're guessing SLAAC addresses, if so we need to receive ping replies */
86
0
  for (context = daemon->dhcp6; context; context = context->next)
87
0
    if ((context->flags & CONTEXT_RA_NAME))
88
0
      break;
89
  
90
  /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
91
92
0
  ICMP6_FILTER_SETBLOCKALL(&filter);
93
0
  if (daemon->doing_ra)
94
0
    {
95
0
      ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
96
0
      if (context)
97
0
  ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
98
0
    }
99
  
100
0
  if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
101
0
      getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
102
0
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
103
0
      setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
104
0
#endif
105
0
      !fix_fd(fd) ||
106
0
      !set_ipv6pktinfo(fd) ||
107
0
      setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
108
0
      setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
109
0
      setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
110
0
    die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
111
  
112
0
   daemon->icmp6fd = fd;
113
   
114
0
   if (daemon->doing_ra)
115
0
     ra_start_unsolicited(now, NULL);
116
0
}
117
118
void ra_start_unsolicited(time_t now, struct dhcp_context *context)
119
0
{   
120
   /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
121
     if it's not appropriate to advertise those contexts.
122
     This gets re-called on a netlink route-change to re-do the advertisement
123
     and pick up new interfaces */
124
  
125
0
  if (context)
126
0
    {
127
0
      context->ra_short_period_start = now;
128
      /* start after 1 second to get logging right at startup. */
129
0
      context->ra_time = now + 1;
130
0
    }
131
0
  else
132
0
    for (context = daemon->dhcp6; context; context = context->next)
133
0
      if (!(context->flags & CONTEXT_TEMPLATE))
134
0
  {
135
0
    context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
136
    /* re-do frequently for a minute or so, in case the first gets lost. */
137
0
    context->ra_short_period_start = now;
138
0
  }
139
0
}
140
141
void icmp6_packet(time_t now)
142
0
{
143
0
  char interface[IF_NAMESIZE+1];
144
0
  ssize_t sz; 
145
0
  int if_index = 0;
146
0
  struct cmsghdr *cmptr;
147
0
  struct msghdr msg;
148
0
  union {
149
0
    struct cmsghdr align; /* this ensures alignment */
150
0
    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
151
0
  } control_u;
152
0
  struct sockaddr_in6 from;
153
0
  unsigned char *packet;
154
0
  struct iname *tmp;
155
156
  /* Note: use outpacket for input buffer */
157
0
  msg.msg_control = control_u.control6;
158
0
  msg.msg_controllen = sizeof(control_u);
159
0
  msg.msg_flags = 0;
160
0
  msg.msg_name = &from;
161
0
  msg.msg_namelen = sizeof(from);
162
0
  msg.msg_iov = &daemon->outpacket;
163
0
  msg.msg_iovlen = 1;
164
  
165
0
  if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
166
0
    return;
167
   
168
0
  packet = (unsigned char *)daemon->outpacket.iov_base;
169
170
0
  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
171
0
    if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
172
0
      {
173
0
  union {
174
0
    unsigned char *c;
175
0
    struct in6_pktinfo *p;
176
0
  } p;
177
0
  p.c = CMSG_DATA(cmptr);
178
        
179
0
  if_index = p.p->ipi6_ifindex;
180
0
      }
181
  
182
0
  if (!indextoname(daemon->icmp6fd, if_index, interface))
183
0
    return;
184
    
185
0
  if (!iface_check(AF_LOCAL, NULL, interface, NULL))
186
0
    return;
187
  
188
0
  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
189
0
    if (tmp->name && (tmp->flags & INAME_6) &&
190
0
  wildcard_match(tmp->name, interface))
191
0
      return;
192
 
193
0
  if (packet[1] != 0)
194
0
    return;
195
196
0
  if (packet[0] == ICMP6_ECHO_REPLY)
197
0
    lease_ping_reply(&from.sin6_addr, packet, interface); 
198
0
  else if (packet[0] == ND_ROUTER_SOLICIT)
199
0
    {
200
0
      char *mac = "";
201
0
      struct dhcp_bridge *bridge, *alias;
202
0
      ssize_t rem;
203
0
      unsigned char *p;
204
0
      int opt_sz;
205
      
206
0
#ifdef HAVE_DUMPFILE
207
0
      dump_packet_icmp(DUMP_RA, (void *)packet, sz, (union mysockaddr *)&from, NULL);
208
0
#endif           
209
      
210
      /* look for link-layer address option for logging */
211
0
      for (rem = sz - 8, p = &packet[8]; rem >= 2; rem -= opt_sz, p += opt_sz)
212
0
  {
213
0
    opt_sz = p[1] * 8;
214
    
215
0
    if (opt_sz == 0 || opt_sz > rem)
216
0
      return; /* Bad packet */
217
    
218
0
    if (p[0] == ICMP6_OPT_SOURCE_MAC && ((opt_sz - 2) * 3 - 1 < MAXDNAME))
219
0
      {
220
0
        print_mac(daemon->namebuff, &p[2], opt_sz - 2);
221
0
        mac = daemon->namebuff;
222
0
      }
223
0
  }
224
      
225
0
      if (!option_bool(OPT_QUIET_RA))
226
0
  my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
227
228
      /* If the incoming interface is an alias of some other one (as
229
         specified by the --bridge-interface option), send an RA using
230
         the context of the aliased interface. */
231
0
      for (bridge = daemon->bridges; bridge; bridge = bridge->next)
232
0
        {
233
0
          int bridge_index = if_nametoindex(bridge->iface);
234
0
          if (bridge_index)
235
0
      {
236
0
        for (alias = bridge->alias; alias; alias = alias->next)
237
0
    if (wildcard_matchn(alias->iface, interface, IF_NAMESIZE))
238
0
      {
239
        /* Send an RA on if_index with information from
240
           bridge_index. */
241
0
        send_ra_alias(now, bridge_index, bridge->iface, NULL, if_index);
242
0
        break;
243
0
      }
244
0
        if (alias)
245
0
    break;
246
0
      }
247
0
        }
248
249
      /* If the incoming interface wasn't an alias, send an RA using
250
   the context of the incoming interface. */
251
0
      if (!bridge)
252
  /* source address may not be valid in solicit request. */
253
0
  send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
254
0
    }
255
0
}
256
257
static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest, int send_iface)
258
0
{
259
0
  struct ra_packet *ra;
260
0
  struct ra_param parm;
261
0
  struct sockaddr_in6 addr;
262
0
  struct dhcp_context *context, *tmp,  **up;
263
0
  struct dhcp_netid iface_id;
264
0
  struct dhcp_opt *opt_cfg;
265
0
  struct ra_interface *ra_param = find_iface_param(iface_name);
266
0
  int done_dns = 0, old_prefix = 0, mtu = 0;
267
0
  unsigned int min_pref_time;
268
0
#ifdef HAVE_LINUX_NETWORK
269
0
  FILE *f;
270
0
#endif
271
  
272
0
  parm.ind = iface;
273
0
  parm.managed = 0;
274
0
  parm.other = 0;
275
0
  parm.found_context = NULL;
276
0
  parm.adv_router = 0;
277
0
  parm.if_name = iface_name;
278
0
  parm.first = 1;
279
0
  parm.now = now;
280
0
  parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
281
0
  parm.adv_interval = calc_interval(ra_param);
282
0
  parm.prio = calc_prio(ra_param);
283
  
284
0
  reset_counter();
285
  
286
0
  if (!(ra = expand(sizeof(struct ra_packet))))
287
0
    return;
288
  
289
0
  ra->type = ND_ROUTER_ADVERT;
290
0
  ra->code = 0;
291
0
  ra->hop_limit = hop_limit;
292
0
  ra->flags = parm.prio;
293
0
  ra->lifetime = htons(calc_lifetime(ra_param));
294
0
  ra->reachable_time = 0;
295
0
  ra->retrans_time = 0;
296
297
  /* set tag with name == interface */
298
0
  iface_id.net = iface_name;
299
0
  iface_id.next = NULL;
300
0
  parm.tags = &iface_id; 
301
  
302
0
  for (context = daemon->dhcp6; context; context = context->next)
303
0
    {
304
0
      context->flags &= ~CONTEXT_RA_DONE;
305
0
      context->netid.next = &context->netid;
306
0
    }
307
308
  /* If no link-local address then we can't advertise since source address of
309
     advertisement must be link local address: RFC 4861 para 6.1.2. */
310
0
  if (!iface_enumerate(AF_INET6, &parm, (callback_t){.af_inet6=add_prefixes}) ||
311
0
      parm.link_pref_time == 0)
312
0
    return;
313
314
  /* Find smallest preferred time within address classes,
315
     to use as lifetime for options. This is a rather arbitrary choice. */
316
0
  min_pref_time = 0xffffffff;
317
0
  if (parm.glob_pref_time != 0 && parm.glob_pref_time < min_pref_time)
318
0
    min_pref_time = parm.glob_pref_time;
319
  
320
0
  if (parm.ula_pref_time != 0 && parm.ula_pref_time < min_pref_time)
321
0
    min_pref_time = parm.ula_pref_time;
322
323
0
  if (parm.link_pref_time != 0 && parm.link_pref_time < min_pref_time)
324
0
    min_pref_time = parm.link_pref_time;
325
326
  /* Look for constructed contexts associated with addresses which have gone, 
327
     and advertise them with preferred_time == 0  RFC 6204 4.3 L-13 */
328
0
  for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
329
0
    {
330
0
      tmp = context->next;
331
332
0
      if (context->if_index == iface && (context->flags & CONTEXT_OLD))
333
0
  {
334
0
    unsigned int old = difftime(now, context->address_lost_time);
335
    
336
0
    if (old > context->saved_valid)
337
0
      { 
338
        /* We've advertised this enough, time to go */
339
       
340
        /* If this context held the timeout, and there's another context in use
341
     transfer the timeout there. */
342
0
        if (context->ra_time != 0 && parm.found_context && parm.found_context->ra_time == 0)
343
0
    new_timeout(parm.found_context, iface_name, now);
344
        
345
0
        *up = context->next;
346
0
        free(context);
347
0
      }
348
0
    else
349
0
      {
350
0
        struct prefix_opt *opt;
351
0
        struct in6_addr local = context->start6;
352
0
        int do_slaac = 0;
353
354
0
        old_prefix = 1;
355
356
        /* zero net part of address */
357
0
        setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
358
       
359
        
360
0
        if (context->flags & CONTEXT_RA)
361
0
    {
362
0
      do_slaac = 1;
363
0
      if (context->flags & CONTEXT_DHCP)
364
0
        {
365
0
          parm.other = 1; 
366
0
          if (!(context->flags & CONTEXT_RA_STATELESS))
367
0
      parm.managed = 1;
368
0
        }
369
0
    }
370
0
        else
371
0
    {
372
      /* don't do RA for non-ra-only unless --enable-ra is set */
373
0
      if (option_bool(OPT_RA))
374
0
        {
375
0
          parm.managed = 1;
376
0
          parm.other = 1;
377
0
        }
378
0
    }
379
380
0
        if ((opt = expand(sizeof(struct prefix_opt))))
381
0
    {
382
0
      opt->type = ICMP6_OPT_PREFIX;
383
0
      opt->len = 4;
384
0
      opt->prefix_len = context->prefix;
385
      /* autonomous only if we're not doing dhcp, set
386
                     "on-link" unless "off-link" was specified */
387
0
      opt->flags = (do_slaac ? 0x40 : 0) |
388
0
                    ((context->flags & CONTEXT_RA_OFF_LINK) ? 0 : 0x80);
389
0
      opt->valid_lifetime = htonl(context->saved_valid - old);
390
0
      opt->preferred_lifetime = htonl(0);
391
0
      opt->reserved = 0; 
392
0
      opt->prefix = local;
393
      
394
0
      inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
395
0
      if (!option_bool(OPT_QUIET_RA))
396
0
        my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);        
397
0
    }
398
     
399
0
        up = &context->next;
400
0
      }
401
0
  }
402
0
      else
403
0
  up = &context->next;
404
0
    }
405
    
406
  /* If we're advertising only old prefixes, set router lifetime to zero. */
407
0
  if (old_prefix && !parm.found_context)
408
0
    ra->lifetime = htons(0);
409
410
  /* No prefixes to advertise. */
411
0
  if (!old_prefix && !parm.found_context)
412
0
    return; 
413
  
414
  /* If we're sending router address instead of prefix in at least one prefix,
415
     include the advertisement interval option. */
416
0
  if (parm.adv_router)
417
0
    {
418
0
      put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
419
0
      put_opt6_char(1);
420
0
      put_opt6_short(0);
421
      /* interval value is in milliseconds */
422
0
      put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
423
0
    }
424
425
  /* Set the MTU from ra_param if any, an MTU of 0 mean automatic for linux, */
426
  /* an MTU of -1 prevents the option from being sent. */
427
0
  if (ra_param)
428
0
    mtu = ra_param->mtu;
429
0
#ifdef HAVE_LINUX_NETWORK
430
  /* Note that IPv6 MTU is not necessarily the same as the IPv4 MTU
431
     available from SIOCGIFMTU */
432
0
  if (mtu == 0)
433
0
    {
434
0
      char *mtu_name = ra_param ? ra_param->mtu_name : NULL;
435
0
      sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", mtu_name ? mtu_name : iface_name);
436
0
      if ((f = fopen(daemon->namebuff, "r")))
437
0
        {
438
0
          if (fgets(daemon->namebuff, MAXDNAME, f))
439
0
            mtu = atoi(daemon->namebuff);
440
0
          fclose(f);
441
0
        }
442
0
    }
443
0
#endif
444
0
  if (mtu > 0)
445
0
    {
446
0
      put_opt6_char(ICMP6_OPT_MTU);
447
0
      put_opt6_char(1);
448
0
      put_opt6_short(0);
449
0
      put_opt6_long(mtu);
450
0
    }
451
     
452
0
  iface_enumerate(AF_LOCAL, &send_iface, (callback_t){.af_local=add_lla});
453
 
454
  /* RDNSS, RFC 6106, use relevant DHCP6 options */
455
0
  (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6, 0);
456
  
457
0
  for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
458
0
    {
459
0
      int i;
460
      
461
      /* netids match and not encapsulated? */
462
0
      if (!(opt_cfg->flags & DHOPT_TAGOK))
463
0
        continue;
464
      
465
0
      if (opt_cfg->opt == OPTION6_DNS_SERVER)
466
0
        {
467
0
    struct in6_addr *a;
468
0
    int len;
469
470
0
    done_dns = 1;
471
472
0
          if (opt_cfg->len == 0)
473
0
      continue;
474
    
475
    /* reduce len for any addresses we can't substitute */
476
0
    for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, i = 0; 
477
0
         i < opt_cfg->len; i += IN6ADDRSZ, a++)
478
0
      if ((IN6_IS_ADDR_UNSPECIFIED(a) && parm.glob_pref_time == 0) ||
479
0
    (IN6_IS_ADDR_ULA_ZERO(a) && parm.ula_pref_time == 0) ||
480
0
    (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && parm.link_pref_time == 0))
481
0
        len -= IN6ADDRSZ;
482
483
0
    if (len != 0)
484
0
      {
485
0
        put_opt6_char(ICMP6_OPT_RDNSS);
486
0
        put_opt6_char((len/8) + 1);
487
0
        put_opt6_short(0);
488
0
        put_opt6_long(min_pref_time);
489
   
490
0
        for (a = (struct in6_addr *)opt_cfg->val, i = 0; i <  opt_cfg->len; i += IN6ADDRSZ, a++)
491
0
    if (IN6_IS_ADDR_UNSPECIFIED(a))
492
0
      {
493
0
        if (parm.glob_pref_time != 0)
494
0
          put_opt6(&parm.link_global, IN6ADDRSZ);
495
0
      }
496
0
    else if (IN6_IS_ADDR_ULA_ZERO(a))
497
0
      {
498
0
        if (parm.ula_pref_time != 0)
499
0
        put_opt6(&parm.ula, IN6ADDRSZ);
500
0
      }
501
0
    else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
502
0
      {
503
0
        if (parm.link_pref_time != 0)
504
0
          put_opt6(&parm.link_local, IN6ADDRSZ);
505
0
      }
506
0
    else
507
0
      put_opt6(a, IN6ADDRSZ);
508
0
      }
509
0
  }
510
      
511
0
      if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
512
0
  {
513
0
    int len = ((opt_cfg->len+7)/8);
514
    
515
0
    put_opt6_char(ICMP6_OPT_DNSSL);
516
0
    put_opt6_char(len + 1);
517
0
    put_opt6_short(0);
518
0
    put_opt6_long(min_pref_time); 
519
0
    put_opt6(opt_cfg->val, opt_cfg->len);
520
    
521
    /* pad */
522
0
    for (i = opt_cfg->len; i < len * 8; i++)
523
0
      put_opt6_char(0);
524
0
  }
525
0
    }
526
  
527
0
  if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
528
0
    {
529
      /* default == us, as long as we are supplying DNS service. */
530
0
      put_opt6_char(ICMP6_OPT_RDNSS);
531
0
      put_opt6_char(3);
532
0
      put_opt6_short(0);
533
0
      put_opt6_long(min_pref_time); 
534
0
      put_opt6(&parm.link_local, IN6ADDRSZ);
535
0
    }
536
537
  /* set managed bits unless we're providing only RA on this link */
538
0
  if (parm.managed)
539
0
    ra->flags |= 0x80; /* M flag, managed, */
540
0
   if (parm.other)
541
0
    ra->flags |= 0x40; /* O flag, other */ 
542
      
543
  /* decide where we're sending */
544
0
  memset(&addr, 0, sizeof(addr));
545
#ifdef HAVE_SOCKADDR_SA_LEN
546
  addr.sin6_len = sizeof(struct sockaddr_in6);
547
#endif
548
0
  addr.sin6_family = AF_INET6;
549
0
  addr.sin6_port = htons(IPPROTO_ICMPV6);
550
0
  if (dest)
551
0
    {
552
0
      addr.sin6_addr = *dest;
553
0
      if (IN6_IS_ADDR_LINKLOCAL(dest) ||
554
0
    IN6_IS_ADDR_MC_LINKLOCAL(dest))
555
0
  addr.sin6_scope_id = iface;
556
0
    }
557
0
  else
558
0
    {
559
0
      inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr); 
560
0
      setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface));
561
0
    }
562
  
563
0
#ifdef HAVE_DUMPFILE
564
0
  {
565
0
    struct sockaddr_in6 src;
566
0
    src.sin6_family = AF_INET6;
567
0
    src.sin6_addr = parm.link_local;
568
    
569
0
    dump_packet_icmp(DUMP_RA, (void *)daemon->outpacket.iov_base, save_counter(-1), (union mysockaddr *)&src, (union mysockaddr *)&addr);
570
0
  }
571
0
#endif
572
573
0
  while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base, 
574
0
         save_counter(-1), 0, (struct sockaddr *)&addr, 
575
0
         sizeof(addr))));
576
  
577
0
}
578
579
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
580
0
{
581
  /* Send an RA on the same interface that the RA content is based
582
     on. */
583
0
  send_ra_alias(now, iface, iface_name, dest, iface);
584
0
}
585
586
static int add_prefixes(struct in6_addr *local,  int prefix,
587
      int scope, int if_index, int flags, 
588
      unsigned int preferred, unsigned int valid, void *vparam)
589
0
{
590
0
  struct ra_param *param = vparam;
591
592
0
  (void)scope; /* warning */
593
  
594
0
  if (if_index == param->ind)
595
0
    {
596
0
      if (IN6_IS_ADDR_LINKLOCAL(local))
597
0
  {
598
    /* Can there be more than one LL address?
599
       Select the one with the longest preferred time 
600
       if there is. */
601
0
    if (preferred > param->link_pref_time)
602
0
      {
603
0
        param->link_pref_time = preferred;
604
0
        param->link_local = *local;
605
0
      }
606
0
  }
607
0
      else if (!IN6_IS_ADDR_LOOPBACK(local) &&
608
0
         !IN6_IS_ADDR_MULTICAST(local))
609
0
  {
610
0
    int real_prefix = 0;
611
0
    int do_slaac = 0;
612
0
    int deprecate  = 0;
613
0
    int constructed = 0;
614
0
    int adv_router = 0;
615
0
    int off_link = 0;
616
0
    unsigned int time = 0xffffffff;
617
0
    struct dhcp_context *context;
618
    
619
0
    for (context = daemon->dhcp6; context; context = context->next)
620
0
      if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
621
0
    prefix <= context->prefix &&
622
0
    is_same_net6(local, &context->start6, context->prefix) &&
623
0
    is_same_net6(local, &context->end6, context->prefix))
624
0
        {
625
0
    context->saved_valid = valid;
626
627
0
    if (context->flags & CONTEXT_RA) 
628
0
      {
629
0
        do_slaac = 1;
630
0
        if (context->flags & CONTEXT_DHCP)
631
0
          {
632
0
      param->other = 1; 
633
0
      if (!(context->flags & CONTEXT_RA_STATELESS))
634
0
        param->managed = 1;
635
0
          }
636
0
      }
637
0
    else
638
0
      {
639
        /* don't do RA for non-ra-only unless --enable-ra is set */
640
0
        if (!option_bool(OPT_RA))
641
0
          continue;
642
0
        param->managed = 1;
643
0
        param->other = 1;
644
0
      }
645
646
    /* Configured to advertise router address, not prefix. See RFC 3775 7.2 
647
     In this case we do all addresses associated with a context, 
648
     hence the real_prefix setting here. */
649
0
    if (context->flags & CONTEXT_RA_ROUTER)
650
0
      {
651
0
        adv_router = 1;
652
0
        param->adv_router = 1;
653
0
        real_prefix = context->prefix;
654
0
      }
655
656
    /* find floor time, don't reduce below 3 * RA interval.
657
       If the lease time has been left as default, don't
658
       use that as a floor. */
659
0
    if ((context->flags & CONTEXT_SETLEASE) &&
660
0
        time > context->lease_time)
661
0
      {
662
0
        time = context->lease_time;
663
0
        if (time < ((unsigned int)(3 * param->adv_interval)))
664
0
          time = 3 * param->adv_interval;
665
0
      }
666
667
0
    if (context->flags & CONTEXT_DEPRECATE)
668
0
      deprecate = 1;
669
    
670
0
    if (context->flags & CONTEXT_CONSTRUCTED)
671
0
      constructed = 1;
672
673
674
    /* collect dhcp-range tags */
675
0
    if (context->netid.next == &context->netid && context->netid.net)
676
0
      {
677
0
        context->netid.next = param->tags;
678
0
        param->tags = &context->netid;
679
0
      }
680
      
681
    /* subsequent prefixes on the same interface 
682
       and subsequent instances of this prefix don't need timers.
683
       Be careful not to find the same prefix twice with different
684
       addresses unless we're advertising the actual addresses. */
685
0
    if (!(context->flags & CONTEXT_RA_DONE))
686
0
      {
687
0
        if (!param->first)
688
0
          context->ra_time = 0;
689
0
        context->flags |= CONTEXT_RA_DONE;
690
0
        real_prefix = context->prefix;
691
0
                    off_link = (context->flags & CONTEXT_RA_OFF_LINK);
692
0
      }
693
694
0
    param->first = 0;
695
    /* found_context is the _last_ one we found, so if there's 
696
       more than one, it's not the first. */
697
0
    param->found_context = context;
698
0
        }
699
700
    /* configured time is ceiling */
701
0
    if (!constructed || valid > time)
702
0
      valid = time;
703
    
704
0
    if (flags & IFACE_DEPRECATED)
705
0
      preferred = 0;
706
    
707
0
    if (deprecate)
708
0
      time = 0;
709
    
710
    /* configured time is ceiling */
711
0
    if (!constructed || preferred > time)
712
0
      preferred = time;
713
    
714
0
    if (IN6_IS_ADDR_ULA(local))
715
0
      {
716
0
        if (preferred > param->ula_pref_time)
717
0
    {
718
0
      param->ula_pref_time = preferred;
719
0
      param->ula = *local;
720
0
    }
721
0
      }
722
0
    else 
723
0
      {
724
0
        if (preferred > param->glob_pref_time)
725
0
    {
726
0
      param->glob_pref_time = preferred;
727
0
      param->link_global = *local;
728
0
    }
729
0
      }
730
    
731
0
    if (real_prefix != 0)
732
0
      {
733
0
        struct prefix_opt *opt;
734
              
735
0
        if ((opt = expand(sizeof(struct prefix_opt))))
736
0
    {
737
      /* zero net part of address */
738
0
      if (!adv_router)
739
0
        setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
740
      
741
0
      opt->type = ICMP6_OPT_PREFIX;
742
0
      opt->len = 4;
743
0
      opt->prefix_len = real_prefix;
744
      /* autonomous only if we're not doing dhcp, set
745
                     "on-link" unless "off-link" was specified */
746
0
      opt->flags = (off_link ? 0 : 0x80);
747
0
      if (do_slaac)
748
0
        opt->flags |= 0x40;
749
0
      if (adv_router)
750
0
        opt->flags |= 0x20;
751
0
      opt->valid_lifetime = htonl(valid);
752
0
      opt->preferred_lifetime = htonl(preferred);
753
0
      opt->reserved = 0; 
754
0
      opt->prefix = *local;
755
      
756
0
      inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
757
0
      if (!option_bool(OPT_QUIET_RA))
758
0
        my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);        
759
0
    }
760
0
      }
761
0
  }
762
0
    }          
763
0
  return 1;
764
0
}
765
766
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
767
0
{
768
0
  (void)type;
769
770
0
  if (index == *((int *)parm))
771
0
    {
772
      /* size is in units of 8 octets and includes type and length (2 bytes)
773
   add 7 to round up */
774
0
      int len = (maclen + 9) >> 3;
775
0
      unsigned char *p = expand(len << 3);
776
0
      if (!p)
777
0
  return 1;
778
0
      memset(p, 0, len << 3);
779
0
      *p++ = ICMP6_OPT_SOURCE_MAC;
780
0
      *p++ = len;
781
0
      memcpy(p, mac, maclen);
782
783
0
      return 0;
784
0
    }
785
786
0
  return 1;
787
0
}
788
789
time_t periodic_ra(time_t now)
790
0
{
791
0
  struct search_param param;
792
0
  struct dhcp_context *context;
793
0
  time_t next_event;
794
0
  struct alias_param aparam;
795
    
796
0
  param.now = now;
797
0
  param.iface = 0;
798
799
0
  while (1)
800
0
    {
801
      /* find overdue events, and time of first future event */
802
0
      for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
803
0
  if (context->ra_time != 0)
804
0
    {
805
0
      if (difftime(context->ra_time, now) <= 0.0)
806
0
        break; /* overdue */
807
      
808
0
      if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
809
0
        next_event = context->ra_time;
810
0
    }
811
      
812
      /* none overdue */
813
0
      if (!context)
814
0
  break;
815
      
816
0
      if ((context->flags & CONTEXT_OLD) && 
817
0
    context->if_index != 0 && 
818
0
    indextoname(daemon->icmp6fd, context->if_index, param.name))
819
0
  {
820
    /* A context for an old address. We'll not find the interface by 
821
       looking for addresses, but we know it anyway, since the context is
822
       constructed */
823
0
    param.iface = context->if_index;
824
0
    new_timeout(context, param.name, now);
825
0
  }
826
0
      else if (iface_enumerate(AF_INET6, &param, (callback_t){.af_inet6=iface_search}))
827
  /* There's a context overdue, but we can't find an interface
828
     associated with it, because it's for a subnet we don't
829
     have an interface on. Probably we're doing DHCP on
830
     a remote subnet via a relay. Zero the timer, since we won't
831
     ever be able to send RAs to satisfy it. */
832
0
  context->ra_time = 0;
833
      
834
0
      if (param.iface != 0 &&
835
0
    iface_check(AF_LOCAL, NULL, param.name, NULL))
836
0
  {
837
0
    struct iname *tmp;
838
0
    for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
839
0
      if (tmp->name && (tmp->flags & INAME_6) &&
840
0
    wildcard_match(tmp->name, param.name))
841
0
        break;
842
0
    if (!tmp)
843
0
            {
844
0
              send_ra(now, param.iface, param.name, NULL); 
845
846
              /* Also send on all interfaces that are aliases of this
847
                 one. */
848
0
              for (aparam.bridge = daemon->bridges;
849
0
                   aparam.bridge;
850
0
                   aparam.bridge = aparam.bridge->next)
851
0
                if ((int)if_nametoindex(aparam.bridge->iface) == param.iface)
852
0
                  {
853
                    /* Count the number of alias interfaces for this
854
                       'bridge', by calling iface_enumerate with
855
                       send_ra_to_aliases and NULL alias_ifs. */
856
0
                    aparam.iface = param.iface;
857
0
                    aparam.alias_ifs = NULL;
858
0
                    aparam.num_alias_ifs = 0;
859
0
                    iface_enumerate(AF_LOCAL, &aparam, (callback_t){.af_local=send_ra_to_aliases});
860
0
                    my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => %d alias(es)",
861
0
                              param.name, daemon->addrbuff, aparam.num_alias_ifs);
862
863
                    /* Allocate memory to store the alias interface
864
                       indices. */
865
0
                    aparam.alias_ifs = (int *)whine_malloc(aparam.num_alias_ifs *
866
0
                                                           sizeof(int));
867
0
                    if (aparam.alias_ifs)
868
0
                      {
869
                        /* Use iface_enumerate again to get the alias
870
                           interface indices, then send on each of
871
                           those. */
872
0
                        aparam.max_alias_ifs = aparam.num_alias_ifs;
873
0
                        aparam.num_alias_ifs = 0;
874
0
                        iface_enumerate(AF_LOCAL, &aparam, (callback_t){.af_local=send_ra_to_aliases});
875
0
                        for (; aparam.num_alias_ifs; aparam.num_alias_ifs--)
876
0
                          {
877
0
                            my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => i/f %d",
878
0
                                      param.name, daemon->addrbuff,
879
0
                                      aparam.alias_ifs[aparam.num_alias_ifs - 1]);
880
0
                            send_ra_alias(now,
881
0
                                          param.iface,
882
0
                                          param.name,
883
0
                                          NULL,
884
0
                                          aparam.alias_ifs[aparam.num_alias_ifs - 1]);
885
0
                          }
886
0
                        free(aparam.alias_ifs);
887
0
                      }
888
889
                    /* The source interface can only appear in at most
890
                       one --bridge-interface. */
891
0
                    break;
892
0
                  }
893
0
            }
894
0
  }
895
0
    }      
896
0
  return next_event;
897
0
}
898
899
static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm)
900
0
{
901
0
  struct alias_param *aparam = (struct alias_param *)parm;
902
0
  char ifrn_name[IFNAMSIZ];
903
0
  struct dhcp_bridge *alias;
904
905
0
  (void)type;
906
0
  (void)mac;
907
0
  (void)maclen;
908
909
0
  if (if_indextoname(index, ifrn_name))
910
0
    for (alias = aparam->bridge->alias; alias; alias = alias->next)
911
0
      if (wildcard_matchn(alias->iface, ifrn_name, IFNAMSIZ))
912
0
        {
913
0
          if (aparam->alias_ifs && (aparam->num_alias_ifs < aparam->max_alias_ifs))
914
0
            aparam->alias_ifs[aparam->num_alias_ifs] = index;
915
0
          aparam->num_alias_ifs++;
916
0
        }
917
918
0
  return 1;
919
0
}
920
921
static int iface_search(struct in6_addr *local,  int prefix,
922
      int scope, int if_index, int flags, 
923
      unsigned int preferred, unsigned int valid, void *vparam)
924
0
{
925
0
  struct search_param *param = vparam;
926
0
  struct dhcp_context *context;
927
0
  struct iname *tmp;
928
  
929
0
  (void)scope;
930
0
  (void)preferred;
931
0
  (void)valid;
932
933
  /* ignore interfaces we're not doing DHCP on. */
934
0
  if (!indextoname(daemon->icmp6fd, if_index, param->name) ||
935
0
      !iface_check(AF_LOCAL, NULL, param->name, NULL))
936
0
    return 1;
937
938
0
  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
939
0
    if (tmp->name && (tmp->flags & INAME_6) &&
940
0
  wildcard_match(tmp->name, param->name))
941
0
      return 1;
942
943
0
  for (context = daemon->dhcp6; context; context = context->next)
944
0
    if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
945
0
  prefix <= context->prefix &&
946
0
  is_same_net6(local, &context->start6, context->prefix) &&
947
0
  is_same_net6(local, &context->end6, context->prefix) &&
948
0
  context->ra_time != 0 && 
949
0
  difftime(context->ra_time, param->now) <= 0.0)
950
0
      {
951
  /* found an interface that's overdue for RA determine new 
952
     timeout value and arrange for RA to be sent unless interface is
953
     still doing DAD.*/
954
0
  if (!(flags & IFACE_TENTATIVE))
955
0
    param->iface = if_index;
956
  
957
0
  new_timeout(context, param->name, param->now);
958
  
959
  /* zero timers for other contexts on the same subnet, so they don't timeout 
960
     independently */
961
0
  for (context = context->next; context; context = context->next)
962
0
    if (prefix <= context->prefix &&
963
0
        is_same_net6(local, &context->start6, context->prefix) &&
964
0
        is_same_net6(local, &context->end6, context->prefix))
965
0
      context->ra_time = 0;
966
  
967
0
  return 0; /* found, abort */
968
0
      }
969
  
970
0
  return 1; /* keep searching */
971
0
}
972
 
973
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
974
0
{
975
0
  if (difftime(now, context->ra_short_period_start) < 60.0)
976
    /* range 5 - 20 */
977
0
    context->ra_time = now + 5 + (rand16()/4400);
978
0
  else
979
0
    {
980
      /* range 3/4 - 1 times MaxRtrAdvInterval */
981
0
      unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
982
0
      context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
983
0
    }
984
0
}
985
986
static struct ra_interface *find_iface_param(char *iface)
987
0
{
988
0
  struct ra_interface *ra;
989
  
990
0
  for (ra = daemon->ra_interfaces; ra; ra = ra->next)
991
0
    if (wildcard_match(ra->name, iface))
992
0
      return ra;
993
994
0
  return NULL;
995
0
}
996
997
static unsigned int calc_interval(struct ra_interface *ra)
998
0
{
999
0
  int interval = 600;
1000
  
1001
0
  if (ra && ra->interval != 0)
1002
0
    {
1003
0
      interval = ra->interval;
1004
0
      if (interval > 1800)
1005
0
  interval = 1800;
1006
0
      else if (interval < 4)
1007
0
  interval = 4;
1008
0
    }
1009
  
1010
0
  return (unsigned int)interval;
1011
0
}
1012
1013
static unsigned int calc_lifetime(struct ra_interface *ra)
1014
0
{
1015
0
  int lifetime, interval = (int)calc_interval(ra);
1016
  
1017
0
  if (!ra || ra->lifetime == -1) /* not specified */
1018
0
    lifetime = 3 * interval;
1019
0
  else
1020
0
    {
1021
0
      lifetime = ra->lifetime;
1022
0
      if (lifetime < interval && lifetime != 0)
1023
0
  lifetime = interval;
1024
0
      else if (lifetime > 9000)
1025
0
  lifetime = 9000;
1026
0
    }
1027
  
1028
0
  return (unsigned int)lifetime;
1029
0
}
1030
1031
static unsigned int calc_prio(struct ra_interface *ra)
1032
0
{
1033
0
  if (ra)
1034
0
    return ra->prio;
1035
  
1036
0
  return 0;
1037
0
}
1038
1039
#endif