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 #include "dhcpv6-ia.h" 20 #include "statefiles.h" 21 22 #include <time.h> 23 #include <fcntl.h> 24 #include <limits.h> 25 #include <stdio.h> 26 #include <resolv.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 #include <stdbool.h> 31 #include <arpa/inet.h> 32 33 #include <libubox/md5.h> 34 35 static void dhcpv6_netevent_cb(unsigned long event, struct netevent_handler_info *info); 36 static void apply_lease(struct dhcpv6_lease *a, bool add); 37 static void set_border_assignment_size(struct interface *iface, struct dhcpv6_lease *b); 38 static void handle_addrlist_change(struct netevent_handler_info *info); 39 static void start_reconf(struct dhcpv6_lease *a); 40 static void stop_reconf(struct dhcpv6_lease *a); 41 static void valid_until_cb(struct uloop_timeout *event); 42 43 static struct netevent_handler dhcpv6_netevent_handler = { .cb = dhcpv6_netevent_cb, }; 44 static struct uloop_timeout valid_until_timeout = {.cb = valid_until_cb}; 45 static uint32_t serial = 0; 46 47 static struct dhcpv6_lease * 48 dhcpv6_alloc_lease(size_t extra_len) 49 { 50 struct dhcpv6_lease *a = calloc(1, sizeof(*a) + extra_len); 51 52 if (!a) 53 return NULL; 54 55 INIT_LIST_HEAD(&a->head); 56 INIT_LIST_HEAD(&a->lease_cfg_list); 57 58 return a; 59 } 60 61 void dhcpv6_free_lease(struct dhcpv6_lease *a) 62 { 63 if (!a) 64 return; 65 66 list_del(&a->head); 67 list_del(&a->lease_cfg_list); 68 69 if (a->bound && (a->flags & OAF_DHCPV6_PD)) 70 apply_lease(a, false); 71 72 if (a->fr_cnt) 73 stop_reconf(a); 74 75 free(a->hostname); 76 free(a); 77 } 78 79 int dhcpv6_ia_init(void) 80 { 81 uloop_timeout_set(&valid_until_timeout, 1000); 82 83 netlink_add_netevent_handler(&dhcpv6_netevent_handler); 84 85 return 0; 86 } 87 88 int dhcpv6_ia_setup_interface(struct interface *iface, bool enable) 89 { 90 enable = enable && (iface->dhcpv6 == MODE_SERVER); 91 92 if (enable) { 93 struct dhcpv6_lease *border; 94 95 if (list_empty(&iface->ia_assignments)) { 96 border = dhcpv6_alloc_lease(0); 97 98 if (!border) { 99 warn("Failed to alloc border on %s", iface->name); 100 return -1; 101 } 102 103 border->length = 64; 104 list_add(&border->head, &iface->ia_assignments); 105 } else 106 border = list_last_entry(&iface->ia_assignments, struct dhcpv6_lease, head); 107 108 set_border_assignment_size(iface, border); 109 } else { 110 struct dhcpv6_lease *c; 111 112 while (!list_empty(&iface->ia_assignments)) { 113 c = list_first_entry(&iface->ia_assignments, struct dhcpv6_lease, head); 114 dhcpv6_free_lease(c); 115 } 116 } 117 118 return 0; 119 } 120 121 122 static void dhcpv6_netevent_cb(unsigned long event, struct netevent_handler_info *info) 123 { 124 struct interface *iface = info->iface; 125 126 if (!iface || iface->dhcpv6 != MODE_SERVER) 127 return; 128 129 switch (event) { 130 case NETEV_ADDR6LIST_CHANGE: 131 handle_addrlist_change(info); 132 break; 133 default: 134 break; 135 } 136 } 137 138 size_t get_preferred_addr(const struct odhcpd_ipaddr *addrs, const size_t addrlen) 139 { 140 size_t i, m; 141 142 for (i = 0, m = 0; i < addrlen; ++i) { 143 if (addrs[i].preferred_lt > addrs[m].preferred_lt || 144 (addrs[i].preferred_lt == addrs[m].preferred_lt && 145 memcmp(&addrs[i].addr, &addrs[m].addr, 16) > 0)) 146 m = i; 147 } 148 149 return m; 150 } 151 152 enum { 153 IOV_HDR = 0, 154 IOV_SERVERID, 155 IOV_CLIENTID, 156 IOV_MESSAGE, 157 IOV_AUTH, 158 IOV_TOTAL 159 }; 160 161 static int send_reconf(struct dhcpv6_lease *assign) 162 { 163 struct interface *iface = assign->iface; 164 struct dhcpv6_client_header hdr = { 165 .msg_type = DHCPV6_MSG_RECONFIGURE, 166 .transaction_id = { 0, 0, 0 }, 167 }; 168 struct { 169 uint16_t code; 170 uint16_t len; 171 uint8_t data[DUID_MAX_LEN]; 172 } _o_packed serverid = { 173 .code = htons(DHCPV6_OPT_SERVERID), 174 .len = 0, 175 .data = { 0 }, 176 }; 177 struct { 178 uint16_t code; 179 uint16_t len; 180 uint8_t data[DUID_MAX_LEN]; 181 } _o_packed clientid = { 182 .code = htons(DHCPV6_OPT_CLIENTID), 183 .len = htons(assign->duid_len), 184 .data = { 0 }, 185 }; 186 struct { 187 uint16_t code; 188 uint16_t len; 189 uint8_t id; 190 } _o_packed message = { 191 .code = htons(DHCPV6_OPT_RECONF_MSG), 192 .len = htons(1), 193 .id = DHCPV6_MSG_RENEW, 194 }; 195 struct dhcpv6_auth_reconfigure auth = { 196 .type = htons(DHCPV6_OPT_AUTH), 197 .len = htons(sizeof(struct dhcpv6_auth_reconfigure)), 198 .protocol = 3, 199 .algorithm = 1, 200 .rdm = 0, 201 .replay = { htonl(time(NULL)), htonl(++serial) }, 202 .reconf_type = 2, 203 .key = { 0 }, 204 }; 205 206 if (config.default_duid_len > 0) { 207 memcpy(serverid.data, config.default_duid, config.default_duid_len); 208 serverid.len = htons(config.default_duid_len); 209 } else { 210 uint16_t duid_ll_hdr[] = { htons(DUID_TYPE_LL), htons(ARPHRD_ETHER) }; 211 memcpy(serverid.data, duid_ll_hdr, sizeof(duid_ll_hdr)); 212 odhcpd_get_mac(iface, &serverid.data[sizeof(duid_ll_hdr)]); 213 serverid.len = htons(sizeof(duid_ll_hdr) + ETH_ALEN); 214 } 215 216 memcpy(clientid.data, assign->duid, assign->duid_len); 217 218 struct iovec iov[IOV_TOTAL] = { 219 [IOV_HDR] = { &hdr, sizeof(hdr) }, 220 [IOV_SERVERID] = { &serverid, sizeof(serverid) }, 221 [IOV_CLIENTID] = { &clientid, sizeof(clientid) }, 222 [IOV_MESSAGE] = { &message, sizeof(message) }, 223 [IOV_AUTH] = { &auth, sizeof(auth) }, 224 }; 225 226 md5_ctx_t md5; 227 uint8_t secretbytes[64]; 228 memset(secretbytes, 0, sizeof(secretbytes)); 229 memcpy(secretbytes, assign->key, sizeof(assign->key)); 230 231 for (size_t i = 0; i < sizeof(secretbytes); ++i) 232 secretbytes[i] ^= 0x36; 233 234 md5_begin(&md5); 235 md5_hash(secretbytes, sizeof(secretbytes), &md5); 236 for (size_t i = 0; i < ARRAY_SIZE(iov); i++) 237 md5_hash(iov[i].iov_base, iov[i].iov_len, &md5); 238 md5_end(auth.key, &md5); 239 240 for (size_t i = 0; i < sizeof(secretbytes); ++i) { 241 secretbytes[i] ^= 0x36; 242 secretbytes[i] ^= 0x5c; 243 } 244 245 md5_begin(&md5); 246 md5_hash(secretbytes, sizeof(secretbytes), &md5); 247 md5_hash(auth.key, 16, &md5); 248 md5_end(auth.key, &md5); 249 250 return odhcpd_send(iface->dhcpv6_event.uloop.fd, &assign->peer, iov, ARRAY_SIZE(iov), iface); 251 } 252 253 static void in6_copy_iid(struct in6_addr *dest, uint64_t iid, unsigned n) 254 { 255 uint64_t iid_be = htobe64(iid); 256 uint8_t *iid_bytes = (uint8_t *)&iid_be; 257 unsigned bytes = n / 8; 258 unsigned bits = n % 8; 259 260 if (n == 0 || n > 64) 261 return; 262 263 memcpy(&dest->s6_addr[16 - bytes], &iid_bytes[8 - bytes], bytes); 264 265 if (bits > 0) { 266 unsigned dest_idx = 16 - bytes - 1; 267 unsigned src_idx = 8 - bytes - 1; 268 uint8_t mask = (1 << bits) - 1; 269 dest->s6_addr[dest_idx] = (dest->s6_addr[dest_idx] & ~mask) | 270 (iid_bytes[src_idx] & mask); 271 } 272 } 273 274 struct in6_addr in6_from_prefix_and_iid(const struct odhcpd_ipaddr *prefix, uint64_t iid) 275 { 276 struct in6_addr addr; 277 uint8_t iid_len = min(128 - prefix->prefix_len, 64); 278 279 addr = prefix->addr.in6; 280 in6_copy_iid(&addr, iid, iid_len); 281 282 return addr; 283 } 284 285 static void __apply_lease(struct dhcpv6_lease *a, 286 struct odhcpd_ipaddr *addrs, ssize_t addr_len, bool add) 287 { 288 if (a->flags & OAF_DHCPV6_NA) 289 return; 290 291 for (ssize_t i = 0; i < addr_len; ++i) { 292 struct in6_addr prefix; 293 294 if (ADDR_MATCH_PIO_FILTER(&addrs[i], a->iface)) 295 continue; 296 297 prefix = addrs[i].addr.in6; 298 prefix.s6_addr32[1] |= htonl(a->assigned_subnet_id); 299 prefix.s6_addr32[2] = prefix.s6_addr32[3] = 0; 300 netlink_setup_route(&prefix, a->length, a->iface->ifindex, 301 &a->peer.sin6_addr, 1024, add); 302 } 303 } 304 305 static void apply_lease(struct dhcpv6_lease *a, bool add) 306 { 307 struct interface *iface = a->iface; 308 struct odhcpd_ipaddr *addrs = iface->addr6; 309 ssize_t addrlen = (ssize_t)iface->addr6_len; 310 311 __apply_lease(a, addrs, addrlen, add); 312 } 313 314 /* Set border assignment size based on the IPv6 address prefixes */ 315 static void set_border_assignment_size(struct interface *iface, struct dhcpv6_lease *b) 316 { 317 time_t now = odhcpd_time(); 318 int minprefix = -1; 319 320 for (size_t i = 0; i < iface->addr6_len; ++i) { 321 struct odhcpd_ipaddr *addr = &iface->addr6[i]; 322 323 if (ADDR_MATCH_PIO_FILTER(addr, iface)) 324 continue; 325 326 if (addr->preferred_lt > (uint32_t)now && 327 addr->prefix_len < 64 && 328 addr->prefix_len > minprefix) 329 minprefix = addr->prefix_len; 330 } 331 332 if (minprefix > 32 && minprefix <= 64) 333 b->assigned_subnet_id = 1U << (64 - minprefix); 334 else 335 b->assigned_subnet_id = 0; 336 } 337 338 static bool assign_pd(struct interface *iface, struct dhcpv6_lease *assign) 339 { 340 struct dhcpv6_lease *c; 341 342 if (iface->addr6_len < 1) 343 return false; 344 345 /* Try honoring the hint first */ 346 uint32_t current = 1, asize = (1 << (64 - assign->length)) - 1; 347 if (assign->assigned_subnet_id) { 348 list_for_each_entry(c, &iface->ia_assignments, head) { 349 if (c->flags & OAF_DHCPV6_NA) 350 continue; 351 352 if (assign->assigned_subnet_id >= current && assign->assigned_subnet_id + asize < c->assigned_subnet_id) { 353 list_add_tail(&assign->head, &c->head); 354 355 if (assign->bound) 356 apply_lease(assign, true); 357 358 return true; 359 } 360 361 current = (c->assigned_subnet_id + (1 << (64 - c->length))); 362 } 363 } 364 365 /* Fallback to a variable assignment */ 366 current = 1; 367 list_for_each_entry(c, &iface->ia_assignments, head) { 368 if (c->flags & OAF_DHCPV6_NA) 369 continue; 370 371 current = (current + asize) & (~asize); 372 373 if (current + asize < c->assigned_subnet_id) { 374 assign->assigned_subnet_id = current; 375 list_add_tail(&assign->head, &c->head); 376 377 if (assign->bound) 378 apply_lease(assign, true); 379 380 return true; 381 } 382 383 current = (c->assigned_subnet_id + (1 << (64 - c->length))); 384 } 385 386 return false; 387 } 388 389 /* Check iid against reserved IPv6 interface identifiers. 390 * Refer to: http://www.iana.org/assignments/ipv6-interface-ids 391 */ 392 static bool is_reserved_ipv6_iid(uint64_t iid) 393 { 394 if (iid == 0x0000000000000000) 395 /* Subnet-Router Anycast [RFC4291] */ 396 return true; 397 398 if ((iid & 0xFFFFFFFFFF000000) == 0x02005EFFFE000000) 399 /* Reserved IPv6 Interface Identifiers corresponding 400 * to the IANA Ethernet Block [RFC4291] 401 */ 402 return true; 403 404 if ((iid & 0xFFFFFFFFFFFFFF80) == 0xFDFFFFFFFFFFFF80) 405 /* Reserved Subnet Anycast Addresses [RFC2526] */ 406 return true; 407 408 return false; 409 } 410 411 static bool assign_na(struct interface *iface, struct dhcpv6_lease *a) 412 { 413 struct dhcpv6_lease *c; 414 uint64_t pool_start = 0x100; 415 uint64_t pool_end = (iface->dhcpv6_hostid_len >= 64) ? UINT64_MAX : ((1ULL << iface->dhcpv6_hostid_len) - 1); 416 uint64_t pool_size = pool_end - pool_start + 1; 417 uint64_t try; 418 unsigned short xsubi[3] = { 0 }; 419 420 /* Preconfigured assignment by static lease */ 421 if (a->assigned_host_id) { 422 list_for_each_entry(c, &iface->ia_assignments, head) { 423 if (!(c->flags & OAF_DHCPV6_NA) || c->assigned_host_id > a->assigned_host_id ) { 424 list_add_tail(&a->head, &c->head); 425 return true; 426 } else if (c->assigned_host_id == a->assigned_host_id) 427 return false; 428 } 429 } 430 431 /* Pick a starting point, using the last bytes of the DUID as seed... */ 432 memcpy(xsubi, 433 a->duid + (a->duid_len > sizeof(xsubi) ? a->duid_len - sizeof(xsubi) : 0), 434 min(a->duid_len, sizeof(xsubi))); 435 try = ((uint64_t)jrand48(xsubi) << 32) | (jrand48(xsubi) & UINT32_MAX); 436 try = pool_start + try % pool_size; 437 438 /* ...then try to assign sequentially from that starting point... */ 439 for (size_t i = 0; i < 100; i++, try++) { 440 if (try > pool_end) 441 try = pool_start; 442 443 if (is_reserved_ipv6_iid(try)) 444 continue; 445 446 if (config_find_lease_cfg_by_hostid(try)) 447 continue; 448 449 list_for_each_entry(c, &iface->ia_assignments, head) { 450 if (!(c->flags & OAF_DHCPV6_NA) || c->assigned_host_id > try) { 451 a->assigned_host_id = try; 452 list_add_tail(&a->head, &c->head); 453 return true; 454 } else if (c->assigned_host_id == try) 455 break; 456 } 457 } 458 459 return false; 460 } 461 462 static void handle_addrlist_change(struct netevent_handler_info *info) 463 { 464 struct interface *iface = info->iface; 465 struct dhcpv6_lease *c, *d, *border = list_last_entry( 466 &iface->ia_assignments, struct dhcpv6_lease, head); 467 struct list_head reassign = LIST_HEAD_INIT(reassign); 468 time_t now = odhcpd_time(); 469 470 list_for_each_entry(c, &iface->ia_assignments, head) { 471 if ((c->flags & OAF_DHCPV6_PD) && !(iface->ra_flags & ND_RA_FLAG_MANAGED) 472 && (c->bound)) 473 __apply_lease(c, info->addrs_old.addrs, 474 info->addrs_old.len, false); 475 } 476 477 set_border_assignment_size(iface, border); 478 479 list_for_each_entry_safe(c, d, &iface->ia_assignments, head) { 480 if (c->duid_len == 0 || 481 !(c->flags & OAF_DHCPV6_PD) || 482 (!INFINITE_VALID(c->valid_until) && c->valid_until < now)) 483 continue; 484 485 if (c->assigned_subnet_id >= border->assigned_subnet_id) 486 list_move(&c->head, &reassign); 487 else if (c->bound) 488 apply_lease(c, true); 489 490 if (c->accept_fr_nonce && c->fr_cnt == 0) { 491 struct dhcpv6_lease *a; 492 493 start_reconf(c); 494 495 /* Leave all other assignments of that client alone */ 496 list_for_each_entry(a, &iface->ia_assignments, head) 497 if (a != c && a->duid_len == c->duid_len && 498 !memcmp(a->duid, c->duid, a->duid_len)) 499 a->fr_cnt = INT_MAX; 500 } 501 } 502 503 while (!list_empty(&reassign)) { 504 c = list_first_entry(&reassign, struct dhcpv6_lease, head); 505 list_del_init(&c->head); 506 if (!assign_pd(iface, c)) 507 dhcpv6_free_lease(c); 508 } 509 510 statefiles_write(); 511 } 512 513 static void reconf_timeout_cb(struct uloop_timeout *event) 514 { 515 struct dhcpv6_lease *a = container_of(event, struct dhcpv6_lease, fr_timer); 516 517 if (a->fr_cnt > 0 && a->fr_cnt < DHCPV6_REC_MAX_RC) { 518 send_reconf(a); 519 uloop_timeout_set(&a->fr_timer, 520 DHCPV6_REC_TIMEOUT << a->fr_cnt); 521 a->fr_cnt++; 522 } else 523 stop_reconf(a); 524 } 525 526 static void start_reconf(struct dhcpv6_lease *a) 527 { 528 uloop_timeout_set(&a->fr_timer, 529 DHCPV6_REC_TIMEOUT << a->fr_cnt); 530 a->fr_timer.cb = reconf_timeout_cb; 531 a->fr_cnt++; 532 533 send_reconf(a); 534 } 535 536 static void stop_reconf(struct dhcpv6_lease *a) 537 { 538 uloop_timeout_cancel(&a->fr_timer); 539 a->fr_cnt = 0; 540 a->fr_timer.cb = NULL; 541 } 542 543 static void valid_until_cb(struct uloop_timeout *event) 544 { 545 struct interface *iface; 546 time_t now = odhcpd_time(); 547 548 avl_for_each_element(&interfaces, iface, avl) { 549 struct dhcpv6_lease *a, *n; 550 551 if (iface->dhcpv6 != MODE_SERVER) 552 continue; 553 554 list_for_each_entry_safe(a, n, &iface->ia_assignments, head) { 555 if (a->duid_len > 0 && !INFINITE_VALID(a->valid_until) && a->valid_until < now) 556 dhcpv6_free_lease(a); 557 } 558 } 559 uloop_timeout_set(event, 1000); 560 } 561 562 static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, 563 const struct dhcpv6_ia_hdr *ia, struct dhcpv6_lease *a, 564 struct interface *iface, bool request) 565 { 566 struct dhcpv6_ia_hdr o_ia = { 567 .type = ia->type, 568 .len = 0, 569 .iaid = ia->iaid, 570 .t1 = 0, 571 .t2 = 0, 572 }; 573 size_t ia_len = sizeof(o_ia); 574 time_t now = odhcpd_time(); 575 576 if (buflen < ia_len) 577 return 0; 578 579 if (status) { 580 struct _o_packed { 581 uint16_t type; 582 uint16_t len; 583 uint16_t val; 584 } o_status = { 585 .type = htons(DHCPV6_OPT_STATUS), 586 .len = htons(sizeof(o_status) - 4), 587 .val = htons(status), 588 }; 589 590 memcpy(buf + ia_len, &o_status, sizeof(o_status)); 591 ia_len += sizeof(o_status); 592 593 o_ia.len = htons(ia_len - 4); 594 memcpy(buf, &o_ia, sizeof(o_ia)); 595 596 return ia_len; 597 } 598 599 if (a) { 600 uint32_t leasetime; 601 602 if (a->leasetime) { 603 leasetime = a->leasetime; 604 } else { 605 leasetime = iface->dhcp_leasetime; 606 } 607 608 uint32_t floor_preferred_lifetime, floor_valid_lifetime; /* For calculating T1 / T2 */ 609 610 if (iface->max_preferred_lifetime && iface->max_preferred_lifetime < leasetime) { 611 floor_preferred_lifetime = iface->max_preferred_lifetime; 612 } else { 613 floor_preferred_lifetime = leasetime; 614 } 615 616 if (iface->max_valid_lifetime && iface->max_valid_lifetime < leasetime) { 617 floor_valid_lifetime = iface->max_valid_lifetime; 618 } else { 619 floor_valid_lifetime = leasetime; 620 } 621 622 struct odhcpd_ipaddr *addrs = iface->addr6; 623 size_t addrlen = iface->addr6_len; 624 size_t m = get_preferred_addr(addrs, addrlen); 625 626 for (size_t i = 0; i < addrlen; ++i) { 627 uint32_t prefix_preferred_lt, prefix_valid_lt; 628 629 if (!valid_addr(&addrs[i], now)) 630 continue; 631 632 /* Filter Out Prefixes */ 633 if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) { 634 char addrbuf[INET6_ADDRSTRLEN]; 635 info("Address %s filtered out on %s", 636 inet_ntop(AF_INET6, &addrs[i].addr.in6, addrbuf, sizeof(addrbuf)), 637 iface->name); 638 continue; 639 } 640 641 prefix_preferred_lt = addrs[i].preferred_lt; 642 prefix_valid_lt = addrs[i].valid_lt; 643 644 if (prefix_preferred_lt != UINT32_MAX) { 645 prefix_preferred_lt -= now; 646 647 if (iface->max_preferred_lifetime && prefix_preferred_lt > iface->max_preferred_lifetime) 648 prefix_preferred_lt = iface->max_preferred_lifetime; 649 } 650 651 if (prefix_valid_lt != UINT32_MAX) { 652 prefix_valid_lt -= now; 653 654 if (iface->max_valid_lifetime && prefix_valid_lt > iface->max_valid_lifetime) 655 prefix_valid_lt = iface->max_valid_lifetime; 656 } 657 658 if (prefix_valid_lt > leasetime) 659 prefix_valid_lt = leasetime; 660 661 if (prefix_preferred_lt > prefix_valid_lt) 662 prefix_preferred_lt = prefix_valid_lt; 663 664 if (a->flags & OAF_DHCPV6_PD) { 665 struct dhcpv6_ia_prefix o_ia_p = { 666 .type = htons(DHCPV6_OPT_IA_PREFIX), 667 .len = htons(sizeof(o_ia_p) - 4), 668 .preferred_lt = htonl(prefix_preferred_lt), 669 .valid_lt = htonl(prefix_valid_lt), 670 .prefix_len = a->length, 671 .addr = addrs[i].addr.in6, 672 }; 673 674 o_ia_p.addr.s6_addr32[1] |= htonl(a->assigned_subnet_id); 675 o_ia_p.addr.s6_addr32[2] = o_ia_p.addr.s6_addr32[3] = 0; 676 677 if (!valid_prefix_length(a, addrs[i].prefix_len)) 678 continue; 679 680 if (buflen < ia_len + sizeof(o_ia_p)) 681 return 0; 682 683 memcpy(buf + ia_len, &o_ia_p, sizeof(o_ia_p)); 684 ia_len += sizeof(o_ia_p); 685 } 686 687 if (a->flags & OAF_DHCPV6_NA) { 688 struct dhcpv6_ia_addr o_ia_a = { 689 .type = htons(DHCPV6_OPT_IA_ADDR), 690 .len = htons(sizeof(o_ia_a) - 4), 691 .addr = in6_from_prefix_and_iid(&addrs[i], a->assigned_host_id), 692 .preferred_lt = htonl(prefix_preferred_lt), 693 .valid_lt = htonl(prefix_valid_lt) 694 }; 695 696 if (!ADDR_ENTRY_VALID_IA_ADDR(iface, i, m, addrs)) 697 continue; 698 699 if (buflen < ia_len + sizeof(o_ia_a)) 700 return 0; 701 702 memcpy(buf + ia_len, &o_ia_a, sizeof(o_ia_a)); 703 ia_len += sizeof(o_ia_a); 704 } 705 706 /* Calculate T1 / T2 based on non-deprecated addresses */ 707 if (prefix_preferred_lt > 0) { 708 if (floor_preferred_lifetime > prefix_preferred_lt) 709 floor_preferred_lifetime = prefix_preferred_lt; 710 711 if (floor_valid_lifetime > prefix_valid_lt) 712 floor_valid_lifetime = prefix_valid_lt; 713 } 714 } 715 716 if (!INFINITE_VALID(a->valid_until)) 717 /* UINT32_MAX is RFC defined as infinite lease-time */ 718 a->valid_until = (floor_valid_lifetime == UINT32_MAX) ? 0 : floor_valid_lifetime + now; 719 720 if (!INFINITE_VALID(a->preferred_until)) 721 /* UINT32_MAX is RFC defined as infinite lease-time */ 722 a->preferred_until = (floor_preferred_lifetime == UINT32_MAX) ? 0 : floor_preferred_lifetime + now; 723 724 o_ia.t1 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 5 / 10); 725 o_ia.t2 = htonl((floor_preferred_lifetime == UINT32_MAX) ? floor_preferred_lifetime : floor_preferred_lifetime * 8 / 10); 726 727 if (!o_ia.t1) 728 o_ia.t1 = htonl(1); 729 730 if (!o_ia.t2) 731 o_ia.t2 = htonl(1); 732 } 733 734 if (!request) { 735 uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + 4; 736 uint16_t otype, olen; 737 738 dhcpv6_for_each_option((uint8_t*)&ia[1], end, otype, olen, odata) { 739 struct dhcpv6_ia_prefix *ia_p = (struct dhcpv6_ia_prefix *)&odata[-4]; 740 struct dhcpv6_ia_addr *ia_a = (struct dhcpv6_ia_addr *)&odata[-4]; 741 bool found = false; 742 743 if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*ia_p) - 4) && 744 (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*ia_a) - 4)) 745 continue; 746 747 if (a) { 748 struct odhcpd_ipaddr *addrs = iface->addr6; 749 size_t addrlen = iface->addr6_len; 750 751 for (size_t i = 0; i < addrlen; ++i) { 752 struct in6_addr addr; 753 754 if (!valid_addr(&addrs[i], now)) 755 continue; 756 757 if (!valid_prefix_length(a, addrs[i].prefix_len)) 758 continue; 759 760 if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) 761 continue; 762 763 if (ia->type == htons(DHCPV6_OPT_IA_PD)) { 764 addr = addrs[i].addr.in6; 765 addr.s6_addr32[1] |= htonl(a->assigned_subnet_id); 766 addr.s6_addr32[2] = addr.s6_addr32[3] = 0; 767 768 if (!memcmp(&ia_p->addr, &addr, sizeof(addr)) && 769 ia_p->prefix_len == a->length) 770 found = true; 771 } else { 772 addr = in6_from_prefix_and_iid(&addrs[i], a->assigned_host_id); 773 774 if (!memcmp(&ia_a->addr, &addr, sizeof(addr))) 775 found = true; 776 } 777 } 778 } 779 780 if (!found) { 781 if (otype == DHCPV6_OPT_IA_PREFIX) { 782 struct dhcpv6_ia_prefix o_ia_p = { 783 .type = htons(DHCPV6_OPT_IA_PREFIX), 784 .len = htons(sizeof(o_ia_p) - 4), 785 .preferred_lt = 0, 786 .valid_lt = 0, 787 .prefix_len = ia_p->prefix_len, 788 .addr = ia_p->addr, 789 }; 790 791 if (buflen < ia_len + sizeof(o_ia_p)) 792 return 0; 793 794 memcpy(buf + ia_len, &o_ia_p, sizeof(o_ia_p)); 795 ia_len += sizeof(o_ia_p); 796 } else { 797 struct dhcpv6_ia_addr o_ia_a = { 798 .type = htons(DHCPV6_OPT_IA_ADDR), 799 .len = htons(sizeof(o_ia_a) - 4), 800 .addr = ia_a->addr, 801 .preferred_lt = 0, 802 .valid_lt = 0, 803 }; 804 805 if (buflen < ia_len + sizeof(o_ia_a)) 806 continue; 807 808 memcpy(buf + ia_len, &o_ia_a, sizeof(o_ia_a)); 809 ia_len += sizeof(o_ia_a); 810 } 811 } 812 } 813 } 814 815 o_ia.len = htons(ia_len - 4); 816 memcpy(buf, &o_ia, sizeof(o_ia)); 817 return ia_len; 818 } 819 820 struct log_ctxt { 821 char *buf; 822 int buf_len; 823 int buf_idx; 824 }; 825 826 static void dhcpv6_log_ia_addr(_o_unused struct dhcpv6_lease *lease, struct in6_addr *addr, uint8_t prefix_len, 827 _o_unused uint32_t pref_lt, _o_unused uint32_t valid_lt, void *arg) 828 { 829 struct log_ctxt *ctxt = (struct log_ctxt *)arg; 830 char addrbuf[INET6_ADDRSTRLEN]; 831 832 inet_ntop(AF_INET6, addr, addrbuf, sizeof(addrbuf)); 833 ctxt->buf_idx += snprintf(ctxt->buf + ctxt->buf_idx, ctxt->buf_len - ctxt->buf_idx, 834 " %s/%" PRIu8, addrbuf, prefix_len); 835 } 836 837 static void dhcpv6_log(uint8_t msgtype, struct interface *iface, time_t now, 838 const char *duidbuf, bool is_pd, struct dhcpv6_lease *a, int code) 839 { 840 const char *type = "UNKNOWN"; 841 const char *status = "UNKNOWN"; 842 843 switch (msgtype) { 844 case DHCPV6_MSG_SOLICIT: 845 type = "SOLICIT"; 846 break; 847 case DHCPV6_MSG_REQUEST: 848 type = "REQUEST"; 849 break; 850 case DHCPV6_MSG_CONFIRM: 851 type = "CONFIRM"; 852 break; 853 case DHCPV6_MSG_RENEW: 854 type = "RENEW"; 855 break; 856 case DHCPV6_MSG_REBIND: 857 type = "REBIND"; 858 break; 859 case DHCPV6_MSG_RELEASE: 860 type = "RELEASE"; 861 break; 862 case DHCPV6_MSG_DECLINE: 863 type = "DECLINE"; 864 break; 865 } 866 867 switch (code) { 868 case DHCPV6_STATUS_OK: 869 status = "ok"; 870 break; 871 case DHCPV6_STATUS_NOADDRSAVAIL: 872 status = "no addresses available"; 873 break; 874 case DHCPV6_STATUS_NOBINDING: 875 status = "no binding"; 876 break; 877 case DHCPV6_STATUS_NOTONLINK: 878 status = "not on-link"; 879 break; 880 case DHCPV6_STATUS_NOPREFIXAVAIL: 881 status = "no prefix available"; 882 break; 883 } 884 885 char leasebuf[256] = ""; 886 887 if (a) { 888 struct log_ctxt ctxt = {.buf = leasebuf, 889 .buf_len = sizeof(leasebuf), 890 .buf_idx = 0 }; 891 892 odhcpd_enum_addr6(iface, a, now, dhcpv6_log_ia_addr, &ctxt); 893 } 894 895 info("DHCPV6 %s %s from %s on %s: %s%s", type, (is_pd) ? "IA_PD" : "IA_NA", 896 duidbuf, iface->name, status, leasebuf); 897 } 898 899 static bool dhcpv6_ia_on_link(const struct dhcpv6_ia_hdr *ia, struct dhcpv6_lease *a, 900 struct interface *iface) 901 { 902 struct odhcpd_ipaddr *addrs = iface->addr6; 903 size_t addrlen = iface->addr6_len; 904 time_t now = odhcpd_time(); 905 uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + 4; 906 uint16_t otype, olen; 907 bool onlink = true; 908 909 dhcpv6_for_each_option((uint8_t*)&ia[1], end, otype, olen, odata) { 910 struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix *)&odata[-4]; 911 struct dhcpv6_ia_addr *n = (struct dhcpv6_ia_addr *)&odata[-4]; 912 913 if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*p) - 4) && 914 (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*n) - 4)) 915 continue; 916 917 onlink = false; 918 for (size_t i = 0; i < addrlen; ++i) { 919 if (!valid_addr(&addrs[i], now)) 920 continue; 921 922 if (ADDR_MATCH_PIO_FILTER(&addrs[i], iface)) 923 continue; 924 925 if (ia->type == htons(DHCPV6_OPT_IA_PD)) { 926 if (p->prefix_len < addrs[i].prefix_len || 927 odhcpd_bmemcmp(&p->addr, &addrs[i].addr.in6, addrs[i].prefix_len)) 928 continue; 929 930 } else if (odhcpd_bmemcmp(&n->addr, &addrs[i].addr.in6, addrs[i].prefix_len)) 931 continue; 932 933 onlink = true; 934 } 935 936 if (!onlink) 937 break; 938 } 939 940 return onlink; 941 } 942 943 ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *iface, 944 const struct sockaddr_in6 *addr, const void *data, const uint8_t *end) 945 { 946 struct dhcpv6_lease *first = NULL; 947 const struct dhcpv6_client_header *hdr = data; 948 time_t now = odhcpd_time(); 949 uint16_t otype, olen, duid_len = 0; 950 uint8_t *start = (uint8_t *)&hdr[1], *odata; 951 uint8_t *duid = NULL, mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 952 size_t hostname_len = 0, response_len = 0; 953 bool notonlink = false, rapid_commit = false, accept_reconf = false; 954 char duidbuf[DUID_HEXSTRLEN], hostname[256]; 955 956 dhcpv6_for_each_option(start, end, otype, olen, odata) { 957 if (otype == DHCPV6_OPT_CLIENTID) { 958 duid = odata; 959 duid_len = olen; 960 961 if (olen == 14 && odata[0] == 0 && odata[1] == 1) 962 memcpy(mac, &odata[8], sizeof(mac)); 963 else if (olen == 10 && odata[0] == 0 && odata[1] == 3) 964 memcpy(mac, &odata[4], sizeof(mac)); 965 966 if (olen <= DUID_MAX_LEN) 967 odhcpd_hexlify(duidbuf, odata, olen); 968 } else if (otype == DHCPV6_OPT_FQDN && olen >= 2 && olen <= 255) { 969 uint8_t fqdn_buf[256]; 970 memcpy(fqdn_buf, odata, olen); 971 fqdn_buf[olen++] = 0; 972 973 if (dn_expand(&fqdn_buf[1], &fqdn_buf[olen], &fqdn_buf[1], hostname, sizeof(hostname)) > 0) 974 hostname_len = strcspn(hostname, "."); 975 } else if (otype == DHCPV6_OPT_RECONF_ACCEPT) 976 accept_reconf = true; 977 else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT) 978 rapid_commit = true; 979 } 980 981 if (!duid || duid_len < DUID_MIN_LEN || duid_len > DUID_MAX_LEN) 982 goto out; 983 984 dhcpv6_for_each_option(start, end, otype, olen, odata) { 985 bool is_pd = (otype == DHCPV6_OPT_IA_PD); 986 bool is_na = (otype == DHCPV6_OPT_IA_NA); 987 bool ia_addr_present = false; 988 if (!is_pd && !is_na) 989 continue; 990 991 struct dhcpv6_ia_hdr *ia = (struct dhcpv6_ia_hdr*)&odata[-4]; 992 size_t ia_response_len = 0; 993 uint8_t reqlen = (is_pd) ? 62 : 128; 994 uint32_t reqhint = 0; 995 struct lease_cfg *lease_cfg; 996 997 lease_cfg = config_find_lease_cfg_by_duid_and_iaid(duid, duid_len, ntohl(ia->iaid)); 998 if (!lease_cfg) 999 lease_cfg = config_find_lease_cfg_by_mac(mac); 1000 1001 if (lease_cfg && lease_cfg->ignore6) 1002 return -1; 1003 1004 /* Parse request hint for IA-PD */ 1005 if (is_pd) { 1006 uint8_t *sdata; 1007 uint16_t stype, slen; 1008 dhcpv6_for_each_sub_option(&ia[1], odata + olen, stype, slen, sdata) { 1009 if (stype != DHCPV6_OPT_IA_PREFIX || slen < sizeof(struct dhcpv6_ia_prefix) - 4) 1010 continue; 1011 1012 struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix*)&sdata[-4]; 1013 if (p->prefix_len) { 1014 reqlen = p->prefix_len; 1015 reqhint = ntohl(p->addr.s6_addr32[1]); 1016 if (reqlen > 32 && reqlen <= 64) 1017 reqhint &= (1U << (64 - reqlen)) - 1; 1018 } 1019 } 1020 1021 if (reqlen > 64) 1022 reqlen = 64; 1023 1024 /* 1025 * A requesting router can include a desired prefix length for its 1026 * delegation. The delegating router (us) is not required to honor 1027 * the hint (RFC3633, section 11.2, we MAY choose to use the 1028 * information in the option; RFC8168, section 3.2 has several SHOULDs 1029 * about desired choices for selecting a prefix to delegate). 1030 * 1031 * We support a policy setting to conserve prefix space, which purposely 1032 * assigns prefixes that might not match the requesting router's hint. 1033 * 1034 * If the minimum prefix length is set in this interface's 1035 * configuration, we use it as a floor for the requested (hinted) 1036 * prefix length. This allows us to conserve prefix space so that 1037 * any single router can't grab too much of it. Consider if we have 1038 * an interface with a /56 prefix. A requesting router could ask for 1039 * a /58 and take 1/4 of our total address space. But if we set a 1040 * minimum of /60, we can limit each requesting router to get only 1041 * 1/16 of our total address space. 1042 */ 1043 if (iface->dhcpv6_pd_min_len && reqlen < iface->dhcpv6_pd_min_len) { 1044 info("clamping requested PD from %d to %d", reqlen, 1045 iface->dhcpv6_pd_min_len); 1046 reqlen = iface->dhcpv6_pd_min_len; 1047 } 1048 } else if (is_na) { 1049 uint8_t *sdata; 1050 uint16_t stype, slen; 1051 dhcpv6_for_each_sub_option(&ia[1], odata + olen, stype, slen, sdata) { 1052 if (stype != DHCPV6_OPT_IA_ADDR || slen < sizeof(struct dhcpv6_ia_addr) - 4) 1053 continue; 1054 1055 ia_addr_present = true; 1056 } 1057 } 1058 1059 /* Find an existing assignment */ 1060 struct dhcpv6_lease *c, *a = NULL; 1061 list_for_each_entry(c, &iface->ia_assignments, head) { 1062 /* If we're looking for a PD, is this a PD? */ 1063 if (is_pd && !(c->flags & OAF_DHCPV6_PD)) 1064 continue; 1065 1066 /* If we're looking for a NA, is this a NA? */ 1067 if (is_na && !(c->flags & OAF_DHCPV6_NA)) 1068 continue; 1069 1070 /* Is this assignment still valid? */ 1071 if (!INFINITE_VALID(c->valid_until) && now >= c->valid_until) 1072 continue; 1073 1074 /* Does the DUID match? */ 1075 if (c->duid_len != duid_len || memcmp(c->duid, duid, duid_len)) 1076 continue; 1077 1078 /* Does the IAID match? */ 1079 if (c->iaid != ia->iaid) { 1080 if (is_pd) 1081 continue; 1082 1083 if (!lease_cfg) 1084 continue; 1085 1086 /* Does the existing assignment stem from the same static lease cfg? */ 1087 if (c->lease_cfg != lease_cfg) 1088 continue; 1089 1090 /* 1091 * If there's a DUID configured for this static lease, but without 1092 * an IAID, we will proceed under the assumption that a request 1093 * with the right DUID but with *any* IAID should be able to take 1094 * over the assignment. E.g. when switching from WiFi to ethernet 1095 * on the same client. This is similar to how multiple MAC adresses 1096 * are handled for DHCPv4. 1097 */ 1098 for (size_t i = 0; i < lease_cfg->duid_count; i++) { 1099 if (lease_cfg->duids[i].iaid_set && lease_cfg->duids[i].iaid != htonl(ia->iaid)) 1100 continue; 1101 1102 if (lease_cfg->duids[i].len != duid_len) 1103 continue; 1104 1105 if (memcmp(lease_cfg->duids[i].id, duid, duid_len)) 1106 continue; 1107 1108 /* 1109 * Reconf doesn't specify the IAID, so we have to assume the client 1110 * already knows or doesn't care about the old assignment. 1111 */ 1112 stop_reconf(c); 1113 dhcpv6_free_lease(c); 1114 goto proceed; 1115 } 1116 continue; 1117 } 1118 1119 /* We have a match */ 1120 a = c; 1121 1122 /* Reset state */ 1123 if (a->bound) 1124 apply_lease(a, false); 1125 1126 stop_reconf(a); 1127 break; 1128 } 1129 1130 if (lease_cfg && a && a->lease_cfg != lease_cfg) { 1131 dhcpv6_free_lease(a); 1132 a = NULL; 1133 } 1134 1135 proceed: 1136 /* Generic message handling */ 1137 uint16_t status = DHCPV6_STATUS_OK; 1138 1139 if (hdr->msg_type == DHCPV6_MSG_SOLICIT || 1140 hdr->msg_type == DHCPV6_MSG_REQUEST || 1141 (hdr->msg_type == DHCPV6_MSG_REBIND && !a)) { 1142 bool assigned = !!a; 1143 1144 if (!a) { 1145 if ((!iface->no_dynamic_dhcp || (lease_cfg && is_na)) && 1146 (iface->dhcpv6_pd || iface->dhcpv6_na)) { 1147 /* Create new binding */ 1148 a = dhcpv6_alloc_lease(duid_len); 1149 1150 if (a) { 1151 a->duid_len = duid_len; 1152 memcpy(a->duid, duid, duid_len); 1153 a->iaid = ia->iaid; 1154 a->length = reqlen; 1155 a->peer = *addr; 1156 if (is_na) 1157 a->assigned_host_id = lease_cfg ? lease_cfg->hostid : 0; 1158 else 1159 a->assigned_subnet_id = reqhint; 1160 a->valid_until = now; 1161 a->preferred_until = now; 1162 a->iface = iface; 1163 a->flags = (is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA); 1164 1165 if (first) 1166 memcpy(a->key, first->key, sizeof(a->key)); 1167 else 1168 odhcpd_urandom(a->key, sizeof(a->key)); 1169 1170 if (is_pd && iface->dhcpv6_pd) 1171 while (!(assigned = assign_pd(iface, a)) && 1172 ++a->length <= 64); 1173 else if (is_na && iface->dhcpv6_na) 1174 assigned = assign_na(iface, a); 1175 1176 if (lease_cfg && assigned) { 1177 if (lease_cfg->hostname) { 1178 a->hostname = strdup(lease_cfg->hostname); 1179 a->hostname_valid = true; 1180 } 1181 1182 if (lease_cfg->leasetime) 1183 a->leasetime = lease_cfg->leasetime; 1184 1185 list_add(&a->lease_cfg_list, &lease_cfg->dhcpv6_leases); 1186 a->lease_cfg = lease_cfg; 1187 } 1188 } 1189 } 1190 } 1191 1192 if (!assigned || iface->addr6_len == 0) 1193 /* Set error status */ 1194 status = (is_pd) ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL; 1195 else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) { 1196 /* Send NOTONLINK status for the IA */ 1197 status = DHCPV6_STATUS_NOTONLINK; 1198 assigned = false; 1199 } else if (accept_reconf && assigned && !first && 1200 hdr->msg_type != DHCPV6_MSG_REBIND) { 1201 size_t handshake_len = 4; 1202 buf[0] = 0; 1203 buf[1] = DHCPV6_OPT_RECONF_ACCEPT; 1204 buf[2] = 0; 1205 buf[3] = 0; 1206 1207 if (hdr->msg_type == DHCPV6_MSG_REQUEST) { 1208 struct dhcpv6_auth_reconfigure auth = { 1209 htons(DHCPV6_OPT_AUTH), 1210 htons(sizeof(auth) - 4), 1211 3, 1, 0, 1212 {htonl(time(NULL)), htonl(++serial)}, 1213 1, 1214 {0} 1215 }; 1216 memcpy(auth.key, a->key, sizeof(a->key)); 1217 memcpy(buf + handshake_len, &auth, sizeof(auth)); 1218 handshake_len += sizeof(auth); 1219 } 1220 1221 1222 buf += handshake_len; 1223 buflen -= handshake_len; 1224 response_len += handshake_len; 1225 1226 first = a; 1227 } 1228 1229 ia_response_len = build_ia(buf, buflen, status, ia, a, iface, 1230 hdr->msg_type == DHCPV6_MSG_REBIND ? false : true); 1231 1232 /* Was only a solicitation: mark binding for removal in 60 seconds */ 1233 if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit) { 1234 a->bound = false; 1235 a->valid_until = now + 60; 1236 1237 } else if (assigned && 1238 ((hdr->msg_type == DHCPV6_MSG_SOLICIT && rapid_commit) || 1239 hdr->msg_type == DHCPV6_MSG_REQUEST || 1240 hdr->msg_type == DHCPV6_MSG_REBIND)) { 1241 if (hostname_len > 0 && (!a->lease_cfg || !a->lease_cfg->hostname)) { 1242 char *tmp = realloc(a->hostname, hostname_len + 1); 1243 if (tmp) { 1244 a->hostname = tmp; 1245 memcpy(a->hostname, hostname, hostname_len); 1246 a->hostname[hostname_len] = 0; 1247 a->hostname_valid = odhcpd_hostname_valid(a->hostname); 1248 } 1249 } 1250 a->accept_fr_nonce = accept_reconf; 1251 a->bound = true; 1252 apply_lease(a, true); 1253 } else if (!assigned) { 1254 /* Cleanup failed assignment */ 1255 dhcpv6_free_lease(a); 1256 a = NULL; 1257 } 1258 } else if (hdr->msg_type == DHCPV6_MSG_RENEW || 1259 hdr->msg_type == DHCPV6_MSG_RELEASE || 1260 hdr->msg_type == DHCPV6_MSG_REBIND || 1261 hdr->msg_type == DHCPV6_MSG_DECLINE) { 1262 if (!a && hdr->msg_type != DHCPV6_MSG_REBIND) { 1263 status = DHCPV6_STATUS_NOBINDING; 1264 ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false); 1265 } else if (hdr->msg_type == DHCPV6_MSG_RENEW || 1266 hdr->msg_type == DHCPV6_MSG_REBIND) { 1267 ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false); 1268 if (a) { 1269 a->bound = true; 1270 apply_lease(a, true); 1271 } 1272 } else if (hdr->msg_type == DHCPV6_MSG_RELEASE) { 1273 a->valid_until = now - 1; 1274 } else if ((a->flags & OAF_DHCPV6_NA) && hdr->msg_type == DHCPV6_MSG_DECLINE) { 1275 a->bound = false; 1276 1277 if (!a->lease_cfg || a->lease_cfg->hostid != a->assigned_host_id) { 1278 memset(a->duid, 0, a->duid_len); 1279 a->valid_until = now + 3600; /* Block address for 1h */ 1280 } else 1281 a->valid_until = now - 1; 1282 } 1283 } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) { 1284 if (ia_addr_present && !dhcpv6_ia_on_link(ia, a, iface)) { 1285 notonlink = true; 1286 break; 1287 } 1288 1289 if (!ia_addr_present || !a || !a->bound) { 1290 response_len = 0; 1291 goto out; 1292 } 1293 } 1294 1295 buf += ia_response_len; 1296 buflen -= ia_response_len; 1297 response_len += ia_response_len; 1298 dhcpv6_log(hdr->msg_type, iface, now, duidbuf, is_pd, a, status); 1299 } 1300 1301 switch (hdr->msg_type) { 1302 case DHCPV6_MSG_RELEASE: 1303 case DHCPV6_MSG_DECLINE: 1304 case DHCPV6_MSG_CONFIRM: 1305 if (response_len + 6 < buflen) { 1306 buf[0] = 0; 1307 buf[1] = DHCPV6_OPT_STATUS; 1308 buf[2] = 0; 1309 buf[3] = 2; 1310 buf[4] = 0; 1311 buf[5] = (notonlink) ? DHCPV6_STATUS_NOTONLINK : DHCPV6_STATUS_OK; 1312 response_len += 6; 1313 } 1314 break; 1315 1316 default: 1317 break; 1318 } 1319 1320 statefiles_write(); 1321 1322 out: 1323 return response_len; 1324 } 1325
This page was automatically generated by LXR 0.3.1. • OpenWrt