1 #include <libubus.h> 2 #include <libubox/uloop.h> 3 #include <netinet/in.h> 4 #include <arpa/inet.h> 5 #include <inttypes.h> 6 7 #include <libubox/utils.h> 8 9 #include "odhcpd.h" 10 #include "dhcpv6.h" 11 #include "dhcpv4.h" 12 #include "statefiles.h" 13 14 static struct ubus_context *ubus = NULL; 15 static struct ubus_subscriber netifd; 16 static struct blob_buf b; 17 static struct blob_attr *dump = NULL; 18 static uint32_t objid = 0; 19 static struct ubus_request req_dump = { .list = LIST_HEAD_INIT(req_dump.list) }; 20 21 #ifdef DHCPV4_SUPPORT 22 static int handle_dhcpv4_leases(struct ubus_context *ctx, _o_unused struct ubus_object *obj, 23 struct ubus_request_data *req, _o_unused const char *method, 24 _o_unused struct blob_attr *msg) 25 { 26 struct interface *iface; 27 time_t now = odhcpd_time(); 28 void *a; 29 30 blob_buf_init(&b, 0); 31 a = blobmsg_open_table(&b, "device"); 32 33 avl_for_each_element(&interfaces, iface, avl) { 34 if (iface->dhcpv4 != MODE_SERVER) 35 continue; 36 37 void *i = blobmsg_open_table(&b, iface->ifname); 38 void *j = blobmsg_open_array(&b, "leases"); 39 struct dhcpv4_lease *c; 40 41 avl_for_each_element(&iface->dhcpv4_leases, c, iface_avl) { 42 if (!INFINITE_VALID(c->valid_until) && c->valid_until < now) 43 continue; 44 45 void *m, *l = blobmsg_open_table(&b, NULL); 46 char *buf = blobmsg_alloc_string_buffer(&b, "mac", sizeof(c->hwaddr) * 2 + 1); 47 48 odhcpd_hexlify(buf, c->hwaddr, sizeof(c->hwaddr)); 49 blobmsg_add_string_buffer(&b); 50 51 if (c->duid_len > 0) { 52 buf = blobmsg_alloc_string_buffer(&b, "duid", DUID_HEXSTRLEN + 1); 53 odhcpd_hexlify(buf, c->duid, c->duid_len); 54 blobmsg_add_string_buffer(&b); 55 blobmsg_add_u32(&b, "iaid", ntohl(c->iaid)); 56 } 57 58 blobmsg_add_string(&b, "hostname", (c->hostname) ? c->hostname : ""); 59 blobmsg_add_u8(&b, "accept-reconf", c->accept_fr_nonce); 60 61 m = blobmsg_open_array(&b, "flags"); 62 if (c->bound) 63 blobmsg_add_string(&b, NULL, "bound"); 64 65 if (c->lease_cfg) 66 blobmsg_add_string(&b, NULL, "static"); 67 68 if (!c->hostname_valid) 69 blobmsg_add_string(&b, NULL, "broken-hostname"); 70 blobmsg_close_array(&b, m); 71 72 buf = blobmsg_alloc_string_buffer(&b, "address", INET_ADDRSTRLEN); 73 inet_ntop(AF_INET, &c->ipv4, buf, INET_ADDRSTRLEN); 74 blobmsg_add_string_buffer(&b); 75 76 blobmsg_add_u32(&b, "valid", INFINITE_VALID(c->valid_until) ? 77 (uint32_t)-1 : (uint32_t)(c->valid_until - now)); 78 79 blobmsg_close_table(&b, l); 80 } 81 82 blobmsg_close_array(&b, j); 83 blobmsg_close_table(&b, i); 84 } 85 86 blobmsg_close_table(&b, a); 87 ubus_send_reply(ctx, req, b.head); 88 89 return 0; 90 } 91 #endif /* DHCPV4_SUPPORT */ 92 93 static void dhcpv6_blobmsg_ia_addr(_o_unused struct dhcpv6_lease *lease, struct in6_addr *addr, uint8_t prefix_len, 94 uint32_t pref_lt, uint32_t valid_lt, _o_unused void *arg) 95 { 96 void *a = blobmsg_open_table(&b, NULL); 97 char *buf = blobmsg_alloc_string_buffer(&b, "address", INET6_ADDRSTRLEN); 98 99 inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN); 100 blobmsg_add_string_buffer(&b); 101 blobmsg_add_u32(&b, "preferred-lifetime", 102 pref_lt == UINT32_MAX ? (uint32_t)-1 : pref_lt); 103 blobmsg_add_u32(&b, "valid-lifetime", 104 valid_lt == UINT32_MAX ? (uint32_t)-1 : valid_lt); 105 106 if (prefix_len != 128) 107 blobmsg_add_u32(&b, "prefix-length", prefix_len); 108 109 blobmsg_close_table(&b, a); 110 } 111 112 static int handle_dhcpv6_leases(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj, 113 _o_unused struct ubus_request_data *req, _o_unused const char *method, 114 _o_unused struct blob_attr *msg) 115 { 116 struct interface *iface; 117 time_t now = odhcpd_time(); 118 void *dev_tbl; 119 120 blob_buf_init(&b, 0); 121 dev_tbl = blobmsg_open_table(&b, "device"); 122 123 avl_for_each_element(&interfaces, iface, avl) { 124 if (iface->dhcpv6 != MODE_SERVER) 125 continue; 126 127 void *i = blobmsg_open_table(&b, iface->ifname); 128 void *j = blobmsg_open_array(&b, "leases"); 129 130 struct dhcpv6_lease *a, *border; 131 132 border = list_last_entry(&iface->ia_assignments, struct dhcpv6_lease, head); 133 134 list_for_each_entry(a, &iface->ia_assignments, head) { 135 if (a == border || (!INFINITE_VALID(a->valid_until) && 136 a->valid_until < now)) 137 continue; 138 139 void *m, *l = blobmsg_open_table(&b, NULL); 140 char *buf = blobmsg_alloc_string_buffer(&b, "duid", DUID_HEXSTRLEN + 1); 141 142 odhcpd_hexlify(buf, a->duid, a->duid_len); 143 blobmsg_add_string_buffer(&b); 144 145 blobmsg_add_u32(&b, "iaid", ntohl(a->iaid)); 146 blobmsg_add_string(&b, "hostname", (a->hostname) ? a->hostname : ""); 147 blobmsg_add_u8(&b, "accept-reconf", a->accept_fr_nonce); 148 if (a->flags & OAF_DHCPV6_NA) 149 blobmsg_add_u64(&b, "assigned", a->assigned_host_id); 150 else 151 blobmsg_add_u16(&b, "assigned", a->assigned_subnet_id); 152 153 m = blobmsg_open_array(&b, "flags"); 154 if (a->bound) 155 blobmsg_add_string(&b, NULL, "bound"); 156 157 if (a->lease_cfg) 158 blobmsg_add_string(&b, NULL, "static"); 159 blobmsg_close_array(&b, m); 160 161 m = blobmsg_open_array(&b, a->flags & OAF_DHCPV6_NA ? "ipv6-addr": "ipv6-prefix"); 162 odhcpd_enum_addr6(iface, a, now, dhcpv6_blobmsg_ia_addr, NULL); 163 blobmsg_close_array(&b, m); 164 165 blobmsg_add_u32(&b, "valid", INFINITE_VALID(a->valid_until) ? 166 (uint32_t)-1 : (uint32_t)(a->valid_until - now)); 167 168 blobmsg_close_table(&b, l); 169 } 170 171 blobmsg_close_array(&b, j); 172 blobmsg_close_table(&b, i); 173 } 174 175 blobmsg_close_table(&b, dev_tbl); 176 ubus_send_reply(ctx, req, b.head); 177 178 return 0; 179 } 180 181 static int handle_ra_pio(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj, 182 _o_unused struct ubus_request_data *req, _o_unused const char *method, 183 _o_unused struct blob_attr *msg) 184 { 185 char ipv6_str[INET6_ADDRSTRLEN]; 186 time_t now = odhcpd_time(); 187 struct interface *iface; 188 void *interfaces_blob; 189 190 blob_buf_init(&b, 0); 191 192 interfaces_blob = blobmsg_open_table(&b, "interfaces"); 193 194 avl_for_each_element(&interfaces, iface, avl) { 195 void *interface_blob; 196 197 if (iface->ra != MODE_SERVER) 198 continue; 199 200 interface_blob = blobmsg_open_array(&b, iface->ifname); 201 202 for (size_t i = 0; i < iface->pio_cnt; i++) { 203 struct ra_pio *cur_pio = &iface->pios[i]; 204 void *cur_pio_blob; 205 uint32_t pio_lt; 206 bool pio_stale; 207 208 if (ra_pio_expired(cur_pio, now)) 209 continue; 210 211 cur_pio_blob = blobmsg_open_table(&b, NULL); 212 213 pio_lt = ra_pio_lifetime(cur_pio, now); 214 pio_stale = ra_pio_stale(cur_pio); 215 216 inet_ntop(AF_INET6, &cur_pio->prefix, ipv6_str, sizeof(ipv6_str)); 217 218 if (pio_lt) 219 blobmsg_add_u32(&b, "lifetime", pio_lt); 220 blobmsg_add_string(&b, "prefix", ipv6_str); 221 blobmsg_add_u16(&b, "length", cur_pio->length); 222 blobmsg_add_u8(&b, "stale", pio_stale); 223 224 blobmsg_close_table(&b, cur_pio_blob); 225 } 226 227 blobmsg_close_array(&b, interface_blob); 228 } 229 230 blobmsg_close_table(&b, interfaces_blob); 231 232 ubus_send_reply(ctx, req, b.head); 233 234 return 0; 235 } 236 237 static int handle_add_lease_cfg(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj, 238 _o_unused struct ubus_request_data *req, _o_unused const char *method, 239 struct blob_attr *msg) 240 { 241 if (!config_set_lease_cfg_from_blobmsg(msg)) 242 return UBUS_STATUS_OK; 243 244 return UBUS_STATUS_INVALID_ARGUMENT; 245 } 246 247 static struct ubus_method main_object_methods[] = { 248 #ifdef DHCPV4_SUPPORT 249 { .name = "ipv4leases", .handler = handle_dhcpv4_leases }, 250 #endif /* DHCPV4_SUPPORT */ 251 { .name = "ipv6leases", .handler = handle_dhcpv6_leases }, 252 { .name = "ipv6ra", .handler = handle_ra_pio }, 253 UBUS_METHOD("add_lease", handle_add_lease_cfg, lease_cfg_attrs), 254 }; 255 256 static struct ubus_object_type main_object_type = 257 UBUS_OBJECT_TYPE("dhcp", main_object_methods); 258 259 static struct ubus_object main_object = { 260 .name = "dhcp", 261 .type = &main_object_type, 262 .methods = main_object_methods, 263 .n_methods = ARRAY_SIZE(main_object_methods), 264 }; 265 266 267 enum { 268 DUMP_ATTR_INTERFACE, 269 DUMP_ATTR_MAX 270 }; 271 272 static const struct blobmsg_policy dump_attrs[DUMP_ATTR_MAX] = { 273 [DUMP_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_ARRAY }, 274 }; 275 276 277 enum { 278 IFACE_ATTR_INTERFACE, 279 IFACE_ATTR_IFNAME, 280 IFACE_ATTR_UP, 281 IFACE_ATTR_DATA, 282 IFACE_ATTR_PREFIX, 283 IFACE_ATTR_ADDRESS, 284 IFACE_ATTR_MAX, 285 }; 286 287 static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { 288 [IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING }, 289 [IFACE_ATTR_IFNAME] = { .name = "l3_device", .type = BLOBMSG_TYPE_STRING }, 290 [IFACE_ATTR_UP] = { .name = "up", .type = BLOBMSG_TYPE_BOOL }, 291 [IFACE_ATTR_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, 292 [IFACE_ATTR_PREFIX] = { .name = "ipv6-prefix", .type = BLOBMSG_TYPE_ARRAY }, 293 [IFACE_ATTR_ADDRESS] = { .name = "ipv6-address", .type = BLOBMSG_TYPE_ARRAY }, 294 }; 295 296 static void handle_dump(_o_unused struct ubus_request *req, _o_unused int type, struct blob_attr *msg) 297 { 298 struct blob_attr *tb[DUMP_ATTR_MAX]; 299 blobmsg_parse(dump_attrs, DUMP_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); 300 301 if (!tb[DUMP_ATTR_INTERFACE]) 302 return; 303 304 free(dump); 305 dump = blob_memdup(tb[DUMP_ATTR_INTERFACE]); 306 odhcpd_reload(); 307 } 308 309 310 static void update_netifd(bool subscribe) 311 { 312 if (subscribe) 313 ubus_subscribe(ubus, &netifd, objid); 314 315 ubus_abort_request(ubus, &req_dump); 316 blob_buf_init(&b, 0); 317 318 if (!ubus_invoke_async(ubus, objid, "dump", b.head, &req_dump)) { 319 req_dump.data_cb = handle_dump; 320 ubus_complete_request_async(ubus, &req_dump); 321 } 322 } 323 324 325 static int handle_update(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj, 326 _o_unused struct ubus_request_data *req, _o_unused const char *method, 327 struct blob_attr *msg) 328 { 329 struct blob_attr *tb[IFACE_ATTR_MAX]; 330 struct interface *c; 331 bool update = true; 332 333 blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); 334 const char *interface = (tb[IFACE_ATTR_INTERFACE]) ? 335 blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]) : ""; 336 337 avl_for_each_element(&interfaces, c, avl) { 338 if (!strcmp(interface, c->name) && c->ignore) { 339 update = false; 340 break; 341 } 342 } 343 344 if (update) 345 update_netifd(false); 346 347 return 0; 348 } 349 350 351 void ubus_apply_network(void) 352 { 353 struct blob_attr *a; 354 unsigned rem; 355 356 if (!dump) 357 return; 358 359 blobmsg_for_each_attr(a, dump, rem) { 360 struct blob_attr *tb[IFACE_ATTR_MAX]; 361 blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blobmsg_data(a), blobmsg_data_len(a)); 362 363 if (!tb[IFACE_ATTR_INTERFACE] || !tb[IFACE_ATTR_DATA]) 364 continue; 365 366 const char *interface = (tb[IFACE_ATTR_INTERFACE]) ? 367 blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]) : ""; 368 369 bool matched = false; 370 struct interface *c, *tmp; 371 avl_for_each_element_safe(&interfaces, c, avl, tmp) { 372 char *f = memmem(c->upstream, c->upstream_len, 373 interface, strlen(interface) + 1); 374 bool cmatched = !strcmp(interface, c->name); 375 matched |= cmatched; 376 377 if (!cmatched && (!c->upstream_len || !f || (f != c->upstream && f[-1] != 0))) 378 continue; 379 380 if (!c->ignore) 381 config_parse_interface(blobmsg_data(tb[IFACE_ATTR_DATA]), 382 blobmsg_data_len(tb[IFACE_ATTR_DATA]), c->name, false); 383 } 384 385 if (!matched) 386 config_parse_interface(blobmsg_data(tb[IFACE_ATTR_DATA]), 387 blobmsg_data_len(tb[IFACE_ATTR_DATA]), interface, false); 388 } 389 } 390 391 392 enum { 393 OBJ_ATTR_ID, 394 OBJ_ATTR_PATH, 395 OBJ_ATTR_MAX 396 }; 397 398 static const struct blobmsg_policy obj_attrs[OBJ_ATTR_MAX] = { 399 [OBJ_ATTR_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 }, 400 [OBJ_ATTR_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, 401 }; 402 403 void ubus_bcast_dhcpv4_event(const char *type, const char *iface, 404 const struct dhcpv4_lease *lease) 405 { 406 char ipv4_str[INET_ADDRSTRLEN]; 407 408 if (!ubus || !main_object.has_subscribers || !iface) 409 return; 410 411 blob_buf_init(&b, 0); 412 blobmsg_add_string(&b, "interface", iface); 413 blobmsg_add_string(&b, "ipv4", inet_ntop(AF_INET, &lease->ipv4, ipv4_str, sizeof(ipv4_str))); 414 blobmsg_add_string(&b, "mac", odhcpd_print_mac(lease->hwaddr, sizeof(lease->hwaddr))); 415 if (lease->hostname) 416 blobmsg_add_string(&b, "hostname", lease->hostname); 417 if (lease->duid_len > 0) { 418 char *buf = blobmsg_alloc_string_buffer(&b, "duid", DUID_HEXSTRLEN + 1); 419 odhcpd_hexlify(buf, lease->duid, lease->duid_len); 420 blobmsg_add_string_buffer(&b); 421 blobmsg_add_u32(&b, "iaid", lease->iaid); 422 } 423 424 ubus_notify(ubus, &main_object, type, b.head, -1); 425 } 426 427 static void handle_event(_o_unused struct ubus_context *ctx, 428 _o_unused struct ubus_event_handler *ev, 429 _o_unused const char *type, struct blob_attr *msg) 430 { 431 struct blob_attr *tb[OBJ_ATTR_MAX]; 432 blobmsg_parse(obj_attrs, OBJ_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); 433 434 if (!tb[OBJ_ATTR_ID] || !tb[OBJ_ATTR_PATH]) 435 return; 436 437 if (strcmp(blobmsg_get_string(tb[OBJ_ATTR_PATH]), "network.interface")) 438 return; 439 440 objid = blobmsg_get_u32(tb[OBJ_ATTR_ID]); 441 update_netifd(true); 442 } 443 444 static struct ubus_event_handler event_handler = { .cb = handle_event }; 445 446 447 const char* ubus_get_ifname(const char *name) 448 { 449 struct blob_attr *c; 450 unsigned rem; 451 452 if (!dump) 453 return NULL; 454 455 blobmsg_for_each_attr(c, dump, rem) { 456 struct blob_attr *tb[IFACE_ATTR_MAX]; 457 blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blobmsg_data(c), blobmsg_data_len(c)); 458 459 if (!tb[IFACE_ATTR_INTERFACE] || strcmp(name, 460 blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]))) 461 continue; 462 463 if (tb[IFACE_ATTR_IFNAME]) 464 return blobmsg_get_string(tb[IFACE_ATTR_IFNAME]); 465 } 466 467 return NULL; 468 } 469 470 471 bool ubus_has_prefix(const char *name, const char *ifname) 472 { 473 struct blob_attr *c, *cur; 474 unsigned rem; 475 476 if (!dump) 477 return false; 478 479 blobmsg_for_each_attr(c, dump, rem) { 480 struct blob_attr *tb[IFACE_ATTR_MAX]; 481 blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blobmsg_data(c), blobmsg_data_len(c)); 482 483 if (!tb[IFACE_ATTR_INTERFACE] || !tb[IFACE_ATTR_IFNAME]) 484 continue; 485 486 if (strcmp(name, blobmsg_get_string(tb[IFACE_ATTR_INTERFACE])) || 487 strcmp(ifname, blobmsg_get_string(tb[IFACE_ATTR_IFNAME]))) 488 continue; 489 490 if ((cur = tb[IFACE_ATTR_PREFIX])) { 491 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, false)) 492 continue; 493 494 struct blob_attr *d; 495 unsigned drem; 496 blobmsg_for_each_attr(d, cur, drem) { 497 return true; 498 } 499 } 500 } 501 502 return false; 503 } 504 505 506 int ubus_init(void) 507 { 508 if (!(ubus = ubus_connect(NULL))) { 509 error("Unable to connect to ubus: %m"); 510 return -1; 511 } 512 513 netifd.cb = handle_update; 514 ubus_register_subscriber(ubus, &netifd); 515 516 ubus_add_uloop(ubus); 517 ubus_add_object(ubus, &main_object); 518 ubus_register_event_handler(ubus, &event_handler, "ubus.object.add"); 519 if (!ubus_lookup_id(ubus, "network.interface", &objid)) 520 update_netifd(true); 521 522 return 0; 523 } 524 525
This page was automatically generated by LXR 0.3.1. • OpenWrt