• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcpd/src/ubus.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt