1 /** 2 * SPDX-License-Identifier: BSD-2-Clause-Patent 3 * 4 * SPDX-FileCopyrightText: Copyright (c) 2024 SoftAtHome 5 * 6 * Redistribution and use in source and binary forms, with or 7 * without modification, are permitted provided that the following 8 * conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * Subject to the terms and conditions of this license, each 19 * copyright holder and contributor hereby grants to those receiving 20 * rights under this license a perpetual, worldwide, non-exclusive, 21 * no-charge, royalty-free, irrevocable (except for failure to 22 * satisfy the conditions of this license) patent license to make, 23 * have made, use, offer to sell, sell, import, and otherwise 24 * transfer this software, where such license applies only to those 25 * patent claims, already acquired or hereafter acquired, licensable 26 * by such copyright holder or contributor that are necessarily 27 * infringed by: 28 * 29 * (a) their Contribution(s) (the licensed copyrights of copyright 30 * holders and non-copyrightable additions of contributors, in 31 * source or binary form) alone; or 32 * 33 * (b) combination of their Contribution(s) with the work of 34 * authorship to which such Contribution(s) was added by such 35 * copyright holder or contributor, if, at the time the Contribution 36 * is added, such addition causes such combination to be necessarily 37 * infringed. The patent license shall not apply to any other 38 * combinations which include the Contribution. 39 * 40 * Except as expressly stated above, no rights or licenses from any 41 * copyright holder or contributor is granted under this license, 42 * whether expressly, by implication, estoppel or otherwise. 43 * 44 * DISCLAIMER 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 47 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 48 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 49 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 50 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 51 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 53 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 54 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 55 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 57 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 58 * POSSIBILITY OF SUCH DAMAGE. 59 * 60 */ 61 62 #include <arpa/inet.h> 63 #include <inttypes.h> 64 #include <libubox/blobmsg.h> 65 #include <resolv.h> 66 #include <stdio.h> 67 #include <sys/types.h> 68 #include <syslog.h> 69 70 #include "config.h" 71 #include "odhcp6c.h" 72 #include "ubus.h" 73 74 #define CHECK(stmt) \ 75 do { \ 76 int ret = (stmt); \ 77 if (ret != UBUS_STATUS_OK) \ 78 { \ 79 syslog(LOG_ERR, "%s failed: %s (%d)", #stmt, ubus_strerror(ret), ret); \ 80 return ret; \ 81 } \ 82 } while (0) 83 84 #define CHECK_ALLOC(buf) \ 85 do { \ 86 if (buf == NULL) \ 87 { \ 88 return UBUS_STATUS_NO_MEMORY; \ 89 } \ 90 } while (0) 91 92 enum entry_type { 93 ENTRY_ADDRESS, 94 ENTRY_HOST, 95 ENTRY_ROUTE, 96 ENTRY_PREFIX 97 }; 98 99 enum { 100 RECONFIGURE_DHCP_ATTR_DSCP, 101 RECONFIGURE_DHCP_ATTR_RELEASE, 102 RECONFIGURE_DHCP_ATTR_SOL_TIMEOUT, 103 RECONFIGURE_DHCP_ATTR_SK_PRIORITY, 104 RECONFIGURE_DHCP_ATTR_OPT_REQUESTED, 105 RECONFIGURE_DHCP_ATTR_OPT_STRICT, 106 RECONFIGURE_DHCP_ATTR_OPT_RECONFIGURE, 107 RECONFIGURE_DHCP_ATTR_OPT_FQDN, 108 RECONFIGURE_DHCP_ATTR_OPT_UNICAST, 109 RECONFIGURE_DHCP_ATTR_OPT_SEND, 110 RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES, 111 RECONFIGURE_DHCP_ATTR_REQ_PREFIXES, 112 RECONFIGURE_DHCP_ATTR_STATEFUL, 113 RECONFIGURE_DHCP_ATTR_MSG_SOLICIT, 114 RECONFIGURE_DHCP_ATTR_MSG_REQUEST, 115 RECONFIGURE_DHCP_ATTR_MSG_RENEW, 116 RECONFIGURE_DHCP_ATTR_MSG_REBIND, 117 RECONFIGURE_DHCP_ATTR_MSG_RELEASE, 118 RECONFIGURE_DHCP_ATTR_MSG_DECLINE, 119 RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ, 120 RECONFIGURE_DHCP_ATTR_IRT_DEFAULT, 121 RECONFIGURE_DHCP_ATTR_IRT_MIN, 122 RECONFIGURE_DHCP_ATTR_RAND_FACTOR, 123 RECONFIGURE_DHCP_ATTR_AUTH_PROTO, 124 RECONFIGURE_DHCP_ATTR_AUTH_TOKEN, 125 RECONFIGURE_DHCP_ATTR_MAX, 126 }; 127 128 struct ubus_context *ubus = NULL; 129 static struct blob_buf b; 130 static char ubus_name[24]; 131 132 static int ubus_handle_get_state(struct ubus_context *ctx, struct ubus_object *obj, 133 struct ubus_request_data *req, const char *method, struct blob_attr *msg); 134 static int ubus_handle_get_stats(struct ubus_context *ctx, struct ubus_object *obj, 135 struct ubus_request_data *req, const char *method, struct blob_attr *msg); 136 static int ubus_handle_reset_stats(struct ubus_context *ctx, struct ubus_object *obj, 137 struct ubus_request_data *req, const char *method, struct blob_attr *msg); 138 static int ubus_handle_reconfigure_dhcp(struct ubus_context *ctx, struct ubus_object *obj, 139 struct ubus_request_data *req, const char *method, struct blob_attr *msg); 140 static int ubus_handle_renew(struct ubus_context *ctx, struct ubus_object *obj, 141 struct ubus_request_data *req, const char *method, struct blob_attr *msg); 142 static int ubus_handle_release(struct ubus_context *ctx, struct ubus_object *obj, 143 struct ubus_request_data *req, const char *method, struct blob_attr *msg); 144 145 static const struct blobmsg_policy reconfigure_dhcp_policy[RECONFIGURE_DHCP_ATTR_MAX] = { 146 [RECONFIGURE_DHCP_ATTR_DSCP] = { .name = "dscp", .type = BLOBMSG_TYPE_INT32}, 147 [RECONFIGURE_DHCP_ATTR_RELEASE] = { .name = "release", .type = BLOBMSG_TYPE_BOOL}, 148 [RECONFIGURE_DHCP_ATTR_SOL_TIMEOUT] = { .name = "sol_timeout", .type = BLOBMSG_TYPE_INT32}, 149 [RECONFIGURE_DHCP_ATTR_SK_PRIORITY] = { .name = "sk_prio", .type = BLOBMSG_TYPE_INT32}, 150 [RECONFIGURE_DHCP_ATTR_OPT_REQUESTED] = { .name = "opt_requested", .type = BLOBMSG_TYPE_ARRAY}, 151 [RECONFIGURE_DHCP_ATTR_OPT_STRICT] = { .name = "opt_strict", .type = BLOBMSG_TYPE_BOOL}, 152 [RECONFIGURE_DHCP_ATTR_OPT_RECONFIGURE] = { .name = "opt_reconfigure", .type = BLOBMSG_TYPE_BOOL}, 153 [RECONFIGURE_DHCP_ATTR_OPT_FQDN] = { .name = "opt_fqdn", .type = BLOBMSG_TYPE_BOOL}, 154 [RECONFIGURE_DHCP_ATTR_OPT_UNICAST] = { .name = "opt_unicast", .type = BLOBMSG_TYPE_BOOL}, 155 [RECONFIGURE_DHCP_ATTR_OPT_SEND] = { .name = "opt_send", .type = BLOBMSG_TYPE_ARRAY}, 156 [RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES] = { .name = "req_addresses", .type = BLOBMSG_TYPE_STRING}, 157 [RECONFIGURE_DHCP_ATTR_REQ_PREFIXES] = { .name = "req_prefixes", .type = BLOBMSG_TYPE_INT32}, 158 [RECONFIGURE_DHCP_ATTR_STATEFUL] = { .name = "stateful_only", .type = BLOBMSG_TYPE_BOOL}, 159 [RECONFIGURE_DHCP_ATTR_MSG_SOLICIT] = { .name = "msg_solicit", .type = BLOBMSG_TYPE_TABLE}, 160 [RECONFIGURE_DHCP_ATTR_MSG_REQUEST] = { .name = "msg_request", .type = BLOBMSG_TYPE_TABLE}, 161 [RECONFIGURE_DHCP_ATTR_MSG_RENEW] = { .name = "msg_renew", .type = BLOBMSG_TYPE_TABLE}, 162 [RECONFIGURE_DHCP_ATTR_MSG_REBIND] = { .name = "msg_rebind", .type = BLOBMSG_TYPE_TABLE}, 163 [RECONFIGURE_DHCP_ATTR_MSG_RELEASE] = { .name = "msg_release", .type = BLOBMSG_TYPE_TABLE}, 164 [RECONFIGURE_DHCP_ATTR_MSG_DECLINE] = { .name = "msg_decline", .type = BLOBMSG_TYPE_TABLE}, 165 [RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ] = { .name = "msg_inforeq", .type = BLOBMSG_TYPE_TABLE}, 166 [RECONFIGURE_DHCP_ATTR_IRT_DEFAULT] = { .name = "irt_default", .type = BLOBMSG_TYPE_INT32}, 167 [RECONFIGURE_DHCP_ATTR_IRT_MIN] = { .name = "irt_min", .type = BLOBMSG_TYPE_INT32}, 168 [RECONFIGURE_DHCP_ATTR_RAND_FACTOR] = { .name = "rand_factor", .type = BLOBMSG_TYPE_INT32}, 169 [RECONFIGURE_DHCP_ATTR_AUTH_PROTO] = { .name = "auth_protocol", .type = BLOBMSG_TYPE_STRING}, 170 [RECONFIGURE_DHCP_ATTR_AUTH_TOKEN] = { .name = "auth_token", .type = BLOBMSG_TYPE_STRING}, 171 }; 172 173 static struct ubus_method odhcp6c_object_methods[] = { 174 UBUS_METHOD_NOARG("get_state", ubus_handle_get_state), 175 UBUS_METHOD_NOARG("get_statistics", ubus_handle_get_stats), 176 UBUS_METHOD_NOARG("reset_statistics", ubus_handle_reset_stats), 177 UBUS_METHOD("reconfigure_dhcp", ubus_handle_reconfigure_dhcp, reconfigure_dhcp_policy), 178 UBUS_METHOD_NOARG("renew", ubus_handle_renew), 179 UBUS_METHOD_NOARG("release", ubus_handle_release), 180 }; 181 182 static struct ubus_object_type odhcp6c_object_type = 183 UBUS_OBJECT_TYPE("odhcp6c", odhcp6c_object_methods); 184 185 static struct ubus_object odhcp6c_object = { 186 .name = NULL, 187 .type = &odhcp6c_object_type, 188 .methods = odhcp6c_object_methods, 189 .n_methods = ARRAY_SIZE(odhcp6c_object_methods), 190 }; 191 192 static void ubus_disconnect_cb(struct ubus_context *ubus) 193 { 194 int ret; 195 196 ret = ubus_reconnect(ubus, NULL); 197 if (ret) { 198 syslog(LOG_ERR, "Cannot reconnect to ubus: %s", ubus_strerror(ret)); 199 ubus_destroy(ubus); 200 } 201 } 202 203 char *ubus_init(const char* interface) 204 { 205 int ret = 0; 206 207 if (!(ubus = ubus_connect(NULL))) 208 return NULL; 209 210 snprintf(ubus_name, 24, "odhcp6c.%s", interface); 211 odhcp6c_object.name = ubus_name; 212 213 ret = ubus_add_object(ubus, &odhcp6c_object); 214 if (ret) { 215 ubus_destroy(ubus); 216 return (char *)ubus_strerror(ret); 217 } 218 219 ubus->connection_lost = ubus_disconnect_cb; 220 return NULL; 221 } 222 223 struct ubus_context *ubus_get_ctx(void) 224 { 225 return ubus; 226 } 227 228 void ubus_destroy(struct ubus_context *ubus) 229 { 230 syslog(LOG_NOTICE, "Disconnecting from ubus"); 231 232 if (ubus != NULL) 233 ubus_free(ubus); 234 ubus = NULL; 235 236 /* Forces re-initialization when we're reusing the same definitions later on. */ 237 odhcp6c_object.id = 0; 238 odhcp6c_object.id = 0; 239 } 240 241 static int ipv6_to_blob(const char *name, 242 const struct in6_addr *addr, size_t cnt) 243 { 244 void *arr = blobmsg_open_array(&b, name); 245 246 for (size_t i = 0; i < cnt; ++i) { 247 char *buf = blobmsg_alloc_string_buffer(&b, NULL, INET6_ADDRSTRLEN); 248 CHECK_ALLOC(buf); 249 inet_ntop(AF_INET6, &addr[i], buf, INET6_ADDRSTRLEN); 250 blobmsg_add_string_buffer(&b); 251 } 252 253 blobmsg_close_array(&b, arr); 254 return UBUS_STATUS_OK; 255 } 256 257 static int fqdn_to_blob(const char *name, const uint8_t *fqdn, size_t len) 258 { 259 size_t buf_size = len > 255 ? 256 : (len + 1); 260 const uint8_t *fqdn_end = fqdn + len; 261 char *buf = NULL; 262 263 void *arr = blobmsg_open_array(&b, name); 264 265 while (fqdn < fqdn_end) { 266 buf = blobmsg_alloc_string_buffer(&b, name, buf_size); 267 CHECK_ALLOC(buf); 268 int l = dn_expand(fqdn, fqdn_end, fqdn, buf, buf_size); 269 if (l < 1) { 270 buf[0] = '\0'; 271 blobmsg_add_string_buffer(&b); 272 break; 273 } 274 buf[l] = '\0'; 275 blobmsg_add_string_buffer(&b); 276 fqdn += l; 277 } 278 279 blobmsg_close_array(&b, arr); 280 return UBUS_STATUS_OK; 281 } 282 283 static int bin_to_blob(uint8_t *opts, size_t len) 284 { 285 uint8_t *oend = opts + len, *odata; 286 uint16_t otype, olen; 287 288 dhcpv6_for_each_option(opts, oend, otype, olen, odata) { 289 char name[14]; 290 char *buf; 291 292 snprintf(name, 14, "OPTION_%hu", otype); 293 buf = blobmsg_alloc_string_buffer(&b, name, olen * 2); 294 CHECK_ALLOC(buf); 295 script_hexlify(buf, odata, olen); 296 blobmsg_add_string_buffer(&b); 297 } 298 return UBUS_STATUS_OK; 299 } 300 301 static int entry_to_blob(const char *name, const void *data, size_t len, enum entry_type type) 302 { 303 const struct odhcp6c_entry *e = data; 304 305 void *arr = blobmsg_open_array(&b, name); 306 307 for (size_t i = 0; i < len / sizeof(*e); ++i) { 308 void *entry = blobmsg_open_table(&b, name); 309 310 /* 311 * The only invalid entries allowed to be passed to the script are prefix entries. 312 * This will allow immediate removal of the old ipv6-prefix-assignment that might 313 * otherwise be kept for up to 2 hours (see L-13 requirement of RFC 7084). 314 */ 315 if (!e[i].valid && type != ENTRY_PREFIX) 316 continue; 317 318 char *buf = blobmsg_alloc_string_buffer(&b, "target", INET6_ADDRSTRLEN); 319 CHECK_ALLOC(buf); 320 inet_ntop(AF_INET6, &e[i].target, buf, INET6_ADDRSTRLEN); 321 blobmsg_add_string_buffer(&b); 322 323 if (type != ENTRY_HOST) { 324 blobmsg_add_u8(&b, "length", e[i].length); 325 if (type == ENTRY_ROUTE) { 326 if (!IN6_IS_ADDR_UNSPECIFIED(&e[i].router)) { 327 buf = blobmsg_alloc_string_buffer(&b, "router", INET6_ADDRSTRLEN); 328 CHECK_ALLOC(buf); 329 inet_ntop(AF_INET6, &e[i].router, buf, INET6_ADDRSTRLEN); 330 blobmsg_add_string_buffer(&b); 331 } 332 333 blobmsg_add_u32(&b, "valid", e[i].valid); 334 blobmsg_add_u16(&b, "priority", e[i].priority); 335 } else { 336 blobmsg_add_u32(&b, "valid", e[i].valid); 337 blobmsg_add_u32(&b, "preferred", e[i].preferred); 338 blobmsg_add_u32(&b, "t1", e[i].t1); 339 blobmsg_add_u32(&b, "t2", e[i].t2); 340 } 341 342 if (type == ENTRY_PREFIX && ntohl(e[i].iaid) != 1) { 343 blobmsg_add_u32(&b, "iaid", ntohl(e[i].iaid)); 344 } 345 346 if (type == ENTRY_PREFIX && e[i].priority) { 347 // priority and router are abused for prefix exclusion 348 buf = blobmsg_alloc_string_buffer(&b, "excluded", INET6_ADDRSTRLEN); 349 CHECK_ALLOC(buf); 350 inet_ntop(AF_INET6, &e[i].router, buf, INET6_ADDRSTRLEN); 351 blobmsg_add_string_buffer(&b); 352 blobmsg_add_u16(&b, "excluded_length", e[i].priority); 353 } 354 } 355 356 blobmsg_close_table(&b, entry); 357 } 358 359 blobmsg_close_array(&b, arr); 360 return UBUS_STATUS_OK; 361 } 362 363 static int search_to_blob(const char *name, const uint8_t *start, size_t len) 364 { 365 void *arr = blobmsg_open_array(&b, name); 366 char *buf = NULL; 367 368 for (struct odhcp6c_entry *e = (struct odhcp6c_entry*)start; 369 (uint8_t*)e < &start[len] && 370 (uint8_t*)odhcp6c_next_entry(e) <= &start[len]; 371 e = odhcp6c_next_entry(e)) { 372 if (!e->valid) 373 continue; 374 375 buf = blobmsg_alloc_string_buffer(&b, NULL, e->auxlen+1); 376 CHECK_ALLOC(buf); 377 buf = mempcpy(buf, e->auxtarget, e->auxlen); 378 *buf = '\0'; 379 blobmsg_add_string_buffer(&b); 380 } 381 382 blobmsg_close_array(&b, arr); 383 return UBUS_STATUS_OK; 384 } 385 386 static int s46_to_blob_portparams(const uint8_t *data, size_t len) 387 { 388 uint8_t *odata; 389 uint16_t otype, olen; 390 391 dhcpv6_for_each_option(data, &data[len], otype, olen, odata) { 392 if (otype == DHCPV6_OPT_S46_PORTPARAMS && 393 olen == sizeof(struct dhcpv6_s46_portparams)) { 394 struct dhcpv6_s46_portparams *params = (void*)odata; 395 blobmsg_add_u8(&b, "offset", params->offset); 396 blobmsg_add_u8(&b, "psidlen", params->psid_len); 397 blobmsg_add_u16(&b, "psid", ntohs(params->psid)); 398 } 399 } 400 return UBUS_STATUS_OK; 401 } 402 403 static int s46_to_blob(enum odhcp6c_state state, const uint8_t *data, size_t len) 404 { 405 const char *name = (state == STATE_S46_MAPE) ? "MAPE" : 406 (state == STATE_S46_MAPT) ? "MAPT" : "LW4O6"; 407 408 if (len == 0) 409 return UBUS_STATUS_OK; 410 411 char *buf = NULL; 412 void *arr = blobmsg_open_array(&b, name); 413 414 const char *type = (state == STATE_S46_MAPE) ? "map-e" : 415 (state == STATE_S46_MAPT) ? "map-t" : "lw4o6"; 416 417 uint8_t *odata; 418 uint16_t otype, olen; 419 420 dhcpv6_for_each_option(data, &data[len], otype, olen, odata) { 421 struct dhcpv6_s46_rule *rule = (struct dhcpv6_s46_rule*)odata; 422 struct dhcpv6_s46_v4v6bind *bind = (struct dhcpv6_s46_v4v6bind*)odata; 423 424 void *option = blobmsg_open_table(&b, NULL); 425 426 if (state != STATE_S46_LW && otype == DHCPV6_OPT_S46_RULE && 427 olen >= sizeof(struct dhcpv6_s46_rule)) { 428 struct in6_addr in6 = IN6ADDR_ANY_INIT; 429 430 size_t prefix6len = rule->prefix6_len; 431 prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1; 432 433 if (prefix6len > sizeof(in6) || 434 olen < sizeof(struct dhcpv6_s46_rule) + prefix6len) 435 continue; 436 437 memcpy(&in6, rule->ipv6_prefix, prefix6len); 438 439 buf = blobmsg_alloc_string_buffer(&b, "ipv4prefix", INET_ADDRSTRLEN); 440 CHECK_ALLOC(buf); 441 inet_ntop(AF_INET, &rule->ipv4_prefix, buf, INET_ADDRSTRLEN); 442 blobmsg_add_string_buffer(&b); 443 444 buf = blobmsg_alloc_string_buffer(&b, "ipv6prefix", INET6_ADDRSTRLEN); 445 CHECK_ALLOC(buf); 446 inet_ntop(AF_INET6, &in6, buf, INET6_ADDRSTRLEN); 447 blobmsg_add_string_buffer(&b); 448 449 blobmsg_add_u8(&b, "fmr", rule->flags); 450 blobmsg_add_string(&b, "type", type); 451 blobmsg_add_u8(&b, "ealen", rule->ea_len); 452 blobmsg_add_u8(&b, "prefix4len", rule->prefix4_len); 453 blobmsg_add_u8(&b, "prefix6len", rule->prefix6_len); 454 455 s46_to_blob_portparams(&rule->ipv6_prefix[prefix6len], 456 olen - sizeof(*rule) - prefix6len); 457 458 dhcpv6_for_each_option(data, &data[len], otype, olen, odata) { 459 if (state != STATE_S46_MAPT && otype == DHCPV6_OPT_S46_BR && 460 olen == sizeof(struct in6_addr)) { 461 buf = blobmsg_alloc_string_buffer(&b, "br", INET6_ADDRSTRLEN); 462 CHECK_ALLOC(buf); 463 inet_ntop(AF_INET6, odata, buf, INET6_ADDRSTRLEN); 464 blobmsg_add_string_buffer(&b); 465 } else if (state == STATE_S46_MAPT && otype == DHCPV6_OPT_S46_DMR && 466 olen >= sizeof(struct dhcpv6_s46_dmr)) { 467 struct dhcpv6_s46_dmr *dmr = (struct dhcpv6_s46_dmr*)odata; 468 memset(&in6, 0, sizeof(in6)); 469 size_t prefix6len = dmr->dmr_prefix6_len; 470 prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1; 471 472 if (prefix6len > sizeof(in6) || 473 olen < sizeof(struct dhcpv6_s46_dmr) + prefix6len) 474 continue; 475 476 buf = blobmsg_alloc_string_buffer(&b, "dmr", INET6_ADDRSTRLEN); 477 CHECK_ALLOC(buf); 478 inet_ntop(AF_INET6, &in6, buf, INET6_ADDRSTRLEN); 479 blobmsg_add_string_buffer(&b); 480 blobmsg_add_u8(&b, "dmrprefix6len", dmr->dmr_prefix6_len); 481 } 482 } 483 } else if (state == STATE_S46_LW && otype == DHCPV6_OPT_S46_V4V6BIND && 484 olen >= sizeof(struct dhcpv6_s46_v4v6bind)) { 485 struct in6_addr in6 = IN6ADDR_ANY_INIT; 486 487 size_t prefix6len = bind->bindprefix6_len; 488 prefix6len = (prefix6len % 8 == 0) ? prefix6len / 8 : prefix6len / 8 + 1; 489 490 if (prefix6len > sizeof(in6) || 491 olen < sizeof(struct dhcpv6_s46_v4v6bind) + prefix6len) 492 continue; 493 494 memcpy(&in6, bind->bind_ipv6_prefix, prefix6len); 495 496 buf = blobmsg_alloc_string_buffer(&b, "ipv4prefix", INET_ADDRSTRLEN); 497 CHECK_ALLOC(buf); 498 inet_ntop(AF_INET, &bind->ipv4_address, buf, INET_ADDRSTRLEN); 499 blobmsg_add_string_buffer(&b); 500 501 buf = blobmsg_alloc_string_buffer(&b, "ipv6prefix", INET6_ADDRSTRLEN); 502 CHECK_ALLOC(buf); 503 inet_ntop(AF_INET6, &in6, buf, INET6_ADDRSTRLEN); 504 blobmsg_add_string_buffer(&b); 505 506 blobmsg_add_string(&b, "type", type); 507 blobmsg_add_u8(&b, "prefix4len", 32); 508 blobmsg_add_u8(&b, "prefix6len", bind->bindprefix6_len); 509 510 s46_to_blob_portparams(&bind->bind_ipv6_prefix[prefix6len], 511 olen - sizeof(*bind) - prefix6len); 512 513 dhcpv6_for_each_option(data, &data[len], otype, olen, odata) { 514 if (otype == DHCPV6_OPT_S46_BR && olen == sizeof(struct in6_addr)) { 515 buf = blobmsg_alloc_string_buffer(&b, "br", INET6_ADDRSTRLEN); 516 CHECK_ALLOC(buf); 517 inet_ntop(AF_INET6, odata, buf, INET6_ADDRSTRLEN); 518 blobmsg_add_string_buffer(&b); 519 } 520 } 521 } 522 blobmsg_close_table(&b, option); 523 } 524 525 blobmsg_close_array(&b, arr); 526 return UBUS_STATUS_OK; 527 } 528 529 static int states_to_blob(void) 530 { 531 char *buf = NULL; 532 size_t dns_len, search_len, custom_len, sntp_ip_len, ntp_ip_len, ntp_dns_len; 533 size_t sip_ip_len, sip_fqdn_len, aftr_name_len, cer_len, addr_len; 534 size_t s46_mapt_len, s46_mape_len, s46_lw_len, passthru_len; 535 struct in6_addr *addr = odhcp6c_get_state(STATE_SERVER_ADDR, &addr_len); 536 struct in6_addr *dns = odhcp6c_get_state(STATE_DNS, &dns_len); 537 uint8_t *search = odhcp6c_get_state(STATE_SEARCH, &search_len); 538 uint8_t *custom = odhcp6c_get_state(STATE_CUSTOM_OPTS, &custom_len); 539 struct in6_addr *sntp = odhcp6c_get_state(STATE_SNTP_IP, &sntp_ip_len); 540 struct in6_addr *ntp = odhcp6c_get_state(STATE_NTP_IP, &ntp_ip_len); 541 uint8_t *ntp_dns = odhcp6c_get_state(STATE_NTP_FQDN, &ntp_dns_len); 542 struct in6_addr *sip = odhcp6c_get_state(STATE_SIP_IP, &sip_ip_len); 543 uint8_t *sip_fqdn = odhcp6c_get_state(STATE_SIP_FQDN, &sip_fqdn_len); 544 uint8_t *aftr_name = odhcp6c_get_state(STATE_AFTR_NAME, &aftr_name_len); 545 struct in6_addr *cer = odhcp6c_get_state(STATE_CER, &cer_len); 546 uint8_t *s46_mapt = odhcp6c_get_state(STATE_S46_MAPT, &s46_mapt_len); 547 uint8_t *s46_mape = odhcp6c_get_state(STATE_S46_MAPE, &s46_mape_len); 548 uint8_t *s46_lw = odhcp6c_get_state(STATE_S46_LW, &s46_lw_len); 549 uint8_t *passthru = odhcp6c_get_state(STATE_PASSTHRU, &passthru_len); 550 551 size_t prefix_len, address_len, ra_pref_len, 552 ra_route_len, ra_dns_len, ra_search_len; 553 uint8_t *prefix = odhcp6c_get_state(STATE_IA_PD, &prefix_len); 554 uint8_t *address = odhcp6c_get_state(STATE_IA_NA, &address_len); 555 uint8_t *ra_pref = odhcp6c_get_state(STATE_RA_PREFIX, &ra_pref_len); 556 uint8_t *ra_route = odhcp6c_get_state(STATE_RA_ROUTE, &ra_route_len); 557 uint8_t *ra_dns = odhcp6c_get_state(STATE_RA_DNS, &ra_dns_len); 558 uint8_t *ra_search = odhcp6c_get_state(STATE_RA_SEARCH, &ra_search_len); 559 560 blob_buf_init(&b, BLOBMSG_TYPE_TABLE); 561 562 blobmsg_add_string(&b, "DHCPV6_STATE", dhcpv6_state_to_str(dhcpv6_get_state())); 563 564 CHECK(ipv6_to_blob("SERVER", addr, addr_len / sizeof(*addr))); 565 CHECK(ipv6_to_blob("RDNSS", dns, dns_len / sizeof(*dns))); 566 CHECK(ipv6_to_blob("SNTP_IP", sntp, sntp_ip_len / sizeof(*sntp))); 567 CHECK(ipv6_to_blob("NTP_IP", ntp, ntp_ip_len / sizeof(*ntp))); 568 CHECK(fqdn_to_blob("NTP_FQDN", ntp_dns, ntp_dns_len)); 569 CHECK(ipv6_to_blob("SIP_IP", sip, sip_ip_len / sizeof(*sip))); 570 CHECK(fqdn_to_blob("DOMAINS", search, search_len)); 571 CHECK(fqdn_to_blob("SIP_DOMAIN", sip_fqdn, sip_fqdn_len)); 572 CHECK(fqdn_to_blob("AFTR", aftr_name, aftr_name_len)); 573 CHECK(ipv6_to_blob("CER", cer, cer_len / sizeof(*cer))); 574 CHECK(s46_to_blob(STATE_S46_MAPE, s46_mape, s46_mape_len)); 575 CHECK(s46_to_blob(STATE_S46_MAPT, s46_mapt, s46_mapt_len)); 576 CHECK(s46_to_blob(STATE_S46_LW, s46_lw, s46_lw_len)); 577 CHECK(bin_to_blob(custom, custom_len)); 578 579 if (odhcp6c_is_bound()) { 580 CHECK(entry_to_blob("PREFIXES", prefix, prefix_len, ENTRY_PREFIX)); 581 CHECK(entry_to_blob("ADDRESSES", address, address_len, ENTRY_ADDRESS)); 582 } 583 584 CHECK(entry_to_blob("RA_ADDRESSES", ra_pref, ra_pref_len, ENTRY_ADDRESS)); 585 CHECK(entry_to_blob("RA_ROUTES", ra_route, ra_route_len, ENTRY_ROUTE)); 586 CHECK(entry_to_blob("RA_DNS", ra_dns, ra_dns_len, ENTRY_HOST)); 587 CHECK(search_to_blob("RA_DOMAINS", ra_search, ra_search_len)); 588 589 blobmsg_add_u32(&b, "RA_HOPLIMIT", ra_get_hoplimit()); 590 blobmsg_add_u32(&b, "RA_MTU", ra_get_mtu()); 591 blobmsg_add_u32(&b, "RA_REACHABLE", ra_get_reachable()); 592 blobmsg_add_u32(&b, "RA_RETRANSMIT", ra_get_retransmit()); 593 594 buf = blobmsg_alloc_string_buffer(&b, "PASSTHRU", passthru_len * 2); 595 CHECK_ALLOC(buf); 596 script_hexlify(buf, passthru, passthru_len); 597 blobmsg_add_string_buffer(&b); 598 599 return UBUS_STATUS_OK; 600 } 601 602 static int ubus_handle_get_stats(struct ubus_context *ctx, _unused struct ubus_object *obj, 603 struct ubus_request_data *req, _unused const char *method, 604 _unused struct blob_attr *msg) 605 { 606 struct dhcpv6_stats stats = dhcpv6_get_stats(); 607 608 blob_buf_init(&b, BLOBMSG_TYPE_TABLE); 609 blobmsg_add_u64(&b, "dhcp_solicit", stats.solicit); 610 blobmsg_add_u64(&b, "dhcp_advertise", stats.advertise); 611 blobmsg_add_u64(&b, "dhcp_request", stats.request); 612 blobmsg_add_u64(&b, "dhcp_confirm", stats.confirm); 613 blobmsg_add_u64(&b, "dhcp_renew", stats.renew); 614 blobmsg_add_u64(&b, "dhcp_rebind", stats.rebind); 615 blobmsg_add_u64(&b, "dhcp_reply", stats.reply); 616 blobmsg_add_u64(&b, "dhcp_release", stats.release); 617 blobmsg_add_u64(&b, "dhcp_decline", stats.decline); 618 blobmsg_add_u64(&b, "dhcp_reconfigure", stats.reconfigure); 619 blobmsg_add_u64(&b, "dhcp_information_request", stats.information_request); 620 blobmsg_add_u64(&b, "dhcp_discarded_packets", stats.discarded_packets); 621 blobmsg_add_u64(&b, "dhcp_transmit_failures", stats.transmit_failures); 622 623 CHECK(ubus_send_reply(ctx, req, b.head)); 624 blob_buf_free(&b); 625 626 return UBUS_STATUS_OK; 627 } 628 629 static int ubus_handle_reset_stats(_unused struct ubus_context *ctx, _unused struct ubus_object *obj, 630 _unused struct ubus_request_data *req, _unused const char *method, 631 _unused struct blob_attr *msg) 632 { 633 dhcpv6_reset_stats(); 634 635 return UBUS_STATUS_OK; 636 } 637 638 static int ubus_handle_get_state(struct ubus_context *ctx, _unused struct ubus_object *obj, 639 struct ubus_request_data *req, _unused const char *method, 640 _unused struct blob_attr *msg) 641 { 642 CHECK(states_to_blob()); 643 CHECK(ubus_send_reply(ctx, req, b.head)); 644 blob_buf_free(&b); 645 646 return UBUS_STATUS_OK; 647 } 648 649 static int ubus_handle_reconfigure_dhcp_rtx(enum config_dhcp_msg msg, struct blob_attr* table) 650 { 651 struct blob_attr *cur = NULL; 652 uint32_t value = 0; 653 size_t rem = 0; 654 655 if (msg >= CONFIG_DHCP_MAX || blobmsg_data_len(table) == 0) 656 return UBUS_STATUS_INVALID_ARGUMENT; 657 658 blobmsg_for_each_attr(cur, table, rem) { 659 if (!blobmsg_check_attr(cur, true) || blobmsg_type(cur) != BLOBMSG_TYPE_INT32) 660 return UBUS_STATUS_INVALID_ARGUMENT; 661 662 const char* name = blobmsg_name(cur); 663 if (strcmp("delay_max", name) == 0) { 664 value = blobmsg_get_u32(cur); 665 if (!config_set_rtx_delay_max(msg, value)) 666 return UBUS_STATUS_INVALID_ARGUMENT; 667 } else if (strcmp("timeout_init", name) == 0 ) { 668 value = blobmsg_get_u32(cur); 669 if (!config_set_rtx_timeout_init(msg, value)) 670 return UBUS_STATUS_INVALID_ARGUMENT; 671 } else if (strcmp("timeout_max", name) == 0 ) { 672 value = blobmsg_get_u32(cur); 673 if (!config_set_rtx_timeout_max(msg, value)) 674 return UBUS_STATUS_INVALID_ARGUMENT; 675 } else if (strcmp("rc_max", name) == 0) { 676 value = blobmsg_get_u32(cur); 677 if (!config_set_rtx_rc_max(msg, value)) 678 return UBUS_STATUS_INVALID_ARGUMENT; 679 } else { 680 return UBUS_STATUS_INVALID_ARGUMENT; 681 } 682 } 683 684 return UBUS_STATUS_OK; 685 } 686 687 static int ubus_handle_reconfigure_dhcp(_unused struct ubus_context *ctx, _unused struct ubus_object *obj, 688 _unused struct ubus_request_data *req, _unused const char *method, 689 struct blob_attr *msg) 690 { 691 const struct blobmsg_policy *policy = reconfigure_dhcp_policy; 692 struct blob_attr *tb[RECONFIGURE_DHCP_ATTR_MAX]; 693 struct blob_attr *cur = NULL; 694 struct blob_attr *elem = NULL; 695 char *string = NULL; 696 uint32_t value = 0; 697 uint32_t index = 0; 698 bool enabled = false; 699 bool valid_args = false; 700 bool need_reinit = false; 701 702 if (blobmsg_parse(policy, RECONFIGURE_DHCP_ATTR_MAX, tb, blob_data(msg), blob_len(msg))) 703 return UBUS_STATUS_INVALID_ARGUMENT; 704 705 if ((cur = tb[RECONFIGURE_DHCP_ATTR_DSCP])) { 706 value = blobmsg_get_u32(cur); 707 if (!config_set_dscp(value)) 708 return UBUS_STATUS_INVALID_ARGUMENT; 709 need_reinit = true; 710 valid_args = true; 711 } 712 713 if ((cur = tb[RECONFIGURE_DHCP_ATTR_RELEASE])) { 714 enabled = blobmsg_get_bool(cur); 715 config_set_release(enabled); 716 valid_args = true; 717 } 718 719 if ((cur = tb[RECONFIGURE_DHCP_ATTR_SOL_TIMEOUT])) { 720 value = blobmsg_get_u32(cur); 721 if (!config_set_rtx_timeout_max(CONFIG_DHCP_SOLICIT, value)) 722 return UBUS_STATUS_INVALID_ARGUMENT; 723 need_reinit = true; 724 valid_args = true; 725 } 726 727 if ((cur = tb[RECONFIGURE_DHCP_ATTR_SK_PRIORITY])) { 728 value = blobmsg_get_u32(cur); 729 if (!config_set_sk_priority(value)) 730 return UBUS_STATUS_INVALID_ARGUMENT; 731 need_reinit = true; 732 valid_args = true; 733 } 734 735 if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_REQUESTED])) { 736 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, false)) 737 return UBUS_STATUS_INVALID_ARGUMENT; 738 739 config_clear_requested_options(); 740 741 blobmsg_for_each_attr(elem, cur, index) { 742 if (blobmsg_type(elem) != BLOBMSG_TYPE_INT32) 743 return UBUS_STATUS_INVALID_ARGUMENT; 744 745 value = blobmsg_get_u32(elem); 746 if (!config_add_requested_options(value)) 747 return UBUS_STATUS_INVALID_ARGUMENT; 748 } 749 750 need_reinit = true; 751 valid_args = true; 752 } 753 754 if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_STRICT])) { 755 enabled = blobmsg_get_bool(cur); 756 config_set_client_options(DHCPV6_STRICT_OPTIONS, enabled); 757 need_reinit = true; 758 valid_args = true; 759 } 760 761 if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_RECONFIGURE])) { 762 enabled = blobmsg_get_bool(cur); 763 config_set_client_options(DHCPV6_ACCEPT_RECONFIGURE, enabled); 764 need_reinit = true; 765 valid_args = true; 766 } 767 768 if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_FQDN])) { 769 enabled = blobmsg_get_bool(cur); 770 config_set_client_options(DHCPV6_CLIENT_FQDN, enabled); 771 need_reinit = true; 772 valid_args = true; 773 } 774 775 if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_UNICAST])) { 776 enabled = blobmsg_get_bool(cur); 777 config_set_client_options(DHCPV6_IGNORE_OPT_UNICAST, enabled); 778 need_reinit = true; 779 valid_args = true; 780 } 781 782 if ((cur = tb[RECONFIGURE_DHCP_ATTR_OPT_SEND])) { 783 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, false)) 784 return UBUS_STATUS_INVALID_ARGUMENT; 785 786 config_clear_send_options(); 787 788 blobmsg_for_each_attr(elem, cur, index) { 789 string = blobmsg_get_string(elem); 790 if (string == NULL || !config_add_send_options(string)) 791 return UBUS_STATUS_INVALID_ARGUMENT; 792 } 793 794 need_reinit = true; 795 valid_args = true; 796 } 797 798 if ((cur = tb[RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES])) { 799 string = blobmsg_get_string(cur); 800 if (string == NULL || !config_set_request_addresses(string)) 801 return UBUS_STATUS_INVALID_ARGUMENT; 802 803 need_reinit = true; 804 valid_args = true; 805 } 806 807 if ((cur = tb[RECONFIGURE_DHCP_ATTR_REQ_PREFIXES])) { 808 value = blobmsg_get_u32(cur); 809 810 if (!config_set_request_prefix(value, 1)) 811 return UBUS_STATUS_INVALID_ARGUMENT; 812 813 need_reinit = true; 814 valid_args = true; 815 } 816 817 if ((cur = tb[RECONFIGURE_DHCP_ATTR_STATEFUL])) { 818 enabled = blobmsg_get_bool(cur); 819 config_set_stateful_only(enabled); 820 need_reinit = true; 821 valid_args = true; 822 } 823 824 if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_SOLICIT])) { 825 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_SOLICIT, cur)) 826 return UBUS_STATUS_INVALID_ARGUMENT; 827 828 need_reinit = true; 829 valid_args = true; 830 } 831 832 if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_REQUEST])) { 833 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_REQUEST, cur)) 834 return UBUS_STATUS_INVALID_ARGUMENT; 835 836 need_reinit = true; 837 valid_args = true; 838 } 839 840 if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_RENEW])) { 841 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_RENEW, cur)) 842 return UBUS_STATUS_INVALID_ARGUMENT; 843 844 need_reinit = true; 845 valid_args = true; 846 } 847 848 if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_REBIND])) { 849 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_REBIND, cur)) 850 return UBUS_STATUS_INVALID_ARGUMENT; 851 852 need_reinit = true; 853 valid_args = true; 854 } 855 856 if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_RELEASE])) { 857 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_RELEASE, cur)) 858 return UBUS_STATUS_INVALID_ARGUMENT; 859 860 need_reinit = true; 861 valid_args = true; 862 } 863 864 if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_DECLINE])) { 865 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_DECLINE, cur)) 866 return UBUS_STATUS_INVALID_ARGUMENT; 867 868 need_reinit = true; 869 valid_args = true; 870 } 871 872 if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ])) { 873 if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_INFO_REQ, cur)) 874 return UBUS_STATUS_INVALID_ARGUMENT; 875 876 need_reinit = true; 877 valid_args = true; 878 } 879 880 if ((cur = tb[RECONFIGURE_DHCP_ATTR_IRT_MIN])) { 881 value = blobmsg_get_u32(cur); 882 883 if (!config_set_irt_min(value)) 884 return UBUS_STATUS_INVALID_ARGUMENT; 885 886 need_reinit = true; 887 valid_args = true; 888 } 889 890 if ((cur = tb[RECONFIGURE_DHCP_ATTR_IRT_DEFAULT])) { 891 value = blobmsg_get_u32(cur); 892 893 if (!config_set_irt_default(value)) 894 return UBUS_STATUS_INVALID_ARGUMENT; 895 896 need_reinit = true; 897 valid_args = true; 898 } 899 900 if ((cur = tb[RECONFIGURE_DHCP_ATTR_RAND_FACTOR])) { 901 value = blobmsg_get_u32(cur); 902 903 if (!config_set_rand_factor(value)) 904 return UBUS_STATUS_INVALID_ARGUMENT; 905 906 need_reinit = true; 907 valid_args = true; 908 } 909 910 if ((cur = tb[RECONFIGURE_DHCP_ATTR_AUTH_PROTO])) { 911 string = blobmsg_get_string(cur); 912 913 if (string == NULL || !config_set_auth_protocol(string)) 914 return UBUS_STATUS_INVALID_ARGUMENT; 915 916 need_reinit = true; 917 valid_args = true; 918 } 919 920 if ((cur = tb[RECONFIGURE_DHCP_ATTR_AUTH_TOKEN])) { 921 string = blobmsg_get_string(cur); 922 923 if (string == NULL || !config_set_auth_token(string)) 924 return UBUS_STATUS_INVALID_ARGUMENT; 925 926 need_reinit = true; 927 valid_args = true; 928 } 929 930 if (need_reinit) 931 raise(SIGUSR2); 932 933 return valid_args ? UBUS_STATUS_OK : UBUS_STATUS_INVALID_ARGUMENT; 934 } 935 936 static int ubus_handle_renew(_unused struct ubus_context *ctx, _unused struct ubus_object *obj, 937 _unused struct ubus_request_data *req, _unused const char *method, 938 _unused struct blob_attr *msg) 939 { 940 raise(SIGUSR1); 941 return UBUS_STATUS_OK; 942 } 943 944 static int ubus_handle_release(_unused struct ubus_context *ctx, _unused struct ubus_object *obj, 945 _unused struct ubus_request_data *req, _unused const char *method, 946 _unused struct blob_attr *msg) 947 { 948 raise(SIGUSR2); 949 return UBUS_STATUS_OK; 950 } 951 952 int ubus_dhcp_event(const char *status) 953 { 954 if (!ubus || !odhcp6c_object.has_subscribers) 955 return UBUS_STATUS_UNKNOWN_ERROR; 956 957 CHECK(states_to_blob()); 958 CHECK(ubus_notify(ubus, &odhcp6c_object, status, b.head, -1)); 959 blob_buf_free(&b); 960 961 return UBUS_STATUS_OK; 962 } 963
This page was automatically generated by LXR 0.3.1. • OpenWrt