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