treewide: init assignment lists head
[oweals/odhcpd.git] / src / dhcpv6-ia.c
1 /**
2  * Copyright (C) 2013 Steven Barth <steven@midlink.org>
3  * Copyright (C) 2016 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 "odhcpd.h"
17 #include "dhcpv6.h"
18 #include "dhcpv4.h"
19
20 #include <time.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <poll.h>
25 #include <alloca.h>
26 #include <resolv.h>
27 #include <limits.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <stdbool.h>
32 #include <arpa/inet.h>
33 #include <sys/timerfd.h>
34
35 #include <libubox/md5.h>
36 #include <libubox/usock.h>
37
38 #define ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs) \
39     ((iface)->dhcpv6_assignall || (i) == (m) || \
40      (addrs)[(i)].prefix > 64)
41
42 static void dhcpv6_netevent_cb(unsigned long event, struct netevent_handler_info *info);
43 static void set_border_assignment_size(struct interface *iface, struct dhcp_assignment *b);
44 static void handle_addrlist_change(struct netevent_handler_info *info);
45 static void start_reconf(struct dhcp_assignment *a);
46 static void stop_reconf(struct dhcp_assignment *a);
47 static void valid_until_cb(struct uloop_timeout *event);
48
49 static struct netevent_handler dhcpv6_netevent_handler = { .cb = dhcpv6_netevent_cb, };
50 static struct uloop_timeout valid_until_timeout = {.cb = valid_until_cb};
51 static uint32_t serial = 0;
52 static uint8_t statemd5[16];
53
54 int dhcpv6_ia_init(void)
55 {
56         uloop_timeout_set(&valid_until_timeout, 1000);
57
58         netlink_add_netevent_handler(&dhcpv6_netevent_handler);
59
60         return 0;
61 }
62
63 int dhcpv6_ia_setup_interface(struct interface *iface, bool enable)
64 {
65         if (!enable) {
66                 struct dhcp_assignment *c;
67
68                 while (!list_empty(&iface->ia_assignments)) {
69                         c = list_first_entry(&iface->ia_assignments, struct dhcp_assignment, head);
70                         free_assignment(c);
71                 }
72         }
73
74         if (enable && iface->dhcpv6 == MODE_SERVER) {
75                 struct dhcp_assignment *border;
76
77                 if (list_empty(&iface->ia_assignments)) {
78                         border = alloc_assignment(0);
79
80                         if (!border) {
81                                 syslog(LOG_ERR, "Failed to alloc border on %s", iface->name);
82                                 return -1;
83                         }
84
85                         border->length = 64;
86                         list_add(&border->head, &iface->ia_assignments);
87                 } else
88                         border = list_last_entry(&iface->ia_assignments, struct dhcp_assignment, head);
89
90                 set_border_assignment_size(iface, border);
91         }
92         return 0;
93 }
94
95
96 static void dhcpv6_netevent_cb(unsigned long event, struct netevent_handler_info *info)
97 {
98         struct interface *iface = info->iface;
99
100         if (!iface || iface->dhcpv6 != MODE_SERVER)
101                 return;
102
103         switch (event) {
104         case NETEV_ADDR6LIST_CHANGE:
105                 handle_addrlist_change(info);
106                 break;
107         default:
108                 break;
109         }
110 }
111
112
113 static inline bool valid_prefix_length(const struct dhcp_assignment *a, const uint8_t prefix_length)
114 {
115         return (a->managed_size || a->length > prefix_length);
116 }
117
118 static inline bool valid_addr(const struct odhcpd_ipaddr *addr, time_t now)
119 {
120         return (addr->prefix <= 96 && addr->preferred > (uint32_t)now);
121 }
122
123 static size_t get_preferred_addr(const struct odhcpd_ipaddr *addrs, const size_t addrlen)
124 {
125         size_t i, m;
126
127         for (i = 0, m = 0; i < addrlen; ++i) {
128                 if (addrs[i].preferred > addrs[m].preferred ||
129                                 (addrs[i].preferred == addrs[m].preferred &&
130                                 memcmp(&addrs[i].addr, &addrs[m].addr, 16) > 0))
131                         m = i;
132         }
133
134         return m;
135 }
136
137 static int send_reconf(struct dhcp_assignment *assign)
138 {
139         struct {
140                 struct dhcpv6_client_header hdr;
141                 uint16_t srvid_type;
142                 uint16_t srvid_len;
143                 uint16_t duid_type;
144                 uint16_t hardware_type;
145                 uint8_t mac[6];
146                 uint16_t msg_type;
147                 uint16_t msg_len;
148                 uint8_t msg_id;
149                 struct dhcpv6_auth_reconfigure auth;
150                 uint16_t clid_type;
151                 uint16_t clid_len;
152                 uint8_t clid_data[128];
153         } __attribute__((packed)) reconf_msg = {
154                 .hdr = {DHCPV6_MSG_RECONFIGURE, {0, 0, 0}},
155                 .srvid_type = htons(DHCPV6_OPT_SERVERID),
156                 .srvid_len = htons(10),
157                 .duid_type = htons(3),
158                 .hardware_type = htons(1),
159                 .msg_type = htons(DHCPV6_OPT_RECONF_MSG),
160                 .msg_len = htons(1),
161                 .msg_id = DHCPV6_MSG_RENEW,
162                 .auth = {htons(DHCPV6_OPT_AUTH),
163                                 htons(sizeof(reconf_msg.auth) - 4), 3, 1, 0,
164                                 {htonl(time(NULL)), htonl(++serial)}, 2, {0}},
165                 .clid_type = htons(DHCPV6_OPT_CLIENTID),
166                 .clid_len = htons(assign->clid_len),
167                 .clid_data = {0},
168         };
169         struct interface *iface = assign->iface;
170
171         odhcpd_get_mac(iface, reconf_msg.mac);
172         memcpy(reconf_msg.clid_data, assign->clid_data, assign->clid_len);
173         struct iovec iov = {&reconf_msg, sizeof(reconf_msg) - 128 + assign->clid_len};
174
175         md5_ctx_t md5;
176         uint8_t secretbytes[64];
177         memset(secretbytes, 0, sizeof(secretbytes));
178         memcpy(secretbytes, assign->key, sizeof(assign->key));
179
180         for (size_t i = 0; i < sizeof(secretbytes); ++i)
181                 secretbytes[i] ^= 0x36;
182
183         md5_begin(&md5);
184         md5_hash(secretbytes, sizeof(secretbytes), &md5);
185         md5_hash(iov.iov_base, iov.iov_len, &md5);
186         md5_end(reconf_msg.auth.key, &md5);
187
188         for (size_t i = 0; i < sizeof(secretbytes); ++i) {
189                 secretbytes[i] ^= 0x36;
190                 secretbytes[i] ^= 0x5c;
191         }
192
193         md5_begin(&md5);
194         md5_hash(secretbytes, sizeof(secretbytes), &md5);
195         md5_hash(reconf_msg.auth.key, 16, &md5);
196         md5_end(reconf_msg.auth.key, &md5);
197
198         return odhcpd_send(iface->dhcpv6_event.uloop.fd, &assign->peer, &iov, 1, iface);
199 }
200
201 static void dhcpv6_ia_free_assignment(struct dhcp_assignment *a)
202 {
203         if (a->managed_sock.fd.registered) {
204                 ustream_free(&a->managed_sock.stream);
205                 close(a->managed_sock.fd.fd);
206         }
207
208         if (a->reconf_cnt)
209                 stop_reconf(a);
210
211         free(a->managed);
212 }
213
214 void dhcpv6_ia_enum_addrs(struct interface *iface, struct dhcp_assignment *c,
215                           time_t now, dhcpv6_binding_cb_handler_t func, void *arg)
216 {
217         struct odhcpd_ipaddr *addrs = (c->managed) ? c->managed : iface->addr6;
218         size_t addrlen = (c->managed) ? (size_t)c->managed_size : iface->addr6_len;
219         size_t m = get_preferred_addr(addrs, addrlen);
220
221         for (size_t i = 0; i < addrlen; ++i) {
222                 struct in6_addr addr;
223                 uint32_t pref, valid;
224                 int prefix = c->managed ? addrs[i].prefix : c->length;
225
226                 if (!valid_addr(&addrs[i], now))
227                         continue;
228
229                 addr = addrs[i].addr.in6;
230                 pref = addrs[i].preferred;
231                 valid = addrs[i].valid;
232                 if (prefix == 128) {
233                         if (!ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs))
234                                 continue;
235
236                         addr.s6_addr32[3] = htonl(c->assigned);
237                 } else {
238                         if (!valid_prefix_length(c, addrs[i].prefix))
239                                 continue;
240
241                         addr.s6_addr32[1] |= htonl(c->assigned);
242                         addr.s6_addr32[2] = addr.s6_addr32[3] = 0;
243                 }
244
245                 if (pref != UINT32_MAX)
246                         pref -= now;
247
248                 if (valid != UINT32_MAX)
249                         valid -= now;
250
251                 func(&addr, prefix, pref, valid, arg);
252         }
253 }
254
255 struct write_ctxt {
256         FILE *fp;
257         md5_ctx_t md5;
258         struct dhcp_assignment *c;
259         struct interface *iface;
260         char *buf;
261         int buf_len;
262         int buf_idx;
263 };
264
265 static void dhcpv6_write_ia_addr(struct in6_addr *addr, int prefix, _unused uint32_t pref,
266                                 _unused uint32_t valid, void *arg)
267 {
268         struct write_ctxt *ctxt = (struct write_ctxt *)arg;
269         char ipbuf[INET6_ADDRSTRLEN];
270
271         inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf) - 1);
272
273         if (ctxt->c->length == 128 && ctxt->c->hostname &&
274             !(ctxt->c->flags & OAF_BROKEN_HOSTNAME)) {
275                 fputs(ipbuf, ctxt->fp);
276
277                 char b[256];
278                 if (dn_expand(ctxt->iface->search, ctxt->iface->search + ctxt->iface->search_len,
279                                 ctxt->iface->search, b, sizeof(b)) > 0)
280                         fprintf(ctxt->fp, "\t%s.%s", ctxt->c->hostname, b);
281
282                 fprintf(ctxt->fp, "\t%s\n", ctxt->c->hostname);
283                 md5_hash(ipbuf, strlen(ipbuf), &ctxt->md5);
284                 md5_hash(ctxt->c->hostname, strlen(ctxt->c->hostname), &ctxt->md5);
285         }
286
287         ctxt->buf_idx += snprintf(ctxt->buf + ctxt->buf_idx,ctxt->buf_len - ctxt->buf_idx,
288                                         "%s/%d ", ipbuf, prefix);
289 }
290
291 void dhcpv6_ia_write_statefile(void)
292 {
293         struct write_ctxt ctxt;
294
295         md5_begin(&ctxt.md5);
296
297         if (config.dhcp_statefile) {
298                 time_t now = odhcpd_time(), wall_time = time(NULL);
299                 int fd = open(config.dhcp_statefile, O_CREAT | O_WRONLY | O_CLOEXEC, 0644);
300                 char leasebuf[512];
301
302                 if (fd < 0)
303                         return;
304                 int ret;
305                 ret = lockf(fd, F_LOCK, 0);
306                 if (ret < 0) {
307                         close(fd);
308                         return;
309                 }
310                 if (ftruncate(fd, 0) < 0) {}
311
312                 ctxt.fp = fdopen(fd, "w");
313                 if (!ctxt.fp) {
314                         close(fd);
315                         return;
316                 }
317
318                 ctxt.buf = leasebuf;
319                 ctxt.buf_len = sizeof(leasebuf);
320
321                 avl_for_each_element(&interfaces, ctxt.iface, avl) {
322                         if (ctxt.iface->dhcpv6 != MODE_SERVER &&
323                                         ctxt.iface->dhcpv4 != MODE_SERVER)
324                                 continue;
325
326                         if (ctxt.iface->dhcpv6 == MODE_SERVER) {
327                                 list_for_each_entry(ctxt.c, &ctxt.iface->ia_assignments, head) {
328                                         if (!(ctxt.c->flags & OAF_BOUND) || ctxt.c->managed_size < 0)
329                                                 continue;
330
331                                         char duidbuf[264];
332
333                                         odhcpd_hexlify(duidbuf, ctxt.c->clid_data, ctxt.c->clid_len);
334
335                                         /* iface DUID iaid hostname lifetime assigned length [addrs...] */
336                                         ctxt.buf_idx = snprintf(ctxt.buf, ctxt.buf_len, "# %s %s %x %s%s %ld %x %u ",
337                                                                 ctxt.iface->ifname, duidbuf, ntohl(ctxt.c->iaid),
338                                                                 (ctxt.c->flags & OAF_BROKEN_HOSTNAME) ? "broken\\x20" : "",
339                                                                 (ctxt.c->hostname ? ctxt.c->hostname : "-"),
340                                                                 (ctxt.c->valid_until > now ?
341                                                                         (ctxt.c->valid_until - now + wall_time) :
342                                                                         (INFINITE_VALID(ctxt.c->valid_until) ? -1 : 0)),
343                                                                 ctxt.c->assigned, (unsigned)ctxt.c->length);
344
345                                         if (INFINITE_VALID(ctxt.c->valid_until) || ctxt.c->valid_until > now)
346                                                 dhcpv6_ia_enum_addrs(ctxt.iface, ctxt.c, now,
347                                                                         dhcpv6_write_ia_addr, &ctxt);
348
349                                         ctxt.buf[ctxt.buf_idx - 1] = '\n';
350                                         fwrite(ctxt.buf, 1, ctxt.buf_idx, ctxt.fp);
351                                 }
352                         }
353
354                         if (ctxt.iface->dhcpv4 == MODE_SERVER) {
355                                 struct dhcp_assignment *c;
356
357                                 list_for_each_entry(c, &ctxt.iface->dhcpv4_assignments, head) {
358                                         if (!(c->flags & OAF_BOUND))
359                                                 continue;
360
361                                         char ipbuf[INET6_ADDRSTRLEN];
362                                         char duidbuf[16];
363                                         odhcpd_hexlify(duidbuf, c->hwaddr, sizeof(c->hwaddr));
364
365                                         /* iface DUID iaid hostname lifetime assigned length [addrs...] */
366                                         ctxt.buf_idx = snprintf(ctxt.buf, ctxt.buf_len, "# %s %s ipv4 %s%s %ld %x 32 ",
367                                                                 ctxt.iface->ifname, duidbuf,
368                                                                 (c->flags & OAF_BROKEN_HOSTNAME) ? "broken\\x20" : "",
369                                                                 (c->hostname ? c->hostname : "-"),
370                                                                 (c->valid_until > now ?
371                                                                         (c->valid_until - now + wall_time) :
372                                                                         (INFINITE_VALID(c->valid_until) ? -1 : 0)),
373                                                                 ntohl(c->addr));
374
375                                         struct in_addr addr = {.s_addr = c->addr};
376                                         inet_ntop(AF_INET, &addr, ipbuf, sizeof(ipbuf) - 1);
377
378                                         if (c->hostname && !(c->flags & OAF_BROKEN_HOSTNAME)) {
379                                                 fputs(ipbuf, ctxt.fp);
380
381                                                 char b[256];
382                                                 if (dn_expand(ctxt.iface->search,
383                                                                 ctxt.iface->search + ctxt.iface->search_len,
384                                                                 ctxt.iface->search, b, sizeof(b)) > 0)
385                                                         fprintf(ctxt.fp, "\t%s.%s", c->hostname, b);
386
387                                                 fprintf(ctxt.fp, "\t%s\n", c->hostname);
388                                                 md5_hash(ipbuf, strlen(ipbuf), &ctxt.md5);
389                                                 md5_hash(c->hostname, strlen(c->hostname), &ctxt.md5);
390                                         }
391
392                                         ctxt.buf_idx += snprintf(ctxt.buf + ctxt.buf_idx,
393                                                                         ctxt.buf_len - ctxt.buf_idx,
394                                                                         "%s/32 ", ipbuf);
395                                         ctxt.buf[ctxt.buf_idx - 1] = '\n';
396                                         fwrite(ctxt.buf, 1, ctxt.buf_idx, ctxt.fp);
397                                 }
398                         }
399                 }
400
401                 fclose(ctxt.fp);
402         }
403
404         uint8_t newmd5[16];
405         md5_end(newmd5, &ctxt.md5);
406
407         if (config.dhcp_cb && memcmp(newmd5, statemd5, sizeof(newmd5))) {
408                 memcpy(statemd5, newmd5, sizeof(statemd5));
409                 char *argv[2] = {config.dhcp_cb, NULL};
410                 if (!vfork()) {
411                         execv(argv[0], argv);
412                         _exit(128);
413                 }
414         }
415 }
416
417 static void __apply_lease(struct interface *iface, struct dhcp_assignment *a,
418                 struct odhcpd_ipaddr *addrs, ssize_t addr_len, bool add)
419 {
420         if (a->length > 64)
421                 return;
422
423         for (ssize_t i = 0; i < addr_len; ++i) {
424                 struct in6_addr prefix = addrs[i].addr.in6;
425                 prefix.s6_addr32[1] |= htonl(a->assigned);
426                 prefix.s6_addr32[2] = prefix.s6_addr32[3] = 0;
427                 netlink_setup_route(&prefix, (a->managed_size) ? addrs[i].prefix : a->length,
428                                 iface->ifindex, &a->peer.sin6_addr, 1024, add);
429         }
430 }
431
432 static void apply_lease(struct interface *iface, struct dhcp_assignment *a, bool add)
433 {
434         struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
435         ssize_t addrlen = (a->managed) ? a->managed_size : (ssize_t)iface->addr6_len;
436
437         __apply_lease(iface, a, addrs, addrlen, add);
438 }
439
440 /* Set border assignment size based on the IPv6 address prefixes */
441 static void set_border_assignment_size(struct interface *iface, struct dhcp_assignment *b)
442 {
443         time_t now = odhcpd_time();
444         int minprefix = -1;
445
446         for (size_t i = 0; i < iface->addr6_len; ++i) {
447                 if (iface->addr6[i].preferred > (uint32_t)now &&
448                                 iface->addr6[i].prefix < 64 &&
449                                 iface->addr6[i].prefix > minprefix)
450                         minprefix = iface->addr6[i].prefix;
451         }
452
453         if (minprefix > 32 && minprefix <= 64)
454                 b->assigned = 1U << (64 - minprefix);
455         else
456                 b->assigned = 0;
457 }
458
459 /* More data was received from TCP connection */
460 static void managed_handle_pd_data(struct ustream *s, _unused int bytes_new)
461 {
462         struct ustream_fd *fd = container_of(s, struct ustream_fd, stream);
463         struct dhcp_assignment *c = container_of(fd, struct dhcp_assignment, managed_sock);
464         time_t now = odhcpd_time();
465         bool first = c->managed_size < 0;
466
467         for (;;) {
468                 int pending;
469                 char *data = ustream_get_read_buf(s, &pending);
470                 char *end = memmem(data, pending, "\n\n", 2);
471
472                 if (!end)
473                         break;
474
475                 end += 2;
476                 end[-1] = 0;
477
478                 c->managed_size = 0;
479                 if (c->accept_reconf)
480                         c->reconf_cnt = 1;
481
482                 char *saveptr;
483                 for (char *line = strtok_r(data, "\n", &saveptr); line; line = strtok_r(NULL, "\n", &saveptr)) {
484                         c->managed = realloc(c->managed, (c->managed_size + 1) * sizeof(*c->managed));
485                         struct odhcpd_ipaddr *n = &c->managed[c->managed_size];
486
487                         char *saveptr2, *x = strtok_r(line, "/", &saveptr2);
488                         if (!x || inet_pton(AF_INET6, x, &n->addr) < 1)
489                                 continue;
490
491                         x = strtok_r(NULL, ",", &saveptr2);
492                         if (sscanf(x, "%hhu", &n->prefix) < 1)
493                                 continue;
494
495                         x = strtok_r(NULL, ",", &saveptr2);
496                         if (sscanf(x, "%u", &n->preferred) < 1)
497                                 continue;
498
499                         x = strtok_r(NULL, ",", &saveptr2);
500                         if (sscanf(x, "%u", &n->valid) < 1)
501                                 continue;
502
503                         if (n->preferred > n->valid)
504                                 continue;
505
506                         if (UINT32_MAX - now < n->preferred)
507                                 n->preferred = UINT32_MAX;
508                         else
509                                 n->preferred += now;
510
511                         if (UINT32_MAX - now < n->valid)
512                                 n->valid = UINT32_MAX;
513                         else
514                                 n->valid += now;
515
516                         n->dprefix = 0;
517
518                         ++c->managed_size;
519                 }
520
521                 ustream_consume(s, end - data);
522         }
523
524         if (first && c->managed_size == 0)
525                 free_assignment(c);
526         else if (first && !(c->flags & OAF_STATIC))
527                 c->valid_until = now + 150;
528 }
529
530
531 /* TCP transmission has ended, either because of success or timeout or other error */
532 static void managed_handle_pd_done(struct ustream *s)
533 {
534         struct ustream_fd *fd = container_of(s, struct ustream_fd, stream);
535         struct dhcp_assignment *c = container_of(fd, struct dhcp_assignment, managed_sock);
536
537         if (!(c->flags & OAF_STATIC))
538                 c->valid_until = odhcpd_time() + 15;
539
540         c->managed_size = 0;
541
542         if (c->accept_reconf)
543                 c->reconf_cnt = 1;
544 }
545
546 static bool assign_pd(struct interface *iface, struct dhcp_assignment *assign)
547 {
548         struct dhcp_assignment *c;
549
550         if (iface->dhcpv6_pd_manager[0]) {
551                 int fd = usock(USOCK_UNIX | USOCK_TCP, iface->dhcpv6_pd_manager, NULL);
552                 if (fd >= 0) {
553                         struct pollfd pfd = { .fd = fd, .events = POLLIN };
554                         char iaidbuf[298];
555
556                         odhcpd_hexlify(iaidbuf, assign->clid_data, assign->clid_len);
557
558                         assign->managed_sock.stream.notify_read = managed_handle_pd_data;
559                         assign->managed_sock.stream.notify_state = managed_handle_pd_done;
560                         ustream_fd_init(&assign->managed_sock, fd);
561                         ustream_printf(&assign->managed_sock.stream, "%s,%x\n::/%d,0,0\n\n",
562                                         iaidbuf, assign->iaid, assign->length);
563                         ustream_write_pending(&assign->managed_sock.stream);
564                         assign->managed_size = -1;
565
566                         if (!(assign->flags & OAF_STATIC))
567                                 assign->valid_until = odhcpd_time() + 15;
568
569                         list_add(&assign->head, &iface->ia_assignments);
570
571                         /* Wait initial period of up to 250ms for immediate assignment */
572                         if (poll(&pfd, 1, 250) < 0) {
573                                 syslog(LOG_ERR, "poll(): %m");
574                                 return false;
575                         }
576
577                         managed_handle_pd_data(&assign->managed_sock.stream, 0);
578
579                         if (fcntl(fd, F_GETFL) >= 0 && assign->managed_size > 0)
580                                 return true;
581                 }
582
583                 return false;
584         } else if (iface->addr6_len < 1)
585                 return false;
586
587         /* Try honoring the hint first */
588         uint32_t current = 1, asize = (1 << (64 - assign->length)) - 1;
589         if (assign->assigned) {
590                 list_for_each_entry(c, &iface->ia_assignments, head) {
591                         if (c->length == 128 || c->length == 0)
592                                 continue;
593
594                         if (assign->assigned >= current && assign->assigned + asize < c->assigned) {
595                                 list_add_tail(&assign->head, &c->head);
596
597                                 if (assign->flags & OAF_BOUND)
598                                         apply_lease(iface, assign, true);
599
600                                 return true;
601                         }
602
603                         if (c->assigned != 0)
604                                 current = (c->assigned + (1 << (64 - c->length)));
605                 }
606         }
607
608         /* Fallback to a variable assignment */
609         current = 1;
610         list_for_each_entry(c, &iface->ia_assignments, head) {
611                 if (c->length == 128 || c->length == 0)
612                         continue;
613
614                 current = (current + asize) & (~asize);
615                 if (current + asize < c->assigned) {
616                         assign->assigned = current;
617                         list_add_tail(&assign->head, &c->head);
618
619                         if (assign->flags & OAF_BOUND)
620                                 apply_lease(iface, assign, true);
621
622                         return true;
623                 }
624
625                 if (c->assigned != 0)
626                         current = (c->assigned + (1 << (64 - c->length)));
627         }
628
629         return false;
630 }
631
632 static bool assign_na(struct interface *iface, struct dhcp_assignment *a)
633 {
634         struct dhcp_assignment *c;
635         uint32_t seed = 0;
636
637         /* Preconfigured assignment by static lease */
638         if (a->assigned) {
639                 list_for_each_entry(c, &iface->ia_assignments, head) {
640                         if (c->length == 0)
641                                 continue;
642
643                         if (c->assigned > a->assigned || c->length != 128) {
644                                 list_add_tail(&a->head, &c->head);
645                                 return true;
646                         } else if (c->assigned == a->assigned)
647                                 return false;
648                 }
649         }
650
651         /* Seed RNG with checksum of DUID */
652         for (size_t i = 0; i < a->clid_len; ++i)
653                 seed += a->clid_data[i];
654         srand(seed);
655
656         /* Try to assign up to 100x */
657         for (size_t i = 0; i < 100; ++i) {
658                 uint32_t try;
659                 do try = ((uint32_t)rand()) % 0x0fff; while (try < 0x100);
660
661                 if (config_find_lease_by_hostid(try))
662                         continue;
663
664                 list_for_each_entry(c, &iface->ia_assignments, head) {
665                         if (c->length == 0)
666                                 continue;
667
668                         if (c->assigned > try || c->length != 128) {
669                                 a->assigned = try;
670                                 list_add_tail(&a->head, &c->head);
671                                 return true;
672                         } else if (c->assigned == try)
673                                 break;
674                 }
675         }
676
677         return false;
678 }
679
680 static void handle_addrlist_change(struct netevent_handler_info *info)
681 {
682         struct interface *iface = info->iface;
683         struct dhcp_assignment *c, *d, *border = list_last_entry(
684                         &iface->ia_assignments, struct dhcp_assignment, head);
685         struct list_head reassign = LIST_HEAD_INIT(reassign);
686         time_t now = odhcpd_time();
687
688         list_for_each_entry(c, &iface->ia_assignments, head) {
689                 if (c != border && iface->ra_managed == RA_MANAGED_NO_MFLAG
690                                 && (c->flags & OAF_BOUND))
691                         __apply_lease(iface, c, info->addrs_old.addrs,
692                                         info->addrs_old.len, false);
693         }
694
695         set_border_assignment_size(iface, border);
696
697         list_for_each_entry_safe(c, d, &iface->ia_assignments, head) {
698                 if (c->clid_len == 0 || (!INFINITE_VALID(c->valid_until) && c->valid_until < now) ||
699                                 c->managed_size)
700                         continue;
701
702                 if (c->length < 128 && c->assigned >= border->assigned && c != border)
703                         list_move(&c->head, &reassign);
704                 else if (c != border && (c->flags & OAF_BOUND))
705                         apply_lease(iface, c, true);
706
707                 if (c->accept_reconf && c->reconf_cnt == 0) {
708                         struct dhcp_assignment *a;
709
710                         start_reconf(c);
711
712                         /* Leave all other assignments of that client alone */
713                         list_for_each_entry(a, &iface->ia_assignments, head)
714                                 if (a != c && a->clid_len == c->clid_len &&
715                                                 !memcmp(a->clid_data, c->clid_data, a->clid_len))
716                                         a->reconf_cnt = INT_MAX;
717                 }
718         }
719
720         while (!list_empty(&reassign)) {
721                 c = list_first_entry(&reassign, struct dhcp_assignment, head);
722                 list_del_init(&c->head);
723                 if (!assign_pd(iface, c)) {
724                         c->assigned = 0;
725                         list_add(&c->head, &iface->ia_assignments);
726                 }
727         }
728
729         dhcpv6_ia_write_statefile();
730 }
731
732 static void reconf_timeout_cb(struct uloop_timeout *event)
733 {
734         struct dhcp_assignment *a = container_of(event, struct dhcp_assignment, reconf_timer);
735
736         if (a->reconf_cnt > 0 && a->reconf_cnt < DHCPV6_REC_MAX_RC) {
737                 send_reconf(a);
738                 uloop_timeout_set(&a->reconf_timer,
739                                         DHCPV6_REC_TIMEOUT << a->reconf_cnt);
740                 a->reconf_cnt++;
741         } else
742                 stop_reconf(a);
743 }
744
745 static void start_reconf(struct dhcp_assignment *a)
746 {
747         uloop_timeout_set(&a->reconf_timer,
748                                 DHCPV6_REC_TIMEOUT << a->reconf_cnt);
749         a->reconf_timer.cb = reconf_timeout_cb;
750         a->reconf_cnt++;
751
752         send_reconf(a);
753 }
754
755 static void stop_reconf(struct dhcp_assignment *a)
756 {
757         uloop_timeout_cancel(&a->reconf_timer);
758         a->reconf_cnt = 0;
759         a->reconf_timer.cb = NULL;
760 }
761
762 static void valid_until_cb(struct uloop_timeout *event)
763 {
764         struct interface *iface;
765         time_t now = odhcpd_time();
766
767         avl_for_each_element(&interfaces, iface, avl) {
768                 struct dhcp_assignment *a, *n;
769
770                 if (iface->dhcpv6 != MODE_SERVER)
771                         continue;
772
773                 list_for_each_entry_safe(a, n, &iface->ia_assignments, head) {
774                         if (!INFINITE_VALID(a->valid_until) && a->valid_until < now) {
775                                 if ((a->length < 128 && a->clid_len > 0) ||
776                                                 (a->length == 128 && a->clid_len == 0))
777                                         free_assignment(a);
778
779                         }
780                 }
781         }
782         uloop_timeout_set(event, 1000);
783 }
784
785 static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status,
786                 const struct dhcpv6_ia_hdr *ia, struct dhcp_assignment *a,
787                 struct interface *iface, bool request)
788 {
789         struct dhcpv6_ia_hdr o_ia = {
790                 .type = ia->type,
791                 .len = 0,
792                 .iaid = ia->iaid,
793                 .t1 = 0,
794                 .t2 = 0,
795         };
796         size_t ia_len = sizeof(o_ia);
797         time_t now = odhcpd_time();
798
799         if (buflen < ia_len)
800                 return 0;
801
802         if (status) {
803                 struct __attribute__((packed)) {
804                         uint16_t type;
805                         uint16_t len;
806                         uint16_t val;
807                 } o_status = {
808                         .type = htons(DHCPV6_OPT_STATUS),
809                         .len = htons(sizeof(o_status) - 4),
810                         .val = htons(status),
811                 };
812
813                 memcpy(buf + ia_len, &o_status, sizeof(o_status));
814                 ia_len += sizeof(o_status);
815
816                 o_ia.len = htons(ia_len - 4);
817                 memcpy(buf, &o_ia, sizeof(o_ia));
818
819                 return ia_len;
820         }
821
822         if (a) {
823                 uint32_t leasetime;
824
825                 if (a->leasetime)
826                         leasetime = a->leasetime;
827                 else
828                         leasetime = iface->dhcpv4_leasetime;
829
830                 uint32_t pref = leasetime;
831                 uint32_t valid = leasetime;
832
833                 struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
834                 size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->addr6_len;
835                 size_t m = get_preferred_addr(addrs, addrlen);
836
837                 for (size_t i = 0; i < addrlen; ++i) {
838                         uint32_t prefix_pref = addrs[i].preferred;
839                         uint32_t prefix_valid = addrs[i].valid;
840
841                         if (!valid_addr(&addrs[i], now))
842                                 continue;
843
844                         if (prefix_pref != UINT32_MAX)
845                                 prefix_pref -= now;
846
847                         if (prefix_valid != UINT32_MAX)
848                                 prefix_valid -= now;
849
850                         if (a->length < 128) {
851                                 struct dhcpv6_ia_prefix o_ia_p = {
852                                         .type = htons(DHCPV6_OPT_IA_PREFIX),
853                                         .len = htons(sizeof(o_ia_p) - 4),
854                                         .preferred = htonl(prefix_pref),
855                                         .valid = htonl(prefix_valid),
856                                         .prefix = (a->managed_size) ? addrs[i].prefix : a->length,
857                                         .addr = addrs[i].addr.in6,
858                                 };
859
860                                 o_ia_p.addr.s6_addr32[1] |= htonl(a->assigned);
861                                 o_ia_p.addr.s6_addr32[2] = o_ia_p.addr.s6_addr32[3] = 0;
862
863                                 if ((a->assigned == 0 && a->managed_size == 0) ||
864                                                 !valid_prefix_length(a, addrs[i].prefix))
865                                         continue;
866
867                                 if (buflen < ia_len + sizeof(o_ia_p))
868                                         return 0;
869
870                                 memcpy(buf + ia_len, &o_ia_p, sizeof(o_ia_p));
871                                 ia_len += sizeof(o_ia_p);
872                         } else {
873                                 struct dhcpv6_ia_addr o_ia_a = {
874                                         .type = htons(DHCPV6_OPT_IA_ADDR),
875                                         .len = htons(sizeof(o_ia_a) - 4),
876                                         .addr = addrs[i].addr.in6,
877                                         .preferred = htonl(prefix_pref),
878                                         .valid = htonl(prefix_valid)
879                                 };
880
881                                 o_ia_a.addr.s6_addr32[3] = htonl(a->assigned);
882
883                                 if (!ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs) ||
884                                                 a->assigned == 0)
885                                         continue;
886
887                                 if (buflen < ia_len + sizeof(o_ia_a))
888                                         return 0;
889
890                                 memcpy(buf + ia_len, &o_ia_a, sizeof(o_ia_a));
891                                 ia_len += sizeof(o_ia_a);
892                         }
893
894                         /* Calculate T1 / T2 based on non-deprecated addresses */
895                         if (prefix_pref > 0) {
896                                 if (prefix_pref < pref)
897                                         pref = prefix_pref;
898
899                                 if (prefix_valid < valid)
900                                         valid = prefix_valid;
901                         }
902                 }
903
904                 if (!INFINITE_VALID(a->valid_until))
905                         /* UINT32_MAX is considered as infinite leasetime */
906                         a->valid_until = (valid == UINT32_MAX) ? 0 : valid + now;
907
908                 o_ia.t1 = htonl((pref == UINT32_MAX) ? pref : pref * 5 / 10);
909                 o_ia.t2 = htonl((pref == UINT32_MAX) ? pref : pref * 8 / 10);
910
911                 if (!o_ia.t1)
912                         o_ia.t1 = htonl(1);
913
914                 if (!o_ia.t2)
915                         o_ia.t2 = htonl(1);
916         }
917
918         if (!request) {
919                 uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + 4;
920                 uint16_t otype, olen;
921
922                 dhcpv6_for_each_option((uint8_t*)&ia[1], end, otype, olen, odata) {
923                         struct dhcpv6_ia_prefix *ia_p = (struct dhcpv6_ia_prefix *)&odata[-4];
924                         struct dhcpv6_ia_addr *ia_a = (struct dhcpv6_ia_addr *)&odata[-4];
925                         bool found = false;
926
927                         if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*ia_p) - 4) &&
928                                         (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*ia_a) - 4))
929                                 continue;
930
931                         if (a) {
932                                 struct odhcpd_ipaddr *addrs = (a->managed) ? a->managed : iface->addr6;
933                                 size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->addr6_len;
934
935                                 for (size_t i = 0; i < addrlen; ++i) {
936                                         if (!valid_addr(&addrs[i], now))
937                                                 continue;
938
939                                         struct in6_addr addr = addrs[i].addr.in6;
940                                         if (ia->type == htons(DHCPV6_OPT_IA_PD)) {
941                                                 addr.s6_addr32[1] |= htonl(a->assigned);
942                                                 addr.s6_addr32[2] = addr.s6_addr32[3] = 0;
943
944                                                 if (!memcmp(&ia_p->addr, &addr, sizeof(addr)) &&
945                                                                 ia_p->prefix == ((a->managed) ? addrs[i].prefix : a->length))
946                                                         found = true;
947                                         } else {
948                                                 addr.s6_addr32[3] = htonl(a->assigned);
949
950                                                 if (!memcmp(&ia_a->addr, &addr, sizeof(addr)))
951                                                         found = true;
952                                         }
953                                 }
954                         }
955
956                         if (!found) {
957                                 if (otype == DHCPV6_OPT_IA_PREFIX) {
958                                         struct dhcpv6_ia_prefix o_ia_p = {
959                                                 .type = htons(DHCPV6_OPT_IA_PREFIX),
960                                                 .len = htons(sizeof(o_ia_p) - 4),
961                                                 .preferred = 0,
962                                                 .valid = 0,
963                                                 .prefix = ia_p->prefix,
964                                                 .addr = ia_p->addr,
965                                         };
966
967                                         if (buflen < ia_len + sizeof(o_ia_p))
968                                                 return 0;
969
970                                         memcpy(buf + ia_len, &o_ia_p, sizeof(o_ia_p));
971                                         ia_len += sizeof(o_ia_p);
972                                 } else {
973                                         struct dhcpv6_ia_addr o_ia_a = {
974                                                 .type = htons(DHCPV6_OPT_IA_ADDR),
975                                                 .len = htons(sizeof(o_ia_a) - 4),
976                                                 .addr = ia_a->addr,
977                                                 .preferred = 0,
978                                                 .valid = 0,
979                                         };
980
981                                         if (buflen < ia_len + sizeof(o_ia_a))
982                                                 continue;
983
984                                         memcpy(buf + ia_len, &o_ia_a, sizeof(o_ia_a));
985                                         ia_len += sizeof(o_ia_a);
986                                 }
987                         }
988                 }
989         }
990
991         o_ia.len = htons(ia_len - 4);
992         memcpy(buf, &o_ia, sizeof(o_ia));
993         return ia_len;
994 }
995
996 struct log_ctxt {
997         char *buf;
998         int buf_len;
999         int buf_idx;
1000 };
1001
1002 static void dhcpv6_log_ia_addr(struct in6_addr *addr, int prefix, _unused uint32_t pref,
1003                                 _unused uint32_t valid, void *arg)
1004 {
1005         struct log_ctxt *ctxt = (struct log_ctxt *)arg;
1006         char addrbuf[INET6_ADDRSTRLEN];
1007
1008         inet_ntop(AF_INET6, addr, addrbuf, sizeof(addrbuf));
1009         ctxt->buf_idx += snprintf(ctxt->buf + ctxt->buf_idx, ctxt->buf_len - ctxt->buf_idx,
1010                                         "%s/%d ", addrbuf, prefix);
1011 }
1012
1013 static void dhcpv6_log(uint8_t msgtype, struct interface *iface, time_t now,
1014                 const char *duidbuf, bool is_pd, struct dhcp_assignment *a, int code)
1015 {
1016         const char *type = "UNKNOWN";
1017         const char *status = "UNKNOWN";
1018
1019         switch (msgtype) {
1020         case DHCPV6_MSG_SOLICIT:
1021                 type = "SOLICIT";
1022                 break;
1023         case DHCPV6_MSG_REQUEST:
1024                 type = "REQUEST";
1025                 break;
1026         case DHCPV6_MSG_CONFIRM:
1027                 type = "CONFIRM";
1028                 break;
1029         case DHCPV6_MSG_RENEW:
1030                 type = "RENEW";
1031                 break;
1032         case DHCPV6_MSG_REBIND:
1033                 type = "REBIND";
1034                 break;
1035         case DHCPV6_MSG_RELEASE:
1036                 type = "RELEASE";
1037                 break;
1038         case DHCPV6_MSG_DECLINE:
1039                 type = "DECLINE";
1040                 break;
1041         }
1042
1043         switch (code) {
1044         case DHCPV6_STATUS_OK:
1045                 status = "ok";
1046                 break;
1047         case DHCPV6_STATUS_NOADDRSAVAIL:
1048                 status = "no addresses available";
1049                 break;
1050         case DHCPV6_STATUS_NOBINDING:
1051                 status = "no binding";
1052                 break;
1053         case DHCPV6_STATUS_NOTONLINK:
1054                 status = "not on-link";
1055                 break;
1056         case DHCPV6_STATUS_NOPREFIXAVAIL:
1057                 status = "no prefix available";
1058                 break;
1059         }
1060
1061         char leasebuf[256] = "";
1062
1063         if (a) {
1064                 struct log_ctxt ctxt = {.buf = leasebuf,
1065                                         .buf_len = sizeof(leasebuf),
1066                                         .buf_idx = 0 };
1067
1068                 dhcpv6_ia_enum_addrs(iface, a, now, dhcpv6_log_ia_addr, &ctxt);
1069         }
1070
1071         syslog(LOG_NOTICE, "DHCPV6 %s %s from %s on %s: %s %s", type, (is_pd) ? "IA_PD" : "IA_NA",
1072                         duidbuf, iface->name, status, leasebuf);
1073 }
1074
1075 static bool dhcpv6_ia_on_link(const struct dhcpv6_ia_hdr *ia, struct dhcp_assignment *a,
1076                 struct interface *iface)
1077 {
1078         struct odhcpd_ipaddr *addrs = (a && a->managed) ? a->managed : iface->addr6;
1079         size_t addrlen = (a && a->managed) ? (size_t)a->managed_size : iface->addr6_len;
1080         time_t now = odhcpd_time();
1081         uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + 4;
1082         uint16_t otype, olen;
1083         bool onlink = true;
1084
1085         dhcpv6_for_each_option((uint8_t*)&ia[1], end, otype, olen, odata) {
1086                 struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix *)&odata[-4];
1087                 struct dhcpv6_ia_addr *n = (struct dhcpv6_ia_addr *)&odata[-4];
1088
1089                 if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*p) - 4) &&
1090                                 (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*n) - 4))
1091                         continue;
1092
1093                 onlink = false;
1094                 for (size_t i = 0; i < addrlen; ++i) {
1095                         if (!valid_addr(&addrs[i], now))
1096                                 continue;
1097
1098                         if (ia->type == htons(DHCPV6_OPT_IA_PD)) {
1099                                 if (p->prefix < addrs[i].prefix ||
1100                                     odhcpd_bmemcmp(&p->addr, &addrs[i].addr.in6, addrs[i].prefix))
1101                                         continue;
1102
1103                         } else if (odhcpd_bmemcmp(&n->addr, &addrs[i].addr.in6, addrs[i].prefix))
1104                                 continue;
1105
1106                         onlink = true;
1107                 }
1108
1109                 if (!onlink)
1110                         break;
1111         }
1112
1113         return onlink;
1114 }
1115
1116 ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *iface,
1117                 const struct sockaddr_in6 *addr, const void *data, const uint8_t *end)
1118 {
1119         struct lease *l;
1120         struct dhcp_assignment *first = NULL;
1121         const struct dhcpv6_client_header *hdr = data;
1122         time_t now = odhcpd_time();
1123         uint16_t otype, olen, clid_len = 0;
1124         uint8_t *start = (uint8_t *)&hdr[1], *odata;
1125         uint8_t *clid_data = NULL, mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1126         size_t hostname_len = 0, response_len = 0;
1127         bool notonlink = false, rapid_commit = false, accept_reconf = false;
1128         char duidbuf[261], hostname[256];
1129
1130         dhcpv6_for_each_option(start, end, otype, olen, odata) {
1131                 if (otype == DHCPV6_OPT_CLIENTID) {
1132                         clid_data = odata;
1133                         clid_len = olen;
1134
1135                         if (olen == 14 && odata[0] == 0 && odata[1] == 1)
1136                                 memcpy(mac, &odata[8], sizeof(mac));
1137                         else if (olen == 10 && odata[0] == 0 && odata[1] == 3)
1138                                 memcpy(mac, &odata[4], sizeof(mac));
1139
1140                         if (olen <= 130)
1141                                 odhcpd_hexlify(duidbuf, odata, olen);
1142                 } else if (otype == DHCPV6_OPT_FQDN && olen >= 2 && olen <= 255) {
1143                         uint8_t fqdn_buf[256];
1144                         memcpy(fqdn_buf, odata, olen);
1145                         fqdn_buf[olen++] = 0;
1146
1147                         if (dn_expand(&fqdn_buf[1], &fqdn_buf[olen], &fqdn_buf[1], hostname, sizeof(hostname)) > 0)
1148                                 hostname_len = strcspn(hostname, ".");
1149                 } else if (otype == DHCPV6_OPT_RECONF_ACCEPT)
1150                         accept_reconf = true;
1151                 else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT)
1152                         rapid_commit = true;
1153         }
1154
1155         if (!clid_data || !clid_len || clid_len > 130)
1156                 goto out;
1157
1158         l = config_find_lease_by_duid(clid_data, clid_len);
1159         if (!l)
1160                 l = config_find_lease_by_mac(mac);
1161
1162         dhcpv6_for_each_option(start, end, otype, olen, odata) {
1163                 bool is_pd = (otype == DHCPV6_OPT_IA_PD);
1164                 bool is_na = (otype == DHCPV6_OPT_IA_NA);
1165                 bool ia_addr_present = false;
1166                 if (!is_pd && !is_na)
1167                         continue;
1168
1169                 struct dhcpv6_ia_hdr *ia = (struct dhcpv6_ia_hdr*)&odata[-4];
1170                 size_t ia_response_len = 0;
1171                 uint8_t reqlen = (is_pd) ? 62 : 128;
1172                 uint32_t reqhint = 0;
1173
1174                 /* Parse request hint for IA-PD */
1175                 if (is_pd) {
1176                         uint8_t *sdata;
1177                         uint16_t stype, slen;
1178                         dhcpv6_for_each_option(&ia[1], odata + olen, stype, slen, sdata) {
1179                                 if (stype != DHCPV6_OPT_IA_PREFIX || slen < sizeof(struct dhcpv6_ia_prefix) - 4)
1180                                         continue;
1181
1182                                 struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix*)&sdata[-4];
1183                                 if (p->prefix) {
1184                                         reqlen = p->prefix;
1185                                         reqhint = ntohl(p->addr.s6_addr32[1]);
1186                                         if (reqlen > 32 && reqlen <= 64)
1187                                                 reqhint &= (1U << (64 - reqlen)) - 1;
1188                                 }
1189                         }
1190
1191                         if (reqlen > 64)
1192                                 reqlen = 64;
1193                 } else if (is_na) {
1194                         uint8_t *sdata;
1195                         uint16_t stype, slen;
1196                         dhcpv6_for_each_option(&ia[1], odata + olen, stype, slen, sdata) {
1197                                 if (stype != DHCPV6_OPT_IA_ADDR || slen < sizeof(struct dhcpv6_ia_addr) - 4)
1198                                         continue;
1199
1200                                 ia_addr_present = true;
1201                         }
1202                 }
1203
1204                 /* Find assignment */
1205                 struct dhcp_assignment *c, *a = NULL;
1206                 list_for_each_entry(c, &iface->ia_assignments, head) {
1207                         if ((c->clid_len == clid_len && !memcmp(c->clid_data, clid_data, clid_len)) &&
1208                             c->iaid == ia->iaid && (INFINITE_VALID(c->valid_until) || now < c->valid_until) &&
1209                             ((is_pd && c->length <= 64) || (is_na && c->length == 128))) {
1210                                 a = c;
1211
1212                                 /* Reset state */
1213                                 if (a->flags & OAF_BOUND)
1214                                         apply_lease(iface, a, false);
1215
1216                                 stop_reconf(a);
1217                                 break;
1218                         }
1219                 }
1220
1221                 if (l && a && a->lease != l) {
1222                         free_assignment(a);
1223                         a = NULL;
1224                 }
1225
1226                 /* Generic message handling */
1227                 uint16_t status = DHCPV6_STATUS_OK;
1228                 if (a && a->managed_size < 0)
1229                         return -1;
1230
1231                 if (hdr->msg_type == DHCPV6_MSG_SOLICIT ||
1232                                 hdr->msg_type == DHCPV6_MSG_REQUEST ||
1233                                 (hdr->msg_type == DHCPV6_MSG_REBIND && !a)) {
1234                         bool assigned = !!a;
1235
1236                         if (!a) {
1237                                 if ((!iface->no_dynamic_dhcp || (l && is_na)) &&
1238                                     (iface->dhcpv6_pd || iface->dhcpv6_na)) {
1239                                         /* Create new binding */
1240                                         a = alloc_assignment(clid_len);
1241
1242                                         if (a) {
1243                                                 a->clid_len = clid_len;
1244                                                 memcpy(a->clid_data, clid_data, clid_len);
1245                                                 a->iaid = ia->iaid;
1246                                                 a->length = reqlen;
1247                                                 a->peer = *addr;
1248                                                 a->assigned = is_na && l ? l->hostid : reqhint;
1249                                                 /* Set valid time to 0 for static lease indicating */
1250                                                 /* infinite lifetime otherwise current time        */
1251                                                 a->valid_until = l ? 0 : now;
1252                                                 a->dhcp_free_cb = dhcpv6_ia_free_assignment;
1253                                                 a->iface = iface;
1254                                                 a->flags = OAF_DHCPV6;
1255
1256                                                 if (first)
1257                                                         memcpy(a->key, first->key, sizeof(a->key));
1258                                                 else
1259                                                         odhcpd_urandom(a->key, sizeof(a->key));
1260
1261                                                 if (is_pd && iface->dhcpv6_pd)
1262                                                         while (!(assigned = assign_pd(iface, a)) &&
1263                                                                !a->managed_size && ++a->length <= 64);
1264                                                 else if (is_na && iface->dhcpv6_na)
1265                                                         assigned = assign_na(iface, a);
1266
1267                                                 if (l && assigned) {
1268                                                         a->flags |= OAF_STATIC;
1269
1270                                                         if (l->hostname)
1271                                                                 a->hostname = strdup(l->hostname);
1272
1273                                                         if (l->leasetime)
1274                                                                 a->leasetime = l->leasetime;
1275
1276                                                         list_add(&a->lease_list, &l->assignments);
1277                                                         a->lease = l;
1278                                                 }
1279
1280                                                 if (a->managed_size && !assigned)
1281                                                         return -1;
1282                                         }
1283                                 }
1284                         }
1285
1286                         if (!assigned || iface->addr6_len == 0)
1287                                 /* Set error status */
1288                                 status = (is_pd) ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL;
1289                         else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) {
1290                                 /* Send NOTONLINK staus for the IA */
1291                                 status = DHCPV6_STATUS_NOTONLINK;
1292                                 assigned = false;
1293                         } else if (accept_reconf && assigned && !first &&
1294                                         hdr->msg_type != DHCPV6_MSG_REBIND) {
1295                                 size_t handshake_len = 4;
1296                                 buf[0] = 0;
1297                                 buf[1] = DHCPV6_OPT_RECONF_ACCEPT;
1298                                 buf[2] = 0;
1299                                 buf[3] = 0;
1300
1301                                 if (hdr->msg_type == DHCPV6_MSG_REQUEST) {
1302                                         struct dhcpv6_auth_reconfigure auth = {
1303                                                 htons(DHCPV6_OPT_AUTH),
1304                                                 htons(sizeof(auth) - 4),
1305                                                 3, 1, 0,
1306                                                 {htonl(time(NULL)), htonl(++serial)},
1307                                                 1,
1308                                                 {0}
1309                                         };
1310                                         memcpy(auth.key, a->key, sizeof(a->key));
1311                                         memcpy(buf + handshake_len, &auth, sizeof(auth));
1312                                         handshake_len += sizeof(auth);
1313                                 }
1314
1315
1316                                 buf += handshake_len;
1317                                 buflen -= handshake_len;
1318                                 response_len += handshake_len;
1319
1320                                 first = a;
1321                         }
1322
1323                         ia_response_len = build_ia(buf, buflen, status, ia, a, iface,
1324                                                         hdr->msg_type == DHCPV6_MSG_REBIND ? false : true);
1325
1326                         /* Was only a solicitation: mark binding for removal */
1327                         if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit) {
1328                                 a->flags &= ~OAF_BOUND;
1329                                 a->flags |= OAF_TENTATIVE;
1330
1331                                 if (!(a->flags & OAF_STATIC))
1332                                         /* Keep tentative assignment around for 60 seconds */
1333                                         a->valid_until = now + 60;
1334
1335                         } else if (assigned &&
1336                                    ((hdr->msg_type == DHCPV6_MSG_SOLICIT && rapid_commit) ||
1337                                     hdr->msg_type == DHCPV6_MSG_REQUEST ||
1338                                     hdr->msg_type == DHCPV6_MSG_REBIND)) {
1339                                 if ((!(a->flags & OAF_STATIC) || !a->hostname) && hostname_len > 0) {
1340                                         a->hostname = realloc(a->hostname, hostname_len + 1);
1341                                         if (a->hostname) {
1342                                                 memcpy(a->hostname, hostname, hostname_len);
1343                                                 a->hostname[hostname_len] = 0;
1344
1345                                                 if (odhcpd_valid_hostname(a->hostname))
1346                                                         a->flags &= ~OAF_BROKEN_HOSTNAME;
1347                                                 else
1348                                                         a->flags |= OAF_BROKEN_HOSTNAME;
1349                                         }
1350                                 }
1351                                 a->accept_reconf = accept_reconf;
1352                                 a->flags &= ~OAF_TENTATIVE;
1353                                 a->flags |= OAF_BOUND;
1354                                 apply_lease(iface, a, true);
1355                         } else if (!assigned && a && a->managed_size == 0) {
1356                                 /* Cleanup failed assignment */
1357                                 free_assignment(a);
1358                                 a = NULL;
1359                         }
1360                 } else if (hdr->msg_type == DHCPV6_MSG_RENEW ||
1361                                 hdr->msg_type == DHCPV6_MSG_RELEASE ||
1362                                 hdr->msg_type == DHCPV6_MSG_REBIND ||
1363                                 hdr->msg_type == DHCPV6_MSG_DECLINE) {
1364                         if (!a && hdr->msg_type != DHCPV6_MSG_REBIND) {
1365                                 status = DHCPV6_STATUS_NOBINDING;
1366                                 ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1367                         } else if (hdr->msg_type == DHCPV6_MSG_RENEW ||
1368                                         hdr->msg_type == DHCPV6_MSG_REBIND) {
1369                                 ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1370                                 if (a) {
1371                                         a->flags |= OAF_BOUND;
1372                                         apply_lease(iface, a, true);
1373                                 }
1374                         } else if (hdr->msg_type == DHCPV6_MSG_RELEASE) {
1375                                 if (!(a->flags & OAF_STATIC))
1376                                         a->valid_until = now - 1;
1377
1378                                 if (a->flags & OAF_BOUND) {
1379                                         apply_lease(iface, a, false);
1380                                         a->flags &= ~OAF_BOUND;
1381                                 }
1382                         } else if (hdr->msg_type == DHCPV6_MSG_DECLINE && a->length == 128) {
1383                                 a->flags &= ~OAF_BOUND;
1384
1385                                 if (!(a->flags & OAF_STATIC)) {
1386                                         a->clid_len = 0;
1387                                         a->valid_until = now + 3600; /* Block address for 1h */
1388                                 }
1389                         }
1390                 } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) {
1391                         if (ia_addr_present && !dhcpv6_ia_on_link(ia, a, iface)) {
1392                                 notonlink = true;
1393                                 break;
1394                         }
1395
1396                         if (!ia_addr_present || !a || !(a->flags & OAF_BOUND)) {
1397                                 response_len = 0;
1398                                 goto out;
1399                         }
1400                 }
1401
1402                 buf += ia_response_len;
1403                 buflen -= ia_response_len;
1404                 response_len += ia_response_len;
1405                 dhcpv6_log(hdr->msg_type, iface, now, duidbuf, is_pd, a, status);
1406         }
1407
1408         switch (hdr->msg_type) {
1409         case DHCPV6_MSG_RELEASE:
1410         case DHCPV6_MSG_DECLINE:
1411         case DHCPV6_MSG_CONFIRM:
1412                 if (response_len + 6 < buflen) {
1413                         buf[0] = 0;
1414                         buf[1] = DHCPV6_OPT_STATUS;
1415                         buf[2] = 0;
1416                         buf[3] = 2;
1417                         buf[4] = 0;
1418                         buf[5] = (notonlink) ? DHCPV6_STATUS_NOTONLINK : DHCPV6_STATUS_OK;
1419                         response_len += 6;
1420                 }
1421                 break;
1422
1423         default:
1424                 break;
1425         }
1426
1427         dhcpv6_ia_write_statefile();
1428
1429 out:
1430         return response_len;
1431 }