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->flags & OAF_BOUND) 63 blobmsg_add_string(&b, NULL, "bound"); 64 65 if (c->flags & OAF_STATIC) 66 blobmsg_add_string(&b, NULL, "static"); 67 68 if (c->flags & OAF_BROKEN_HOSTNAME) 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, int prefix, 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 != 128) 107 blobmsg_add_u32(&b, "prefix-length", prefix); 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 *a; 119 120 blob_buf_init(&b, 0); 121 a = 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->flags & OAF_BOUND) 155 blobmsg_add_string(&b, NULL, "bound"); 156 157 if (a->flags & OAF_STATIC) 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, a); 176 ubus_send_reply(ctx, req, b.head); 177 return 0; 178 } 179 180 static int handle_ra_pio(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj, 181 _o_unused struct ubus_request_data *req, _o_unused const char *method, 182 _o_unused struct blob_attr *msg) 183 { 184 char ipv6_str[INET6_ADDRSTRLEN]; 185 time_t now = odhcpd_time(); 186 struct interface *iface; 187 void *interfaces_blob; 188 189 blob_buf_init(&b, 0); 190 191 interfaces_blob = blobmsg_open_table(&b, "interfaces"); 192 193 avl_for_each_element(&interfaces, iface, avl) { 194 void *interface_blob; 195 196 if (iface->ra != MODE_SERVER) 197 continue; 198 199 interface_blob = blobmsg_open_array(&b, iface->ifname); 200 201 for (size_t i = 0; i < iface->pio_cnt; i++) { 202 struct ra_pio *cur_pio = &iface->pios[i]; 203 void *cur_pio_blob; 204 uint32_t pio_lt; 205 bool pio_stale; 206 207 if (ra_pio_expired(cur_pio, now)) 208 continue; 209 210 cur_pio_blob = blobmsg_open_table(&b, NULL); 211 212 pio_lt = ra_pio_lifetime(cur_pio, now); 213 pio_stale = ra_pio_stale(cur_pio); 214 215 inet_ntop(AF_INET6, &cur_pio->prefix, ipv6_str, sizeof(ipv6_str)); 216 217 if (pio_lt) 218 blobmsg_add_u32(&b, "lifetime", pio_lt); 219 blobmsg_add_string(&b, "prefix", ipv6_str); 220 blobmsg_add_u16(&b, "length", cur_pio->length); 221 blobmsg_add_u8(&b, "stale", pio_stale); 222 223 blobmsg_close_table(&b, cur_pio_blob); 224 } 225 226 blobmsg_close_array(&b, interface_blob); 227 } 228 229 blobmsg_close_table(&b, interfaces_blob); 230 231 ubus_send_reply(ctx, req, b.head); 232 233 return 0; 234 } 235 236 static int handle_add_lease_cfg(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj, 237 _o_unused struct ubus_request_data *req, _o_unused const char *method, 238 struct blob_attr *msg) 239 { 240 if (!config_set_lease_cfg_from_blobmsg(msg)) 241 return UBUS_STATUS_OK; 242 243 return UBUS_STATUS_INVALID_ARGUMENT; 244 } 245 246 static struct ubus_method main_object_methods[] = { 247 #ifdef DHCPV4_SUPPORT 248 { .name = "ipv4leases", .handler = handle_dhcpv4_leases }, 249 #endif /* DHCPV4_SUPPORT */ 250 { .name = "ipv6leases", .handler = handle_dhcpv6_leases }, 251 { .name = "ipv6ra", .handler = handle_ra_pio }, 252 UBUS_METHOD("add_lease", handle_add_lease_cfg, lease_cfg_attrs), 253 }; 254 255 static struct ubus_object_type main_object_type = 256 UBUS_OBJECT_TYPE("dhcp", main_object_methods); 257 258 static struct ubus_object main_object = { 259 .name = "dhcp", 260 .type = &main_object_type, 261 .methods = main_object_methods, 262 .n_methods = ARRAY_SIZE(main_object_methods), 263 }; 264 265 266 enum { 267 DUMP_ATTR_INTERFACE, 268 DUMP_ATTR_MAX 269 }; 270 271 static const struct blobmsg_policy dump_attrs[DUMP_ATTR_MAX] = { 272 [DUMP_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_ARRAY }, 273 }; 274 275 276 enum { 277 IFACE_ATTR_INTERFACE, 278 IFACE_ATTR_IFNAME, 279 IFACE_ATTR_UP, 280 IFACE_ATTR_DATA, 281 IFACE_ATTR_PREFIX, 282 IFACE_ATTR_ADDRESS, 283 IFACE_ATTR_MAX, 284 }; 285 286 static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { 287 [IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING }, 288 [IFACE_ATTR_IFNAME] = { .name = "l3_device", .type = BLOBMSG_TYPE_STRING }, 289 [IFACE_ATTR_UP] = { .name = "up", .type = BLOBMSG_TYPE_BOOL }, 290 [IFACE_ATTR_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, 291 [IFACE_ATTR_PREFIX] = { .name = "ipv6-prefix", .type = BLOBMSG_TYPE_ARRAY }, 292 [IFACE_ATTR_ADDRESS] = { .name = "ipv6-address", .type = BLOBMSG_TYPE_ARRAY }, 293 }; 294 295 static void handle_dump(_o_unused struct ubus_request *req, _o_unused int type, struct blob_attr *msg) 296 { 297 struct blob_attr *tb[DUMP_ATTR_MAX]; 298 blobmsg_parse(dump_attrs, DUMP_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); 299 300 if (!tb[DUMP_ATTR_INTERFACE]) 301 return; 302 303 free(dump); 304 dump = blob_memdup(tb[DUMP_ATTR_INTERFACE]); 305 odhcpd_reload(); 306 } 307 308 309 static void update_netifd(bool subscribe) 310 { 311 if (subscribe) 312 ubus_subscribe(ubus, &netifd, objid); 313 314 ubus_abort_request(ubus, &req_dump); 315 blob_buf_init(&b, 0); 316 317 if (!ubus_invoke_async(ubus, objid, "dump", b.head, &req_dump)) { 318 req_dump.data_cb = handle_dump; 319 ubus_complete_request_async(ubus, &req_dump); 320 } 321 } 322 323 324 static int handle_update(_o_unused struct ubus_context *ctx, _o_unused struct ubus_object *obj, 325 _o_unused struct ubus_request_data *req, _o_unused const char *method, 326 struct blob_attr *msg) 327 { 328 struct blob_attr *tb[IFACE_ATTR_MAX]; 329 struct interface *c; 330 bool update = true; 331 332 blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); 333 const char *interface = (tb[IFACE_ATTR_INTERFACE]) ? 334 blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]) : ""; 335 336 avl_for_each_element(&interfaces, c, avl) { 337 if (!strcmp(interface, c->name) && c->ignore) { 338 update = false; 339 break; 340 } 341 } 342 343 if (update) 344 update_netifd(false); 345 346 return 0; 347 } 348 349 350 void ubus_apply_network(void) 351 { 352 struct blob_attr *a; 353 unsigned rem; 354 355 if (!dump) 356 return; 357 358 blobmsg_for_each_attr(a, dump, rem) { 359 struct blob_attr *tb[IFACE_ATTR_MAX]; 360 blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blobmsg_data(a), blobmsg_data_len(a)); 361 362 if (!tb[IFACE_ATTR_INTERFACE] || !tb[IFACE_ATTR_DATA]) 363 continue; 364 365 const char *interface = (tb[IFACE_ATTR_INTERFACE]) ? 366 blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]) : ""; 367 368 bool matched = false; 369 struct interface *c, *tmp; 370 avl_for_each_element_safe(&interfaces, c, avl, tmp) { 371 char *f = memmem(c->upstream, c->upstream_len, 372 interface, strlen(interface) + 1); 373 bool cmatched = !strcmp(interface, c->name); 374 matched |= cmatched; 375 376 if (!cmatched && (!c->upstream_len || !f || (f != c->upstream && f[-1] != 0))) 377 continue; 378 379 if (!c->ignore) 380 config_parse_interface(blobmsg_data(tb[IFACE_ATTR_DATA]), 381 blobmsg_data_len(tb[IFACE_ATTR_DATA]), c->name, false); 382 } 383 384 if (!matched) 385 config_parse_interface(blobmsg_data(tb[IFACE_ATTR_DATA]), 386 blobmsg_data_len(tb[IFACE_ATTR_DATA]), interface, false); 387 } 388 } 389 390 391 enum { 392 OBJ_ATTR_ID, 393 OBJ_ATTR_PATH, 394 OBJ_ATTR_MAX 395 }; 396 397 static const struct blobmsg_policy obj_attrs[OBJ_ATTR_MAX] = { 398 [OBJ_ATTR_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 }, 399 [OBJ_ATTR_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, 400 }; 401 402 void ubus_bcast_dhcpv4_event(const char *type, const char *iface, 403 const struct dhcpv4_lease *lease) 404 { 405 char ipv4_str[INET_ADDRSTRLEN]; 406 407 if (!ubus || !main_object.has_subscribers || !iface) 408 return; 409 410 blob_buf_init(&b, 0); 411 blobmsg_add_string(&b, "interface", iface); 412 blobmsg_add_string(&b, "ipv4", inet_ntop(AF_INET, &lease->ipv4, ipv4_str, sizeof(ipv4_str))); 413 blobmsg_add_string(&b, "mac", odhcpd_print_mac(lease->hwaddr, sizeof(lease->hwaddr))); 414 if (lease->hostname) 415 blobmsg_add_string(&b, "hostname", lease->hostname); 416 if (lease->duid_len > 0) { 417 char *buf = blobmsg_alloc_string_buffer(&b, "duid", DUID_HEXSTRLEN + 1); 418 odhcpd_hexlify(buf, lease->duid, lease->duid_len); 419 blobmsg_add_string_buffer(&b); 420 blobmsg_add_u32(&b, "iaid", lease->iaid); 421 } 422 423 ubus_notify(ubus, &main_object, type, b.head, -1); 424 } 425 426 static void handle_event(_o_unused struct ubus_context *ctx, 427 _o_unused struct ubus_event_handler *ev, 428 _o_unused const char *type, struct blob_attr *msg) 429 { 430 struct blob_attr *tb[OBJ_ATTR_MAX]; 431 blobmsg_parse(obj_attrs, OBJ_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); 432 433 if (!tb[OBJ_ATTR_ID] || !tb[OBJ_ATTR_PATH]) 434 return; 435 436 if (strcmp(blobmsg_get_string(tb[OBJ_ATTR_PATH]), "network.interface")) 437 return; 438 439 objid = blobmsg_get_u32(tb[OBJ_ATTR_ID]); 440 update_netifd(true); 441 } 442 443 static struct ubus_event_handler event_handler = { .cb = handle_event }; 444 445 446 const char* ubus_get_ifname(const char *name) 447 { 448 struct blob_attr *c; 449 unsigned rem; 450 451 if (!dump) 452 return NULL; 453 454 blobmsg_for_each_attr(c, dump, rem) { 455 struct blob_attr *tb[IFACE_ATTR_MAX]; 456 blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blobmsg_data(c), blobmsg_data_len(c)); 457 458 if (!tb[IFACE_ATTR_INTERFACE] || strcmp(name, 459 blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]))) 460 continue; 461 462 if (tb[IFACE_ATTR_IFNAME]) 463 return blobmsg_get_string(tb[IFACE_ATTR_IFNAME]); 464 } 465 466 return NULL; 467 } 468 469 470 bool ubus_has_prefix(const char *name, const char *ifname) 471 { 472 struct blob_attr *c, *cur; 473 unsigned rem; 474 475 if (!dump) 476 return false; 477 478 blobmsg_for_each_attr(c, dump, rem) { 479 struct blob_attr *tb[IFACE_ATTR_MAX]; 480 blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blobmsg_data(c), blobmsg_data_len(c)); 481 482 if (!tb[IFACE_ATTR_INTERFACE] || !tb[IFACE_ATTR_IFNAME]) 483 continue; 484 485 if (strcmp(name, blobmsg_get_string(tb[IFACE_ATTR_INTERFACE])) || 486 strcmp(ifname, blobmsg_get_string(tb[IFACE_ATTR_IFNAME]))) 487 continue; 488 489 if ((cur = tb[IFACE_ATTR_PREFIX])) { 490 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, false)) 491 continue; 492 493 struct blob_attr *d; 494 unsigned drem; 495 blobmsg_for_each_attr(d, cur, drem) { 496 return true; 497 } 498 } 499 } 500 501 return false; 502 } 503 504 505 int ubus_init(void) 506 { 507 if (!(ubus = ubus_connect(NULL))) { 508 error("Unable to connect to ubus: %m"); 509 return -1; 510 } 511 512 netifd.cb = handle_update; 513 ubus_register_subscriber(ubus, &netifd); 514 515 ubus_add_uloop(ubus); 516 ubus_add_object(ubus, &main_object); 517 ubus_register_event_handler(ubus, &event_handler, "ubus.object.add"); 518 if (!ubus_lookup_id(ubus, "network.interface", &objid)) 519 update_netifd(true); 520 521 return 0; 522 } 523 524
This page was automatically generated by LXR 0.3.1. • OpenWrt