• 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 <arpa/inet.h>
 17 #include <ctype.h>
 18 #include <errno.h>
 19 #include <fcntl.h>
 20 #include <inttypes.h>
 21 #include <libubox/md5.h>
 22 #include <limits.h>
 23 #include <netinet/in.h>
 24 #include <net/if.h>
 25 #include <net/ethernet.h>
 26 #include <resolv.h>
 27 #include <signal.h>
 28 #include <stdbool.h>
 29 #include <stdlib.h>
 30 #include <string.h>
 31 #include <sys/ioctl.h>
 32 #include <sys/socket.h>
 33 #include <sys/time.h>
 34 #include <time.h>
 35 #include <unistd.h>
 36 
 37 #include "config.h"
 38 #include "odhcp6c.h"
 39 
 40 #define ALL_DHCPV6_RELAYS {{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
 41                 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02}}}
 42 #define DHCPV6_CLIENT_PORT 546
 43 #define DHCPV6_SERVER_PORT 547
 44 #define DHCPV6_DUID_LLADDR 3
 45 
 46 #define DHCPV6_SOL_MAX_RT_MIN 60
 47 #define DHCPV6_SOL_MAX_RT_MAX 86400
 48 #define DHCPV6_INF_MAX_RT_MIN 60
 49 #define DHCPV6_INF_MAX_RT_MAX 86400
 50 
 51 static bool dhcpv6_response_is_valid(const void *buf, ssize_t len,
 52                 const uint8_t transaction[3], enum dhcpv6_msg req_msg_type,
 53                 const struct in6_addr *daddr);
 54 
 55 static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret);
 56 
 57 static unsigned int dhcpv6_calc_refresh_timers(void);
 58 static void dhcpv6_handle_status_code(_o_unused const enum dhcpv6_msg orig,
 59                 const uint16_t code, const void *status_msg, const int len,
 60                 int *ret);
 61 static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
 62                 const struct dhcpv6_ia_hdr *ia_hdr, const uint16_t code,
 63                 const void *status_msg, const int len,
 64                 bool handled_status_codes[_DHCPV6_Status_Max],
 65                 int *ret);
 66 static void dhcpv6_add_server_cand(const struct dhcpv6_server_cand *cand);
 67 static void dhcpv6_clear_all_server_cand(void);
 68 
 69 static void dhcpv6_log_status_code(const uint16_t code, const char *scope,
 70                 const void *status_msg, int len);
 71 
 72 static reply_handler dhcpv6_handle_reply;
 73 static reply_handler dhcpv6_handle_advert;
 74 static reply_handler dhcpv6_handle_rebind_reply;
 75 static reply_handler dhcpv6_handle_reconfigure;
 76 static int dhcpv6_commit_advert(void);
 77 
 78 // RFC 3315 - 5.5 Timeout and Delay values
 79 static const struct dhcpv6_retx dhcpv6_retx_default[_DHCPV6_MSG_MAX] = {
 80         [DHCPV6_MSG_UNKNOWN] = {
 81                 0,
 82                 1,
 83                 120,
 84                 0,
 85                 "<POLL>",
 86                 dhcpv6_handle_reconfigure,
 87                 NULL,
 88                 false,
 89                 0,
 90                 0,
 91                 0,
 92                 {0, 0, 0},
 93                 0,
 94                 0,
 95                 0,
 96                 -1,
 97                 0
 98         },
 99         [DHCPV6_MSG_SOLICIT] = {
100                 DHCPV6_MAX_DELAY,
101                 DHCPV6_SOL_INIT_RT,
102                 DHCPV6_SOL_MAX_RT,
103                 0,
104                 "SOLICIT",
105                 dhcpv6_handle_advert,
106                 dhcpv6_commit_advert,
107                 false,
108                 0,
109                 0,
110                 0,
111                 {0, 0, 0},
112                 0,
113                 0,
114                 0,
115                 -1,
116                 0
117         },
118         [DHCPV6_MSG_REQUEST] = {
119                 0,
120                 DHCPV6_REQ_INIT_RT,
121                 DHCPV6_REQ_MAX_RT,
122                 DHCPV6_REQ_MAX_RC,
123                 "REQUEST",
124                 dhcpv6_handle_reply,
125                 NULL,
126                 false,
127                 0,
128                 0,
129                 0,
130                 {0, 0, 0},
131                 0,
132                 0,
133                 0,
134                 -1,
135                 0
136         },
137         [DHCPV6_MSG_RENEW] = {
138                 0,
139                 DHCPV6_REN_INIT_RT,
140                 DHCPV6_REN_MAX_RT,
141                 0,
142                 "RENEW",
143                 dhcpv6_handle_reply,
144                 NULL,
145                 false,
146                 0,
147                 0,
148                 0,
149                 {0, 0, 0},
150                 0,
151                 0,
152                 0,
153                 -1,
154                 0
155         },
156         [DHCPV6_MSG_REBIND] = {
157                 0,
158                 DHCPV6_REB_INIT_RT,
159                 DHCPV6_REB_MAX_RT,
160                 0,
161                 "REBIND",
162                         dhcpv6_handle_rebind_reply,
163                 NULL,
164                 false,
165                 0,
166                 0,
167                 0,
168                 {0, 0, 0},
169                 0,
170                 0,
171                 0,
172                 -1,
173                 0
174         },
175         [DHCPV6_MSG_RELEASE] = {
176                 0,
177                 DHCPV6_REL_INIT_RT,
178                 0,
179                 DHCPV6_REL_MAX_RC,
180                 "RELEASE",
181                 NULL,
182                 NULL,
183                 false,
184                 0,
185                 0,
186                 0,
187                 {0, 0, 0},
188                 0,
189                 0,
190                 0,
191                 -1,
192                 0
193         },
194         [DHCPV6_MSG_DECLINE] = {
195                 0,
196                 DHCPV6_DEC_INIT_RT,
197                 0,
198                 DHCPV6_DEC_MAX_RC,
199                 "DECLINE",
200                 NULL,
201                 NULL,
202                 false,
203                 0,
204                 0,
205                 0,
206                 {0, 0, 0},
207                 0,
208                 0,
209                 0,
210                 -1,
211                 0
212         },
213         [DHCPV6_MSG_INFO_REQ] = {
214                 DHCPV6_MAX_DELAY,
215                 DHCPV6_INF_INIT_RT,
216                 DHCPV6_INF_MAX_RT,
217                 0,
218                 "INFOREQ",
219                 dhcpv6_handle_reply,
220                 NULL,
221                 false,
222                 0,
223                 0,
224                 0,
225                 {0, 0, 0},
226                 0,
227                 0,
228                 0,
229                 -1,
230                 0
231         },
232 };
233 static struct dhcpv6_retx dhcpv6_retx[_DHCPV6_MSG_MAX] = {0};
234 
235 // Sockets
236 static int sock = -1;
237 static int ifindex = -1;
238 static int64_t t1 = 0, t2 = 0, t3 = 0;
239 
240 // IA states
241 static enum odhcp6c_ia_mode na_mode = IA_MODE_NONE, pd_mode = IA_MODE_NONE;
242 static bool stateful_only_mode = false;
243 static bool accept_reconfig = false;
244 // Server unicast address
245 static struct in6_addr server_addr = IN6ADDR_ANY_INIT;
246 
247 // Initial state of the DHCPv6 service
248 static enum dhcpv6_state dhcpv6_state = DHCPV6_INIT;
249 static int dhcpv6_state_timeout = 0;
250 
251 // Authentication options
252 static enum odhcp6c_auth_protocol auth_protocol = AUTH_PROT_RKAP;
253 static uint8_t reconf_key[16];
254 
255 // client options
256 static unsigned int client_options = 0;
257 
258 // counters for statistics
259 static struct dhcpv6_stats dhcpv6_stats = {0};
260 
261 // config
262 static struct config_dhcp* config_dhcp = NULL;
263 
264 // store unique ifname hash to use as IA->IAID
265 static uint32_t ifname_hash_iaid = 0;
266 
267 static uint32_t ntohl_unaligned(const uint8_t *data)
268 {
269         uint32_t buf;
270 
271         memcpy(&buf, data, sizeof(buf));
272         return ntohl(buf);
273 }
274 
275 static void dhcpv6_next_state(void)
276 {
277         dhcpv6_state++;
278         dhcpv6_reset_state_timeout();
279 }
280 
281 static void dhcpv6_prev_state(void)
282 {
283         dhcpv6_state--;
284         dhcpv6_reset_state_timeout();
285 }
286 
287 static void dhcpv6_inc_counter(enum dhcpv6_msg type)
288 {
289         switch (type) {
290         case DHCPV6_MSG_SOLICIT:
291                 dhcpv6_stats.solicit++;
292                 break;
293 
294         case DHCPV6_MSG_ADVERT:
295                 dhcpv6_stats.advertise++;
296                 break;
297 
298         case DHCPV6_MSG_REQUEST:
299                 dhcpv6_stats.request++;
300                 break;
301 
302         case DHCPV6_MSG_RENEW:
303                 dhcpv6_stats.renew++;
304                 break;
305 
306         case DHCPV6_MSG_REBIND:
307                 dhcpv6_stats.rebind++;
308                 break;
309 
310         case DHCPV6_MSG_REPLY:
311                 dhcpv6_stats.reply++;
312                 break;
313 
314         case DHCPV6_MSG_RELEASE:
315                 dhcpv6_stats.release++;
316                 break;
317 
318         case DHCPV6_MSG_DECLINE:
319                 dhcpv6_stats.decline++;
320                 break;
321 
322         case DHCPV6_MSG_RECONF:
323                 dhcpv6_stats.reconfigure++;
324                 break;
325 
326         case DHCPV6_MSG_INFO_REQ:
327                 dhcpv6_stats.information_request++;
328                 break;
329 
330         default:
331                 break;
332         }
333 }
334 
335 static char *dhcpv6_msg_to_str(enum dhcpv6_msg msg)
336 {
337         switch (msg) {
338         case DHCPV6_MSG_SOLICIT:
339                 return "SOLICIT";
340 
341         case DHCPV6_MSG_ADVERT:
342                 return "ADVERTISE";
343 
344         case DHCPV6_MSG_REQUEST:
345                 return "REQUEST";
346 
347         case DHCPV6_MSG_RENEW:
348                 return "RENEW";
349 
350         case DHCPV6_MSG_REBIND:
351                 return "REBIND";
352 
353         case DHCPV6_MSG_REPLY:
354                 return "REPLY";
355 
356         case DHCPV6_MSG_RELEASE:
357                 return "RELEASE";
358 
359         case DHCPV6_MSG_DECLINE:
360                 return "DECLINE";
361 
362         case DHCPV6_MSG_RECONF:
363                 return "RECONFIGURE";
364 
365         case DHCPV6_MSG_INFO_REQ:
366                 return "INFORMATION REQUEST";
367 
368         default:
369                 break;
370         }
371 
372         return "UNKNOWN";
373 }
374 
375 static char *dhcpv6_status_code_to_str(uint16_t code)
376 {
377         switch (code) {
378         case DHCPV6_Success:
379                 return "Success";
380 
381         case DHCPV6_UnspecFail:
382                 return "Unspecified Failure";
383 
384         case DHCPV6_NoAddrsAvail:
385                 return "No Address Available";
386 
387         case DHCPV6_NoBinding:
388                 return "No Binding";
389 
390         case DHCPV6_NotOnLink:
391                 return "Not On Link";
392 
393         case DHCPV6_UseMulticast:
394                 return "Use Multicast";
395 
396         case DHCPV6_NoPrefixAvail:
397                 return "No Prefix Available";
398 
399         default:
400                 break;
401         }
402 
403         return "Unknown";
404 }
405 
406 const char *dhcpv6_state_to_str(enum dhcpv6_state state)
407 {
408         switch (state) {
409         case DHCPV6_INIT:
410                 return "INIT";
411 
412         case DHCPV6_SOLICIT:
413                 return "SOLICIT";
414 
415         case DHCPV6_SOLICIT_PROCESSING:
416                 return "SOLICIT_PROCESSING";
417 
418         case DHCPV6_ADVERT:
419                 return "ADVERT";
420 
421         case DHCPV6_REQUEST:
422                 return "REQUEST";
423 
424         case DHCPV6_REQUEST_PROCESSING:
425                 return "REQUEST_PROCESSING";
426 
427         case DHCPV6_REPLY:
428                 return "REPLY";
429 
430         case DHCPV6_BOUND:
431                 return "BOUND";
432 
433         case DHCPV6_BOUND_PROCESSING:
434                 return "BOUND_PROCESSING";
435 
436         case DHCPV6_BOUND_REPLY:
437                 return "BOUND_REPLY";
438 
439         case DHCPV6_RECONF:
440                 return "RECONF";
441 
442         case DHCPV6_RECONF_PROCESSING:
443                 return "RECONF_PROCESSING";
444 
445         case DHCPV6_RECONF_REPLY:
446                 return "RECONF_REPLY";
447 
448         case DHCPV6_RENEW:
449                 return "RENEW";
450 
451         case DHCPV6_RENEW_PROCESSING:
452                 return "RENEW_PROCESSING";
453 
454         case DHCPV6_RENEW_REPLY:
455                 return "RENEW_REPLY";
456 
457         case DHCPV6_REBIND:
458                 return "REBIND";
459 
460         case DHCPV6_REBIND_PROCESSING:
461                 return "REBIND_PROCESSING";
462 
463         case DHCPV6_REBIND_REPLY:
464                 return "REBIND_REPLY";
465 
466         case DHCPV6_INFO:
467                 return "INFO";
468 
469         case DHCPV6_INFO_PROCESSING:
470                 return "INFO_PROCESSING";
471 
472         case DHCPV6_INFO_REPLY:
473                 return "INFO_REPLY";
474 
475         case DHCPV6_EXIT:
476                 return "EXIT";
477 
478         default:
479                 return "INVALID_STATE";
480         }
481 }
482 
483 static int fd_set_nonblocking(int sockfd)
484 {
485         int flags = fcntl(sockfd, F_GETFL, 0);
486         if (flags == -1) {
487                 error(
488                         "Failed to get the dhcpv6 socket flags: fcntl F_GETFL failed (%s)",
489                         strerror(errno));
490                 return -1;
491         }
492 
493         // Set the socket to non-blocking
494         if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
495                 error(
496                         "Failed to set the dhcpv6 socket to non-blocking: fcntl F_SETFL failed (%s)",
497                         strerror(errno));
498                 return -1;
499         }
500 
501         return 0;
502 }
503 
504 int dhcpv6_get_socket(void)
505 {
506         return sock;
507 }
508 
509 enum dhcpv6_state dhcpv6_get_state(void)
510 {
511         return dhcpv6_state;
512 }
513 
514 void dhcpv6_set_state(enum dhcpv6_state state)
515 {
516         dhcpv6_state = state;
517         dhcpv6_reset_state_timeout();
518 }
519 
520 int dhcpv6_get_state_timeout(void)
521 {
522         return dhcpv6_state_timeout;
523 }
524 
525 void dhcpv6_set_state_timeout(int timeout)
526 {
527         if (timeout > 0 && (dhcpv6_state_timeout == 0 || timeout < dhcpv6_state_timeout)) {
528                 dhcpv6_state_timeout = timeout;
529         }
530 }
531 
532 void dhcpv6_reset_state_timeout(void)
533 {
534         dhcpv6_state_timeout = 0;
535 }
536 
537 struct dhcpv6_stats dhcpv6_get_stats(void)
538 {
539         return dhcpv6_stats;
540 }
541 
542 void dhcpv6_reset_stats(void)
543 {
544         memset(&dhcpv6_stats, 0, sizeof(dhcpv6_stats));
545 }
546 
547 static uint32_t dhcpv6_generate_iface_iaid(const char *ifname) {
548         uint8_t hash[16] = {0};
549         uint32_t iaid;
550         md5_ctx_t md5;
551 
552         md5_begin(&md5);
553         md5_hash(ifname, strlen(ifname), &md5);
554         md5_end(hash, &md5);
555 
556         iaid = hash[0] << 24;
557         iaid |= hash[1] << 16;
558         iaid |= hash[2] << 8;
559         iaid |= hash[3];
560 
561         return iaid;
562 }
563 
564 int init_dhcpv6(const char *ifname)
565 {
566         config_dhcp = config_dhcp_get();
567 
568         memcpy(dhcpv6_retx, dhcpv6_retx_default, sizeof(dhcpv6_retx));
569         config_apply_dhcp_rtx(dhcpv6_retx);
570 
571         client_options = config_dhcp->client_options;
572         na_mode = config_dhcp->ia_na_mode;
573         pd_mode = config_dhcp->ia_pd_mode;
574         stateful_only_mode = config_dhcp->stateful_only_mode;
575         auth_protocol = config_dhcp->auth_protocol;
576 
577         sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
578         if (sock < 0)
579                 goto failure;
580 
581         // Detect interface
582         struct ifreq ifr;
583         memset(&ifr, 0, sizeof(ifr));
584         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
585         if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
586                 goto failure;
587 
588         ifname_hash_iaid = dhcpv6_generate_iface_iaid(ifname);
589 
590         ifindex = ifr.ifr_ifindex;
591 
592         // Set the socket to non-blocking mode
593         if (fd_set_nonblocking(sock) < 0)
594                 goto failure;
595 
596         // Build our FQDN
597         size_t fqdn_len;
598         odhcp6c_get_state(STATE_OUR_FQDN, &fqdn_len);
599         if(fqdn_len == 0) {
600                 char fqdn_buf[256];
601                 gethostname(fqdn_buf, sizeof(fqdn_buf));
602                 struct {
603                         uint16_t type;
604                         uint16_t len;
605                         uint8_t flags;
606                         uint8_t data[256];
607                 } fqdn = {0};
608                 int dn_result = dn_comp(fqdn_buf, fqdn.data,
609                                 sizeof(fqdn.data), NULL, NULL);
610                 fqdn_len = 0;
611                 if (dn_result > 0) {
612                         fqdn.type = htons(DHCPV6_OPT_FQDN);
613                         fqdn.len = htons(1 + dn_result);
614                         fqdn.flags = 0;
615                         fqdn_len = DHCPV6_OPT_HDR_SIZE + 1 + dn_result;
616                 }
617                 odhcp6c_add_state(STATE_OUR_FQDN, &fqdn, fqdn_len);
618         }
619 
620         // Create client DUID
621         size_t client_id_len;
622         odhcp6c_get_state(STATE_CLIENT_ID, &client_id_len);
623         if (client_id_len == 0) {
624                 uint8_t duid[14] = {0, DHCPV6_OPT_CLIENTID, 0, 10, 0,
625                                 DHCPV6_DUID_LLADDR, 0, 1};
626 
627                 if (ioctl(sock, SIOCGIFHWADDR, &ifr) >= 0)
628                         memcpy(&duid[8], ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
629 
630                 uint8_t zero[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
631                 struct ifreq ifs[100], *ifp, *ifend;
632                 struct ifconf ifc;
633                 ifc.ifc_req = ifs;
634                 ifc.ifc_len = sizeof(ifs);
635 
636                 if (!memcmp(&duid[8], zero, ETHER_ADDR_LEN) &&
637                                 ioctl(sock, SIOCGIFCONF, &ifc) >= 0) {
638                         // If our interface doesn't have an address...
639                         ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
640                         for (ifp = ifc.ifc_req; ifp < ifend &&
641                                         !memcmp(&duid[8], zero, ETHER_ADDR_LEN); ifp++) {
642                                 memcpy(ifr.ifr_name, ifp->ifr_name,
643                                                 sizeof(ifr.ifr_name));
644                                 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
645                                         continue;
646 
647                                 memcpy(&duid[8], ifr.ifr_hwaddr.sa_data,
648                                                 ETHER_ADDR_LEN);
649                         }
650                 }
651 
652                 odhcp6c_add_state(STATE_CLIENT_ID, duid, sizeof(duid));
653         }
654 
655         // Create ORO
656         if (!(client_options & DHCPV6_STRICT_OPTIONS)) {
657                 uint16_t oro[] = {
658                         htons(DHCPV6_OPT_SIP_SERVER_D),
659                         htons(DHCPV6_OPT_SIP_SERVER_A),
660                         htons(DHCPV6_OPT_DNS_SERVERS),
661                         htons(DHCPV6_OPT_DNS_DOMAIN),
662                         htons(DHCPV6_OPT_SNTP_SERVERS),
663                         htons(DHCPV6_OPT_NTP_SERVER),
664                         htons(DHCPV6_OPT_PD_EXCLUDE),
665                         /* RFC8910: Clients that support this option SHOULD include it */
666                         htons(DHCPV6_OPT_CAPTIVE_PORTAL),
667                 };
668                 odhcp6c_add_state(STATE_ORO, oro, sizeof(oro));
669         }
670         // Required ORO
671         uint16_t req_oro[] = {
672                 htons(DHCPV6_OPT_INF_MAX_RT),
673                 htons(DHCPV6_OPT_SOL_MAX_RT),
674                 htons(DHCPV6_OPT_INFO_REFRESH),
675         };
676         odhcp6c_add_state(STATE_ORO, req_oro, sizeof(req_oro));
677 
678         // Configure IPv6-options
679         int val = 1;
680         if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)) < 0)
681                 goto failure;
682 
683         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
684                 goto failure;
685 
686         if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)) < 0)
687                 goto failure;
688 
689         if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0)
690                 goto failure;
691 
692         if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &(config_dhcp->sk_prio), sizeof(config_dhcp->sk_prio)) < 0)
693                 goto failure;
694 
695         val = config_dhcp->dscp << 2;
696         if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) {
697                 goto failure;
698         }
699 
700         struct sockaddr_in6 client_addr = { .sin6_family = AF_INET6,
701                 .sin6_port = htons(DHCPV6_CLIENT_PORT), .sin6_flowinfo = 0 };
702 
703         if (bind(sock, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0)
704                 goto failure;
705 
706         return 0;
707 
708 failure:
709         if (sock >= 0)
710                 close(sock);
711 
712         return -1;
713 }
714 
715 enum {
716         IOV_HDR=0,
717         IOV_ORO,
718         IOV_CL_ID,
719         IOV_SRV_ID,
720         IOV_OPTS,
721         IOV_RECONF_ACCEPT,
722         IOV_FQDN,
723         IOV_HDR_IA_NA,
724         IOV_IA_NA,
725         IOV_IA_PD,
726         IOV_TOTAL
727 };
728 
729 int dhcpv6_get_ia_mode(void)
730 {
731         int mode = DHCPV6_UNKNOWN;
732 
733         if (na_mode == IA_MODE_NONE && pd_mode == IA_MODE_NONE)
734                 mode = DHCPV6_STATELESS;
735         else if (na_mode == IA_MODE_FORCE || pd_mode == IA_MODE_FORCE)
736                 mode = DHCPV6_STATEFUL;
737 
738         return mode;
739 }
740 
741 static void dhcpv6_send(enum dhcpv6_msg req_msg_type, uint8_t trid[3], uint32_t ecs)
742 {
743         // Build FQDN
744         size_t fqdn_len;
745         void *fqdn = odhcp6c_get_state(STATE_OUR_FQDN, &fqdn_len);
746 
747         // Build Client ID
748         size_t cl_id_len;
749         void *cl_id = odhcp6c_get_state(STATE_CLIENT_ID, &cl_id_len);
750 
751         // Get Server ID
752         size_t srv_id_len;
753         void *srv_id = odhcp6c_get_state(STATE_SERVER_ID, &srv_id_len);
754 
755         // Build IA_PDs
756         size_t ia_pd_entry_cnt = 0, ia_pd_len = 0;
757         uint8_t *ia_pd;
758         struct odhcp6c_entry *pd_entries = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entry_cnt);
759         ia_pd_entry_cnt /= sizeof(*pd_entries);
760 
761         if (req_msg_type == DHCPV6_MSG_SOLICIT || (req_msg_type == DHCPV6_MSG_REQUEST && ia_pd_entry_cnt == 0 && pd_mode != IA_MODE_NONE)) {
762                 odhcp6c_clear_state(STATE_IA_PD);
763                 size_t n_prefixes;
764                 struct odhcp6c_request_prefix *request_prefixes = odhcp6c_get_state(STATE_IA_PD_INIT, &n_prefixes);
765                 n_prefixes /= sizeof(struct odhcp6c_request_prefix);
766 
767                 ia_pd = alloca(n_prefixes * (sizeof(struct dhcpv6_ia_hdr) + sizeof(struct dhcpv6_ia_prefix)));
768 
769                 for (size_t i = 0; i < n_prefixes; i++) {
770                         struct dhcpv6_ia_hdr hdr_ia_pd = {
771                                 htons(DHCPV6_OPT_IA_PD),
772                                 htons(sizeof(hdr_ia_pd) - DHCPV6_OPT_HDR_SIZE +
773                                       sizeof(struct dhcpv6_ia_prefix) * !!request_prefixes[i].length),
774                                 request_prefixes[i].iaid, 0, 0
775                         };
776                         struct dhcpv6_ia_prefix pref = {
777                                 .type = htons(DHCPV6_OPT_IA_PREFIX),
778                                 .len = htons(sizeof(pref) - DHCPV6_OPT_HDR_SIZE),
779                                 .prefix = request_prefixes[i].length,
780                                 .addr = request_prefixes[i].addr
781                         };
782                         memcpy(ia_pd + ia_pd_len, &hdr_ia_pd, sizeof(hdr_ia_pd));
783                         ia_pd_len += sizeof(hdr_ia_pd);
784                         if (request_prefixes[i].length) {
785                                 memcpy(ia_pd + ia_pd_len, &pref, sizeof(pref));
786                                 ia_pd_len += sizeof(pref);
787                         }
788                 }
789         } else {
790                 // we're too lazy to count our distinct IAIDs,
791                 // so just allocate maximally needed space
792                 ia_pd = alloca(ia_pd_entry_cnt * (sizeof(struct dhcpv6_ia_prefix) + 10 +
793                                         sizeof(struct dhcpv6_ia_hdr)));
794 
795                 for (size_t i = 0; i < ia_pd_entry_cnt; ++i) {
796                         uint32_t iaid = pd_entries[i].iaid;
797 
798                         // check if this is an unprocessed IAID and skip if not.
799                         bool new_iaid = true;
800                         for (int j = i-1; j >= 0; j--) {
801                                 if (pd_entries[j].iaid == iaid) {
802                                         new_iaid = false;
803                                         break;
804                                 }
805                         }
806 
807                         if (!new_iaid)
808                                 continue;
809 
810                         // construct header
811                         struct dhcpv6_ia_hdr hdr_ia_pd = {
812                                 htons(DHCPV6_OPT_IA_PD),
813                                 htons(sizeof(hdr_ia_pd) - DHCPV6_OPT_HDR_SIZE),
814                                 iaid, 0, 0
815                         };
816 
817                         memcpy(ia_pd + ia_pd_len, &hdr_ia_pd, sizeof(hdr_ia_pd));
818                         struct dhcpv6_ia_hdr *hdr = (struct dhcpv6_ia_hdr *) (ia_pd + ia_pd_len);
819                         ia_pd_len += sizeof(hdr_ia_pd);
820 
821                         for (size_t j = i; j < ia_pd_entry_cnt; j++) {
822                                 if (pd_entries[j].iaid != iaid)
823                                         continue;
824 
825                                 uint8_t ex_len = 0;
826                                 if (pd_entries[j].exclusion_length > 0)
827                                         ex_len = ((pd_entries[j].exclusion_length - pd_entries[j].length - 1) / 8) + 6;
828 
829                                 struct dhcpv6_ia_prefix p = {
830                                         .type = htons(DHCPV6_OPT_IA_PREFIX),
831                                         .len = htons(sizeof(p) - DHCPV6_OPT_HDR_SIZE_U + ex_len),
832                                         .prefix = pd_entries[j].length,
833                                         .addr = pd_entries[j].target
834                                 };
835 
836                                 if (req_msg_type == DHCPV6_MSG_REQUEST) {
837                                         p.preferred = htonl(pd_entries[j].preferred);
838                                         p.valid = htonl(pd_entries[j].valid);
839                                 }
840 
841                                 memcpy(ia_pd + ia_pd_len, &p, sizeof(p));
842                                 ia_pd_len += sizeof(p);
843 
844                                 if (ex_len) {
845                                         ia_pd[ia_pd_len++] = 0;
846                                         ia_pd[ia_pd_len++] = DHCPV6_OPT_PD_EXCLUDE;
847                                         ia_pd[ia_pd_len++] = 0;
848                                         ia_pd[ia_pd_len++] = ex_len - DHCPV6_OPT_HDR_SIZE;
849                                         ia_pd[ia_pd_len++] = pd_entries[j].exclusion_length;
850 
851                                         uint32_t excl = ntohl(pd_entries[j].router.s6_addr32[1]);
852                                         excl >>= (64 - pd_entries[j].exclusion_length);
853                                         excl <<= 8 - ((pd_entries[j].exclusion_length - pd_entries[j].length) % 8);
854 
855                                         for (size_t k = ex_len - 5; k > 0; --k, excl >>= 8)
856                                                 ia_pd[ia_pd_len + k] = excl & 0xff;
857 
858                                         ia_pd_len += ex_len - 5;
859                                 }
860 
861                                 hdr->len = htons(ntohs(hdr->len) + ntohs(p.len) + 4U);
862                         }
863                 }
864         }
865 
866         // Build IA_NAs
867         size_t ia_na_entry_cnt, ia_na_len = 0;
868         void *ia_na = NULL;
869         struct odhcp6c_entry *ia_entries = odhcp6c_get_state(STATE_IA_NA, &ia_na_entry_cnt);
870         ia_na_entry_cnt /= sizeof(*ia_entries);
871 
872         struct dhcpv6_ia_hdr hdr_ia_na = {
873                 .type = htons(DHCPV6_OPT_IA_NA),
874                 .len = htons(sizeof(hdr_ia_na) - DHCPV6_OPT_HDR_SIZE),
875                 .iaid = htonl(ifname_hash_iaid),
876                 .t1 = 0,
877                 .t2 = 0,
878         };
879 
880         struct dhcpv6_ia_addr ia_na_array[ia_na_entry_cnt];
881         for (size_t i = 0; i < ia_na_entry_cnt; ++i) {
882                 ia_na_array[i].type = htons(DHCPV6_OPT_IA_ADDR);
883                 ia_na_array[i].len = htons(sizeof(ia_na_array[i]) - DHCPV6_OPT_HDR_SIZE_U);
884                 ia_na_array[i].addr = ia_entries[i].target;
885 
886                 if (req_msg_type == DHCPV6_MSG_REQUEST) {
887                         ia_na_array[i].preferred = htonl(ia_entries[i].preferred);
888                         ia_na_array[i].valid = htonl(ia_entries[i].valid);
889                 } else {
890                         ia_na_array[i].preferred = 0;
891                         ia_na_array[i].valid = 0;
892                 }
893         }
894 
895         ia_na = ia_na_array;
896         ia_na_len = sizeof(ia_na_array);
897         hdr_ia_na.len = htons(ntohs(hdr_ia_na.len) + ia_na_len);
898 
899         // Reconfigure Accept
900         struct {
901                 uint16_t type;
902                 uint16_t length;
903         } reconf_accept = {htons(DHCPV6_OPT_RECONF_ACCEPT), 0};
904 
905         // Option list
906         size_t opts_len;
907         void *opts = odhcp6c_get_state(STATE_OPTS, &opts_len);
908 
909         // Option Request List
910         size_t oro_entries, oro_len = 0;
911         uint16_t *oro, *s_oro = odhcp6c_get_state(STATE_ORO, &oro_entries);
912 
913         oro_entries /= sizeof(*s_oro);
914         oro = alloca(oro_entries * sizeof(*oro));
915 
916         for (size_t i = 0; i < oro_entries; i++) {
917                 struct odhcp6c_opt *opt = odhcp6c_find_opt(htons(s_oro[i]));
918 
919                 if (opt) {
920                         if (!(opt->flags & OPT_ORO))
921                                 continue;
922 
923                         if ((opt->flags & OPT_ORO_SOLICIT) && req_msg_type != DHCPV6_MSG_SOLICIT)
924                                 continue;
925 
926                         if ((opt->flags & OPT_ORO_STATELESS) && req_msg_type != DHCPV6_MSG_INFO_REQ)
927                                 continue;
928 
929                         if ((opt->flags & OPT_ORO_STATEFUL) && req_msg_type == DHCPV6_MSG_INFO_REQ)
930                                 continue;
931                 }
932 
933                 oro[oro_len++] = s_oro[i];
934         }
935         oro_len *= sizeof(*oro);
936 
937         // Prepare Header
938         struct {
939                 uint8_t type;
940                 uint8_t trid[3];
941                 uint16_t elapsed_type;
942                 uint16_t elapsed_len;
943                 uint16_t elapsed_value;
944                 uint16_t oro_type;
945                 uint16_t oro_len;
946         } hdr = {
947                 req_msg_type, {trid[0], trid[1], trid[2]},
948                 htons(DHCPV6_OPT_ELAPSED), htons(2),
949                         htons((ecs > 0xffff) ? 0xffff : ecs),
950                 htons(DHCPV6_OPT_ORO), htons(oro_len),
951         };
952 
953         struct iovec iov[IOV_TOTAL] = {
954                 [IOV_HDR] = {&hdr, sizeof(hdr)},
955                 [IOV_ORO] = {oro, oro_len},
956                 [IOV_CL_ID] = {cl_id, cl_id_len},
957                 [IOV_SRV_ID] = {srv_id, srv_id_len},
958                 [IOV_OPTS] = { opts, opts_len },
959                 [IOV_RECONF_ACCEPT] = {&reconf_accept, sizeof(reconf_accept)},
960                 [IOV_FQDN] = {fqdn, fqdn_len},
961                 [IOV_HDR_IA_NA] = {&hdr_ia_na, sizeof(hdr_ia_na)},
962                 [IOV_IA_NA] = {ia_na, ia_na_len},
963                 [IOV_IA_PD] = {ia_pd, ia_pd_len},
964         };
965 
966         size_t cnt = IOV_TOTAL;
967         if (req_msg_type == DHCPV6_MSG_INFO_REQ)
968                 cnt = IOV_HDR_IA_NA;
969 
970         // Disable IAs if not used
971         if (na_mode == IA_MODE_NONE) {
972                 iov[IOV_HDR_IA_NA].iov_len = 0;
973         } else if (ia_na_len == 0) {
974                 /* RFC7550 §4.2
975                  *    Solution: a client SHOULD accept Advertise messages, even
976                  *    when not all IA option types are being offered. And, in
977                  *    this case, the client SHOULD include the not offered IA
978                  *    option types in its Request. A client SHOULD only ignore
979                  *    an Advertise message when none of the requested IA
980                  *    options include offered addresses or delegated prefixes.
981                  *    Note that ignored messages MUST still be processed for
982                  *    SOL_MAX_RT and INF_MAX_RT options as specified in
983                  *    [RFC7083].
984                  */
985 
986                 switch (req_msg_type) {
987                 case DHCPV6_MSG_REQUEST:
988                         if (!config_dhcp->strict_rfc7550) {
989                                 /* Some broken ISPs won't behave properly if IA_NA is
990                                  * sent on Requests when they have provided an empty
991                                  * IA_NA on Advertise.
992                                  * Therefore we don't comply with RFC7550 and omit
993                                  * IA_NA as a workaround.
994                                  */
995                                 iov[IOV_HDR_IA_NA].iov_len = 0;
996                         }
997                         break;
998                 case DHCPV6_MSG_SOLICIT:
999                         break;
1000                 default:
1001                         iov[IOV_HDR_IA_NA].iov_len = 0;
1002                         break;
1003                 }
1004         }
1005 
1006         if ((req_msg_type != DHCPV6_MSG_SOLICIT && req_msg_type != DHCPV6_MSG_REQUEST) ||
1007                         !(client_options & DHCPV6_ACCEPT_RECONFIGURE))
1008                 iov[IOV_RECONF_ACCEPT].iov_len = 0;
1009 
1010         if (!(client_options & DHCPV6_CLIENT_FQDN)) {
1011                 iov[IOV_FQDN].iov_len = 0;
1012         } else {
1013                 switch (req_msg_type) {
1014                 /*  RFC4704 §5
1015                         A client MUST only include the Client FQDN option in SOLICIT,
1016                         REQUEST, RENEW, or REBIND messages.
1017                 */
1018                 case DHCPV6_MSG_SOLICIT:
1019                 case DHCPV6_MSG_REQUEST:
1020                 case DHCPV6_MSG_RENEW:
1021                 case DHCPV6_MSG_REBIND:
1022                 /*  RFC4704 §6
1023                         Servers MUST only include a Client FQDN option in ADVERTISE and REPLY
1024                         messages...
1025                 case DHCPV6_MSG_ADVERT:
1026                 case DHCPV6_MSG_REPLY:
1027                 */
1028                         /* leave FQDN as-is */
1029                         break;
1030                 default:
1031                         /* remaining MSG types cannot contain client FQDN */
1032                         iov[IOV_FQDN].iov_len = 0;
1033                         break;
1034                 }
1035         }
1036 
1037         struct sockaddr_in6 srv = {AF_INET6, htons(DHCPV6_SERVER_PORT),
1038                 0, ALL_DHCPV6_RELAYS, ifindex};
1039         struct msghdr msg = {.msg_name = &srv, .msg_namelen = sizeof(srv),
1040                         .msg_iov = iov, .msg_iovlen = cnt};
1041 
1042         switch (req_msg_type) {
1043         case DHCPV6_MSG_REQUEST:
1044         case DHCPV6_MSG_RENEW:
1045         case DHCPV6_MSG_RELEASE:
1046         case DHCPV6_MSG_DECLINE:
1047                 if (!IN6_IS_ADDR_UNSPECIFIED(&server_addr) &&
1048                         odhcp6c_addr_in_scope(&server_addr)) {
1049                         srv.sin6_addr = server_addr;
1050                         if (!IN6_IS_ADDR_LINKLOCAL(&server_addr))
1051                                 srv.sin6_scope_id = 0;
1052                 }
1053                 break;
1054         default:
1055                 break;
1056         }
1057 
1058         if (sendmsg(sock, &msg, 0) < 0) {
1059                 char in6_str[INET6_ADDRSTRLEN];
1060 
1061                 error("Failed to send %s message to %s (%s)",
1062                         dhcpv6_msg_to_str(req_msg_type),
1063                         inet_ntop(AF_INET6, (const void *)&srv.sin6_addr,
1064                                 in6_str, sizeof(in6_str)), strerror(errno));
1065                 dhcpv6_stats.transmit_failures++;
1066         } else {
1067                 dhcpv6_inc_counter(req_msg_type);
1068         }
1069 }
1070 
1071 static int64_t dhcpv6_rand_delay(int64_t time)
1072 {
1073         int random;
1074         odhcp6c_random(&random, sizeof(random));
1075 
1076         return (time * ((int64_t)random % (config_dhcp->rand_factor*10LL))) / 10000LL;
1077 }
1078 
1079 // Message validation checks according to RFC3315 chapter 15
1080 static bool dhcpv6_response_is_valid(const void *buf, ssize_t len,
1081                 const uint8_t transaction[3], enum dhcpv6_msg req_msg_type,
1082                 const struct in6_addr *daddr)
1083 {
1084         const struct dhcpv6_header *response_buf = buf;
1085         if (len < (ssize_t)sizeof(*response_buf) || memcmp(response_buf->tr_id,
1086                         transaction, sizeof(response_buf->tr_id)))
1087                 return false; // Invalid reply
1088 
1089         if (req_msg_type == DHCPV6_MSG_SOLICIT) {
1090                 if (response_buf->msg_type != DHCPV6_MSG_ADVERT &&
1091                                 response_buf->msg_type != DHCPV6_MSG_REPLY)
1092                         return false;
1093         } else if (req_msg_type == DHCPV6_MSG_UNKNOWN) {
1094                 if (!accept_reconfig || response_buf->msg_type != DHCPV6_MSG_RECONF)
1095                         return false;
1096         } else if (response_buf->msg_type != DHCPV6_MSG_REPLY) {
1097                 return false;
1098         }
1099 
1100         uint8_t *end = ((uint8_t*)buf) + len, *odata = NULL,
1101                 rcmsg = DHCPV6_MSG_UNKNOWN;
1102         uint16_t otype, olen = UINT16_MAX;
1103         bool clientid_ok = false, serverid_ok = false, rcauth_ok = false,
1104                 auth_present = false, ia_present = false, options_valid = true;
1105 
1106         size_t client_id_len, server_id_len;
1107         void *client_id = odhcp6c_get_state(STATE_CLIENT_ID, &client_id_len);
1108         void *server_id = odhcp6c_get_state(STATE_SERVER_ID, &server_id_len);
1109 
1110         dhcpv6_for_each_option(&response_buf[1], end, otype, olen, odata) {
1111                 switch (otype) {
1112                 case DHCPV6_OPT_CLIENTID:
1113                         clientid_ok = (olen + DHCPV6_OPT_HDR_SIZE_U == client_id_len) && !memcmp(
1114                                         &odata[-DHCPV6_OPT_HDR_SIZE], client_id, client_id_len);                        
1115                         break;
1116 
1117                 case DHCPV6_OPT_SERVERID:
1118                         if (server_id_len)
1119                                 serverid_ok = (olen + DHCPV6_OPT_HDR_SIZE_U == server_id_len) && !memcmp(
1120                                                 &odata[-DHCPV6_OPT_HDR_SIZE], server_id, server_id_len);
1121                         else
1122                                 serverid_ok = true;
1123                         break;
1124 
1125                 case DHCPV6_OPT_AUTH:
1126                         struct dhcpv6_auth *r = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1127                         if (auth_present) {
1128                                 options_valid = false;
1129                                 continue;
1130                         }
1131 
1132                         auth_present = true;
1133                         if (auth_protocol == AUTH_PROT_RKAP) {
1134                                 struct dhcpv6_auth_reconfigure *rkap = (void*)r->data;
1135                                 if (r->protocol != AUTH_PROT_RKAP || r->algorithm != AUTH_ALG_HMACMD5 || r->len != 28 || rkap->reconf_type != RKAP_TYPE_HMACMD5)
1136                                         continue;
1137 
1138                                 md5_ctx_t md5;
1139                                 uint8_t serverhash[16], secretbytes[64];
1140                                 uint32_t hash[4];
1141                                 memcpy(serverhash, rkap->key, sizeof(serverhash));
1142                                 memset(rkap->key, 0, sizeof(rkap->key));
1143 
1144                                 memset(secretbytes, 0, sizeof(secretbytes));
1145                                 memcpy(secretbytes, reconf_key, sizeof(reconf_key));
1146 
1147                                 for (size_t i = 0; i < sizeof(secretbytes); ++i)
1148                                         secretbytes[i] ^= 0x36;
1149 
1150                                 md5_begin(&md5);
1151                                 md5_hash(secretbytes, sizeof(secretbytes), &md5);
1152                                 md5_hash(buf, len, &md5);
1153                                 md5_end(hash, &md5);
1154 
1155                                 for (size_t i = 0; i < sizeof(secretbytes); ++i) {
1156                                         secretbytes[i] ^= 0x36;
1157                                         secretbytes[i] ^= 0x5c;
1158                                 }
1159 
1160                                 md5_begin(&md5);
1161                                 md5_hash(secretbytes, sizeof(secretbytes), &md5);
1162                                 md5_hash(hash, 16, &md5);
1163                                 md5_end(hash, &md5);
1164 
1165                                 rcauth_ok = !memcmp(hash, serverhash, sizeof(hash));
1166                         } else if (auth_protocol == AUTH_PROT_TOKEN) {
1167                                 if (r->protocol != AUTH_PROT_TOKEN || r->algorithm != AUTH_ALG_TOKEN || r->len < 12)
1168                                         continue;
1169 
1170                                 uint16_t token_len = r->len - 11;
1171                                 if (config_dhcp->auth_token == NULL || strlen(config_dhcp->auth_token) != token_len)
1172                                         continue;
1173 
1174                                 rcauth_ok = !memcmp(r->data, config_dhcp->auth_token, token_len);
1175                         }
1176                         break;
1177                 case DHCPV6_OPT_RECONF_MESSAGE:
1178                         if (olen != 1)
1179                                 return false;
1180                         rcmsg = odata[0];
1181                         break;
1182 
1183                 case DHCPV6_OPT_IA_PD:
1184                 case DHCPV6_OPT_IA_NA:
1185                         ia_present = true;
1186                         if (olen < sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE)
1187                                 options_valid = false;
1188                         break;
1189 
1190                 case DHCPV6_OPT_IA_ADDR:
1191                 case DHCPV6_OPT_IA_PREFIX:
1192                 case DHCPV6_OPT_PD_EXCLUDE:
1193                         // Options are not allowed on global level
1194                         options_valid = false;
1195                         break;
1196 
1197                 default:
1198                         break;
1199                 }
1200         }
1201 
1202         if (!options_valid || ((odata + olen) > end))
1203                 return false;
1204 
1205         if (req_msg_type == DHCPV6_MSG_INFO_REQ && ia_present)
1206                 return false;
1207 
1208         if (response_buf->msg_type == DHCPV6_MSG_RECONF) {
1209                 if ((rcmsg != DHCPV6_MSG_RENEW && rcmsg != DHCPV6_MSG_REBIND && rcmsg != DHCPV6_MSG_INFO_REQ) ||
1210                         (rcmsg == DHCPV6_MSG_INFO_REQ && ia_present) ||
1211                         !rcauth_ok || IN6_IS_ADDR_MULTICAST(daddr))
1212                         return false;
1213         }
1214 
1215         return clientid_ok && serverid_ok;
1216 }
1217 
1218 static int dhcpv6_handle_reconfigure(enum dhcpv6_msg orig, const int rc,
1219                 const void *opt, const void *end, _o_unused const struct sockaddr_in6 *from)
1220 {
1221         uint16_t otype, olen;
1222         uint8_t *odata;
1223         enum dhcpv6_msg msg = DHCPV6_MSG_UNKNOWN;
1224 
1225         dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1226                 if (otype == DHCPV6_OPT_RECONF_MESSAGE && olen == 1) {
1227                         switch (odata[0]) {
1228                         case DHCPV6_MSG_REBIND:
1229                                 if (t2 != UINT32_MAX)
1230                                         t2 = 0;
1231                                 _o_fallthrough;
1232                         case DHCPV6_MSG_RENEW:
1233                                 if (t1 != UINT32_MAX)
1234                                         t1 = 0;
1235                                 _o_fallthrough;
1236                         case DHCPV6_MSG_INFO_REQ:
1237                                 msg = odata[0];
1238                                 notice("Need to respond with %s in reply to %s",
1239                                        dhcpv6_msg_to_str(msg), dhcpv6_msg_to_str(DHCPV6_MSG_RECONF));
1240                                 break;
1241 
1242                         default:
1243                                 break;
1244                         }
1245                 }
1246         }
1247 
1248         if (msg != DHCPV6_MSG_UNKNOWN)
1249                 dhcpv6_handle_reply(orig, rc, NULL, NULL, NULL);
1250 
1251         return (msg == DHCPV6_MSG_UNKNOWN? -1: (int)msg);
1252 }
1253 
1254 // Collect all advertised servers
1255 static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc,
1256                 const void *opt, const void *end, _o_unused const struct sockaddr_in6 *from)
1257 {
1258         uint16_t olen, otype;
1259         uint8_t *odata, pref = 0;
1260         struct dhcpv6_server_cand cand = {false, false, 0, 0, {0},
1261                                         IN6ADDR_ANY_INIT, DHCPV6_SOL_MAX_RT,
1262                                         DHCPV6_INF_MAX_RT, NULL, NULL, 0, 0};
1263         bool have_na = false;
1264         int have_pd = 0;
1265 
1266         dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1267                 if (orig == DHCPV6_MSG_SOLICIT &&
1268                                 ((otype == DHCPV6_OPT_IA_PD && pd_mode != IA_MODE_NONE) ||
1269                                  (otype == DHCPV6_OPT_IA_NA && na_mode != IA_MODE_NONE)) &&
1270                                 olen > sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1271                         struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-DHCPV6_OPT_HDR_SIZE]);
1272                         dhcpv6_parse_ia(ia_hdr, odata + olen + sizeof(*ia_hdr), NULL);
1273                 }
1274 
1275                 switch (otype) {
1276                 case DHCPV6_OPT_SERVERID:
1277                         if (olen <= DHCPV6_DUID_MAX_LEN) {
1278                                 memcpy(cand.duid, odata, olen);
1279                                 cand.duid_len = olen;
1280                         }
1281                         break;
1282 
1283                 case DHCPV6_OPT_PREF:
1284                         if (olen >= 1 && cand.preference >= 0)
1285                                 cand.preference = pref = odata[0];
1286                         break;
1287 
1288                 case DHCPV6_OPT_UNICAST:
1289                         if (olen == sizeof(cand.server_addr) &&
1290                             !(client_options & DHCPV6_IGNORE_OPT_UNICAST))
1291                                 cand.server_addr = *(struct in6_addr *)odata;
1292                         break;
1293 
1294                 case DHCPV6_OPT_RECONF_ACCEPT:
1295                         cand.wants_reconfigure = true;
1296                         break;
1297 
1298                 case DHCPV6_OPT_SOL_MAX_RT:
1299                         if (olen == 4) {
1300                                 uint32_t sol_max_rt = ntohl_unaligned(odata);
1301                                 if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN &&
1302                                     sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX)
1303                                         cand.sol_max_rt = sol_max_rt;
1304                         }
1305                         break;
1306 
1307                 case DHCPV6_OPT_INF_MAX_RT:
1308                         if (olen == 4) {
1309                                 uint32_t inf_max_rt = ntohl_unaligned(odata);
1310                                 if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN &&
1311                                     inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
1312                                         cand.inf_max_rt = inf_max_rt;
1313                         }
1314                         break;
1315 
1316                 case DHCPV6_OPT_IA_PD:
1317                         if (olen >= sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1318                                 struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr *)&odata[-DHCPV6_OPT_HDR_SIZE];
1319                                 uint8_t *oend = odata + olen, *d;
1320 
1321                                 dhcpv6_for_each_option(&h[1], oend, otype, olen, d) {
1322                                         if (otype == DHCPV6_OPT_IA_PREFIX &&
1323                                             olen >= sizeof(struct dhcpv6_ia_prefix) - DHCPV6_OPT_HDR_SIZE) {
1324                                                 struct dhcpv6_ia_prefix *p =
1325                                                         (struct dhcpv6_ia_prefix *)&d[-DHCPV6_OPT_HDR_SIZE];
1326                                                 have_pd = p->prefix;
1327                                         }
1328                                 }
1329                         }
1330                         break;
1331 
1332                 case DHCPV6_OPT_IA_NA:
1333                         if (olen >= sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1334                                 struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr *)&odata[-DHCPV6_OPT_HDR_SIZE];
1335                                 uint8_t *oend = odata + olen, *d;
1336 
1337                                 dhcpv6_for_each_option(&h[1], oend, otype, olen, d) {
1338                                         if (otype == DHCPV6_OPT_IA_ADDR &&
1339                                             olen >= sizeof(struct dhcpv6_ia_addr) - DHCPV6_OPT_HDR_SIZE)
1340                                                 have_na = true;
1341                                 }
1342                         }
1343                         break;
1344 
1345                 default:
1346                         break;
1347                 }
1348         }
1349 
1350         if ((stateful_only_mode && !have_na && !have_pd) ||
1351                         (!have_na && na_mode == IA_MODE_FORCE) ||
1352                         (!have_pd && pd_mode == IA_MODE_FORCE)) {
1353                 /*
1354                  * RFC7083 states to process the SOL_MAX_RT and
1355                  * INF_MAX_RT options even if the DHCPv6 server
1356                  * did not propose any IA_NA and/or IA_PD
1357                  */
1358                 dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand.sol_max_rt;
1359                 dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand.inf_max_rt;
1360                 return -1;
1361         }
1362 
1363         if (na_mode != IA_MODE_NONE && !have_na) {
1364                 cand.has_noaddravail = true;
1365                 cand.preference -= 1000;
1366         }
1367 
1368         if (pd_mode != IA_MODE_NONE) {
1369                 if (have_pd)
1370                         cand.preference += 2000 + (128 - have_pd);
1371                 else
1372                         cand.preference -= 2000;
1373         }
1374 
1375         if (cand.duid_len > 0) {
1376                 cand.ia_na = odhcp6c_move_state(STATE_IA_NA, &cand.ia_na_len);
1377                 cand.ia_pd = odhcp6c_move_state(STATE_IA_PD, &cand.ia_pd_len);
1378                 dhcpv6_add_server_cand(&cand);
1379         }
1380 
1381         return (rc > 1 || (pref == 255 && cand.preference > 0)) ? 1 : -1;
1382 }
1383 
1384 static int dhcpv6_commit_advert(void)
1385 {
1386         return dhcpv6_promote_server_cand();
1387 }
1388 
1389 static int dhcpv6_handle_rebind_reply(enum dhcpv6_msg orig, const int rc,
1390                 const void *opt, const void *end, const struct sockaddr_in6 *from)
1391 {
1392         dhcpv6_handle_advert(orig, rc, opt, end, from);
1393         if (dhcpv6_commit_advert() < 0)
1394                 return -1;
1395 
1396         return dhcpv6_handle_reply(orig, rc, opt, end, from);
1397 }
1398 
1399 static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _o_unused const int rc,
1400                 const void *opt, const void *end, const struct sockaddr_in6 *from)
1401 {
1402         uint8_t *odata;
1403         uint16_t otype, olen;
1404         uint32_t refresh = config_dhcp->irt_default;
1405         int ret = 1;
1406         unsigned int state_IAs;
1407         unsigned int updated_IAs = 0;
1408         bool handled_status_codes[_DHCPV6_Status_Max] = { false, };
1409 
1410         odhcp6c_expire(true);
1411 
1412         if (orig == DHCPV6_MSG_UNKNOWN) {
1413                 static time_t last_update = 0;
1414                 time_t now = odhcp6c_get_milli_time() / 1000;
1415 
1416                 uint32_t elapsed = (last_update > 0) ? now - last_update : 0;
1417                 last_update = now;
1418 
1419                 if (t1 != UINT32_MAX)
1420                         t1 -= elapsed;
1421 
1422                 if (t2 != UINT32_MAX)
1423                         t2 -= elapsed;
1424 
1425                 if (t3 != UINT32_MAX)
1426                         t3 -= elapsed;
1427 
1428                 if (t1 < 0)
1429                         t1 = 0;
1430 
1431                 if (t2 < 0)
1432                         t2 = 0;
1433 
1434                 if (t3 < 0)
1435                         t3 = 0;
1436         }
1437 
1438         if (orig == DHCPV6_MSG_REQUEST && !odhcp6c_is_bound()) {
1439                 // Delete NA and PD we have in the state from the Advert
1440                 odhcp6c_clear_state(STATE_IA_NA);
1441                 odhcp6c_clear_state(STATE_IA_PD);
1442         }
1443 
1444         if (opt) {
1445                 odhcp6c_clear_state(STATE_DNS);
1446                 odhcp6c_clear_state(STATE_SEARCH);
1447                 odhcp6c_clear_state(STATE_SNTP_IP);
1448                 odhcp6c_clear_state(STATE_NTP_IP);
1449                 odhcp6c_clear_state(STATE_NTP_FQDN);
1450                 odhcp6c_clear_state(STATE_SIP_IP);
1451                 odhcp6c_clear_state(STATE_SIP_FQDN);
1452                 odhcp6c_clear_state(STATE_AFTR_NAME);
1453                 odhcp6c_clear_state(STATE_S46_MAPT);
1454                 odhcp6c_clear_state(STATE_S46_MAPE);
1455                 odhcp6c_clear_state(STATE_S46_LW);
1456                 odhcp6c_clear_state(STATE_CAPT_PORT_DHCPV6);
1457                 odhcp6c_clear_state(STATE_PASSTHRU);
1458                 odhcp6c_clear_state(STATE_CUSTOM_OPTS);
1459 
1460                 // Parse and find all matching IAs
1461                 dhcpv6_for_each_option(opt, end, otype, olen, odata) {
1462                         struct odhcp6c_opt *dopt = odhcp6c_find_opt(otype);
1463 
1464                         switch (otype) {
1465 
1466                         case DHCPV6_OPT_IA_NA:
1467                         case DHCPV6_OPT_IA_PD:
1468                                 if (olen > sizeof(struct dhcpv6_ia_hdr) - DHCPV6_OPT_HDR_SIZE) {
1469                                         struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-DHCPV6_OPT_HDR_SIZE]);
1470 
1471                                         if ((na_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_NA) ||
1472                                                 (pd_mode == IA_MODE_NONE && otype == DHCPV6_OPT_IA_PD))
1473                                                 continue;
1474 
1475                                         // Test ID
1476                                         if (ia_hdr->iaid != htonl(ifname_hash_iaid) && otype == DHCPV6_OPT_IA_NA)
1477                                                 continue;
1478 
1479                                         uint16_t code = DHCPV6_Success;
1480                                         uint16_t stype, slen;
1481                                         uint8_t *sdata;
1482                                         bool dhcpv6_successful_once = false;
1483                                         // Get and handle status code
1484                                         dhcpv6_for_each_option(&ia_hdr[1], odata + olen, stype, slen, sdata) {
1485                                                 if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1486                                                         uint8_t *mdata = (slen > 2) ? &sdata[2] : NULL;
1487                                                         uint16_t mlen = (slen > 2) ? slen - 2 : 0;
1488 
1489                                                         code = ((int)sdata[0] << 8) | ((int)sdata[1]);
1490 
1491                                                         if (code == DHCPV6_Success) {
1492                                                                 dhcpv6_successful_once = true;
1493                                                                 continue;
1494                                                         }
1495 
1496                                                         dhcpv6_handle_ia_status_code(orig, ia_hdr,
1497                                                                 code, mdata, mlen, handled_status_codes, &ret);
1498 
1499                                                         break;
1500                                                 }
1501                                         }
1502 
1503                                         if (!dhcpv6_successful_once && code != DHCPV6_Success)
1504                                                 continue;
1505 
1506                                         updated_IAs += dhcpv6_parse_ia(ia_hdr, odata + olen, &ret);
1507                                 }
1508                                 break;
1509 
1510                         case DHCPV6_OPT_UNICAST:
1511                                 if (olen == sizeof(server_addr) &&
1512                                     !(client_options & DHCPV6_IGNORE_OPT_UNICAST))
1513                                         server_addr = *(struct in6_addr *)odata;
1514                                 break;
1515 
1516                         case DHCPV6_OPT_STATUS:
1517                                 if (olen >= 2) {
1518                                         uint8_t *mdata = (olen > 2) ? &odata[2] : NULL;
1519                                         uint16_t mlen = (olen > 2) ? olen - 2 : 0;
1520                                         uint16_t code = ((int)odata[0] << 8) | ((int)odata[1]);
1521 
1522                                         dhcpv6_handle_status_code(orig, code, mdata, mlen, &ret);
1523                                 }
1524                                 break;
1525 
1526                         case DHCPV6_OPT_DNS_SERVERS:
1527                                 if (olen % sizeof(struct in6_addr) == 0)
1528                                         odhcp6c_add_state(STATE_DNS, odata, olen);
1529                                 break;
1530 
1531                         case DHCPV6_OPT_DNS_DOMAIN:
1532                                 odhcp6c_add_state(STATE_SEARCH, odata, olen);
1533                                 break;
1534 
1535                         case DHCPV6_OPT_SNTP_SERVERS:
1536                                 if (olen % sizeof(struct in6_addr) == 0)
1537                                         odhcp6c_add_state(STATE_SNTP_IP, odata, olen);
1538                                 break;
1539 
1540                         case DHCPV6_OPT_NTP_SERVER:
1541                                 uint16_t stype, slen;
1542                                 uint8_t *sdata;
1543                                 // Test status and bail if error
1544                                 dhcpv6_for_each_option(odata, odata + olen,
1545                                                 stype, slen, sdata) {
1546                                         if (slen == sizeof(struct in6_addr) && (stype == NTP_MC_ADDR || stype == NTP_SRV_ADDR))
1547                                                 odhcp6c_add_state(STATE_NTP_IP, sdata, slen);
1548                                         else if (slen > 0 && stype == NTP_SRV_FQDN)
1549                                                 odhcp6c_add_state(STATE_NTP_FQDN, sdata, slen);
1550                                 }
1551                                 break;
1552 
1553                         case DHCPV6_OPT_SIP_SERVER_A:
1554                                 if (olen == sizeof(struct in6_addr))
1555                                         odhcp6c_add_state(STATE_SIP_IP, odata, olen);
1556                                 break;
1557 
1558                         case DHCPV6_OPT_SIP_SERVER_D:
1559                                 odhcp6c_add_state(STATE_SIP_FQDN, odata, olen);
1560                                 break;
1561 
1562                         case DHCPV6_OPT_INFO_REFRESH:
1563                                 if (olen == 4)
1564                                         refresh = ntohl_unaligned(odata);
1565                                 break;
1566 
1567                         case DHCPV6_OPT_AUTH:
1568                                 struct dhcpv6_auth *r = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1569                                 if (auth_protocol == AUTH_PROT_RKAP) {
1570                                         struct dhcpv6_auth_reconfigure *rkap = (void*)r->data;
1571                                         if (r->protocol == AUTH_PROT_RKAP || r->algorithm == AUTH_ALG_HMACMD5 ||
1572                                                 r->len == 28 || rkap->reconf_type == RKAP_TYPE_KEY)
1573                                                 memcpy(reconf_key, rkap->key, sizeof(rkap->key));
1574                                 }
1575                                 break;
1576 
1577                         case DHCPV6_OPT_AFTR_NAME:
1578                                 if (olen > 3) {
1579                                         size_t cur_len;
1580                                         odhcp6c_get_state(STATE_AFTR_NAME, &cur_len);
1581                                         if (cur_len == 0)
1582                                                 odhcp6c_add_state(STATE_AFTR_NAME, odata, olen);
1583                                 }
1584                                 break;
1585 
1586                         case DHCPV6_OPT_SOL_MAX_RT:
1587                                 if (olen == 4) {
1588                                         uint32_t sol_max_rt = ntohl_unaligned(odata);
1589                                         if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX)
1590                                                 dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_max_rt;
1591                                 }
1592                                 break;
1593 
1594                         case DHCPV6_OPT_INF_MAX_RT:
1595                                 if (olen == 4) {
1596                                         uint32_t inf_max_rt = ntohl_unaligned(odata);
1597                                         if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
1598                                                 dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = inf_max_rt;
1599                                 }
1600                                 break;
1601 
1602                         case DHCPV6_OPT_S46_CONT_MAPT:
1603                                 odhcp6c_add_state(STATE_S46_MAPT, odata, olen);
1604                                 break;
1605 
1606                         case DHCPV6_OPT_S46_CONT_MAPE:
1607                                 size_t mape_len;
1608                                 odhcp6c_get_state(STATE_S46_MAPE, &mape_len);
1609                                 if (mape_len == 0)
1610                                         odhcp6c_add_state(STATE_S46_MAPE, odata, olen);
1611                                 break;
1612 
1613                         case DHCPV6_OPT_S46_CONT_LW:
1614                                 odhcp6c_add_state(STATE_S46_LW, odata, olen);
1615                                 break;
1616 
1617                         case DHCPV6_OPT_CAPTIVE_PORTAL: /* RFC8910 §2.2 */
1618                                 size_t ref_len = sizeof(URN_IETF_CAPT_PORT_UNRESTR) - 1;
1619                                 /* RFC8910 §2:
1620                                  * Networks with no captive portals may explicitly indicate this
1621                                  * condition by using this option with the IANA-assigned URI for
1622                                  * this purpose. Clients observing the URI value ... may forego
1623                                  * time-consuming forms of captive portal detection. */
1624                                 if (memcmp(odata, URN_IETF_CAPT_PORT_UNRESTR, ref_len)) {
1625                                         /* RFC8910 §2.2:
1626                                          * Note that the URI parameter is not null terminated.
1627                                          * Allocate new buffer including room for '\0' */
1628                                         size_t uri_len = olen + 1;
1629                                         uint8_t *copy = malloc(uri_len);
1630                                         if (!copy)
1631                                                 continue;
1632                                         memcpy(copy, odata, olen);
1633                                         copy[uri_len] = '\0';
1634                                         odhcp6c_add_state(STATE_CAPT_PORT_DHCPV6, odata, olen);
1635                                         free(copy);
1636                                 }
1637                                 break;
1638 
1639                         default:
1640                                 odhcp6c_add_state(STATE_CUSTOM_OPTS, &odata[-DHCPV6_OPT_HDR_SIZE], olen + DHCPV6_OPT_HDR_SIZE);
1641                                 break;
1642                         }
1643 
1644                         // Pass-through unless explicitly disabled, for every option
1645                         if (!dopt || !(dopt->flags & OPT_NO_PASSTHRU))
1646                                 odhcp6c_add_state(STATE_PASSTHRU, &odata[-DHCPV6_OPT_HDR_SIZE], olen + DHCPV6_OPT_HDR_SIZE);
1647                 }
1648         }
1649 
1650         // Bail out if fatal status code was received
1651         if (ret <= 0)
1652                 return ret;
1653 
1654         switch (orig) {
1655         case DHCPV6_MSG_REQUEST:
1656         case DHCPV6_MSG_REBIND:
1657         case DHCPV6_MSG_RENEW:
1658                 state_IAs = dhcpv6_calc_refresh_timers();
1659                 // In case there're no state IA entries
1660                 // keep sending request/renew/rebind messages
1661                 if (state_IAs == 0) {
1662                         ret = 0;
1663                         break;
1664                 }
1665 
1666                 switch (orig) {
1667                 case DHCPV6_MSG_REQUEST:
1668                         // All server candidates can be cleared if not yet bound
1669                         if (!odhcp6c_is_bound())
1670                                 dhcpv6_clear_all_server_cand();
1671 
1672                         odhcp6c_clear_state(STATE_SERVER_ADDR);
1673                         odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, sizeof(struct in6_addr));
1674                         break;
1675                 case DHCPV6_MSG_RENEW:
1676                         // Send further renews if T1 is not set and if
1677                         // there're IAs which were not in the Reply message
1678                         if (!t1 && state_IAs != updated_IAs) {
1679                                 if (updated_IAs)
1680                                         // Publish updates
1681                                         notify_state_change("updated", 0, false);
1682 
1683                                 /*
1684                                  * RFC8415 states following in §18.2.10.1 :
1685                                  * Sends a Renew/Rebind if any of the IAs are not in the Reply
1686                                  * message, but as this likely indicates that the server that
1687                                  * responded does not support that IA type, sending immediately is
1688                                  * unlikely to produce a different result.  Therefore, the client
1689                                  * MUST rate-limit its transmissions (see Section 14.1) and MAY just
1690                                  * wait for the normal retransmission time (as if the Reply message
1691                                  * had not been received).  The client continues to use other
1692                                  * bindings for which the server did return information
1693                                  */
1694                                 ret = -1;
1695                         }
1696                         break;
1697                 case DHCPV6_MSG_REBIND:
1698                         odhcp6c_clear_state(STATE_SERVER_ADDR);
1699                         odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, sizeof(struct in6_addr));
1700 
1701                         // Send further rebinds if T1 and T2 is not set and if
1702                         // there're IAs which were not in the Reply message
1703                         if (!t1 && !t2 && state_IAs != updated_IAs) {
1704                                 if (updated_IAs)
1705                                         // Publish updates
1706                                         notify_state_change("updated", 0, false);
1707 
1708                                 /*
1709                                  * RFC8415 states following in §18.2.10.1 :
1710                                  * Sends a Renew/Rebind if any of the IAs are not in the Reply
1711                                  * message, but as this likely indicates that the server that
1712                                  * responded does not support that IA type, sending immediately is
1713                                  * unlikely to produce a different result.  Therefore, the client
1714                                  * MUST rate-limit its transmissions (see Section 14.1) and MAY just
1715                                  * wait for the normal retransmission time (as if the Reply message
1716                                  * had not been received).  The client continues to use other
1717                                  * bindings for which the server did return information
1718                                  */
1719                                 ret = -1;
1720                         }
1721                         break;
1722 
1723                 default:
1724                         break;
1725                 }
1726                 break;
1727 
1728         case DHCPV6_MSG_INFO_REQ:
1729                 // All server candidates can be cleared if not yet bound
1730                 if (!odhcp6c_is_bound())
1731                         dhcpv6_clear_all_server_cand();
1732 
1733                 odhcp6c_clear_state(STATE_SERVER_ADDR);
1734                 odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, sizeof(struct in6_addr));
1735 
1736                 t1 = (refresh < config_dhcp->irt_min) ? config_dhcp->irt_min : refresh;
1737                 break;
1738 
1739         default:
1740                 break;
1741         }
1742 
1743         return ret;
1744 }
1745 
1746 static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
1747 {
1748         struct dhcpv6_ia_hdr *ia_hdr = (struct dhcpv6_ia_hdr *)opt;
1749         unsigned int updated_IAs = 0;
1750         uint32_t t1, t2;
1751         uint16_t otype, olen;
1752         uint8_t *odata;
1753         char buf[INET6_ADDRSTRLEN];
1754 
1755         t1 = ntohl(ia_hdr->t1);
1756         t2 = ntohl(ia_hdr->t2);
1757 
1758         /* RFC 8415 §21.4
1759         If a client receives an IA_NA with T1 greater than T2 and both T1 and
1760         T2 are greater than 0, the client discards the IA_NA option and
1761         processes the remainder of the message as though the server had not
1762         included the invalid IA_NA option. */
1763         if (t1 > t2 && t1 > 0 && t2 > 0)
1764                 return 0;
1765 
1766         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);
1767 
1768         // Update address IA
1769         dhcpv6_for_each_option(&ia_hdr[1], end, otype, olen, odata) {
1770                 struct odhcp6c_entry entry = {
1771                         .router = IN6ADDR_ANY_INIT,
1772                         .auxlen = 0,
1773                         .length = 0,
1774                         .ra_flags = 0,
1775                         .exclusion_length = 0,
1776                         .target = IN6ADDR_ANY_INIT,
1777                         .priority = 0,
1778                         .valid = 0,
1779                         .preferred = 0,
1780                         .t1 = 0,
1781                         .t2 = 0,
1782                         .iaid = ia_hdr->iaid,
1783                 };
1784 
1785                 switch (otype) {
1786                 case DHCPV6_OPT_IA_PREFIX: {
1787                         struct dhcpv6_ia_prefix *prefix = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1788                         if (olen + DHCPV6_OPT_HDR_SIZE_U < sizeof(*prefix))
1789                                 continue;
1790 
1791                         entry.valid = ntohl(prefix->valid);
1792                         entry.preferred = ntohl(prefix->preferred);
1793 
1794                         if (entry.preferred > entry.valid)
1795                                 continue;
1796 
1797                         /*      RFC 8415 §21.21
1798                         Recommended values for T1 and T2 are 0.5 and 0.8 times the
1799                         shortest preferred lifetime of the prefixes in the IA_PD that the
1800                         server is willing to extend. */
1801                         entry.t1 = (t1 ? t1 : (entry.preferred != UINT32_MAX ? 0.5 * entry.preferred : UINT32_MAX));
1802                         entry.t2 = (t2 ? t2 : (entry.preferred != UINT32_MAX ? 0.8 * entry.preferred : UINT32_MAX));
1803                         if (entry.t1 > entry.t2)
1804                                 entry.t1 = entry.t2;
1805 
1806                         entry.length = prefix->prefix;
1807                         entry.target = prefix->addr;
1808                         uint16_t stype, slen;
1809                         uint8_t *sdata;
1810 
1811                         // Parse sub-options for PD-exclude or error status code
1812                         bool update_state = true;
1813                         dhcpv6_for_each_option(odata + sizeof(*prefix) - DHCPV6_OPT_HDR_SIZE,
1814                                         odata + olen, stype, slen, sdata) {
1815                                 if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1816                                         /* RFC 8415 §21.22
1817                                         The status of any operations involving this IA Prefix option is
1818                                         indicated in a Status Code option (see Section 21.13) in the
1819                                         IAprefix-options field. */
1820                                         uint8_t *status_msg = (slen > 2) ? &sdata[2] : NULL;
1821                                         uint16_t msg_len = (slen > 2) ? slen - 2 : 0;
1822                                         uint16_t code = ((int)sdata[0]) << 8 | ((int)sdata[1]);
1823 
1824                                         if (code == DHCPV6_Success)
1825                                                 continue;
1826 
1827                                         dhcpv6_log_status_code(code, "IA_PREFIX", status_msg, msg_len);
1828                                         if (ret) *ret = 0; // renewal failed
1829                                 } else if (stype == DHCPV6_OPT_PD_EXCLUDE && slen > 2) {
1830                                         /*      RFC 6603 §4.2 Prefix Exclude option */
1831                                         uint8_t exclude_length = sdata[0];
1832                                         if (exclude_length > 64)
1833                                                 exclude_length = 64;
1834 
1835                                         if (entry.length < 32 || exclude_length <= entry.length) {
1836                                                 update_state = false;
1837                                                 continue;
1838                                         }
1839 
1840                                         uint8_t bytes_needed = ((exclude_length - entry.length - 1) / 8) + 1;
1841                                         if (slen <= bytes_needed) {
1842                                                 update_state = false;
1843                                                 continue;
1844                                         }
1845 
1846                                         // this decrements through the ipaddr bytes masking against 
1847                                         // the address in the option until byte 0, the option length field.
1848                                         uint32_t excluded_bits = 0;
1849                                         do {
1850                                                 excluded_bits = excluded_bits << 8 | sdata[bytes_needed];
1851                                         } while (--bytes_needed);
1852 
1853                                         excluded_bits >>= 8 - ((exclude_length - entry.length) % 8);
1854                                         excluded_bits <<= 64 - exclude_length;
1855 
1856                                         // Re-using router field to hold the prefix
1857                                         entry.router = entry.target; // base prefix
1858                                         entry.router.s6_addr32[1] |= htonl(excluded_bits);
1859                                         entry.exclusion_length = exclude_length;
1860                                 }
1861                         }
1862 
1863                         if (update_state) {
1864                                 if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0))
1865                                         updated_IAs++;
1866 
1867                                 info("%s/%d preferred %d valid %d",
1868                                                 inet_ntop(AF_INET6, &entry.target, buf, sizeof(buf)),
1869                                                 entry.length, entry.preferred , entry.valid);
1870                         }
1871 
1872                         entry.priority = 0;
1873                         memset(&entry.router, 0, sizeof(entry.router));
1874                         break;
1875                 }
1876                 case DHCPV6_OPT_IA_ADDR: {
1877                         struct dhcpv6_ia_addr *addr = (void*)&odata[-DHCPV6_OPT_HDR_SIZE];
1878                         if (olen + DHCPV6_OPT_HDR_SIZE_U < sizeof(*addr))
1879                                 continue;
1880 
1881                         entry.preferred = ntohl(addr->preferred);
1882                         entry.valid = ntohl(addr->valid);
1883 
1884                         if (entry.preferred > entry.valid)
1885                                 continue;
1886 
1887                         entry.t1 = (t1 ? t1 : (entry.preferred != UINT32_MAX ? 0.5 * entry.preferred : UINT32_MAX));
1888                         entry.t2 = (t2 ? t2 : (entry.preferred != UINT32_MAX ? 0.8 * entry.preferred : UINT32_MAX));
1889                         if (entry.t1 > entry.t2)
1890                                 entry.t1 = entry.t2;
1891 
1892                         entry.length = 128;
1893                         entry.target = addr->addr;
1894                         uint16_t stype, slen;
1895                         uint8_t *sdata;
1896 
1897                         bool update_state = true;
1898                         dhcpv6_for_each_option(odata + sizeof(*addr) - DHCPV6_OPT_HDR_SIZE_U,
1899                                         odata + olen, stype, slen, sdata) {
1900                                 if (stype == DHCPV6_OPT_STATUS && slen >= 2) {
1901                                         /* RFC 8415 §21.6
1902                                         The status of any operations involving this IA Address is indicated
1903                                         in a Status Code option in the IAaddr-options field, as specified in
1904                                         Section 21.13. */
1905                                         uint8_t *status_msg = (slen > 2) ? &sdata[2] : NULL;
1906                                         uint16_t msg_len = (slen > 2) ? slen - 2 : 0;
1907                                         uint16_t code = ((int)sdata[0]) << 8 | ((int)sdata[1]);
1908 
1909                                         if (code == DHCPV6_Success)
1910                                                 continue;
1911 
1912                                         dhcpv6_log_status_code(code, "IA_ADDR", status_msg, msg_len);
1913                                         if (ret) *ret = 0; // renewal failed
1914                                         update_state = false;
1915                                 }
1916                         }
1917 
1918                         if (update_state) {
1919                                 if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0))
1920                                         updated_IAs++;
1921 
1922                                 info("%s preferred %d valid %d",
1923                                                 inet_ntop(AF_INET6, &entry.target, buf, sizeof(buf)),
1924                                                 entry.preferred , entry.valid);
1925                         }
1926                         break;
1927                 }
1928                 default:
1929                         break;
1930                 }
1931         }
1932 
1933         return updated_IAs;
1934 }
1935 
1936 static unsigned int dhcpv6_calc_refresh_timers(void)
1937 {
1938         struct odhcp6c_entry *pd_entries;
1939         struct odhcp6c_entry *ia_entries;
1940         size_t ia_na_entry_cnt, ia_pd_entry_cnt, i;
1941         size_t invalid_entries = 0;
1942         int64_t l_t1 = UINT32_MAX, l_t2 = UINT32_MAX, l_t3 = 0;
1943 
1944         ia_entries = odhcp6c_get_state(STATE_IA_NA, &ia_na_entry_cnt);
1945         ia_na_entry_cnt /= sizeof(*ia_entries);
1946 
1947         for (i = 0; i < ia_na_entry_cnt; i++) {
1948                 /* Exclude invalid IA_NA entries */
1949                 if (!ia_entries[i].valid) {
1950                         invalid_entries++;
1951                         continue;
1952                 }
1953 
1954                 if (ia_entries[i].t1 < l_t1)
1955                         l_t1 = ia_entries[i].t1;
1956 
1957                 if (ia_entries[i].t2 < l_t2)
1958                         l_t2 = ia_entries[i].t2;
1959 
1960                 if (ia_entries[i].valid > l_t3)
1961                         l_t3 = ia_entries[i].valid;
1962         }
1963 
1964         pd_entries = odhcp6c_get_state(STATE_IA_PD, &ia_pd_entry_cnt);
1965         ia_pd_entry_cnt /= sizeof(*pd_entries);
1966 
1967         for (i = 0; i < ia_pd_entry_cnt; i++) {
1968                 /* Exclude invalid IA_PD entries */
1969                 if (!pd_entries[i].valid) {
1970                         invalid_entries++;
1971                         continue;
1972                 }
1973 
1974                 if (pd_entries[i].t1 < l_t1)
1975                         l_t1 = pd_entries[i].t1;
1976 
1977                 if (pd_entries[i].t2 < l_t2)
1978                         l_t2 = pd_entries[i].t2;
1979 
1980                 if (pd_entries[i].valid > l_t3)
1981                         l_t3 = pd_entries[i].valid;
1982         }
1983 
1984         if (ia_pd_entry_cnt + ia_na_entry_cnt - invalid_entries) {
1985                 t1 = l_t1;
1986                 t2 = l_t2;
1987                 t3 = l_t3;
1988 
1989                 info("T1 %"PRId64"s, T2 %"PRId64"s, T3 %"PRId64"s", t1, t2, t3);
1990         }
1991 
1992         return (unsigned int)(ia_pd_entry_cnt + ia_na_entry_cnt);
1993 }
1994 
1995 static void dhcpv6_log_status_code(const uint16_t code, const char *scope,
1996                 const void *status_msg, int len)
1997 {
1998         const char *src = status_msg;
1999         char buf[len + 3];
2000         char *dst = buf;
2001 
2002         if (len) {
2003                 *dst++ = '(';
2004                 while (len--) {
2005                         *dst = isprint((unsigned char)*src) ? *src : '?';
2006                         src++;
2007                         dst++;
2008                 }
2009                 *dst++ = ')';
2010         }
2011 
2012         *dst = 0;
2013 
2014         warn("Server returned %s status '%s %s'",
2015                 scope, dhcpv6_status_code_to_str(code), buf);
2016 }
2017 
2018 static void dhcpv6_handle_status_code(const enum dhcpv6_msg orig,
2019                 const uint16_t code, const void *status_msg, const int len,
2020                 int *ret)
2021 {
2022         dhcpv6_log_status_code(code, "message", status_msg, len);
2023 
2024         switch (code) {
2025         case DHCPV6_UnspecFail:
2026                 // Generic failure
2027                 *ret = 0;
2028                 break;
2029 
2030         case DHCPV6_UseMulticast:
2031                 switch(orig) {
2032                 case DHCPV6_MSG_REQUEST:
2033                 case DHCPV6_MSG_RENEW:
2034                 case DHCPV6_MSG_RELEASE:
2035                 case DHCPV6_MSG_DECLINE:
2036                         // Message needs to be retransmitted according to RFC3315 chapter 18.1.8
2037                         server_addr = in6addr_any;
2038                         *ret = 0;
2039                         break;
2040                 default:
2041                         break;
2042                 }
2043                 break;
2044 
2045         case DHCPV6_NoAddrsAvail:
2046         case DHCPV6_NoPrefixAvail:
2047                 if (orig == DHCPV6_MSG_REQUEST)
2048                         *ret = 0; // Failure
2049                 break;
2050 
2051         default:
2052                 break;
2053         }
2054 }
2055 
2056 static void dhcpv6_handle_ia_status_code(const enum dhcpv6_msg orig,
2057                 const struct dhcpv6_ia_hdr *ia_hdr, const uint16_t code,
2058                 const void *status_msg, const int len,
2059                 bool handled_status_codes[_DHCPV6_Status_Max], int *ret)
2060 {
2061         dhcpv6_log_status_code(code, ntohs(ia_hdr->type) == DHCPV6_OPT_IA_NA ?
2062                 "IA_NA" : "IA_PD", status_msg, len);
2063 
2064         switch (code) {
2065         case DHCPV6_NoBinding:
2066                 switch (orig) {
2067                 case DHCPV6_MSG_RENEW:
2068                 case DHCPV6_MSG_REBIND:
2069                         if ((*ret > 0) && !handled_status_codes[code]) {
2070                                 dhcpv6_set_state(DHCPV6_REQUEST);
2071                                 *ret = -1;
2072                         }
2073                         break;
2074 
2075                 default:
2076                         *ret = 0;
2077                         break;
2078                 }
2079                 break;
2080 
2081         case DHCPV6_NoAddrsAvail:
2082         case DHCPV6_NoPrefixAvail:
2083                 break;
2084 
2085         default:
2086                 *ret = 0;
2087                 break;
2088         }
2089 }
2090 
2091 // Note this always takes ownership of cand->ia_na and cand->ia_pd
2092 static void dhcpv6_add_server_cand(const struct dhcpv6_server_cand *cand)
2093 {
2094         size_t cand_len, i;
2095         struct dhcpv6_server_cand *srv_candidates = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2096 
2097         // Remove identical DUID server candidate
2098         for (i = 0; i < cand_len / sizeof(*srv_candidates); ++i) {
2099                 if (cand->duid_len == srv_candidates[i].duid_len &&
2100                                 !memcmp(cand->duid, srv_candidates[i].duid, cand->duid_len)) {
2101                         free(srv_candidates[i].ia_na);
2102                         free(srv_candidates[i].ia_pd);
2103                         odhcp6c_remove_state(STATE_SERVER_CAND, i * sizeof(*srv_candidates), sizeof(*srv_candidates));
2104                         break;
2105                 }
2106         }
2107 
2108         for (i = 0, srv_candidates = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2109                 i < cand_len / sizeof(*srv_candidates); ++i) {
2110                 if (srv_candidates[i].preference < cand->preference)
2111                         break;
2112         }
2113 
2114         if (odhcp6c_insert_state(STATE_SERVER_CAND, i * sizeof(*srv_candidates), cand, sizeof(*cand))) {
2115                 free(cand->ia_na);
2116                 free(cand->ia_pd);
2117         }
2118 }
2119 
2120 static void dhcpv6_clear_all_server_cand(void)
2121 {
2122         size_t cand_len, i;
2123         struct dhcpv6_server_cand *srv_candidates = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2124 
2125         // Server candidates need deep delete for IA_NA/IA_PD
2126         for (i = 0; i < cand_len / sizeof(*srv_candidates); ++i) {
2127                 free(srv_candidates[i].ia_na);
2128                 free(srv_candidates[i].ia_pd);
2129         }
2130         odhcp6c_clear_state(STATE_SERVER_CAND);
2131 }
2132 
2133 int dhcpv6_promote_server_cand(void)
2134 {
2135         size_t cand_len;
2136         struct dhcpv6_server_cand *cand = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
2137         uint16_t hdr[2];
2138         int ret = DHCPV6_STATELESS;
2139         bool override_ia = false;
2140 
2141         // Clear lingering candidate state info
2142         odhcp6c_clear_state(STATE_SERVER_ID);
2143         odhcp6c_clear_state(STATE_IA_NA);
2144         odhcp6c_clear_state(STATE_IA_PD);
2145 
2146         if (!cand_len)
2147                 return -1;
2148 
2149         if (config_dhcp->strict_rfc7550) {
2150                 if (!cand->ia_pd_len && cand->has_noaddravail) {
2151                         /* Some ISPs provide neither IA_NA nor IA_PD, so we
2152                          * should fallback to SLAAC.
2153                          */
2154 
2155                         if (na_mode == IA_MODE_TRY) {
2156                                 na_mode = IA_MODE_NONE;
2157                                 override_ia = true;
2158                         }
2159 
2160                         if (pd_mode == IA_MODE_TRY) {
2161                                 pd_mode = IA_MODE_NONE;
2162                                 override_ia = true;
2163                         }
2164                 }
2165         } else {
2166                 if (cand->has_noaddravail && na_mode == IA_MODE_TRY) {
2167                         /* Some broken ISPs require a new Solicit message
2168                          * without IA_NA if they haven't provided an address
2169                          * on the Advertise message.
2170                          */
2171                         na_mode = IA_MODE_NONE;
2172                         override_ia = true;
2173                 }
2174 
2175                 if (!cand->ia_pd_len && pd_mode == IA_MODE_TRY) {
2176                         /* Some broken ISPs require a new Solicit message
2177                          * without IA_PD if they haven't provided a prefix
2178                          * on the Advertise message.
2179                          */
2180                         pd_mode = IA_MODE_NONE;
2181                         override_ia = true;
2182                 }
2183         }
2184 
2185         if (override_ia) {
2186                 dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
2187                 dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
2188 
2189                 return -1;
2190         }
2191 
2192         hdr[0] = htons(DHCPV6_OPT_SERVERID);
2193         hdr[1] = htons(cand->duid_len);
2194         odhcp6c_add_state(STATE_SERVER_ID, hdr, sizeof(hdr));
2195         odhcp6c_add_state(STATE_SERVER_ID, cand->duid, cand->duid_len);
2196         accept_reconfig = cand->wants_reconfigure;
2197         memset(reconf_key, 0, sizeof(reconf_key));
2198 
2199         if (cand->ia_na_len) {
2200                 odhcp6c_add_state(STATE_IA_NA, cand->ia_na, cand->ia_na_len);
2201                 free(cand->ia_na);
2202                 if (na_mode != IA_MODE_NONE)
2203                         ret = DHCPV6_STATEFUL;
2204         }
2205 
2206         if (cand->ia_pd_len) {
2207                 odhcp6c_add_state(STATE_IA_PD, cand->ia_pd, cand->ia_pd_len);
2208                 free(cand->ia_pd);
2209                 if (pd_mode != IA_MODE_NONE)
2210                         ret = DHCPV6_STATEFUL;
2211         }
2212 
2213         dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
2214         dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
2215 
2216         odhcp6c_remove_state(STATE_SERVER_CAND, 0, sizeof(*cand));
2217 
2218         return ret;
2219 }
2220 
2221 int dhcpv6_send_request(enum dhcpv6_msg req_msg_type)
2222 {
2223         struct dhcpv6_retx *retx = &dhcpv6_retx[req_msg_type];
2224         uint64_t current_milli_time = 0;
2225 
2226         if (!retx->is_retransmit) {
2227                 // Initial delay handling
2228                 if (retx->max_delay) {
2229                         if (retx->delay_msec == 0) {
2230                                 // Initial delay before starting the transaction
2231                                 retx->delay_msec = (dhcpv6_rand_delay((10000 * retx->max_delay) / 2) + (1000 * retx->max_delay) / 2);
2232                                 dhcpv6_set_state_timeout(retx->delay_msec);
2233                                 // Add current time to calculate absolute time
2234                                 retx->delay_msec += odhcp6c_get_milli_time();
2235                                 return 1;
2236                         } else {
2237                                 // Wait until delay expires
2238                                 current_milli_time = odhcp6c_get_milli_time();
2239                                 if (current_milli_time < retx->delay_msec) {
2240                                         // Still waiting
2241                                         dhcpv6_set_state_timeout(retx->delay_msec - current_milli_time);
2242                                         return 1;
2243                                 }
2244                                 retx->delay_msec = 0;
2245                         }
2246                 }
2247 
2248                 retx->is_retransmit = true;
2249                 retx->rc = 0;
2250                 retx->timeout = UINT32_MAX;
2251                 retx->reply_ret = -1;
2252 
2253                 if (req_msg_type == DHCPV6_MSG_UNKNOWN)
2254                         retx->timeout = t1;
2255                 else if (req_msg_type == DHCPV6_MSG_RENEW)
2256                         retx->timeout = (t2 > t1) ? t2 - t1 : ((t1 == UINT32_MAX) ? UINT32_MAX : 0);
2257                 else if (req_msg_type == DHCPV6_MSG_REBIND)
2258                         retx->timeout = (t3 > t2) ? t3 - t2 : ((t2 == UINT32_MAX) ? UINT32_MAX : 0);
2259 
2260                 if (retx->timeout == 0)
2261                         return -1;
2262 
2263                 notice("Starting %s transaction (timeout %"PRIu64"s, max rc %d)",
2264                         retx->name, retx->timeout, retx->max_rc);
2265 
2266                 // Generate transaction ID
2267                 if (req_msg_type != DHCPV6_MSG_UNKNOWN) {
2268                         odhcp6c_random(retx->tr_id, sizeof(retx->tr_id));
2269                 }
2270 
2271                 // Record start time
2272                 retx->start = odhcp6c_get_milli_time();
2273                 retx->round_start = retx->start;
2274                 // Reset retransmission timeout initial value
2275                 retx->rto = 0;
2276         }
2277 
2278         if (retx->rto == 0) {
2279                 int64_t delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
2280 
2281                 // First RT MUST be strictly greater than IRT for solicit messages (RFC3313 17.1.2)
2282                 while (req_msg_type == DHCPV6_MSG_SOLICIT && delay <= 0)
2283                         delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
2284 
2285                 // First timeout
2286                 retx->rto = (retx->init_timeo * 1000 + delay);
2287         } else {
2288                 // Exponential back-off with randomization to avoid synchronization
2289                 retx->rto = (2 * retx->rto + dhcpv6_rand_delay(retx->rto));
2290         }
2291 
2292         if (retx->max_timeo && (retx->rto >= retx->max_timeo * 1000)) {
2293                 // Cap to max timeout if set and exceeded
2294                 retx->rto = retx->max_timeo * 1000 +
2295                         dhcpv6_rand_delay(retx->max_timeo * 1000);
2296         }
2297 
2298         // Calculate end for this round and elapsed time
2299         retx->round_end = retx->round_start + retx->rto;
2300         uint64_t elapsed = retx->round_start - retx->start;
2301 
2302         // Don't wait too long if timeout differs from infinite
2303         if ((retx->timeout != UINT32_MAX) && (retx->round_end - retx->start > retx->timeout * 1000))
2304                 retx->round_end = retx->timeout * 1000 + retx->start;
2305 
2306         dhcpv6_set_state_timeout(retx->round_end - odhcp6c_get_milli_time());
2307 
2308         // Built and send package
2309         switch (req_msg_type) {
2310         case DHCPV6_MSG_UNKNOWN:
2311                 break;
2312         default:
2313                 notice("Send %s message (elapsed %"PRIu64"ms, rc %d)",
2314                                 retx->name, elapsed, retx->rc);
2315                 _o_fallthrough;
2316         case DHCPV6_MSG_SOLICIT:
2317         case DHCPV6_MSG_INFO_REQ:
2318                 dhcpv6_send(req_msg_type, retx->tr_id, elapsed / 10);
2319                 retx->rc++;
2320         }
2321 
2322         if (dhcpv6_get_state() != DHCPV6_EXIT)
2323                 dhcpv6_next_state();
2324 
2325         return 0;
2326 }
2327 
2328 int dhcpv6_receive_response(enum dhcpv6_msg req_msg_type)
2329 {
2330         ssize_t len = -1;
2331         struct dhcpv6_retx *retx = &dhcpv6_retx[req_msg_type];
2332 
2333         uint8_t buf[1536];
2334         union {
2335                 struct cmsghdr hdr;
2336                 uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
2337         } cmsg_buf;
2338 
2339         struct iovec iov = {buf, sizeof(buf)};
2340         struct sockaddr_in6 addr;
2341         struct msghdr msg = {.msg_name = &addr, .msg_namelen = sizeof(addr),
2342                         .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsg_buf.buf,
2343                         .msg_controllen = sizeof(cmsg_buf)};
2344         struct in6_pktinfo *pktinfo = NULL;
2345         const struct dhcpv6_header *hdr = (const struct dhcpv6_header *)buf;
2346 
2347         // Receive cycle
2348         len = recvmsg(sock, &msg, 0);
2349         if (len < 0) {
2350                 error("Error occurred when reading the response of (%s) error(%s)",
2351                         retx->name, strerror(errno));
2352                 return -1;
2353         }
2354 
2355         for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL;
2356                 ch = CMSG_NXTHDR(&msg, ch)) {
2357                 if (ch->cmsg_level == SOL_IPV6 &&
2358                         ch->cmsg_type == IPV6_PKTINFO) {
2359                         pktinfo = (struct in6_pktinfo *)CMSG_DATA(ch);
2360                         break;
2361                 }
2362         }
2363 
2364         if (pktinfo == NULL) {
2365                 dhcpv6_stats.discarded_packets++;
2366                 return -1;
2367         }
2368 
2369         if (!dhcpv6_response_is_valid(buf, len, retx->tr_id, req_msg_type,
2370                                          &pktinfo->ipi6_addr)) {
2371                 dhcpv6_stats.discarded_packets++;
2372                 return -1;
2373         }
2374 
2375         dhcpv6_inc_counter(hdr->msg_type);
2376 
2377         uint8_t *opt = &buf[4];
2378         uint8_t *opt_end = opt + len - DHCPV6_OPT_HDR_SIZE;
2379         retx->round_start = odhcp6c_get_milli_time();
2380         uint64_t elapsed = retx->round_start - retx->start;
2381 
2382         notice("Got a valid %s after %"PRIu64"ms",
2383                 dhcpv6_msg_to_str(hdr->msg_type), elapsed);
2384 
2385         if (retx->handler_reply) {
2386                 retx->reply_ret = retx->handler_reply(req_msg_type, retx->rc, opt, opt_end, &addr);
2387                 len = retx->reply_ret;
2388         }
2389 
2390         // Clamp round end (Round Trip Time) to 1s max wait after receiving a valid response (in milliseconds)
2391         if (len > 0 && retx->round_end - retx->round_start > 1000)
2392                 retx->round_end = 1000 + retx->round_start;
2393 
2394         return retx->reply_ret;
2395 }
2396 
2397 int dhcpv6_state_processing(enum dhcpv6_msg req_msg_type)
2398 {
2399         struct dhcpv6_retx *retx = &dhcpv6_retx[req_msg_type];
2400         int ret = retx->reply_ret;
2401         retx->round_start = odhcp6c_get_milli_time();
2402         uint64_t elapsed = retx->round_start - retx->start;
2403 
2404         if (retx->round_start >= retx->round_end || ret >=0 ) {
2405                 if (retx->handler_finish)
2406                         ret = retx->handler_finish();
2407 
2408                 if (ret < 0 && ((retx->timeout == UINT32_MAX) || (elapsed / 1000 < retx->timeout)) &&
2409                         (!retx->max_rc || retx->rc < retx->max_rc)) {
2410                                 retx->reply_ret = -1;
2411                                 dhcpv6_prev_state();
2412                 } else {
2413                         retx->is_retransmit = false;
2414                         dhcpv6_next_state();
2415                 }
2416         } else {
2417                 // This sets the response polling timeout (round_end - round_start) in milliseconds
2418                 dhcpv6_set_state_timeout(retx->round_end - retx->round_start);
2419         }
2420 
2421         return ret;
2422 }
2423 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt