1 /** 2 * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org> 3 * Copyright (C) 2018 Hans Dedecker <dedeckeh@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License v2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 */ 15 16 #include <errno.h> 17 #include <unistd.h> 18 #include <stddef.h> 19 #include <arpa/inet.h> 20 21 #include <libubox/utils.h> 22 23 #include "odhcpd.h" 24 #include "dhcpv6.h" 25 #include "dhcpv6-pxe.h" 26 #ifdef DHCPV4_SUPPORT 27 #include "dhcpv4.h" 28 #endif 29 30 static void relay_client_request(struct sockaddr_in6 *source, 31 const void *data, size_t len, struct interface *iface, 32 struct in6_addr *dest); 33 static void relay_server_response(uint8_t *data, size_t len); 34 35 static void handle_dhcpv6(void *addr, void *data, size_t len, 36 struct interface *iface, void *dest); 37 static void handle_client_request(void *addr, void *data, size_t len, 38 struct interface *iface, void *dest_addr); 39 40 41 /* Create socket and register events */ 42 int dhcpv6_init(void) 43 { 44 return dhcpv6_ia_init(); 45 } 46 47 int dhcpv6_setup_interface(struct interface *iface, bool enable) 48 { 49 int ret = 0; 50 51 enable = enable && (iface->dhcpv6 != MODE_DISABLED); 52 53 if (iface->dhcpv6_event.uloop.fd >= 0) { 54 uloop_fd_delete(&iface->dhcpv6_event.uloop); 55 close(iface->dhcpv6_event.uloop.fd); 56 iface->dhcpv6_event.uloop.fd = -1; 57 } 58 59 /* Configure multicast settings */ 60 if (enable) { 61 struct sockaddr_in6 bind_addr = {AF_INET6, htons(DHCPV6_SERVER_PORT), 62 0, IN6ADDR_ANY_INIT, 0}; 63 struct ipv6_mreq mreq; 64 int val = 1; 65 66 iface->dhcpv6_event.uloop.fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); 67 if (iface->dhcpv6_event.uloop.fd < 0) { 68 error("socket(AF_INET6): %m"); 69 ret = -1; 70 goto out; 71 } 72 73 /* Basic IPv6 configuration */ 74 if (setsockopt(iface->dhcpv6_event.uloop.fd, SOL_SOCKET, SO_BINDTODEVICE, 75 iface->ifname, strlen(iface->ifname)) < 0) { 76 error("setsockopt(SO_BINDTODEVICE): %m"); 77 ret = -1; 78 goto out; 79 } 80 81 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_V6ONLY, 82 &val, sizeof(val)) < 0) { 83 error("setsockopt(IPV6_V6ONLY): %m"); 84 ret = -1; 85 goto out; 86 } 87 88 if (setsockopt(iface->dhcpv6_event.uloop.fd, SOL_SOCKET, SO_REUSEADDR, 89 &val, sizeof(val)) < 0) { 90 error("setsockopt(SO_REUSEADDR): %m"); 91 ret = -1; 92 goto out; 93 } 94 95 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 96 &val, sizeof(val)) < 0) { 97 error("setsockopt(IPV6_RECVPKTINFO): %m"); 98 ret = -1; 99 goto out; 100 } 101 102 val = DHCPV6_HOP_COUNT_LIMIT; 103 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 104 &val, sizeof(val)) < 0) { 105 error("setsockopt(IPV6_MULTICAST_HOPS): %m"); 106 ret = -1; 107 goto out; 108 } 109 110 val = 0; 111 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 112 &val, sizeof(val)) < 0) { 113 error("setsockopt(IPV6_MULTICAST_LOOP): %m"); 114 ret = -1; 115 goto out; 116 } 117 118 if (bind(iface->dhcpv6_event.uloop.fd, (struct sockaddr*)&bind_addr, 119 sizeof(bind_addr)) < 0) { 120 error("bind(): %m"); 121 ret = -1; 122 goto out; 123 } 124 125 memset(&mreq, 0, sizeof(mreq)); 126 inet_pton(AF_INET6, ALL_DHCPV6_RELAYS, &mreq.ipv6mr_multiaddr); 127 mreq.ipv6mr_interface = iface->ifindex; 128 129 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, 130 &mreq, sizeof(mreq)) < 0) { 131 error("setsockopt(IPV6_ADD_MEMBERSHIP): %m"); 132 ret = -1; 133 goto out; 134 } 135 136 if (iface->dhcpv6 == MODE_SERVER) { 137 memset(&mreq, 0, sizeof(mreq)); 138 inet_pton(AF_INET6, ALL_DHCPV6_SERVERS, &mreq.ipv6mr_multiaddr); 139 mreq.ipv6mr_interface = iface->ifindex; 140 141 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, 142 &mreq, sizeof(mreq)) < 0) { 143 error("setsockopt(IPV6_ADD_MEMBERSHIP): %m"); 144 ret = -1; 145 goto out; 146 } 147 } 148 149 iface->dhcpv6_event.handle_dgram = handle_dhcpv6; 150 odhcpd_register(&iface->dhcpv6_event); 151 } 152 153 ret = dhcpv6_ia_setup_interface(iface, enable); 154 155 out: 156 if (ret < 0 && iface->dhcpv6_event.uloop.fd >= 0) { 157 close(iface->dhcpv6_event.uloop.fd); 158 iface->dhcpv6_event.uloop.fd = -1; 159 } 160 161 return ret; 162 } 163 164 enum { 165 IOV_NESTED = 0, 166 IOV_DEST, 167 IOV_CLIENTID, 168 IOV_MAXRT, 169 #define IOV_STAT IOV_MAXRT 170 IOV_RAPID_COMMIT, 171 IOV_DNS, 172 IOV_DNS_ADDR, 173 IOV_SEARCH, 174 IOV_SEARCH_DOMAIN, 175 IOV_PDBUF, 176 #define IOV_REFRESH IOV_PDBUF 177 IOV_DHCPV6_RAW, 178 IOV_NTP, 179 IOV_NTP_ADDR, 180 IOV_SNTP, 181 IOV_SNTP_ADDR, 182 IOV_RELAY_MSG, 183 IOV_DHCPV4O6_SERVER, 184 IOV_DNR, 185 IOV_BOOTFILE_URL, 186 IOV_POSIX_TZ, 187 IOV_POSIX_TZ_STR, 188 IOV_TZDB_TZ, 189 IOV_TZDB_TZ_STR, 190 IOV_CAPT_PORTAL, 191 IOV_CAPT_PORTAL_URI, 192 IOV_TOTAL 193 }; 194 195 static void handle_nested_message(uint8_t *data, size_t len, unsigned depth, 196 struct dhcpv6_client_header **c_hdr, uint8_t **opts, 197 uint8_t **end, struct iovec iov[IOV_TOTAL]) 198 { 199 struct dhcpv6_relay_header *r_hdr = (struct dhcpv6_relay_header *)data; 200 uint16_t otype, olen; 201 uint8_t *odata; 202 203 if (iov[IOV_NESTED].iov_base == NULL) { 204 iov[IOV_NESTED].iov_base = data; 205 iov[IOV_NESTED].iov_len = len; 206 } 207 208 if (len < sizeof(struct dhcpv6_client_header)) 209 return; 210 211 if (r_hdr->msg_type != DHCPV6_MSG_RELAY_FORW) { 212 iov[IOV_NESTED].iov_len = data - (uint8_t *)iov[IOV_NESTED].iov_base; 213 *c_hdr = (void *)data; 214 *opts = (uint8_t *)&(*c_hdr)[1]; 215 *end = data + len; 216 return; 217 } 218 219 /* Each nested Relay-Forward is one relay hop; RFC8415 bounds a relay 220 * chain via HOP_COUNT_LIMIT (defined in §7.6, enforced in §19.1.2), 221 * so refuse to recurse deeper and avoid stack exhaustion on crafted 222 * relay loops. */ 223 if (depth >= DHCPV6_HOP_COUNT_LIMIT) 224 return; 225 226 dhcpv6_for_each_option(r_hdr->options, data + len, otype, olen, odata) { 227 if (otype == DHCPV6_OPT_RELAY_MSG) { 228 iov[IOV_RELAY_MSG].iov_base = odata + olen; 229 iov[IOV_RELAY_MSG].iov_len = (((uint8_t *)iov[IOV_NESTED].iov_base) + 230 iov[IOV_NESTED].iov_len) - (odata + olen); 231 handle_nested_message(odata, olen, depth + 1, c_hdr, opts, end, iov); 232 return; 233 } 234 } 235 } 236 237 238 static void update_nested_message(uint8_t *data, size_t len, unsigned depth, ssize_t pdiff) 239 { 240 struct dhcpv6_relay_header *hdr = (struct dhcpv6_relay_header*)data; 241 if (hdr->msg_type != DHCPV6_MSG_RELAY_FORW) 242 return; 243 244 hdr->msg_type = DHCPV6_MSG_RELAY_REPL; 245 246 /* Bound recursion to mirror handle_nested_message(). */ 247 if (depth >= DHCPV6_HOP_COUNT_LIMIT) 248 return; 249 250 uint16_t otype, olen; 251 uint8_t *odata; 252 dhcpv6_for_each_option(hdr->options, data + len, otype, olen, odata) { 253 if (otype == DHCPV6_OPT_RELAY_MSG) { 254 ssize_t newlen = (ssize_t)olen + pdiff; 255 256 /* olen was validated to lie within the buffer by the option 257 * iterator. Reject a pdiff that would make the rewritten 258 * RELAY_MSG length wrap the 16-bit field, which would also feed 259 * a bogus length into the recursion below and walk options past 260 * the end of the (untrusted) packet buffer. */ 261 if (newlen < 0 || newlen > UINT16_MAX) 262 return; 263 264 odata[-2] = (newlen >> 8) & 0xff; 265 odata[-1] = newlen & 0xff; 266 update_nested_message(odata, olen, depth + 1, pdiff); 267 return; 268 } 269 } 270 } 271 272 #ifdef DHCPV4_SUPPORT 273 274 struct dhcpv4_msg_data { 275 uint8_t *msg; 276 size_t maxsize; 277 ssize_t len; 278 }; 279 280 static ssize_t dhcpv6_4o6_send_reply(struct iovec *iov, size_t iov_len, 281 _o_unused struct sockaddr *dest, 282 _o_unused socklen_t dest_len, 283 void *opaque) 284 { 285 struct dhcpv4_msg_data *reply = opaque; 286 size_t len = 0; 287 288 for (size_t i = 0; i < iov_len; i++) 289 len += iov[i].iov_len; 290 291 if (len > reply->maxsize) { 292 error("4o6: reply too large, %zu > %zu", len, reply->maxsize); 293 reply->len = -1; 294 return -1; 295 } 296 297 for (size_t i = 0, off = 0; i < iov_len; i++) { 298 memcpy(reply->msg + off, iov[i].iov_base, iov[i].iov_len); 299 off += iov[i].iov_len; 300 } 301 reply->len = len; 302 303 return len; 304 } 305 306 static ssize_t dhcpv6_4o6_query(uint8_t *buf, size_t buflen, 307 struct interface *iface, 308 const struct sockaddr_in6 *addr, 309 const void *data, const uint8_t *end) 310 { 311 const struct dhcpv6_client_header *hdr = data; 312 uint16_t otype, olen, msgv4_len = 0; 313 uint8_t *msgv4_data = NULL; 314 uint8_t *start = (uint8_t *)&hdr[1], *odata; 315 struct sockaddr_in addrv4; 316 struct dhcpv4_msg_data reply = { .msg = buf, .maxsize = buflen, .len = -1 }; 317 318 dhcpv6_for_each_option(start, end, otype, olen, odata) { 319 if (otype == DHCPV6_OPT_DHCPV4_MSG) { 320 msgv4_data = odata; 321 msgv4_len = olen; 322 } 323 } 324 325 if (!msgv4_data || msgv4_len == 0) { 326 error("4o6: missing DHCPv4 message option (%d)", DHCPV6_OPT_DHCPV4_MSG); 327 return -1; 328 } 329 330 /* dhcpv4_handle_msg() reads the full BOOTP fixed header (op, htype, 331 * hlen, hops, xid, secs, flags, ciaddr, yiaddr, siaddr, giaddr, 332 * chaddr, sname, file, cookie = offsetof(options) bytes) before 333 * parsing options. The normal DHCPv4 socket path enforces this via a 334 * BPF filter, but the DHCPv4-over-DHCPv6 path bypasses that filter, 335 * so validate the length here to prevent an out-of-bounds read on a 336 * truncated DHCPV4_MSG option. RFC7341 §7.1 defines the DHCPv4 Message 337 * option but mandates no minimum length, so this floor is ours. */ 338 if (msgv4_len < offsetof(struct dhcpv4_message, options)) { 339 error("4o6: encapsulated DHCPv4 message too short (%u)", msgv4_len); 340 return -1; 341 } 342 343 // Dummy IPv4 address 344 memset(&addrv4, 0, sizeof(addrv4)); 345 addrv4.sin_family = AF_INET; 346 addrv4.sin_addr.s_addr = INADDR_ANY; 347 addrv4.sin_port = htons(DHCPV4_CLIENT_PORT); 348 349 dhcpv4_handle_msg(&addrv4, msgv4_data, msgv4_len, 350 iface, NULL, dhcpv6_4o6_send_reply, &reply); 351 352 return reply.len; 353 } 354 #endif /* DHCPV4_SUPPORT */ 355 356 /* Simple DHCPv6-server for information requests */ 357 static void handle_client_request(void *addr, void *data, size_t len, 358 struct interface *iface, void *dest_addr) 359 { 360 struct dhcpv6_client_header *hdr = data; 361 uint8_t *opts = (uint8_t *)&hdr[1], *opts_end = (uint8_t *)data + len; 362 bool o_rapid_commit = false; 363 364 if (len < sizeof(*hdr)) 365 return; 366 367 switch (hdr->msg_type) { 368 /* Valid message types for clients */ 369 case DHCPV6_MSG_SOLICIT: 370 case DHCPV6_MSG_REQUEST: 371 case DHCPV6_MSG_CONFIRM: 372 case DHCPV6_MSG_RENEW: 373 case DHCPV6_MSG_REBIND: 374 case DHCPV6_MSG_RELEASE: 375 case DHCPV6_MSG_DECLINE: 376 case DHCPV6_MSG_INFORMATION_REQUEST: 377 case DHCPV6_MSG_RELAY_FORW: 378 #ifdef DHCPV4_SUPPORT 379 /* if we include DHCPV4 support, handle this message type */ 380 case DHCPV6_MSG_DHCPV4_QUERY: 381 #endif 382 break; 383 /* Invalid message types for clients i.e. server messages */ 384 case DHCPV6_MSG_ADVERTISE: 385 case DHCPV6_MSG_REPLY: 386 case DHCPV6_MSG_RECONFIGURE: 387 case DHCPV6_MSG_RELAY_REPL: 388 #ifndef DHCPV4_SUPPORT 389 /* if we omit DHCPV4 support, ignore this client message type */ 390 case DHCPV6_MSG_DHCPV4_QUERY: 391 #endif 392 case DHCPV6_MSG_DHCPV4_RESPONSE: 393 default: 394 return; 395 } 396 397 debug("Got a DHCPv6-request on %s", iface->name); 398 399 /* Construct reply message */ 400 struct _o_packed { 401 uint8_t msg_type; 402 uint8_t tr_id[3]; 403 uint16_t serverid_type; 404 uint16_t serverid_length; 405 uint8_t serverid_buf[DUID_MAX_LEN]; 406 } dest = { 407 .msg_type = DHCPV6_MSG_REPLY, 408 .serverid_type = htons(DHCPV6_OPT_SERVERID), 409 .serverid_length = 0, 410 .serverid_buf = { 0 }, 411 }; 412 413 if (config.default_duid_len > 0) { 414 memcpy(dest.serverid_buf, config.default_duid, config.default_duid_len); 415 dest.serverid_length = htons(config.default_duid_len); 416 } else { 417 uint16_t duid_ll_hdr[] = { htons(DUID_TYPE_LL), htons(ARPHRD_ETHER) }; 418 memcpy(dest.serverid_buf, duid_ll_hdr, sizeof(duid_ll_hdr)); 419 odhcpd_get_mac(iface, &dest.serverid_buf[sizeof(duid_ll_hdr)]); 420 dest.serverid_length = htons(sizeof(duid_ll_hdr) + ETH_ALEN); 421 } 422 423 struct _o_packed { 424 uint16_t type; 425 uint16_t len; 426 uint8_t buf[DUID_MAX_LEN]; 427 } clientid = { 428 .type = htons(DHCPV6_OPT_CLIENTID), 429 .len = 0, 430 .buf = { 0 }, 431 }; 432 433 struct _o_packed { 434 uint16_t type; 435 uint16_t len; 436 uint32_t value; 437 } maxrt = {htons(DHCPV6_OPT_SOL_MAX_RT), htons(sizeof(maxrt) - DHCPV6_OPT_HDR_SIZE), 438 htonl(60)}; 439 440 struct _o_packed { 441 uint16_t type; 442 uint16_t len; 443 } rapid_commit = {htons(DHCPV6_OPT_RAPID_COMMIT), 0}; 444 445 struct _o_packed { 446 uint16_t type; 447 uint16_t len; 448 uint16_t value; 449 } stat = {htons(DHCPV6_OPT_STATUS), htons(sizeof(stat) - DHCPV6_OPT_HDR_SIZE), 450 htons(DHCPV6_STATUS_USEMULTICAST)}; 451 452 struct _o_packed { 453 uint16_t type; 454 uint16_t len; 455 uint32_t value; 456 } refresh = {htons(DHCPV6_OPT_INFO_REFRESH), htons(sizeof(uint32_t)), 457 htonl(600)}; 458 459 struct in6_addr *dns_addrs6 = NULL, dns_addr6; 460 size_t dns_addrs6_cnt = 0; 461 462 if (iface->dns_addrs6_cnt > 0) { 463 dns_addrs6 = iface->dns_addrs6; 464 dns_addrs6_cnt = iface->dns_addrs6_cnt; 465 } else if (!odhcpd_get_interface_dns_addr6(iface, &dns_addr6)) { 466 dns_addrs6 = &dns_addr6; 467 dns_addrs6_cnt = 1; 468 } 469 470 struct { 471 uint16_t type; 472 uint16_t len; 473 } dns_hdr = { htons(DHCPV6_OPT_DNS_SERVERS), htons(dns_addrs6_cnt * sizeof(*dns_addrs6)) }; 474 475 /* SNTP */ 476 struct in6_addr *sntp_addr_ptr = iface->dhcpv6_sntp; 477 size_t sntp_cnt = 0; 478 struct { 479 uint16_t type; 480 uint16_t len; 481 } dhcpv6_sntp; 482 483 /* RFC 4833 - Timezones */ 484 bool posix_want = false; 485 uint8_t *posix_ptr = sys_conf.posix_tz; 486 uint16_t posix_len = sys_conf.posix_tz_len; 487 /* RFC 4833 - OPTION_NEW_POSIX_TIMEZONE (41) 488 * e.g. EST5EDT4,M3.2.0/02:00,M11.1.0/02:00 489 * Variable-length opaque tz_string blob. 490 */ 491 struct { 492 uint16_t type; 493 uint16_t len; 494 } posix_tz; 495 496 bool tzdb_want = false; 497 uint8_t *tzdb_ptr = sys_conf.tzdb_tz; 498 uint16_t tzdb_len = sys_conf.tzdb_tz_len; 499 /* RFC 4833 - OPTION_NEW_TZDB_TIMEZONE (42) 500 * e.g. Europe/Zurich 501 * Variable-length opaque tz_name blob. 502 */ 503 struct { 504 uint16_t type; 505 uint16_t len; 506 } tzdb_tz; 507 508 /* NTP */ 509 uint8_t *ntp_ptr = iface->dhcpv6_ntp; 510 uint16_t ntp_len = iface->dhcpv6_ntp_len; 511 size_t ntp_cnt = 0; 512 struct { 513 uint16_t type; 514 uint16_t len; 515 } ntp; 516 517 /* DNR */ 518 struct dhcpv6_dnr { 519 uint16_t type; 520 uint16_t len; 521 uint16_t priority; 522 uint16_t adn_len; 523 uint8_t body[]; 524 }; 525 struct dhcpv6_dnr *dnrs = NULL; 526 size_t dnrs_len = 0; 527 528 /* RFC8910 Captive-Portal URI */ 529 uint8_t *capt_portal_ptr = (uint8_t *)iface->captive_portal_uri; 530 size_t capt_portal_len = iface->captive_portal_uri_len; 531 struct { 532 uint16_t type; 533 uint16_t len; 534 } capt_portal; 535 536 /* RFC8910 §2: 537 * DHCP servers MAY send the Captive Portal option without any explicit request 538 * If it is configured, send it. 539 */ 540 capt_portal.type = htons(DHCPV6_OPT_CAPTIVE_PORTAL); 541 capt_portal.len = htons(capt_portal_len); 542 543 uint16_t otype, olen; 544 uint8_t *odata; 545 /* OPTION_ORO payload is an array of uint16_t but the underlying buffer 546 * isn't guaranteed to be 2-byte aligned (it's at an arbitrary offset 547 * inside the packed wire packet), so keep it as a byte pointer and 548 * memcpy each value out rather than casting to uint16_t *. */ 549 uint8_t *reqopts = NULL; 550 size_t reqopts_cnt = 0; 551 552 /* FIXME: this should be merged with the second loop further down */ 553 dhcpv6_for_each_option(opts, opts_end, otype, olen, odata) { 554 /* Requested options, array of uint16_t, RFC 8415 §21.7 */ 555 if (otype == DHCPV6_OPT_ORO) { 556 reqopts_cnt = olen / sizeof(uint16_t); 557 reqopts = odata; 558 break; 559 } 560 } 561 562 /* Requested options */ 563 for (size_t i = 0; i < reqopts_cnt; i++) { 564 uint16_t opt; 565 566 memcpy(&opt, &reqopts[i * sizeof(uint16_t)], sizeof(opt)); 567 opt = ntohs(opt); 568 569 switch (opt) { 570 case DHCPV6_OPT_SNTP_SERVERS: 571 sntp_cnt = iface->dhcpv6_sntp_cnt; 572 dhcpv6_sntp.type = htons(DHCPV6_OPT_SNTP_SERVERS); 573 dhcpv6_sntp.len = htons(sntp_cnt * sizeof(*sntp_addr_ptr)); 574 break; 575 576 case DHCPV6_OPT_NTP_SERVERS: 577 ntp_cnt = iface->dhcpv6_ntp_cnt; 578 ntp.type = htons(DHCPV6_OPT_NTP_SERVERS); 579 ntp.len = htons(ntp_len); 580 break; 581 582 case DHCPV6_OPT_NEW_POSIX_TIMEZONE: 583 posix_want = true; 584 posix_tz.type = htons(DHCPV6_OPT_NEW_POSIX_TIMEZONE); 585 posix_tz.len = htons(posix_len); 586 break; 587 588 case DHCPV6_OPT_NEW_TZDB_TIMEZONE: 589 tzdb_want = true; 590 tzdb_tz.type = htons(DHCPV6_OPT_NEW_TZDB_TIMEZONE); 591 tzdb_tz.len = htons(tzdb_len); 592 break; 593 594 case DHCPV6_OPT_DNR: 595 for (size_t j = 0; j < iface->dnr_cnt; j++) { 596 struct dnr_options *dnr = &iface->dnr[j]; 597 598 if (dnr->addr6_cnt == 0 && dnr->addr4_cnt > 0) 599 continue; 600 601 dnrs_len += sizeof(struct dhcpv6_dnr); 602 dnrs_len += dnr->adn_len; 603 604 if (dnr->addr6_cnt > 0 || dnr->svc_len > 0) { 605 dnrs_len += sizeof(uint16_t); 606 dnrs_len += dnr->addr6_cnt * sizeof(*dnr->addr6); 607 dnrs_len += dnr->svc_len; 608 } 609 } 610 611 dnrs = alloca(dnrs_len); 612 uint8_t *pos = (uint8_t *)dnrs; 613 614 for (size_t j = 0; j < iface->dnr_cnt; j++) { 615 struct dnr_options *dnr = &iface->dnr[j]; 616 struct dhcpv6_dnr *d6dnr = (struct dhcpv6_dnr *)pos; 617 uint16_t d6dnr_type_be = htons(DHCPV6_OPT_DNR); 618 uint16_t d6dnr_len = 2 * sizeof(uint16_t) + dnr->adn_len; 619 uint16_t d6dnr_len_be; 620 uint16_t d6dnr_priority_be = htons(dnr->priority); 621 uint16_t d6dnr_adn_len_be = htons(dnr->adn_len); 622 623 if (dnr->addr6_cnt == 0 && dnr->addr4_cnt > 0) 624 continue; 625 626 /* memcpy as the struct is unaligned */ 627 memcpy(&d6dnr->type, &d6dnr_type_be, sizeof(d6dnr_type_be)); 628 memcpy(&d6dnr->priority, &d6dnr_priority_be, sizeof(d6dnr_priority_be)); 629 memcpy(&d6dnr->adn_len, &d6dnr_adn_len_be, sizeof(d6dnr_adn_len_be)); 630 631 pos = d6dnr->body; 632 memcpy(pos, dnr->adn, dnr->adn_len); 633 pos += dnr->adn_len; 634 635 if (dnr->addr6_cnt > 0 || dnr->svc_len > 0) { 636 uint16_t addr6_len = dnr->addr6_cnt * sizeof(*dnr->addr6); 637 uint16_t addr6_len_be = htons(addr6_len); 638 639 memcpy(pos, &addr6_len_be, sizeof(addr6_len_be)); 640 pos += sizeof(addr6_len_be); 641 memcpy(pos, dnr->addr6, addr6_len); 642 pos += addr6_len; 643 memcpy(pos, dnr->svc, dnr->svc_len); 644 pos += dnr->svc_len; 645 646 d6dnr_len += sizeof(addr6_len_be) + addr6_len + dnr->svc_len; 647 } 648 649 d6dnr_len_be = htons(d6dnr_len); 650 memcpy(&d6dnr->len, &d6dnr_len_be, sizeof(d6dnr_len_be)); 651 } 652 break; 653 } 654 } 655 656 /* DNS Search options */ 657 struct { 658 uint16_t type; 659 uint16_t len; 660 } dns_search_hdr = { htons(DHCPV6_OPT_DNS_DOMAIN), htons(iface->dns_search_len) }; 661 662 663 struct _o_packed dhcpv4o6_server { 664 uint16_t type; 665 uint16_t len; 666 struct in6_addr addr; 667 } dhcpv4o6_server = {htons(DHCPV6_OPT_4O6_SERVER), htons(sizeof(struct in6_addr)), 668 IN6ADDR_ANY_INIT}; 669 670 uint8_t pdbuf[512]; 671 struct iovec iov[IOV_TOTAL] = { 672 [IOV_NESTED] = {NULL, 0}, 673 [IOV_DEST] = {&dest, offsetof(typeof(dest), serverid_buf) + ntohs(dest.serverid_length) }, 674 [IOV_CLIENTID] = {&clientid, 0}, 675 [IOV_MAXRT] = {&maxrt, sizeof(maxrt)}, 676 [IOV_RAPID_COMMIT] = {&rapid_commit, 0}, 677 [IOV_DNS] = { &dns_hdr, (dns_addrs6_cnt) ? sizeof(dns_hdr) : 0}, 678 [IOV_DNS_ADDR] = { dns_addrs6, dns_addrs6_cnt * sizeof(*dns_addrs6) }, 679 [IOV_SEARCH] = { &dns_search_hdr, iface->dns_search_len ? sizeof(dns_search_hdr) : 0 }, 680 [IOV_SEARCH_DOMAIN] = { iface->dns_search, iface->dns_search_len }, 681 [IOV_PDBUF] = {pdbuf, 0}, 682 [IOV_DHCPV6_RAW] = {iface->dhcpv6_raw, iface->dhcpv6_raw_len}, 683 [IOV_NTP] = {&ntp, (ntp_cnt) ? sizeof(ntp) : 0}, 684 [IOV_NTP_ADDR] = {ntp_ptr, (ntp_cnt) ? ntp_len : 0}, 685 [IOV_SNTP] = {&dhcpv6_sntp, (sntp_cnt) ? sizeof(dhcpv6_sntp) : 0}, 686 [IOV_SNTP_ADDR] = {sntp_addr_ptr, sntp_cnt * sizeof(*sntp_addr_ptr)}, 687 [IOV_POSIX_TZ] = {&posix_tz, (posix_want) ? sizeof(posix_tz) : 0}, 688 [IOV_POSIX_TZ_STR] = {posix_ptr, (posix_want) ? posix_len : 0 }, 689 [IOV_TZDB_TZ] = {&tzdb_tz, (tzdb_want) ? sizeof(tzdb_tz) : 0}, 690 [IOV_TZDB_TZ_STR] = {tzdb_ptr, (tzdb_want) ? tzdb_len : 0 }, 691 [IOV_DNR] = {dnrs, dnrs_len}, 692 [IOV_RELAY_MSG] = {NULL, 0}, 693 [IOV_DHCPV4O6_SERVER] = {&dhcpv4o6_server, 0}, 694 [IOV_CAPT_PORTAL] = {&capt_portal, capt_portal_len ? sizeof(capt_portal) : 0}, 695 [IOV_CAPT_PORTAL_URI] = {capt_portal_ptr, capt_portal_len ? capt_portal_len : 0}, 696 [IOV_BOOTFILE_URL] = {NULL, 0} 697 }; 698 699 if (hdr->msg_type == DHCPV6_MSG_RELAY_FORW) 700 handle_nested_message(data, len, 0, &hdr, &opts, &opts_end, iov); 701 702 if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 && 703 (hdr->msg_type == DHCPV6_MSG_SOLICIT || hdr->msg_type == DHCPV6_MSG_CONFIRM || 704 hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST)) 705 return; 706 707 memcpy(dest.tr_id, hdr->transaction_id, sizeof(dest.tr_id)); 708 709 /* Go through options and find what we need */ 710 dhcpv6_for_each_option(opts, opts_end, otype, olen, odata) { 711 if (otype == DHCPV6_OPT_CLIENTID && olen <= DUID_MAX_LEN) { 712 clientid.len = htons(olen); 713 memcpy(clientid.buf, odata, olen); 714 iov[IOV_CLIENTID].iov_len = offsetof(typeof(clientid), buf) + olen; 715 } else if (otype == DHCPV6_OPT_SERVERID) { 716 if (olen != ntohs(dest.serverid_length) || 717 memcmp(odata, &dest.serverid_buf, olen)) 718 return; /* Not for us */ 719 } else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT) { 720 iov[IOV_RAPID_COMMIT].iov_len = sizeof(rapid_commit); 721 o_rapid_commit = true; 722 } else if (otype == DHCPV6_OPT_ORO) { 723 for (int i = 0; i < olen / 2; i++) { 724 uint16_t option; 725 726 /* odata is not guaranteed to be uint16-aligned. */ 727 memcpy(&option, &odata[i * 2], sizeof(option)); 728 option = ntohs(option); 729 730 switch (option) { 731 #ifdef DHCPV4_SUPPORT 732 case DHCPV6_OPT_4O6_SERVER: 733 if (iface->dhcpv4) { 734 /* According to RFC 7341, 7.2. DHCP 4o6 Server Address Option Format: 735 * This option may also carry no IPv6 addresses, which instructs the 736 * client to use the All_DHCP_Relay_Agents_and_Servers multicast address 737 * as the destination address. 738 * 739 * The ISC dhclient logs a missing IPv6 address as an error but seems to 740 * work anyway: 741 * dhcp4-o-dhcp6-server: expecting at least 16 bytes; got 0 742 * 743 * Include the All_DHCP_Relay_Agents_and_Servers multicast address 744 * to make it explicit which address to use. */ 745 struct dhcpv4o6_server *server = iov[IOV_DHCPV4O6_SERVER].iov_base; 746 747 inet_pton(AF_INET6, ALL_DHCPV6_RELAYS, &server->addr); 748 749 iov[IOV_DHCPV4O6_SERVER].iov_len = sizeof(dhcpv4o6_server); 750 } 751 break; 752 #endif /* DHCPV4_SUPPORT */ 753 default: 754 break; 755 } 756 } 757 } else if (otype == DHCPV6_OPT_CLIENT_ARCH && olen >= sizeof(uint16_t)) { 758 uint16_t arch_code; 759 760 /* odata is not guaranteed to be uint16-aligned, and 761 * RFC5970 §3.3 mandates olen be a multiple of 2 with 762 * at least one architecture entry — read defensively. */ 763 memcpy(&arch_code, odata, sizeof(arch_code)); 764 arch_code = ntohs(arch_code); 765 ipv6_pxe_serve_boot_url(arch_code, &iov[IOV_BOOTFILE_URL]); 766 } 767 } 768 769 if (dest.serverid_length == clientid.len && 770 !memcmp(clientid.buf, dest.serverid_buf, ntohs(dest.serverid_length))) { 771 /* Bail if we are in a network loop where we talk with ourself */ 772 return; 773 } 774 775 if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 && 776 (hdr->msg_type == DHCPV6_MSG_REQUEST || hdr->msg_type == DHCPV6_MSG_RENEW || 777 hdr->msg_type == DHCPV6_MSG_RELEASE || hdr->msg_type == DHCPV6_MSG_DECLINE)) { 778 iov[IOV_STAT].iov_base = &stat; 779 iov[IOV_STAT].iov_len = sizeof(stat); 780 781 for (ssize_t i = IOV_STAT + 1; i < IOV_TOTAL; ++i) 782 iov[i].iov_len = 0; 783 784 odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface); 785 return; 786 } 787 788 if (hdr->msg_type == DHCPV6_MSG_SOLICIT && !o_rapid_commit) { 789 dest.msg_type = DHCPV6_MSG_ADVERTISE; 790 } else if (hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST) { 791 iov[IOV_REFRESH].iov_base = &refresh; 792 iov[IOV_REFRESH].iov_len = sizeof(refresh); 793 794 /* Return inf max rt option in reply to information request */ 795 maxrt.type = htons(DHCPV6_OPT_INF_MAX_RT); 796 } 797 798 #ifdef DHCPV4_SUPPORT 799 if (hdr->msg_type == DHCPV6_MSG_DHCPV4_QUERY) { 800 struct _o_packed dhcpv4_msg_data { 801 uint16_t type; 802 uint16_t len; 803 uint8_t msg[1]; 804 } *msg_opt = (struct dhcpv4_msg_data*)pdbuf; 805 ssize_t msglen; 806 807 memset(pdbuf, 0, sizeof(pdbuf)); 808 809 msglen = dhcpv6_4o6_query(msg_opt->msg, sizeof(pdbuf) - sizeof(*msg_opt) + 1, 810 iface, addr, (const void *)hdr, opts_end); 811 if (msglen <= 0) { 812 error("4o6: query failed"); 813 return; 814 } 815 816 msg_opt->type = htons(DHCPV6_OPT_DHCPV4_MSG); 817 msg_opt->len = htons(msglen); 818 iov[IOV_PDBUF].iov_len = sizeof(*msg_opt) - 1 + msglen; 819 dest.msg_type = DHCPV6_MSG_DHCPV4_RESPONSE; 820 } else 821 #endif /* DHCPV4_SUPPORT */ 822 823 if (hdr->msg_type != DHCPV6_MSG_INFORMATION_REQUEST) { 824 ssize_t ialen = dhcpv6_ia_handle_IAs(pdbuf, sizeof(pdbuf), iface, addr, (const void *)hdr, opts_end); 825 826 iov[IOV_PDBUF].iov_len = ialen; 827 if (ialen < 0 || 828 (ialen == 0 && (hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_CONFIRM))) 829 return; 830 } 831 832 if (iov[IOV_NESTED].iov_len > 0) /* Update length */ 833 update_nested_message(data, len, 0, iov[IOV_DEST].iov_len + iov[IOV_MAXRT].iov_len + 834 iov[IOV_RAPID_COMMIT].iov_len + iov[IOV_DNS].iov_len + 835 iov[IOV_DNS_ADDR].iov_len + iov[IOV_SEARCH].iov_len + 836 iov[IOV_SEARCH_DOMAIN].iov_len + iov[IOV_PDBUF].iov_len + 837 iov[IOV_DHCPV4O6_SERVER].iov_len + 838 iov[IOV_DHCPV6_RAW].iov_len + 839 iov[IOV_NTP].iov_len + iov[IOV_NTP_ADDR].iov_len + 840 iov[IOV_SNTP].iov_len + iov[IOV_SNTP_ADDR].iov_len + 841 iov[IOV_POSIX_TZ].iov_len + iov[IOV_POSIX_TZ_STR].iov_len + 842 iov[IOV_TZDB_TZ].iov_len + iov[IOV_TZDB_TZ_STR].iov_len + 843 iov[IOV_CAPT_PORTAL].iov_len + iov[IOV_CAPT_PORTAL_URI].iov_len + 844 iov[IOV_DNR].iov_len + iov[IOV_BOOTFILE_URL].iov_len - 845 (4 + opts_end - opts)); 846 847 debug("Sending a DHCPv6-%s on %s", iov[IOV_NESTED].iov_len ? "relay-reply" : "reply", iface->name); 848 849 odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface); 850 } 851 852 853 /* Central DHCPv6-relay handler */ 854 static void handle_dhcpv6(void *addr, void *data, size_t len, 855 struct interface *iface, void *dest_addr) 856 { 857 if (iface->dhcpv6 == MODE_SERVER) { 858 handle_client_request(addr, data, len, iface, dest_addr); 859 } else if (iface->dhcpv6 == MODE_RELAY) { 860 if (iface->master) { 861 relay_server_response(data, len); 862 } else if (iface->dhcpv6_relay_server_addrs6_cnt > 0) { 863 for (size_t i = 0; i < iface->dhcpv6_relay_server_addrs6_cnt; i++) { 864 relay_client_request(addr, data, len, iface, &iface->dhcpv6_relay_server_addrs6[i]); 865 } 866 } else { 867 relay_client_request(addr, data, len, iface, NULL); 868 } 869 } 870 } 871 872 873 /* Relay server response (regular relay server handling) */ 874 static void relay_server_response(uint8_t *data, size_t len) 875 { 876 /* Information we need to gather */ 877 uint8_t *payload_data = NULL; 878 size_t payload_len = 0; 879 int32_t ifaceidx = 0; 880 struct sockaddr_in6 target = {AF_INET6, htons(DHCPV6_CLIENT_PORT), 881 0, IN6ADDR_ANY_INIT, 0}; 882 uint16_t otype, olen; 883 uint8_t *odata, *end = data + len; 884 /* Relay DHCPv6 reply from server to client */ 885 struct dhcpv6_relay_header *h = (void*)data; 886 887 debug("Got a DHCPv6-relay-reply"); 888 889 if (len < sizeof(*h) || h->msg_type != DHCPV6_MSG_RELAY_REPL) 890 return; 891 892 memcpy(&target.sin6_addr, &h->peer_address, sizeof(struct in6_addr)); 893 894 /* Go through options and find what we need */ 895 dhcpv6_for_each_option(h->options, end, otype, olen, odata) { 896 if (otype == DHCPV6_OPT_INTERFACE_ID 897 && olen == sizeof(ifaceidx)) { 898 memcpy(&ifaceidx, odata, sizeof(ifaceidx)); 899 } else if (otype == DHCPV6_OPT_RELAY_MSG) { 900 payload_data = odata; 901 payload_len = olen; 902 } 903 } 904 905 /* Invalid interface-id or basic payload */ 906 struct interface *iface = odhcpd_get_interface_by_index(ifaceidx); 907 if (!iface || iface->master || !payload_data || payload_len < 4) 908 return; 909 910 bool is_authenticated = false; 911 struct in6_addr *dns_addrs6 = NULL; 912 size_t dns_addrs6_cnt = 0; 913 914 /* If the payload is relay-reply we have to send to the server port */ 915 if (payload_data[0] == DHCPV6_MSG_RELAY_REPL) { 916 target.sin6_port = htons(DHCPV6_SERVER_PORT); 917 } else { /* Go through the payload data */ 918 struct dhcpv6_client_header *dch = (void*)payload_data; 919 end = payload_data + payload_len; 920 921 dhcpv6_for_each_option(&dch[1], end, otype, olen, odata) { 922 if (otype == DHCPV6_OPT_DNS_SERVERS && olen >= sizeof(struct in6_addr)) { 923 dns_addrs6 = (struct in6_addr*)odata; 924 dns_addrs6_cnt = olen / sizeof(struct in6_addr); 925 } else if (otype == DHCPV6_OPT_AUTH) { 926 is_authenticated = true; 927 } 928 } 929 } 930 931 /* Rewrite DNS servers if requested */ 932 if (iface->always_rewrite_dns && dns_addrs6 && dns_addrs6_cnt > 0) { 933 if (is_authenticated) 934 return; /* Impossible to rewrite */ 935 936 const struct in6_addr *rewrite = iface->dns_addrs6; 937 struct in6_addr addr; 938 size_t rewrite_cnt = iface->dns_addrs6_cnt; 939 940 if (rewrite_cnt == 0) { 941 if (odhcpd_get_interface_dns_addr6(iface, &addr)) 942 return; /* Unable to get interface address */ 943 944 rewrite = &addr; 945 rewrite_cnt = 1; 946 } 947 948 /* Copy over any other addresses */ 949 for (size_t i = 0; i < dns_addrs6_cnt; ++i) { 950 size_t j = (i < rewrite_cnt) ? i : rewrite_cnt - 1; 951 memcpy(&dns_addrs6[i], &rewrite[j], sizeof(*rewrite)); 952 } 953 } 954 955 struct iovec iov = {payload_data, payload_len}; 956 957 debug("Sending a DHCPv6-reply on %s", iface->name); 958 959 odhcpd_send(iface->dhcpv6_event.uloop.fd, &target, &iov, 1, iface); 960 } 961 962 static struct odhcpd_ipaddr *relay_link_address(struct interface *iface) 963 { 964 struct odhcpd_ipaddr *addr = NULL; 965 time_t now = odhcpd_time(); 966 967 for (size_t i = 0; i < iface->addr6_len; i++) { 968 if (iface->addr6[i].valid_lt <= (uint32_t)now) 969 continue; 970 971 if (iface->addr6[i].preferred_lt > (uint32_t)now) { 972 addr = &iface->addr6[i]; 973 break; 974 } 975 976 if (!addr || (iface->addr6[i].valid_lt > addr->valid_lt)) 977 addr = &iface->addr6[i]; 978 } 979 980 return addr; 981 } 982 983 /* Relay client request (regular DHCPv6-relay) */ 984 static void relay_client_request(struct sockaddr_in6 *source, 985 const void *data, size_t len, struct interface *iface, 986 struct in6_addr *dest) 987 { 988 const struct dhcpv6_relay_header *h = data; 989 /* Construct our forwarding envelope */ 990 struct dhcpv6_relay_forward_envelope hdr = { 991 .msg_type = DHCPV6_MSG_RELAY_FORW, 992 .hop_count = 0, 993 .interface_id_type = htons(DHCPV6_OPT_INTERFACE_ID), 994 .interface_id_len = htons(sizeof(uint32_t)), 995 .relay_message_type = htons(DHCPV6_OPT_RELAY_MSG), 996 .relay_message_len = htons(len), 997 }; 998 struct iovec iov[2] = {{&hdr, sizeof(hdr)}, {(void *)data, len}}; 999 struct interface *c; 1000 struct odhcpd_ipaddr *ip; 1001 struct sockaddr_in6 s; 1002 1003 /* A bare UDP socket can deliver a zero/short payload; the relay-reply 1004 * path (relay_server_response) checks this but the client-side relay 1005 * did not. relay_client_request() reads h->msg_type, plus h->hop_count 1006 * for a RELAY_FORW, out of the relay header and forwards the rest 1007 * verbatim, so require at least those two leading header bytes. */ 1008 if (len < offsetof(struct dhcpv6_relay_header, link_address)) 1009 return; 1010 1011 switch (h->msg_type) { 1012 /* Valid message types from clients */ 1013 case DHCPV6_MSG_SOLICIT: 1014 case DHCPV6_MSG_REQUEST: 1015 case DHCPV6_MSG_CONFIRM: 1016 case DHCPV6_MSG_RENEW: 1017 case DHCPV6_MSG_REBIND: 1018 case DHCPV6_MSG_RELEASE: 1019 case DHCPV6_MSG_DECLINE: 1020 case DHCPV6_MSG_INFORMATION_REQUEST: 1021 case DHCPV6_MSG_RELAY_FORW: 1022 case DHCPV6_MSG_DHCPV4_QUERY: 1023 break; 1024 /* Invalid message types from clients i.e. server messages */ 1025 case DHCPV6_MSG_ADVERTISE: 1026 case DHCPV6_MSG_REPLY: 1027 case DHCPV6_MSG_RECONFIGURE: 1028 case DHCPV6_MSG_RELAY_REPL: 1029 case DHCPV6_MSG_DHCPV4_RESPONSE: 1030 return; 1031 default: 1032 break; 1033 } 1034 1035 debug("Got a DHCPv6-request on %s", iface->name); 1036 1037 if (h->msg_type == DHCPV6_MSG_RELAY_FORW) { /* handle relay-forward */ 1038 if (h->hop_count >= DHCPV6_HOP_COUNT_LIMIT) 1039 return; /* Invalid hop count */ 1040 1041 hdr.hop_count = h->hop_count + 1; 1042 } 1043 1044 /* use memcpy here as the destination fields are unaligned */ 1045 memcpy(&hdr.peer_address, &source->sin6_addr, sizeof(struct in6_addr)); 1046 memcpy(&hdr.interface_id_data, &iface->ifindex, sizeof(iface->ifindex)); 1047 1048 /* Detect public IP of slave interface to use as link-address */ 1049 ip = relay_link_address(iface); 1050 if (ip) 1051 memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address)); 1052 1053 memset(&s, 0, sizeof(s)); 1054 s.sin6_family = AF_INET6; 1055 s.sin6_port = htons(DHCPV6_SERVER_PORT); 1056 1057 if (dest) 1058 s.sin6_addr = *dest; 1059 else 1060 inet_pton(AF_INET6, ALL_DHCPV6_SERVERS, &s.sin6_addr); 1061 1062 avl_for_each_element(&interfaces, c, avl) { 1063 if (!c->master || c->dhcpv6 != MODE_RELAY) 1064 continue; 1065 1066 if (!ip) { 1067 /* No suitable address! Is the slave not configured yet? 1068 * Detect public IP of master interface and use it instead 1069 * This is WRONG and probably violates the RFC. However 1070 * otherwise we have a hen and egg problem because the 1071 * slave-interface cannot be auto-configured. */ 1072 ip = relay_link_address(c); 1073 if (!ip) 1074 continue; /* Could not obtain a suitable address */ 1075 1076 memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address)); 1077 ip = NULL; 1078 } 1079 1080 debug("Sending a DHCPv6-relay-forward on %s", c->name); 1081 1082 odhcpd_send(c->dhcpv6_event.uloop.fd, &s, iov, 2, c); 1083 } 1084 } 1085
This page was automatically generated by LXR 0.3.1. • OpenWrt