• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcp6c/src/dhcpv6.c

  1 /**
  2  * Copyright (C) 2012-2014 Steven Barth <steven@midlink.org>
  3  * Copyright (C) 2017-2018 Hans Dedecker <dedeckeh@gmail.com>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License v2 as published by
  7  * the Free Software Foundation.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  *
 14  */
 15 
 16 #include <time.h>
 17 #include <fcntl.h>
 18 #include <errno.h>
 19 #include <inttypes.h>
 20 #include <stdlib.h>
 21 #include <signal.h>
 22 #include <limits.h>
 23 #include <resolv.h>
 24 #include <string.h>
 25 #include <unistd.h>
 26 #include <syslog.h>
 27 #include <stdbool.h>
 28 #include <ctype.h>
 29 #include <sys/time.h>
 30 #include <sys/ioctl.h>
 31 #include <sys/socket.h>
 32 #include <arpa/inet.h>
 33 #include <netinet/in.h>
 34 
 35 #include <net/if.h>
 36 #include <net/ethernet.h>
 37 
 38 #include "odhcp6c.h"
 39 #ifdef USE_LIBUBOX
 40 #include <libubox/md5.h>
 41 #else
 42 #include "md5.h"
 43 #endif
 44 
 45 
 46 #define ALL_DHCPV6_RELAYS {{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
 47                 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02}}}
 48 #define DHCPV6_CLIENT_PORT 546
 49 #define DHCPV6_SERVER_PORT 547
 50 #define DHCPV6_DUID_LLADDR 3
 51 #define DHCPV6_REQ_DELAY 1
 52 
 53 #define DHCPV6_SOL_MAX_RT_MIN 60
 54 #define DHCPV6_SOL_MAX_RT_MAX 86400
 55 #define DHCPV6_INF_MAX_RT_MIN 60
 56 #define DHCPV6_INF_MAX_RT_MAX 86400
 57 
 58 static bool dhcpv6_response_is_valid(const void *buf, ssize_t len,
 59                 const uint8_t transaction[3], enum dhcpv6_msg type,
 60                 const struct in6_addr *daddr);
 61 
 62 static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret);
 63 
 64 static unsigned int dhcpv6_calc_refresh_timers(void);
 65 static void dhcpv6_handle_status_code(_unused const enum dhcpv6_msg orig,
 66                 const uint16_t code, const void *status_msg, const int len,
 67                 int *ret);
 68 static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
 69                 const struct dhcpv6_ia_hdr *ia_hdr, const uint16_t code,
 70                 const void *status_msg, const int len,
 71                 bool handled_status_codes[_DHCPV6_Status_Max],
 72                 int *ret);
 73 static void dhcpv6_add_server_cand(const struct dhcpv6_server_cand *cand);
 74 static void dhcpv6_clear_all_server_cand(void);
 75 
 76 static void dhcpv6_log_status_code(const uint16_t code, const char *scope,
 77                 const void *status_msg, int len);
 78 
 79 static reply_handler dhcpv6_handle_reply;
 80 static reply_handler dhcpv6_handle_advert;
 81 static reply_handler dhcpv6_handle_rebind_reply;
 82 static reply_handler dhcpv6_handle_reconfigure;
 83 static int dhcpv6_commit_advert(void);
 84 
 85 // RFC 3315 - 5.5 Timeout and Delay values
 86 static struct dhcpv6_retx dhcpv6_retx[_DHCPV6_MSG_MAX] = {
 87         [DHCPV6_MSG_UNKNOWN] = {false, 1, 120, 0, "<POLL>",
 88                         dhcpv6_handle_reconfigure, NULL},
 89         [DHCPV6_MSG_SOLICIT] = {true, 1, DHCPV6_SOL_MAX_RT, 0, "SOLICIT",
 90                         dhcpv6_handle_advert, dhcpv6_commit_advert},
 91         [DHCPV6_MSG_REQUEST] = {true, 1, DHCPV6_REQ_MAX_RT, 10, "REQUEST",
 92                         dhcpv6_handle_reply, NULL},
 93         [DHCPV6_MSG_RENEW] = {false, 10, DHCPV6_REN_MAX_RT, 0, "RENEW",
 94                         dhcpv6_handle_reply, NULL},
 95         [DHCPV6_MSG_REBIND] = {false, 10, DHCPV6_REB_MAX_RT, 0, "REBIND",
 96                         dhcpv6_handle_rebind_reply, NULL},
 97         [DHCPV6_MSG_RELEASE] = {false, 1, 0, 5, "RELEASE", NULL, NULL},
 98         [DHCPV6_MSG_DECLINE] = {false, 1, 0, 5, "DECLINE", NULL, NULL},
 99         [DHCPV6_MSG_INFO_REQ] = {true, 1, DHCPV6_INF_MAX_RT, 0, "INFOREQ",
100                         dhcpv6_handle_reply, NULL},
101 };
102 
103 // Sockets
104 static int sock = -1;
105 static int ifindex = -1;
106 static int64_t t1 = 0, t2 = 0, t3 = 0;
107 
108 // IA states
109 static enum odhcp6c_ia_mode na_mode = IA_MODE_NONE, pd_mode = IA_MODE_NONE;
110 static bool stateful_only_mode = false;
111 static bool accept_reconfig = false;
112 // Server unicast address
113 static struct in6_addr server_addr = IN6ADDR_ANY_INIT;
114 
115 // Reconfigure key
116 static uint8_t reconf_key[16];
117 
118 // client options
119 static unsigned int client_options = 0;
120 
121 static uint32_t ntohl_unaligned(const uint8_t *data)
122 {
123         uint32_t buf;
124 
125         memcpy(&buf, data, sizeof(buf));
126         return ntohl(buf);
127 }
128 
129 static char *dhcpv6_msg_to_str(enum dhcpv6_msg msg)
130 {
131         switch (msg) {
132         case DHCPV6_MSG_SOLICIT:
133                 return "SOLICIT";
134 
135         case DHCPV6_MSG_ADVERT:
136                 return "ADVERTISE";
137 
138         case DHCPV6_MSG_REQUEST:
139                 return "REQUEST";
140 
141         case DHCPV6_MSG_RENEW:
142                 return "RENEW";
143 
144         case DHCPV6_MSG_REBIND:
145                 return "REBIND";
146 
147         case DHCPV6_MSG_REPLY:
148                 return "REPLY";
149 
150         case DHCPV6_MSG_RELEASE:
151                 return "RELEASE";
152 
153         case DHCPV6_MSG_DECLINE:
154                 return "DECLINE";
155 
156         case DHCPV6_MSG_RECONF:
157                 return "RECONFIGURE";
158 
159         case DHCPV6_MSG_INFO_REQ:
160                 return "INFORMATION REQUEST";
161 
162         default:
163                 break;
164         }
165 
166         return "UNKNOWN";
167 }
168 
169 static char *dhcpv6_status_code_to_str(uint16_t code)
170 {
171         switch (code) {
172         case DHCPV6_Success:
173                 return "Success";
174 
175         case DHCPV6_UnspecFail:
176                 return "Unspecified Failure";
177 
178         case DHCPV6_NoAddrsAvail:
179                 return "No Address Available";
180 
181         case DHCPV6_NoBinding:
182                 return "No Binding";
183 
184         case DHCPV6_NotOnLink:
185                 return "Not On Link";
186 
187         case DHCPV6_UseMulticast:
188                 return "Use Multicast";
189 
190         case DHCPV6_NoPrefixAvail:
191                 return "No Prefix Available";
192 
193         default:
194                 break;
195         }
196 
197         return "Unknown";
198 }
199 
200 int init_dhcpv6(const char *ifname, unsigned int options, int sk_prio, int sol_timeout)
201 {
202         client_options = options;
203         dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_timeout;
204 
205         sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
206         if (sock < 0)
207                 goto failure;
208 
209         // Detect interface
210         struct ifreq ifr;
211         memset(&ifr, 0, sizeof(ifr));
212         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
213         if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
214                 goto failure;
215 
216         ifindex = ifr.ifr_ifindex;
217 
218         // Create client DUID
219         size_t client_id_len;
220         odhcp6c_get_state(STATE_CLIENT_ID, &client_id_len);
221         if (client_id_len == 0) {
222                 uint8_t duid[14] = {0, DHCPV6_OPT_CLIENTID, 0, 10, 0,
223                                 DHCPV6_DUID_LLADDR, 0, 1};
224 
225                 if (ioctl(sock, SIOCGIFHWADDR, &ifr) >= 0)
226                         memcpy(&duid[8], ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
227 
228                 uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
229                 struct ifreq ifs[100], *ifp, *ifend;
230                 struct ifconf ifc;
231                 ifc.ifc_req = ifs;
232                 ifc.ifc_len = sizeof(ifs);
233 
234                 if (!memcmp(&duid[8], zero, ETHER_ADDR_LEN) &&
235                                 ioctl(sock, SIOCGIFCONF, &ifc) >= 0) {
236                         // If our interface doesn't have an address...
237                         ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
238                         for (ifp = ifc.ifc_req; ifp < ifend &&
239                                         !memcmp(&duid[8], zero, ETHER_ADDR_LEN); ifp++) {
240                                 memcpy(ifr.ifr_name, ifp->ifr_name,
241                                                 sizeof(ifr.ifr_name));
242                                 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
243                                         continue;
244 
245                                 memcpy(&duid[8], ifr.ifr_hwaddr.sa_data,
246                                                 ETHER_ADDR_LEN);
247                         }
248                 }
249 
250                 odhcp6c_add_state(STATE_CLIENT_ID, duid, sizeof(duid));
251         }
252 
253         // Create ORO
254         if (!(client_options & DHCPV6_STRICT_OPTIONS)) {
255                 uint16_t oro[] = {
256                         htons(DHCPV6_OPT_SIP_SERVER_D),
257                         htons(DHCPV6_OPT_SIP_SERVER_A),
258                         htons(DHCPV6_OPT_DNS_SERVERS),
259                         htons(DHCPV6_OPT_DNS_DOMAIN),
260                         htons(DHCPV6_OPT_SNTP_SERVERS),
261                         htons(DHCPV6_OPT_NTP_SERVER),
262                         htons(DHCPV6_OPT_PD_EXCLUDE),
263 #ifdef EXT_CER_ID
264                         htons(DHCPV6_OPT_CER_ID),
265 #endif
266                 };
267                 odhcp6c_add_state(STATE_ORO, oro, sizeof(oro));
268         }
269         // Required oro
270         uint16_t req_oro[] = {
271                 htons(DHCPV6_OPT_INF_MAX_RT),
272                 htons(DHCPV6_OPT_SOL_MAX_RT),
273                 htons(DHCPV6_OPT_INFO_REFRESH),
274         };
275         odhcp6c_add_state(STATE_ORO, req_oro, sizeof(req_oro));
276 
277         // Configure IPv6-options
278         int val = 1;
279         if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)) < 0)
280                 goto failure;
281 
282         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
283                 goto failure;
284 
285         if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)) < 0)
286                 goto failure;
287 
288         if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0)
289                 goto failure;
290 
291         if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &sk_prio, sizeof(sk_prio)) < 0)
292                 goto failure;
293 
294         struct sockaddr_in6 client_addr = { .sin6_family = AF_INET6,
295                 .sin6_port = htons(DHCPV6_CLIENT_PORT), .sin6_flowinfo = 0 };
296 
297         if (bind(sock, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0)
298                 goto failure;
299 
300         return 0;
301 
302 failure:
303         if (sock >= 0)
304                 close(sock);
305 
306         return -1;
307 }
308 
309 enum {
310         IOV_HDR=0,
311         IOV_ORO,
312         IOV_CL_ID,
313         IOV_SRV_ID,
314         IOV_OPTS,
315         IOV_RECONF_ACCEPT,
316         IOV_FQDN,
317         IOV_HDR_IA_NA,
318         IOV_IA_NA,
319         IOV_IA_PD,
320         IOV_TOTAL
321 };
322 
323 int dhcpv6_set_ia_mode(enum odhcp6c_ia_mode na, enum odhcp6c_ia_mode pd, bool stateful_only)
324 {
325         int mode = DHCPV6_UNKNOWN;
326 
327         na_mode = na;
328         pd_mode = pd;
329         stateful_only_mode = stateful_only;
330 
331         if (na_mode == IA_MODE_NONE && pd_mode == IA_MODE_NONE)
332                 mode = DHCPV6_STATELESS;
333         else if (na_mode == IA_MODE_FORCE || pd_mode == IA_MODE_FORCE)
334                 mode = DHCPV6_STATEFUL;
335 
336         return mode;
337 }
338 
339 static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
340 {
341         // Build FQDN
342         char fqdn_buf[256];
343         gethostname(fqdn_buf, sizeof(fqdn_buf));
344         struct {
345                 uint16_t type;
346                 uint16_t len;
347                 uint8_t flags;
348                 uint8_t data[256];
349         } fqdn;
350         size_t fqdn_len = 5 + dn_comp(fqdn_buf, fqdn.data,
351                         sizeof(fqdn.data), NULL, NULL);
352         fqdn.type = htons(DHCPV6_OPT_FQDN);
353         fqdn.len = htons(fqdn_len - 4);
354         fqdn.flags = 0;
355 
356         // Build Client ID
357         size_t cl_id_len;
358         void *cl_id = odhcp6c_get_state(STATE_CLIENT_ID, &cl_id_len);
359 
360         // Get Server ID
361         size_t srv_id_len;
362         void *srv_id = odhcp6c_get_state(STATE_SERVER_ID, &srv_id_len);
363 
364         // Build IA_PDs
365         size_t ia_pd_entries = 0, ia_pd_len = 0;
366         uint8_t *ia_pd;
367 
368         if (type == DHCPV6_MSG_SOLICIT) {
369                 odhcp6c_clear_state(STATE_IA_PD);
370                 size_t n_prefixes;
371                 struct odhcp6c_request_prefix *request_prefixes = odhcp6c_get_state(STATE_IA_PD_INIT, &n_prefixes);
372                 n_prefixes /= sizeof(struct odhcp6c_request_prefix);
373 
374                 ia_pd = alloca(n_prefixes * (sizeof(struct dhcpv6_ia_hdr) + sizeof(struct dhcpv6_ia_prefix)));
375 
376                 for (size_t i = 0; i < n_prefixes; i++) {
377                         struct dhcpv6_ia_hdr hdr_ia_pd = {
378                                 htons(DHCPV6_OPT_IA_PD),
379                                 htons(sizeof(hdr_ia_pd) - 4 +
380                                       sizeof(struct dhcpv6_ia_prefix) * !!request_prefixes[i].length),
381                                 request_prefixes[i].iaid, 0, 0
382                         };
383                         struct dhcpv6_ia_prefix pref = {
384                                 .type = htons(DHCPV6_OPT_IA_PREFIX),
385                                 .len = htons(sizeof(pref) - 4),
386                                 .prefix = request_prefixes[i].length,
387                                 .addr = request_prefixes[i].addr
388                         };
389                         memcpy(ia_pd + ia_pd_len, &hdr_ia_pd, sizeof(hdr_ia_pd));
390                         ia_pd_len += sizeof(hdr_ia_pd);
391                         if (request_prefixes[i].length) {
392                                 memcpy(ia_pd + ia_pd_len, &pref, sizeof(pref));
393                                 ia_pd_len += sizeof(pref);
394                         }
395                 }
396         } else {
397                 struct odhcp6c_entry *e = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entries);
398                 ia_pd_entries /= sizeof(*e);
399 
400                 // we're too lazy to count our distinct IAIDs,
401                 // so just allocate maximally needed space
402                 ia_pd = alloca(ia_pd_entries * (sizeof(struct dhcpv6_ia_prefix) + 10 +
403                                         sizeof(struct dhcpv6_ia_hdr)));
404 
405                 for (size_t i = 0; i < ia_pd_entries; ++i) {
406                         uint32_t iaid = e[i].iaid;
407 
408                         // check if this is an unprocessed IAID and skip if not.
409                         int new_iaid = 1;
410                         for (int j = i-1; j >= 0; j--) {
411                                 if (e[j].iaid == iaid) {
412                                         new_iaid = 0;
413                                         break;
414                                 }
415                         }
416 
417                         if (!new_iaid)
418                                 continue;
419 
420                         // construct header
421                         struct dhcpv6_ia_hdr hdr_ia_pd = {
422                                 htons(DHCPV6_OPT_IA_PD),
423                                 htons(sizeof(hdr_ia_pd) - 4),
424                                 iaid, 0, 0
425                         };
426 
427                         memcpy(ia_pd + ia_pd_len, &hdr_ia_pd, sizeof(hdr_ia_pd));
428                         struct dhcpv6_ia_hdr *hdr = (struct dhcpv6_ia_hdr *) (ia_pd + ia_pd_len);
429                         ia_pd_len += sizeof(hdr_ia_pd);
430 
431                         for (size_t j = i; j < ia_pd_entries; j++) {
432                                 if (e[j].iaid != iaid)
433                                         continue;
434 
435                                 uint8_t ex_len = 0;
436                                 if (e[j].priority > 0)
437                                         ex_len = ((e[j].priority - e[j].length - 1) / 8) + 6;
438 
439                                 struct dhcpv6_ia_prefix p = {
440                                         .type = htons(DHCPV6_OPT_IA_PREFIX),
441                                         .len = htons(sizeof(p) - 4U + ex_len),
442                                         .prefix = e[j].length,
443                                         .addr = e[j].target
444                                 };
445 
446                                 if (type == DHCPV6_MSG_REQUEST) {
447                                         p.preferred = htonl(e[j].preferred);
448                                         p.valid = htonl(e[j].valid);
449                                 }
450 
451                                 memcpy(ia_pd + ia_pd_len, &p, sizeof(p));
452                                 ia_pd_len += sizeof(p);
453 
454                                 if (ex_len) {
455                                         ia_pd[ia_pd_len++] = 0;
456                                         ia_pd[ia_pd_len++] = DHCPV6_OPT_PD_EXCLUDE;
457                                         ia_pd[ia_pd_len++] = 0;
458                                         ia_pd[ia_pd_len++] = ex_len - 4;
459                                         ia_pd[ia_pd_len++] = e[j].priority;
460 
461                                         uint32_t excl = ntohl(e[j].router.s6_addr32[1]);
462                                         excl >>= (64 - e[j].priority);
463                                         excl <<= 8 - ((e[j].priority - e[j].length) % 8);
464 
465                                         for (size_t i = ex_len - 5; i > 0; --i, excl >>= 8)
466                                                 ia_pd[ia_pd_len + i] = excl & 0xff;
467                                         ia_pd_len += ex_len - 5;
468                                 }
469 
470                                 hdr->len = htons(ntohs(hdr->len) + ntohs(p.len) + 4U);
471                         }
472                 }
473         }
474 
475         // Build IA_NAs
476         size_t ia_na_entries, ia_na_len = 0;
477         void *ia_na = NULL;
478         struct odhcp6c_entry *e = odhcp6c_get_state(STATE_IA_NA, &ia_na_entries);
479         ia_na_entries /= sizeof(*e);
480 
481         struct dhcpv6_ia_hdr hdr_ia_na = {
482                 .type = htons(DHCPV6_OPT_IA_NA),
483                 .len = htons(sizeof(hdr_ia_na) - 4),
484                 .iaid = htonl(ifindex),
485                 .t1 = 0,
486                 .t2 = 0,
487         };
488 
489         struct dhcpv6_ia_addr pa[ia_na_entries];
490         for (size_t i = 0; i < ia_na_entries; ++i) {
491                 pa[i].type = htons(DHCPV6_OPT_IA_ADDR);
492                 pa[i].len = htons(sizeof(pa[i]) - 4U);
493                 pa[i].addr = e[i].target;
494 
495                 if (type == DHCPV6_MSG_REQUEST) {
496                         pa[i].preferred = htonl(e[i].preferred);
497                         pa[i].valid = htonl(e[i].valid);
498                 } else {
499                         pa[i].preferred = 0;
500                         pa[i].valid = 0;
501                 }
502         }
503 
504         ia_na = pa;
505         ia_na_len = sizeof(pa);
506         hdr_ia_na.len = htons(ntohs(hdr_ia_na.len) + ia_na_len);
507 
508         // Reconfigure Accept
509         struct {
510                 uint16_t type;
511                 uint16_t length;
512         } reconf_accept = {htons(DHCPV6_OPT_RECONF_ACCEPT), 0};
513 
514         // Option list
515         size_t opts_len;
516         void *opts = odhcp6c_get_state(STATE_OPTS, &opts_len);
517 
518         // Option Request List
519         size_t oro_entries, oro_len = 0;
520         uint16_t *oro, *s_oro = odhcp6c_get_state(STATE_ORO, &oro_entries);
521 
522         oro_entries /= sizeof(*s_oro);
523         oro = alloca(oro_entries * sizeof(*oro));
524 
525         for (size_t i = 0; i < oro_entries; i++) {
526                 struct odhcp6c_opt *opt = odhcp6c_find_opt(htons(s_oro[i]));
527 
528                 if (opt) {
529                         if (!(opt->flags & OPT_ORO))
530                                 continue;
531 
532                         if ((opt->flags & OPT_ORO_SOLICIT) && type != DHCPV6_MSG_SOLICIT)
533                                 continue;
534 
535                         if ((opt->flags & OPT_ORO_STATELESS) && type != DHCPV6_MSG_INFO_REQ)
536                                 continue;
537 
538                         if ((opt->flags & OPT_ORO_STATEFUL) && type == DHCPV6_MSG_INFO_REQ)
539                                 continue;
540                 }
541 
542                 oro[oro_len++] = s_oro[i];
543         }
544         oro_len *= sizeof(*oro);
545 
546         // Prepare Header
547         struct {
548                 uint8_t type;
549                 uint8_t trid[3];
550                 uint16_t elapsed_type;
551                 uint16_t elapsed_len;
552                 uint16_t elapsed_value;
553                 uint16_t oro_type;
554                 uint16_t oro_len;
555         } hdr = {
556                 type, {trid[0], trid[1], trid[2]},
557                 htons(DHCPV6_OPT_ELAPSED), htons(2),
558                         htons((ecs > 0xffff) ? 0xffff : ecs),
559                 htons(DHCPV6_OPT_ORO), htons(oro_len),
560         };
561 
562         struct iovec iov[IOV_TOTAL] = {
563                 [IOV_HDR] = {&hdr, sizeof(hdr)},
564                 [IOV_ORO] = {oro, oro_len},
565                 [IOV_CL_ID] = {cl_id, cl_id_len},
566                 [IOV_SRV_ID] = {srv_id, srv_id_len},
567                 [IOV_OPTS] = { opts, opts_len },
568                 [IOV_RECONF_ACCEPT] = {&reconf_accept, sizeof(reconf_accept)},
569                 [IOV_FQDN] = {&fqdn, fqdn_len},
570                 [IOV_HDR_IA_NA] = {&hdr_ia_na, sizeof(hdr_ia_na)},
571                 [IOV_IA_NA] = {ia_na, ia_na_len},
572                 [IOV_IA_PD] = {ia_pd, ia_pd_len},
573         };
574 
575         size_t cnt = IOV_TOTAL;
576         if (type == DHCPV6_MSG_INFO_REQ)
577                 cnt = IOV_HDR_IA_NA;
578 
579         // Disable IAs if not used
580         if (type != DHCPV6_MSG_SOLICIT && ia_na_len == 0)
581                 iov[IOV_HDR_IA_NA].iov_len = 0;
582 
583         if (na_mode == IA_MODE_NONE)
584                 iov[IOV_HDR_IA_NA].iov_len = 0;
585 
586         if ((type != DHCPV6_MSG_SOLICIT && type != DHCPV6_MSG_REQUEST) ||
587                         !(client_options & DHCPV6_ACCEPT_RECONFIGURE))
588                 iov[IOV_RECONF_ACCEPT].iov_len = 0;
589 
590         if (!(client_options & DHCPV6_CLIENT_FQDN)) {
591                 iov[IOV_FQDN].iov_len = 0;
592         } else {
593                 switch (type) {
594                 /*  rfc4704 §5
595                         A client MUST only include the Client FQDN option in SOLICIT,
596                         REQUEST, RENEW, or REBIND messages.
597                 */
598                 case DHCPV6_MSG_SOLICIT:
599                 case DHCPV6_MSG_REQUEST:
600                 case DHCPV6_MSG_RENEW:
601                 case DHCPV6_MSG_REBIND:
602                 /*  rfc4704 §6
603                         Servers MUST only include a Client FQDN option in ADVERTISE and REPLY
604                         messages...
605                 case DHCPV6_MSG_ADVERT:
606                 case DHCPV6_MSG_REPLY:
607                 */
608                         /* leave FQDN as-is */
609                     break;
610                 default:
611                         /* remaining MSG types cannot contain client FQDN */
612                         iov[IOV_FQDN].iov_len = 0;
613                     break;
614                 }
615         }
616 
617         struct sockaddr_in6 srv = {AF_INET6, htons(DHCPV6_SERVER_PORT),
618                 0, ALL_DHCPV6_RELAYS, ifindex};
619         struct msghdr msg = {.msg_name = &srv, .msg_namelen = sizeof(srv),
620                         .msg_iov = iov, .msg_iovlen = cnt};
621 
622         switch (type) {
623         case DHCPV6_MSG_REQUEST:
624         case DHCPV6_MSG_RENEW:
625         case DHCPV6_MSG_RELEASE:
626         case DHCPV6_MSG_DECLINE:
627                 if (!IN6_IS_ADDR_UNSPECIFIED(&server_addr) &&
628                         odhcp6c_addr_in_scope(&server_addr)) {
629                         srv.sin6_addr = server_addr;
630                         if (!IN6_IS_ADDR_LINKLOCAL(&server_addr))
631                                 srv.sin6_scope_id = 0;
632                 }
633                 break;
634         default:
635                 break;
636         }
637 
638         if (sendmsg(sock, &msg, 0) < 0) {
639                 char in6_str[INET6_ADDRSTRLEN];
640 
641                 syslog(LOG_ERR, "Failed to send %s message to %s (%s)",
642                         dhcpv6_msg_to_str(type),
643                         inet_ntop(AF_INET6, (const void *)&srv.sin6_addr,
644                                 in6_str, sizeof(in6_str)), strerror(errno));
645         }
646 }
647 
648 static int64_t dhcpv6_rand_delay(int64_t time)
649 {
650         int random;
651         odhcp6c_random(&random, sizeof(random));
652 
653         return (time * ((int64_t)random % 1000LL)) / 10000LL;
654 }
655 
656 int dhcpv6_request(enum dhcpv6_msg type)
657 {
658         uint8_t rc = 0;
659         uint64_t timeout = UINT32_MAX;
660         struct dhcpv6_retx *retx = &dhcpv6_retx[type];
661 
662         if (retx->delay) {
663                 struct timespec ts = {0, 0};
664                 ts.tv_nsec = (dhcpv6_rand_delay((10000 * DHCPV6_REQ_DELAY) / 2) + (1000 * DHCPV6_REQ_DELAY) / 2) * 1000000;
665 
666                 while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
667         }
668 
669         if (type == DHCPV6_MSG_UNKNOWN)
670                 timeout = t1;
671         else if (type == DHCPV6_MSG_RENEW)
672                 timeout = (t2 > t1) ? t2 - t1 : ((t1 == UINT32_MAX) ? UINT32_MAX : 0);
673         else if (type == DHCPV6_MSG_REBIND)
674                 timeout = (t3 > t2) ? t3 - t2 : ((t2 == UINT32_MAX) ? UINT32_MAX : 0);
675 
676         if (timeout == 0)
677                 return -1;
678 
679         syslog(LOG_NOTICE, "Starting %s transaction (timeout %"PRIu64"s, max rc %d)",
680                         retx->name, timeout, retx->max_rc);
681 
682         uint64_t start = odhcp6c_get_milli_time(), round_start = start, elapsed;
683 
684         // Generate transaction ID
685         uint8_t trid[3] = {0, 0, 0};
686         if (type != DHCPV6_MSG_UNKNOWN)
687                 odhcp6c_random(trid, sizeof(trid));
688 
689         ssize_t len = -1;
690         int64_t rto = 0;
691 
692         do {
693                 if (rto == 0) {
694                         int64_t delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
695 
696                         // First RT MUST be strictly greater than IRT for solicit messages (RFC3313 17.1.2)
697                         while (type == DHCPV6_MSG_SOLICIT && delay <= 0)
698                                 delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
699 
700                         rto = (retx->init_timeo * 1000 + delay);
701                 } else
702                         rto = (2 * rto + dhcpv6_rand_delay(rto));
703 
704                 if (retx->max_timeo && (rto >= retx->max_timeo * 1000))
705                         rto = retx->max_timeo * 1000 +
706                                 dhcpv6_rand_delay(retx->max_timeo * 1000);
707 
708                 // Calculate end for this round and elapsed time
709                 uint64_t round_end = round_start + rto;
710                 elapsed = round_start - start;
711 
712                 // Don't wait too long if timeout differs from infinite
713                 if ((timeout != UINT32_MAX) && (round_end - start > timeout * 1000))
714                         round_end = timeout * 1000 + start;
715 
716                 // Built and send package
717                 switch (type) {
718                 case DHCPV6_MSG_UNKNOWN:
719                         break;
720                 default:
721                         syslog(LOG_NOTICE, "Send %s message (elapsed %"PRIu64"ms, rc %d)",
722                                         retx->name, elapsed, rc);
723                         // Fall through
724                 case DHCPV6_MSG_SOLICIT:
725                 case DHCPV6_MSG_INFO_REQ:
726                         dhcpv6_send(type, trid, elapsed / 10);
727                         rc++;
728                 }
729 
730                 // Receive rounds
731                 for (; len < 0 && (round_start < round_end);
732                                 round_start = odhcp6c_get_milli_time()) {
733                         uint8_t buf[1536];
734                         union {
735                                 struct cmsghdr hdr;
736                                 uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
737                         } cmsg_buf;
738                         struct iovec iov = {buf, sizeof(buf)};
739                         struct sockaddr_in6 addr;
740                         struct msghdr msg = {.msg_name = &addr, .msg_namelen = sizeof(addr),
741                                         .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsg_buf.buf,
742                                         .msg_controllen = sizeof(cmsg_buf)};
743                         struct in6_pktinfo *pktinfo = NULL;
744                         const struct dhcpv6_header *hdr = (const struct dhcpv6_header *)buf;
745 
746                         // Check for pending signal
747                         if (odhcp6c_signal_process())
748                                 return -1;
749 
750                         // Set timeout for receiving
751                         uint64_t t = round_end - round_start;
752                         struct timeval tv = {t / 1000, (t % 1000) * 1000};
753                         if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
754                                         &tv, sizeof(tv)) < 0)
755                                 syslog(LOG_ERR, "setsockopt SO_RCVTIMEO failed (%s)",
756                                                 strerror(errno));
757 
758                         // Receive cycle
759                         len = recvmsg(sock, &msg, 0);
760                         if (len < 0)
761                                 continue;
762 
763                         for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL;
764                                 ch = CMSG_NXTHDR(&msg, ch)) {
765                                 if (ch->cmsg_level == SOL_IPV6 &&
766                                         ch->cmsg_type == IPV6_PKTINFO) {
767                                         pktinfo = (struct in6_pktinfo *)CMSG_DATA(ch);
768                                         break;
769                                 }
770                         }
771 
772                         if (pktinfo == NULL) {
773                                 len = -1;
774                                 continue;
775                         }
776 
777                         if (!dhcpv6_response_is_valid(buf, len, trid,
778                                                         type, &pktinfo->ipi6_addr)) {
779                                 len = -1;
780                                 continue;
781                         }
782 
783                         uint8_t *opt = &buf[4];
784                         uint8_t *opt_end = opt + len - 4;
785 
786                         round_start = odhcp6c_get_milli_time();
787                         elapsed = round_start - start;
788                         syslog(LOG_NOTICE, "Got a valid %s after %"PRIu64"ms",
789                                dhcpv6_msg_to_str(hdr->msg_type), elapsed);
790 
791                         if (retx->handler_reply)
792                                 len = retx->handler_reply(type, rc, opt, opt_end, &addr);
793 
794                         if (len > 0 && round_end - round_start > 1000)
795                                 round_end = 1000 + round_start;
796                 }
797 
798                 // Allow
799                 if (retx->handler_finish)
800                         len = retx->handler_finish();
801         } while (len < 0 && ((timeout == UINT32_MAX) || (elapsed / 1000 < timeout)) &&
802                         (!retx->max_rc || rc < retx->max_rc));
803         return len;
804 }
805 
806 // Message validation checks according to RFC3315 chapter 15
807 static bool dhcpv6_response_is_valid(const void *buf, ssize_t len,
808                 const uint8_t transaction[3], enum dhcpv6_msg type,
809                 const struct in6_addr *daddr)
810 {
811         const struct dhcpv6_header *rep = buf;
812         if (len < (ssize_t)sizeof(*rep) || memcmp(rep->tr_id,
813                         transaction, sizeof(rep->tr_id)))
814                 return false; // Invalid reply
815 
816         if (type == DHCPV6_MSG_SOLICIT) {
817                 if (rep->msg_type != DHCPV6_MSG_ADVERT &&
818                                 rep->msg_type != DHCPV6_MSG_REPLY)
819                         return false;
820 
821         } else if (type == DHCPV6_MSG_UNKNOWN) {
822                 if (!accept_reconfig || rep->msg_type != DHCPV6_MSG_RECONF)
823                         return false;
824 
825         } else if (rep->msg_type != DHCPV6_MSG_REPLY)
826                 return false;
827 
828         uint8_t *end = ((uint8_t*)buf) + len, *odata = NULL,
829                 rcmsg = DHCPV6_MSG_UNKNOWN;
830         uint16_t otype, olen = UINT16_MAX;
831         bool clientid_ok = false, serverid_ok = false, rcauth_ok = false,
832                 ia_present = false, options_valid = true;
833 
834         size_t client_id_len, server_id_len;
835         void *client_id = odhcp6c_get_state(STATE_CLIENT_ID, &client_id_len);
836         void *server_id = odhcp6c_get_state(STATE_SERVER_ID, &server_id_len);
837 
838         dhcpv6_for_each_option(&rep[1], end, otype, olen, odata) {
839                 if (otype == DHCPV6_OPT_CLIENTID) {
840                         clientid_ok = (olen + 4U == client_id_len) && !memcmp(
841                                         &odata[-4], client_id, client_id_len);
842                 } else if (otype == DHCPV6_OPT_SERVERID) {
843                         if (server_id_len)
844                                 serverid_ok = (olen + 4U == server_id_len) && !memcmp(
845                                                 &odata[-4], server_id, server_id_len);
846                         else
847                                 serverid_ok = true;
848                 } else if (otype == DHCPV6_OPT_AUTH && olen == -4 +
849                                 sizeof(struct dhcpv6_auth_reconfigure)) {
850                         struct dhcpv6_auth_reconfigure *r = (void*)&odata[-4];
851                         if (r->protocol != 3 || r->algorithm != 1 || r->reconf_type != 2)
852                                 continue;
853 
854                         md5_ctx_t md5;
855                         uint8_t serverhash[16], secretbytes[64];
856                         uint32_t hash[4];
857                         memcpy(serverhash, r->key, sizeof(serverhash));
858                         memset(r->key, 0, sizeof(r->key));
859 
860                         memset(secretbytes, 0, sizeof(secretbytes));
861                         memcpy(secretbytes, reconf_key, sizeof(reconf_key));
862 
863                         for (size_t i = 0; i < sizeof(secretbytes); ++i)
864                                 secretbytes[i] ^= 0x36;
865 
866                         md5_begin(&md5);
867                         md5_hash(secretbytes, sizeof(secretbytes), &md5);
868                         md5_hash(buf, len, &md5);
869                         md5_end(hash, &md5);
870 
871                         for (size_t i = 0; i < sizeof(secretbytes); ++i) {
872                                 secretbytes[i] ^= 0x36;
873                                 secretbytes[i] ^= 0x5c;
874                         }
875 
876                         md5_begin(&md5);
877                         md5_hash(secretbytes, sizeof(secretbytes), &md5);
878                         md5_hash(hash, 16, &md5);
879                         md5_end(hash, &md5);
880 
881                         rcauth_ok = !memcmp(hash, serverhash, sizeof(hash));
882                 } else if (otype == DHCPV6_OPT_RECONF_MESSAGE && olen == 1) {
883                         rcmsg = odata[0];
884                 } else if ((otype == DHCPV6_OPT_IA_PD || otype == DHCPV6_OPT_IA_NA)) {
885                         ia_present = true;
886                         if (olen < -4 + sizeof(struct dhcpv6_ia_hdr))
887                                 options_valid = false;
888                 } else if ((otype == DHCPV6_OPT_IA_ADDR) || (otype == DHCPV6_OPT_IA_PREFIX) ||
889                                 (otype == DHCPV6_OPT_PD_EXCLUDE))
890                         // Options are not allowed on global level
891                         options_valid = false;
892         }
893 
894         if (!options_valid || ((odata + olen) > end))
895                 return false;
896 
897         if (type == DHCPV6_MSG_INFO_REQ && ia_present)
898                 return false;
899 
900         if (rep->msg_type == DHCPV6_MSG_RECONF) {
901                 if ((rcmsg != DHCPV6_MSG_RENEW && rcmsg != DHCPV6_MSG_REBIND && rcmsg != DHCPV6_MSG_INFO_REQ) ||
902                         (rcmsg == DHCPV6_MSG_INFO_REQ && ia_present) ||
903                         !rcauth_ok || IN6_IS_ADDR_MULTICAST(daddr))
904                         return false;
905         }
906 
907         return clientid_ok && serverid_ok;
908 }
909 
910 int dhcpv6_poll_reconfigure(void)
911 {
912         int ret = dhcpv6_request(DHCPV6_MSG_UNKNOWN);
913 
914         switch (ret) {
915         /*
916          * Only RENEW/REBIND/INFORMATION REQUEST
917          * message transmission can be requested
918          * by a RECONFIGURE
919          */
920         case DHCPV6_MSG_RENEW:
921         case DHCPV6_MSG_REBIND:
922         case DHCPV6_MSG_INFO_REQ:
923                 ret = dhcpv6_request(ret);
924                 break;
925 
926         default:
927                 break;
928         }
929 
930         return ret;
931 }
932 
933 static int dhcpv6_handle_reconfigure(enum dhcpv6_msg orig, const int rc,
934                 const void *opt, const void *end, _unused const struct sockaddr_in6 *from)
935 {
936         uint16_t otype, olen;
937         uint8_t *odata;
938         enum dhcpv6_msg msg = DHCPV6_MSG_UNKNOWN;
939 
940         dhcpv6_for_each_option(opt, end, otype, olen, odata) {
941                 if (otype == DHCPV6_OPT_RECONF_MESSAGE && olen == 1) {
942                         switch (odata[0]) {
943                         case DHCPV6_MSG_REBIND:
944                                 if (t2 != UINT32_MAX)
945                                         t2 = 0;
946                         // Fall through
947                         case DHCPV6_MSG_RENEW:
948                                 if (t1 != UINT32_MAX)
949                                         t1 = 0;
950                         // Fall through
951                         case DHCPV6_MSG_INFO_REQ:
952                                 msg = odata[0];
953                                 syslog(LOG_NOTICE, "Need to respond with %s in reply to %s",
954                                        dhcpv6_msg_to_str(msg), dhcpv6_msg_to_str(DHCPV6_MSG_RECONF));
955                                 break;
956 
957                         default:
958                                 break;
959                         }
960                 }
961         }
962 
963         if (msg != DHCPV6_MSG_UNKNOWN)
964                 dhcpv6_handle_reply(orig, rc, NULL, NULL, NULL);
965 
966         return (msg == DHCPV6_MSG_UNKNOWN? -1: (int)msg);
967 }
968 
969 // Collect all advertised servers
970 static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc,
971                 const void *opt, const void *end, _unused const struct sockaddr_in6 *from)
972 {
973         uint16_t olen, otype;
974         uint8_t *odata, pref = 0;
975         struct dhcpv6_server_cand cand = {false, false, 0, 0, {0},
976                                         IN6ADDR_ANY_INIT, DHCPV6_SOL_MAX_RT,
977                                         DHCPV6_INF_MAX_RT, NULL, NULL, 0, 0};
978         bool have_na = false;
979         int have_pd = 0;
980 
981         dhcpv6_for_each_option(opt, end, otype, olen, odata) {
982                 if (orig == DHCPV6_MSG_SOLICIT &&
983                                 ((otype == DHCPV6_OPT_IA_PD && pd_mode != IA_MODE_NONE) ||
984                                  (otype == DHCPV6_OPT_IA_NA && na_mode != IA_MODE_NONE)) &&
985                                 olen > -4 + sizeof(struct dhcpv6_ia_hdr)) {
986                         struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-4]);
987                         dhcpv6_parse_ia(ia_hdr, odata + olen + sizeof(*ia_hdr), NULL);
988                 }
989 
990                 if (otype == DHCPV6_OPT_SERVERID && olen <= 130) {
991                         memcpy(cand.duid, odata, olen);
992                         cand.duid_len = olen;
993                 } else if (otype == DHCPV6_OPT_PREF && olen >= 1 &&
994                                 cand.preference >= 0) {
995                         cand.preference = pref = odata[0];
996                 } else if (otype == DHCPV6_OPT_UNICAST && olen == sizeof(cand.server_addr)) {
997                         if (!(client_options & DHCPV6_IGNORE_OPT_UNICAST))
998                                 cand.server_addr = *(struct in6_addr *)odata;
999 
1000                 } else if (otype == DHCPV6_OPT_RECONF_ACCEPT) {
1001                         cand.wants_reconfigure = true;
1002                 } else if (otype == DHCPV6_OPT_SOL_MAX_RT && olen == 4) {
1003                         uint32_t sol_max_rt = ntohl_unaligned(odata);
1004                         if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN &&
1005                                         sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX)
1006                                 cand.sol_max_rt = sol_max_rt;
1007 
1008                 } else if (otype == DHCPV6_OPT_INF_MAX_RT && olen == 4) {
1009                         uint32_t inf_max_rt = ntohl_unaligned(odata);
1010                         if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN &&
1011                                         inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
1012                                 cand.inf_max_rt = inf_max_rt;
1013 
1014                 } else if (otype == DHCPV6_OPT_IA_PD &&
1015                                         olen >= -4 + sizeof(struct dhcpv6_ia_hdr)) {
1016                         struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr*)&odata[-4];
1017                         uint8_t *oend = odata + olen, *d;
1018                         dhcpv6_for_each_option(&h[1], oend, otype, olen, d) {
1019                                 if (otype == DHCPV6_OPT_IA_PREFIX &&
1020                                                 olen >= -4 + sizeof(struct dhcpv6_ia_prefix)) {
1021                                         struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix*)&d[-4];
1022                                         have_pd = p->prefix;
1023                                 }
1024                         }
1025                 } else if (otype == DHCPV6_OPT_IA_NA &&
1026                                         olen >= -4 + sizeof(struct dhcpv6_ia_hdr)) {
1027                         struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr*)&odata[-4];
1028                         uint8_t *oend = odata + olen, *d;
1029 
1030                         dhcpv6_for_each_option(&h[1], oend, otype, olen, d) {
1031                                 if (otype == DHCPV6_OPT_IA_ADDR &&
1032                                                 olen >= -4 + sizeof(struct dhcpv6_ia_addr))
1033                                         have_na = true;
1034                         }
1035                 }
1036         }
1037 
1038         if ((stateful_only_mode && !have_na && !have_pd) ||
1039                         (!have_na && na_mode == IA_MODE_FORCE) ||
1040                         (!have_pd && pd_mode == IA_MODE_FORCE)) {
1041                 /*
1042                  * RFC7083 states to process the SOL_MAX_RT and
1043                  * INF_MAX_RT options even if the DHCPv6 server
1044                  * did not propose any IA_NA and/or IA_PD
1045                  */
1046                 dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand.sol_max_rt;
1047                 dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand.inf_max_rt;
1048                 return -1;
1049         }
1050 
1051         if (na_mode != IA_MODE_NONE && !have_na) {
1052                 cand.has_noaddravail = true;
1053                 cand.preference -= 1000;
1054         }
1055 
1056         if (pd_mode != IA_MODE_NONE) {
1057                 if (have_pd)
1058                         cand.preference += 2000 + (128 - have_pd);
1059                 else
1060                         cand.preference -= 2000;
1061         }
1062 
1063         if (cand.duid_len > 0) {
1064                 cand.ia_na = odhcp6c_move_state(STATE_IA_NA, &cand.ia_na_len);
1065                 cand.ia_pd = odhcp6c_move_state(STATE_IA_PD, &cand.ia_pd_len);
1066                 dhcpv6_add_server_cand(&cand);
1067         }
1068 
1069         return (rc > 1 || (pref == 255 && cand.preference > 0)) ? 1 : -1;
1070 }
1071 
1072 static int dhcpv6_commit_advert(void)
1073 {
1074         return dhcpv6_promote_server_cand();
1075 }
1076 
1077 static int dhcpv6_handle_rebind_reply(enum dhcpv6_msg orig, const int rc,
1078                 const void *opt, const void *end, const struct sockaddr_in6 *from)
1079 {
1080         dhcpv6_handle_advert(orig, rc, opt, end, from);
1081         if (dhcpv6_commit_advert() < 0)
1082                 return -1;
1083 
1084         return dhcpv6_handle_reply(orig, rc, opt, end, from);
1085 }
1086 
1087 static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc,
1088                 const void *opt, const void *end, const struct sockaddr_in6 *from)
1089 {
1090         uint8_t *odata;
1091         uint16_t otype, olen;
1092         uint32_t refresh = 86400;
1093         int ret = 1;
1094         unsigned int state_IAs;
1095         unsigned int updated_IAs = 0;
1096         bool handled_status_codes[_DHCPV6_Status_Max] = { false, };
1097 
1098         odhcp6c_expire(true);
1099 
1100         if (orig == DHCPV6_MSG_UNKNOWN) {
1101                 static time_t last_update = 0;
1102                 time_t now = odhcp6c_get_milli_time() / 1000;
1103 
1104                 uint32_t elapsed = (last_update > 0) ? now - last_update : 0;
1105                 last_update = now;
1106 
1107                 if (t1 != UINT32_MAX)
1108                         t1 -= elapsed;
1109 
1110                 if (t2 != UINT32_MAX)
1111                         t2 -= elapsed;
1112 
1113                 if (t3 != UINT32_MAX)
1114                         t3 -= elapsed;
1115 
1116                 if (t1 < 0)
1117                         t1 = 0;
1118 
1119                 if (t2 < 0)
1120                         t2 = 0;
1121 
1122                 if (t3 < 0)
1123                         t3 = 0;
1124         }
1125 
1126         if (orig == DHCPV6_MSG_REQUEST && !odhcp6c_is_bound()) {
1127                 // Delete NA and PD we have in the state from the Advert
1128                 odhcp6c_clear_state(STATE_IA_NA);
1129                 odhcp6c_clear_state(STATE_IA_PD);
1130         }
1131 
1132         if (opt) {
1133                 odhcp6c_clear_state(STATE_DNS);
1134                 odhcp6c_clear_state(STATE_SEARCH);
1135                 odhcp6c_clear_state(STATE_SNTP_IP);
1136                 odhcp6c_clear_state(STATE_NTP_IP);
1137                 odhcp6c_clear_state(STATE_NTP_FQDN);
1138                 odhcp6c_clear_state(STATE_SIP_IP);
1139                 odhcp6c_clear_state(STATE_SIP_FQDN);
1140                 odhcp6c_clear_state(STATE_AFTR_NAME);
1141                 odhcp6c_clear_state(STATE_CER);
1142                 odhcp6c_clear_state(STATE_S46_MAPT);
1143                 odhcp6c_clear_state(STATE_S46_MAPE);
1144                 odhcp6c_clear_state(STATE_S46_LW);
1145                 odhcp6c_clear_state(STATE_PASSTHRU);
1146                 odhcp6c_clear_state(STATE_CUSTOM_OPTS);
1147 
1148                 // Parse and find all matching IAs
1149                 dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1150                         struct odhcp6c_opt *dopt = odhcp6c_find_opt(otype);
1151 
1152                         if ((otype == DHCPV6_OPT_IA_PD || otype == DHCPV6_OPT_IA_NA)
1153                                         && olen > -4 + sizeof(struct dhcpv6_ia_hdr)) {
1154                                 struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-4]);
1155 
1156                                 if ((na_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_NA) ||
1157                                         (pd_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_PD))
1158                                         continue;
1159 
1160                                 // Test ID
1161                                 if (ia_hdr->iaid != htonl(ifindex) && otype == DHCPV6_OPT_IA_NA)
1162                                         continue;
1163 
1164                                 uint16_t code = DHCPV6_Success;
1165                                 uint16_t stype, slen;
1166                                 uint8_t *sdata;
1167                                 // Get and handle status code
1168                                 dhcpv6_for_each_option(&ia_hdr[1], odata + olen,
1169                                                 stype, slen, sdata) {
1170                                         if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1171                                                 uint8_t *mdata = (slen > 2) ? &sdata[2] : NULL;
1172                                                 uint16_t mlen = (slen > 2) ? slen - 2 : 0;
1173 
1174                                                 code = ((int)sdata[0]) << 8 | ((int)sdata[1]);
1175 
1176                                                 if (code == DHCPV6_Success)
1177                                                         continue;
1178 
1179                                                 dhcpv6_handle_ia_status_code(orig, ia_hdr,
1180                                                         code, mdata, mlen, handled_status_codes, &ret);
1181 
1182                                                 if (ret > 0)
1183                                                         return ret;
1184 
1185                                                 break;
1186                                         }
1187                                 }
1188 
1189                                 if (code != DHCPV6_Success)
1190                                         continue;
1191 
1192                                 updated_IAs += dhcpv6_parse_ia(ia_hdr, odata + olen, &ret);
1193                         } else if (otype == DHCPV6_OPT_UNICAST && olen == sizeof(server_addr)) {
1194                                 if (!(client_options & DHCPV6_IGNORE_OPT_UNICAST))
1195                                         server_addr = *(struct in6_addr *)odata;
1196 
1197                         }
1198                         else if (otype == DHCPV6_OPT_STATUS && olen >= 2) {
1199                                 uint8_t *mdata = (olen > 2) ? &odata[2] : NULL;
1200                                 uint16_t mlen = (olen > 2) ? olen - 2 : 0;
1201                                 uint16_t code = ((int)odata[0]) << 8 | ((int)odata[1]);
1202 
1203                                 dhcpv6_handle_status_code(orig, code, mdata, mlen, &ret);
1204                         } else if (otype == DHCPV6_OPT_DNS_SERVERS) {
1205                                 if (olen % 16 == 0)
1206                                         odhcp6c_add_state(STATE_DNS, odata, olen);
1207                         } else if (otype == DHCPV6_OPT_DNS_DOMAIN)
1208                                 odhcp6c_add_state(STATE_SEARCH, odata, olen);
1209                         else if (otype == DHCPV6_OPT_SNTP_SERVERS) {
1210                                 if (olen % 16 == 0)
1211                                         odhcp6c_add_state(STATE_SNTP_IP, odata, olen);
1212                         } else if (otype == DHCPV6_OPT_NTP_SERVER) {
1213                                 uint16_t stype, slen;
1214                                 uint8_t *sdata;
1215                                 // Test status and bail if error
1216                                 dhcpv6_for_each_option(odata, odata + olen,
1217                                                 stype, slen, sdata) {
1218                                         if (slen == 16 && (stype == NTP_MC_ADDR ||
1219                                                         stype == NTP_SRV_ADDR))
1220                                                 odhcp6c_add_state(STATE_NTP_IP,
1221                                                                 sdata, slen);
1222                                         else if (slen > 0 && stype == NTP_SRV_FQDN)
1223                                                 odhcp6c_add_state(STATE_NTP_FQDN,
1224                                                                 sdata, slen);
1225                                 }
1226                         } else if (otype == DHCPV6_OPT_SIP_SERVER_A) {
1227                                 if (olen == 16)
1228                                         odhcp6c_add_state(STATE_SIP_IP, odata, olen);
1229                         } else if (otype == DHCPV6_OPT_SIP_SERVER_D)
1230                                 odhcp6c_add_state(STATE_SIP_FQDN, odata, olen);
1231                         else if (otype == DHCPV6_OPT_INFO_REFRESH && olen >= 4) {
1232                                 refresh = ntohl_unaligned(odata);
1233                         } else if (otype == DHCPV6_OPT_AUTH) {
1234                                 if (olen == -4 + sizeof(struct dhcpv6_auth_reconfigure)) {
1235                                         struct dhcpv6_auth_reconfigure *r = (void*)&odata[-4];
1236                                         if (r->protocol == 3 && r->algorithm == 1 &&
1237                                                         r->reconf_type == 1)
1238                                                 memcpy(reconf_key, r->key, sizeof(r->key));
1239                                 }
1240                         } else if (otype == DHCPV6_OPT_AFTR_NAME && olen > 3) {
1241                                 size_t cur_len;
1242                                 odhcp6c_get_state(STATE_AFTR_NAME, &cur_len);
1243                                 if (cur_len == 0)
1244                                         odhcp6c_add_state(STATE_AFTR_NAME, odata, olen);
1245                         } else if (otype == DHCPV6_OPT_SOL_MAX_RT && olen == 4) {
1246                                 uint32_t sol_max_rt = ntohl_unaligned(odata);
1247                                 if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN &&
1248                                                 sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX)
1249                                         dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_max_rt;
1250                         } else if (otype == DHCPV6_OPT_INF_MAX_RT && olen == 4) {
1251                                 uint32_t inf_max_rt = ntohl_unaligned(odata);
1252                                 if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN &&
1253                                                 inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
1254                                         dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = inf_max_rt;
1255         #ifdef EXT_CER_ID
1256                         } else if (otype == DHCPV6_OPT_CER_ID && olen == -4 +
1257                                         sizeof(struct dhcpv6_cer_id)) {
1258                                 struct dhcpv6_cer_id *cer_id = (void*)&odata[-4];
1259                                 struct in6_addr any = IN6ADDR_ANY_INIT;
1260                                 if (memcmp(&cer_id->addr, &any, sizeof(any)))
1261                                         odhcp6c_add_state(STATE_CER, &cer_id->addr, sizeof(any));
1262         #endif
1263                         } else if (otype == DHCPV6_OPT_S46_CONT_MAPT) {
1264                                 odhcp6c_add_state(STATE_S46_MAPT, odata, olen);
1265                         } else if (otype == DHCPV6_OPT_S46_CONT_MAPE) {
1266                                 size_t mape_len;
1267                                 odhcp6c_get_state(STATE_S46_MAPE, &mape_len);
1268                                 if (mape_len == 0)
1269                                         odhcp6c_add_state(STATE_S46_MAPE, odata, olen);
1270                         } else if (otype == DHCPV6_OPT_S46_CONT_LW) {
1271                                 odhcp6c_add_state(STATE_S46_LW, odata, olen);
1272                         } else
1273                                 odhcp6c_add_state(STATE_CUSTOM_OPTS, &odata[-4], olen + 4);
1274 
1275                         if (!dopt || !(dopt->flags & OPT_NO_PASSTHRU))
1276                                 odhcp6c_add_state(STATE_PASSTHRU, &odata[-4], olen + 4);
1277                 }
1278         }
1279 
1280         // Bail out if fatal status code was received
1281         if (ret <= 0)
1282                 return ret;
1283 
1284         switch (orig) {
1285         case DHCPV6_MSG_REQUEST:
1286         case DHCPV6_MSG_REBIND:
1287         case DHCPV6_MSG_RENEW:
1288                 state_IAs = dhcpv6_calc_refresh_timers();
1289                 // In case there're no state IA entries
1290                 // keep sending request/renew/rebind messages
1291                 if (state_IAs == 0) {
1292                         ret = 0;
1293                         break;
1294                 }
1295 
1296                 if (orig == DHCPV6_MSG_REQUEST) {
1297                         // All server candidates can be cleared if not yet bound
1298                         if (!odhcp6c_is_bound())
1299                                 dhcpv6_clear_all_server_cand();
1300 
1301                         odhcp6c_clear_state(STATE_SERVER_ADDR);
1302                         odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, 16);
1303                 } else if (orig == DHCPV6_MSG_RENEW) {
1304                         // Send further renews if T1 is not set and if
1305                         // there're IAs which were not in the Reply message
1306                         if (!t1 && state_IAs != updated_IAs) {
1307                                 if (updated_IAs)
1308                                         // Publish updates
1309                                         script_call("updated", 0, false);
1310 
1311                                 /*
1312                                  * RFC8415 states following in §18.2.10.1 :
1313                                  * Sends a Renew/Rebind if any of the IAs are not in the Reply
1314                                  * message, but as this likely indicates that the server that
1315                                  * responded does not support that IA type, sending immediately is
1316                                  * unlikely to produce a different result.  Therefore, the client
1317                                  * MUST rate-limit its transmissions (see Section 14.1) and MAY just
1318                                  * wait for the normal retransmission time (as if the Reply message
1319                                  * had not been received).  The client continues to use other
1320                                  * bindings for which the server did return information
1321                                  */
1322                                 ret = -1;
1323                         }
1324                 } else if (orig == DHCPV6_MSG_REBIND) {
1325                         odhcp6c_clear_state(STATE_SERVER_ADDR);
1326                         odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, 16);
1327 
1328                         // Send further rebinds if T1 and T2 is not set and if
1329                         // there're IAs which were not in the Reply message
1330                         if (!t1 && !t2 && state_IAs != updated_IAs) {
1331                                 if (updated_IAs)
1332                                         // Publish updates
1333                                         script_call("updated", 0, false);
1334 
1335                                 /*
1336                                  * RFC8415 states following in §18.2.10.1 :
1337                                  * Sends a Renew/Rebind if any of the IAs are not in the Reply
1338                                  * message, but as this likely indicates that the server that
1339                                  * responded does not support that IA type, sending immediately is
1340                                  * unlikely to produce a different result.  Therefore, the client
1341                                  * MUST rate-limit its transmissions (see Section 14.1) and MAY just
1342                                  * wait for the normal retransmission time (as if the Reply message
1343                                  * had not been received).  The client continues to use other
1344                                  * bindings for which the server did return information
1345                                  */
1346                                 ret = -1;
1347                         }
1348                 }
1349                 break;
1350 
1351         case DHCPV6_MSG_INFO_REQ:
1352                 // All server candidates can be cleared if not yet bound
1353                 if (!odhcp6c_is_bound())
1354                         dhcpv6_clear_all_server_cand();
1355 
1356                 odhcp6c_clear_state(STATE_SERVER_ADDR);
1357                 odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, 16);
1358 
1359                 t1 = refresh;
1360                 break;
1361 
1362         default:
1363                 break;
1364         }
1365 
1366         return ret;
1367 }
1368 
1369 static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
1370 {
1371         struct dhcpv6_ia_hdr *ia_hdr = (struct dhcpv6_ia_hdr *)opt;
1372         unsigned int updated_IAs = 0;
1373         uint32_t t1, t2;
1374         uint16_t otype, olen;
1375         uint8_t *odata;
1376         char buf[INET6_ADDRSTRLEN];
1377 
1378         t1 = ntohl(ia_hdr->t1);
1379         t2 = ntohl(ia_hdr->t2);
1380 
1381         /* RFC 8415 §21.4
1382         If a client receives an IA_NA with T1 greater than T2 and both T1 and
1383         T2 are greater than 0, the client discards the IA_NA option and
1384         processes the remainder of the message as though the server had not
1385         included the invalid IA_NA option. */
1386         if (t1 > t2 && t1 > 0 && t2 > 0)
1387                 return 0;
1388 
1389         syslog(LOG_INFO, "%s %04x T1 %d T2 %d", ntohs(ia_hdr->type) == DHCPV6_OPT_IA_PD ? "IA_PD" : "IA_NA", ntohl(ia_hdr->iaid), t1, t2);
1390 
1391         // Update address IA
1392         dhcpv6_for_each_option(&ia_hdr[1], end, otype, olen, odata) {
1393                 struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT, 0, 0,
1394                                 IN6ADDR_ANY_INIT, 0, 0, 0, 0, 0, 0};
1395 
1396                 entry.iaid = ia_hdr->iaid;
1397 
1398                 switch (otype) {
1399                 case DHCPV6_OPT_IA_PREFIX: {
1400                         struct dhcpv6_ia_prefix *prefix = (void*)&odata[-4];
1401                         if (olen + 4U < sizeof(*prefix))
1402                                 continue;
1403 
1404                         entry.valid = ntohl(prefix->valid);
1405                         entry.preferred = ntohl(prefix->preferred);
1406 
1407                         if (entry.preferred > entry.valid)
1408                                 continue;
1409 
1410                         /*      RFC 8415 §21.21
1411                         Recommended values for T1 and T2 are 0.5 and 0.8 times the
1412                         shortest preferred lifetime of the prefixes in the IA_PD that the
1413                         server is willing to extend. */
1414                         entry.t1 = (t1 ? t1 : (entry.preferred != UINT32_MAX ? 0.5 * entry.preferred : UINT32_MAX));
1415                         entry.t2 = (t2 ? t2 : (entry.preferred != UINT32_MAX ? 0.8 * entry.preferred : UINT32_MAX));
1416                         if (entry.t1 > entry.t2)
1417                                 entry.t1 = entry.t2;
1418 
1419                         entry.length = prefix->prefix;
1420                         entry.target = prefix->addr;
1421                         uint16_t stype, slen;
1422                         uint8_t *sdata;
1423 
1424                         // Parse sub-options for PD-exclude or error status code
1425                         bool update_state = true;
1426                         dhcpv6_for_each_option(odata + sizeof(*prefix) - 4U,
1427                                         odata + olen, stype, slen, sdata) {
1428                                 if (stype == DHCPV6_OPT_STATUS && slen > 2) {
1429                                         /* RFC 8415 §21.22
1430                                         The status of any operations involving this IA Prefix option is
1431                                         indicated in a Status Code option (see Section 21.13) in the
1432                                         IAprefix-options field. */
1433                                         uint8_t *status_msg = &sdata[2];
1434                                         uint16_t msg_len = slen - 2;
1435                                         uint16_t code = ((int)sdata[0]) << 8 | ((int)sdata[1]);
1436 
1437                                         if (code == DHCPV6_Success)
1438                                                 continue;
1439 
1440                                         dhcpv6_log_status_code(code, "IA_PREFIX", status_msg, msg_len);
1441                                         if (ret) *ret = 0; // renewal failed
1442                                 } else if (stype == DHCPV6_OPT_PD_EXCLUDE && slen > 2) {
1443                                         /*      RFC 6603 §4.2 Prefix Exclude option */
1444                                         uint8_t elen = sdata[0];
1445                                         if (elen > 64)
1446                                                 elen = 64;
1447 
1448                                         if (entry.length < 32 || elen <= entry.length) {
1449                                                 update_state = false;
1450                                                 continue;
1451                                         }
1452 
1453                                         uint8_t bytes = ((elen - entry.length - 1) / 8) + 1;
1454                                         if (slen <= bytes) {
1455                                                 update_state = false;
1456                                                 continue;
1457                                         }
1458 
1459                                         uint32_t exclude = 0;
1460                                         do {
1461                                                 exclude = exclude << 8 | sdata[bytes];
1462                                         } while (--bytes);
1463 
1464                                         exclude >>= 8 - ((elen - entry.length) % 8);
1465                                         exclude <<= 64 - elen;
1466 
1467                                         // Abusing router & priority fields for exclusion
1468                                         entry.router = entry.target;
1469                                         entry.router.s6_addr32[1] |= htonl(exclude);
1470                                         entry.priority = elen;
1471                                 }
1472                         }
1473 
1474                         if (update_state) {
1475                                 if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0, 0))
1476                                         updated_IAs++;
1477 
1478                                 syslog(LOG_INFO, "%s/%d preferred %d valid %d",
1479                                                 inet_ntop(AF_INET6, &entry.target, buf, sizeof(buf)),
1480                                                 entry.length, entry.preferred , entry.valid);
1481                         }
1482 
1483                         entry.priority = 0;
1484                         memset(&entry.router, 0, sizeof(entry.router));
1485                         break;
1486                 }
1487                 case DHCPV6_OPT_IA_ADDR: {
1488                         struct dhcpv6_ia_addr *addr = (void*)&odata[-4];
1489                         if (olen + 4U < sizeof(*addr))
1490                                 continue;
1491 
1492                         entry.preferred = ntohl(addr->preferred);
1493                         entry.valid = ntohl(addr->valid);
1494 
1495                         if (entry.preferred > entry.valid)
1496                                 continue;
1497 
1498                         entry.t1 = (t1 ? t1 : (entry.preferred != UINT32_MAX ? 0.5 * entry.preferred : UINT32_MAX));
1499                         entry.t2 = (t2 ? t2 : (entry.preferred != UINT32_MAX ? 0.8 * entry.preferred : UINT32_MAX));
1500                         if (entry.t1 > entry.t2)
1501                                 entry.t1 = entry.t2;
1502 
1503                         entry.length = 128;
1504                         entry.target = addr->addr;
1505                         uint16_t stype, slen;
1506                         uint8_t *sdata;
1507 
1508                         bool update_state = true;
1509                         dhcpv6_for_each_option(odata + sizeof(*addr) - 4U,
1510                                         odata + olen, stype, slen, sdata) {
1511                                 if (stype == DHCPV6_OPT_STATUS && slen > 2) {
1512                                         /* RFC 8415 §21.6
1513                                         The status of any operations involving this IA Address is indicated
1514                                         in a Status Code option in the IAaddr-options field, as specified in
1515                                         Section 21.13. */
1516                                         uint8_t *status_msg = &sdata[2];
1517                                         uint16_t msg_len = slen - 2;
1518                                         uint16_t code = ((int)sdata[0]) << 8 | ((int)sdata[1]);
1519 
1520                                         if (code == DHCPV6_Success)
1521                                                 continue;
1522 
1523                                         dhcpv6_log_status_code(code, "IA_ADDR", status_msg, msg_len);
1524                                         if (ret) *ret = 0; // renewal failed
1525                                         update_state = false;
1526                                 }
1527                         }
1528 
1529                         if (update_state) {
1530                                 if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0, 0))
1531                                         updated_IAs++;
1532 
1533                                 syslog(LOG_INFO, "%s preferred %d valid %d",
1534                                                 inet_ntop(AF_INET6, &entry.target, buf, sizeof(buf)),
1535                                                 entry.preferred , entry.valid);
1536                         }
1537                         break;
1538                 }
1539                 default:
1540                         break;
1541                 }
1542         }
1543 
1544         return updated_IAs;
1545 }
1546 
1547 static unsigned int dhcpv6_calc_refresh_timers(void)
1548 {
1549         struct odhcp6c_entry *e;
1550         size_t ia_na_entries, ia_pd_entries, i;
1551         size_t invalid_entries = 0;
1552         int64_t l_t1 = UINT32_MAX, l_t2 = UINT32_MAX, l_t3 = 0;
1553 
1554         e = odhcp6c_get_state(STATE_IA_NA, &ia_na_entries);
1555         ia_na_entries /= sizeof(*e);
1556 
1557         for (i = 0; i < ia_na_entries; i++) {
1558                 /* Exclude invalid IA_NA entries */
1559                 if (!e[i].valid) {
1560                         invalid_entries++;
1561                         continue;
1562                 }
1563 
1564                 if (e[i].t1 < l_t1)
1565                         l_t1 = e[i].t1;
1566 
1567                 if (e[i].t2 < l_t2)
1568                         l_t2 = e[i].t2;
1569 
1570                 if (e[i].valid > l_t3)
1571                         l_t3 = e[i].valid;
1572         }
1573 
1574         e = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entries);
1575         ia_pd_entries /= sizeof(*e);
1576 
1577         for (i = 0; i < ia_pd_entries; i++) {
1578                 /* Exclude invalid IA_PD entries */
1579                 if (!e[i].valid) {
1580                         invalid_entries++;
1581                         continue;
1582                 }
1583 
1584                 if (e[i].t1 < l_t1)
1585                         l_t1 = e[i].t1;
1586 
1587                 if (e[i].t2 < l_t2)
1588                         l_t2 = e[i].t2;
1589 
1590                 if (e[i].valid > l_t3)
1591                         l_t3 = e[i].valid;
1592         }
1593 
1594         if (ia_pd_entries + ia_na_entries - invalid_entries) {
1595                 t1 = l_t1;
1596                 t2 = l_t2;
1597                 t3 = l_t3;
1598 
1599                 syslog(LOG_INFO, "T1 %"PRId64"s, T2 %"PRId64"s, T3 %"PRId64"s", t1, t2, t3);
1600         }
1601 
1602         return (unsigned int)(ia_pd_entries + ia_na_entries);
1603 }
1604 
1605 static void dhcpv6_log_status_code(const uint16_t code, const char *scope,
1606                 const void *status_msg, int len)
1607 {
1608         const char *src = status_msg;
1609         char buf[len + 3];
1610         char *dst = buf;
1611 
1612         if (len) {
1613                 *dst++ = '(';
1614                 while (len--) {
1615                         *dst = isprint((unsigned char)*src) ? *src : '?';
1616                         src++;
1617                         dst++;
1618                 }
1619                 *dst++ = ')';
1620         }
1621 
1622         *dst = 0;
1623 
1624         syslog(LOG_WARNING, "Server returned %s status '%s %s'",
1625                 scope, dhcpv6_status_code_to_str(code), buf);
1626 }
1627 
1628 static void dhcpv6_handle_status_code(const enum dhcpv6_msg orig,
1629                 const uint16_t code, const void *status_msg, const int len,
1630                 int *ret)
1631 {
1632         dhcpv6_log_status_code(code, "message", status_msg, len);
1633 
1634         switch (code) {
1635         case DHCPV6_UnspecFail:
1636                 // Generic failure
1637                 *ret = 0;
1638                 break;
1639 
1640         case DHCPV6_UseMulticast:
1641                 switch(orig) {
1642                 case DHCPV6_MSG_REQUEST:
1643                 case DHCPV6_MSG_RENEW:
1644                 case DHCPV6_MSG_RELEASE:
1645                 case DHCPV6_MSG_DECLINE:
1646                         // Message needs to be retransmitted according to RFC3315 chapter 18.1.8
1647                         server_addr = in6addr_any;
1648                         *ret = 0;
1649                         break;
1650                 default:
1651                         break;
1652                 }
1653                 break;
1654 
1655         case DHCPV6_NoAddrsAvail:
1656         case DHCPV6_NoPrefixAvail:
1657                 if (orig == DHCPV6_MSG_REQUEST)
1658                         *ret = 0; // Failure
1659                 break;
1660 
1661         default:
1662                 break;
1663         }
1664 }
1665 
1666 static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
1667                 const struct dhcpv6_ia_hdr *ia_hdr, const uint16_t code,
1668                 const void *status_msg, const int len,
1669                 bool handled_status_codes[_DHCPV6_Status_Max], int *ret)
1670 {
1671         dhcpv6_log_status_code(code, ia_hdr->type == DHCPV6_OPT_IA_NA ?
1672                 "IA_NA" : "IA_PD", status_msg, len);
1673 
1674         switch (code) {
1675         case DHCPV6_NoBinding:
1676                 switch (orig) {
1677                 case DHCPV6_MSG_RENEW:
1678                 case DHCPV6_MSG_REBIND:
1679                         if ((*ret > 0) && !handled_status_codes[code])
1680                                 *ret = dhcpv6_request(DHCPV6_MSG_REQUEST);
1681                         break;
1682 
1683                 default:
1684                         break;
1685                 }
1686                 break;
1687 
1688         default:
1689                 *ret = 0;
1690                 break;
1691         }
1692 }
1693 
1694 // Note this always takes ownership of cand->ia_na and cand->ia_pd
1695 static void dhcpv6_add_server_cand(const struct dhcpv6_server_cand *cand)
1696 {
1697         size_t cand_len, i;
1698         struct dhcpv6_server_cand *c = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
1699 
1700         // Remove identical duid server candidate
1701         for (i = 0; i < cand_len / sizeof(*c); ++i) {
1702                 if (cand->duid_len == c[i].duid_len &&
1703                                 !memcmp(cand->duid, c[i].duid, cand->duid_len)) {
1704                         free(c[i].ia_na);
1705                         free(c[i].ia_pd);
1706                         odhcp6c_remove_state(STATE_SERVER_CAND, i * sizeof(*c), sizeof(*c));
1707                         break;
1708                 }
1709         }
1710 
1711         for (i = 0, c = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
1712                 i < cand_len / sizeof(*c); ++i) {
1713                 if (c[i].preference < cand->preference)
1714                         break;
1715         }
1716 
1717         if (odhcp6c_insert_state(STATE_SERVER_CAND, i * sizeof(*c), cand, sizeof(*cand))) {
1718                 free(cand->ia_na);
1719                 free(cand->ia_pd);
1720         }
1721 }
1722 
1723 static void dhcpv6_clear_all_server_cand(void)
1724 {
1725         size_t cand_len, i;
1726         struct dhcpv6_server_cand *c = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
1727 
1728         // Server candidates need deep delete for IA_NA/IA_PD
1729         for (i = 0; i < cand_len / sizeof(*c); ++i) {
1730                 free(c[i].ia_na);
1731                 free(c[i].ia_pd);
1732         }
1733         odhcp6c_clear_state(STATE_SERVER_CAND);
1734 }
1735 
1736 int dhcpv6_promote_server_cand(void)
1737 {
1738         size_t cand_len;
1739         struct dhcpv6_server_cand *cand = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
1740         uint16_t hdr[2];
1741         int ret = DHCPV6_STATELESS;
1742 
1743         // Clear lingering candidate state info
1744         odhcp6c_clear_state(STATE_SERVER_ID);
1745         odhcp6c_clear_state(STATE_IA_NA);
1746         odhcp6c_clear_state(STATE_IA_PD);
1747 
1748         if (!cand_len)
1749                 return -1;
1750 
1751         if (cand->has_noaddravail && na_mode == IA_MODE_TRY) {
1752                 na_mode = IA_MODE_NONE;
1753 
1754                 dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
1755                 dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
1756 
1757                 return dhcpv6_request(DHCPV6_MSG_SOLICIT);
1758         }
1759 
1760         hdr[0] = htons(DHCPV6_OPT_SERVERID);
1761         hdr[1] = htons(cand->duid_len);
1762         odhcp6c_add_state(STATE_SERVER_ID, hdr, sizeof(hdr));
1763         odhcp6c_add_state(STATE_SERVER_ID, cand->duid, cand->duid_len);
1764         accept_reconfig = cand->wants_reconfigure;
1765 
1766         if (cand->ia_na_len) {
1767                 odhcp6c_add_state(STATE_IA_NA, cand->ia_na, cand->ia_na_len);
1768                 free(cand->ia_na);
1769                 if (na_mode != IA_MODE_NONE)
1770                         ret = DHCPV6_STATEFUL;
1771         }
1772 
1773         if (cand->ia_pd_len) {
1774                 odhcp6c_add_state(STATE_IA_PD, cand->ia_pd, cand->ia_pd_len);
1775                 free(cand->ia_pd);
1776                 if (pd_mode != IA_MODE_NONE)
1777                         ret = DHCPV6_STATEFUL;
1778         }
1779 
1780         dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
1781         dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
1782 
1783         odhcp6c_remove_state(STATE_SERVER_CAND, 0, sizeof(*cand));
1784 
1785         return ret;
1786 }
1787 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt