2 * luci-rpcd - LuCI UBUS RPC server
4 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #include <arpa/inet.h>
29 static struct blob_buf buf;
30 static struct uci_context *cursor;
34 rpc_errno_status(void)
39 return UBUS_STATUS_PERMISSION_DENIED;
42 return UBUS_STATUS_INVALID_ARGUMENT;
45 return UBUS_STATUS_NOT_FOUND;
48 return UBUS_STATUS_INVALID_ARGUMENT;
51 return UBUS_STATUS_UNKNOWN_ERROR;
56 log_read(FILE *log, int logsize)
62 logsize = RPC_LUCI2_DEF_LOGSIZE;
64 len = (logsize > RPC_LUCI2_MAX_LOGSIZE) ? RPC_LUCI2_MAX_LOGSIZE : logsize;
65 logbuf = blobmsg_alloc_string_buffer(&buf, "log", len + 1);
70 while (logsize > RPC_LUCI2_MAX_LOGSIZE)
72 len = logsize % RPC_LUCI2_MAX_LOGSIZE;
75 len = RPC_LUCI2_MAX_LOGSIZE;
77 fread(logbuf, 1, len, log);
81 len = fread(logbuf, 1, logsize, log);
84 blobmsg_add_string_buffer(&buf);
88 rpc_luci2_system_log(struct ubus_context *ctx, struct ubus_object *obj,
89 struct ubus_request_data *req, const char *method,
90 struct blob_attr *msg)
94 const char *logfile = NULL;
96 struct uci_package *p;
97 struct uci_element *e;
98 struct uci_section *s;
99 struct uci_ptr ptr = { .package = "system" };
101 uci_load(cursor, ptr.package, &p);
104 return UBUS_STATUS_NOT_FOUND;
106 uci_foreach_element(&p->sections, e)
108 s = uci_to_section(e);
110 if (strcmp(s->type, "system"))
114 ptr.option = "log_type";
115 ptr.section = e->name;
116 uci_lookup_ptr(cursor, &ptr, NULL, true);
120 if (ptr.o && ptr.o->type == UCI_TYPE_STRING &&
121 !strcmp(ptr.o->v.string, "file"))
124 ptr.option = "log_file";
125 uci_lookup_ptr(cursor, &ptr, NULL, true);
127 if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
128 logfile = ptr.o->v.string;
130 logfile = "/var/log/messages";
132 if (stat(logfile, &st) || !(log = fopen(logfile, "r")))
135 logsize = st.st_size;
140 ptr.option = "log_size";
141 uci_lookup_ptr(cursor, &ptr, NULL, true);
143 if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
144 logsize = atoi(ptr.o->v.string) * 1024;
146 if (!(log = popen("logread", "r")))
150 blob_buf_init(&buf, 0);
152 log_read(log, logsize);
155 uci_unload(cursor, p);
156 ubus_send_reply(ctx, req, buf.head);
160 uci_unload(cursor, p);
161 return rpc_errno_status();
165 rpc_luci2_system_dmesg(struct ubus_context *ctx, struct ubus_object *obj,
166 struct ubus_request_data *req, const char *method,
167 struct blob_attr *msg)
171 if (!(log = popen("dmesg", "r")))
172 return rpc_errno_status();
174 blob_buf_init(&buf, 0);
176 log_read(log, RPC_LUCI2_MAX_LOGSIZE);
179 ubus_send_reply(ctx, req, buf.head);
185 dnsmasq_leasefile(void)
188 struct uci_package *p;
189 struct uci_element *e;
190 struct uci_section *s;
191 struct uci_ptr ptr = {
194 .option = "leasefile"
197 uci_load(cursor, ptr.package, &p);
202 uci_foreach_element(&p->sections, e)
204 s = uci_to_section(e);
206 if (strcmp(s->type, "dnsmasq"))
209 ptr.section = e->name;
210 uci_lookup_ptr(cursor, &ptr, NULL, true);
214 if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
215 leases = fopen(ptr.o->v.string, "r");
217 uci_unload(cursor, p);
223 rpc_luci2_network_leases(struct ubus_context *ctx, struct ubus_object *obj,
224 struct ubus_request_data *req, const char *method,
225 struct blob_attr *msg)
230 char *ts, *mac, *addr, *name;
231 time_t now = time(NULL);
233 blob_buf_init(&buf, 0);
234 c = blobmsg_open_array(&buf, "leases");
236 leases = dnsmasq_leasefile();
241 while (fgets(line, sizeof(line) - 1, leases))
243 ts = strtok(line, " \t");
244 mac = strtok(NULL, " \t");
245 addr = strtok(NULL, " \t");
246 name = strtok(NULL, " \t");
248 if (!ts || !mac || !addr || !name)
251 if (strchr(addr, ':'))
254 d = blobmsg_open_table(&buf, NULL);
256 blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
257 blobmsg_add_string(&buf, "macaddr", mac);
258 blobmsg_add_string(&buf, "ipaddr", addr);
260 if (strcmp(name, "*"))
261 blobmsg_add_string(&buf, "hostname", name);
263 blobmsg_close_table(&buf, d);
269 blobmsg_close_array(&buf, c);
270 ubus_send_reply(ctx, req, buf.head);
276 rpc_luci2_network_leases6(struct ubus_context *ctx, struct ubus_object *obj,
277 struct ubus_request_data *req, const char *method,
278 struct blob_attr *msg)
283 char *ts, *mac, *addr, *name, *duid;
284 time_t now = time(NULL);
286 blob_buf_init(&buf, 0);
287 c = blobmsg_open_array(&buf, "leases");
289 leases = fopen("/tmp/hosts/6relayd", "r");
293 while (fgets(line, sizeof(line) - 1, leases))
295 if (strncmp(line, "# ", 2))
298 strtok(line + 2, " \t"); /* iface */
300 duid = strtok(NULL, " \t");
302 strtok(NULL, " \t"); /* iaid */
304 name = strtok(NULL, " \t");
305 ts = strtok(NULL, " \t");
307 strtok(NULL, " \t"); /* id */
308 strtok(NULL, " \t"); /* length */
310 addr = strtok(NULL, " \t\n");
315 d = blobmsg_open_table(&buf, NULL);
317 blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
318 blobmsg_add_string(&buf, "duid", duid);
319 blobmsg_add_string(&buf, "ip6addr", addr);
321 if (strcmp(name, "-"))
322 blobmsg_add_string(&buf, "hostname", name);
324 blobmsg_close_array(&buf, d);
331 leases = dnsmasq_leasefile();
336 while (fgets(line, sizeof(line) - 1, leases))
338 ts = strtok(line, " \t");
339 mac = strtok(NULL, " \t");
340 addr = strtok(NULL, " \t");
341 name = strtok(NULL, " \t");
342 duid = strtok(NULL, " \t\n");
344 if (!ts || !mac || !addr || !duid)
347 if (!strchr(addr, ':'))
350 d = blobmsg_open_table(&buf, NULL);
352 blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
353 blobmsg_add_string(&buf, "macaddr", mac);
354 blobmsg_add_string(&buf, "ip6addr", addr);
356 if (strcmp(name, "*"))
357 blobmsg_add_string(&buf, "hostname", name);
359 if (strcmp(duid, "*"))
360 blobmsg_add_string(&buf, "duid", name);
362 blobmsg_close_table(&buf, d);
369 blobmsg_close_array(&buf, c);
370 ubus_send_reply(ctx, req, buf.head);
376 rpc_luci2_network_ct_count(struct ubus_context *ctx, struct ubus_object *obj,
377 struct ubus_request_data *req, const char *method,
378 struct blob_attr *msg)
383 blob_buf_init(&buf, 0);
385 if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_count", "r")) != NULL)
387 if (fgets(line, sizeof(line) - 1, f))
388 blobmsg_add_u32(&buf, "count", atoi(line));
393 if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_max", "r")) != NULL)
395 if (fgets(line, sizeof(line) - 1, f))
396 blobmsg_add_u32(&buf, "limit", atoi(line));
401 ubus_send_reply(ctx, req, buf.head);
407 rpc_luci2_network_ct_table(struct ubus_context *ctx, struct ubus_object *obj,
408 struct ubus_request_data *req, const char *method,
409 struct blob_attr *msg)
417 blob_buf_init(&buf, 0);
418 c = blobmsg_open_array(&buf, "entries");
420 if ((f = fopen("/proc/net/nf_conntrack", "r")) != NULL)
422 while (fgets(line, sizeof(line) - 1, f))
424 d = blobmsg_open_table(&buf, NULL);
425 memset(seen, 0, sizeof(seen));
427 for (i = 0, p = strtok(line, " "); p; i++, p = strtok(NULL, " "))
430 blobmsg_add_u8(&buf, "ipv6", !strcmp(p, "ipv6"));
432 blobmsg_add_u32(&buf, "protocol", atoi(p));
434 blobmsg_add_u32(&buf, "expires", atoi(p));
440 if (!seen[0] && !strncmp(p, "src=", 4))
442 blobmsg_add_string(&buf, "src", p + 4);
445 else if (!seen[1] && !strncmp(p, "dst=", 4))
447 blobmsg_add_string(&buf, "dest", p + 4);
450 else if (!seen[2] && !strncmp(p, "sport=", 6))
452 blobmsg_add_u32(&buf, "sport", atoi(p + 6));
455 else if (!seen[3] && !strncmp(p, "dport=", 6))
457 blobmsg_add_u32(&buf, "dport", atoi(p + 6));
460 else if (!strncmp(p, "packets=", 8))
462 blobmsg_add_u32(&buf,
463 seen[4] ? "tx_packets" : "rx_packets",
467 else if (!strncmp(p, "bytes=", 6))
469 blobmsg_add_u32(&buf,
470 seen[5] ? "tx_bytes" : "rx_bytes",
477 blobmsg_close_table(&buf, d);
483 blobmsg_close_array(&buf, c);
484 ubus_send_reply(ctx, req, buf.head);
490 rpc_luci2_network_arp_table(struct ubus_context *ctx, struct ubus_object *obj,
491 struct ubus_request_data *req, const char *method,
492 struct blob_attr *msg)
496 char *addr, *mac, *dev, line[128];
498 blob_buf_init(&buf, 0);
499 c = blobmsg_open_array(&buf, "entries");
501 if ((f = fopen("/proc/net/arp", "r")) != NULL)
503 /* skip header line */
504 fgets(line, sizeof(line) - 1, f);
506 while (fgets(line, sizeof(line) - 1, f))
508 addr = strtok(line, " \t");
510 strtok(NULL, " \t"); /* HW type */
511 strtok(NULL, " \t"); /* Flags */
513 mac = strtok(NULL, " \t");
515 strtok(NULL, " \t"); /* Mask */
517 dev = strtok(NULL, " \t\n");
522 d = blobmsg_open_table(&buf, NULL);
523 blobmsg_add_string(&buf, "ipaddr", addr);
524 blobmsg_add_string(&buf, "macaddr", mac);
525 blobmsg_add_string(&buf, "device", dev);
526 blobmsg_close_table(&buf, d);
532 blobmsg_close_array(&buf, c);
533 ubus_send_reply(ctx, req, buf.head);
539 put_hexaddr(const char *name, const char *s, const char *m)
543 char as[sizeof("255.255.255.255/32\0")];
545 a.s_addr = strtoul(s, NULL, 16);
546 inet_ntop(AF_INET, &a, as, sizeof(as));
550 for (a.s_addr = ntohl(strtoul(m, NULL, 16)), bits = 0;
551 a.s_addr & 0x80000000;
555 sprintf(as + strlen(as), "/%u", bits);
558 blobmsg_add_string(&buf, name, as);
562 rpc_luci2_network_routes(struct ubus_context *ctx, struct ubus_object *obj,
563 struct ubus_request_data *req, const char *method,
564 struct blob_attr *msg)
568 char *dst, *dmask, *next, *metric, *device;
572 if (!(routes = fopen("/proc/net/route", "r")))
573 return rpc_errno_status();
575 blob_buf_init(&buf, 0);
576 c = blobmsg_open_array(&buf, "routes");
578 /* skip header line */
579 fgets(line, sizeof(line) - 1, routes);
581 while (fgets(line, sizeof(line) - 1, routes))
583 device = strtok(line, "\t ");
584 dst = strtok(NULL, "\t ");
585 next = strtok(NULL, "\t ");
587 strtok(NULL, "\t "); /* flags */
588 strtok(NULL, "\t "); /* refcount */
589 strtok(NULL, "\t "); /* usecount */
591 metric = strtok(NULL, "\t ");
592 dmask = strtok(NULL, "\t ");
597 d = blobmsg_open_table(&buf, NULL);
599 put_hexaddr("target", dst, dmask);
600 put_hexaddr("nexthop", next, NULL);
602 n = strtoul(metric, NULL, 10);
603 blobmsg_add_u32(&buf, "metric", n);
605 blobmsg_add_string(&buf, "device", device);
607 blobmsg_close_table(&buf, d);
610 blobmsg_close_array(&buf, c);
613 ubus_send_reply(ctx, req, buf.head);
618 put_hex6addr(const char *name, const char *s, const char *m)
622 char as[INET6_ADDRSTRLEN + sizeof("/128")];
625 (((x) <= '9') ? ((x) - '0') : \
626 (((x) <= 'F') ? ((x) - 'A' + 10) : \
629 for (i = 0; i < 16; i++, s += 2)
630 a.s6_addr[i] = (16 * hex(*s)) + hex(*(s+1));
632 inet_ntop(AF_INET6, &a, as, sizeof(as));
635 sprintf(as + strlen(as), "/%lu", strtoul(m, NULL, 16));
637 blobmsg_add_string(&buf, name, as);
641 rpc_luci2_network_routes6(struct ubus_context *ctx, struct ubus_object *obj,
642 struct ubus_request_data *req, const char *method,
643 struct blob_attr *msg)
647 char *src, *smask, *dst, *dmask, *next, *metric, *flags, *device;
651 if (!(routes = fopen("/proc/net/ipv6_route", "r")))
652 return rpc_errno_status();
654 blob_buf_init(&buf, 0);
655 c = blobmsg_open_array(&buf, "routes");
657 while (fgets(line, sizeof(line) - 1, routes))
659 dst = strtok(line, " ");
660 dmask = strtok(NULL, " ");
661 src = strtok(NULL, " ");
662 smask = strtok(NULL, " ");
663 next = strtok(NULL, " ");
664 metric = strtok(NULL, " ");
666 strtok(NULL, " "); /* refcount */
667 strtok(NULL, " "); /* usecount */
669 flags = strtok(NULL, " ");
670 device = strtok(NULL, " \n");
675 n = strtoul(flags, NULL, 16);
680 d = blobmsg_open_table(&buf, NULL);
682 put_hex6addr("target", dst, dmask);
683 put_hex6addr("source", src, smask);
684 put_hex6addr("nexthop", next, NULL);
686 n = strtoul(metric, NULL, 16);
687 blobmsg_add_u32(&buf, "metric", n);
689 blobmsg_add_string(&buf, "device", device);
691 blobmsg_close_table(&buf, d);
694 blobmsg_close_array(&buf, c);
697 ubus_send_reply(ctx, req, buf.head);
702 int rpc_luci2_api_init(struct ubus_context *ctx)
706 static const struct ubus_method luci2_system_methods[] = {
707 UBUS_METHOD_NOARG("syslog", rpc_luci2_system_log),
708 UBUS_METHOD_NOARG("dmesg", rpc_luci2_system_dmesg),
711 static struct ubus_object_type luci2_system_type =
712 UBUS_OBJECT_TYPE("luci-rpc-luci2-system", luci2_system_methods);
714 static struct ubus_object system_obj = {
715 .name = "luci2.system",
716 .type = &luci2_system_type,
717 .methods = luci2_system_methods,
718 .n_methods = ARRAY_SIZE(luci2_system_methods),
722 static const struct ubus_method luci2_network_methods[] = {
723 UBUS_METHOD_NOARG("conntrack_count", rpc_luci2_network_ct_count),
724 UBUS_METHOD_NOARG("conntrack_table", rpc_luci2_network_ct_table),
725 UBUS_METHOD_NOARG("arp_table", rpc_luci2_network_arp_table),
726 UBUS_METHOD_NOARG("dhcp_leases", rpc_luci2_network_leases),
727 UBUS_METHOD_NOARG("dhcp6_leases", rpc_luci2_network_leases6),
728 UBUS_METHOD_NOARG("routes", rpc_luci2_network_routes),
729 UBUS_METHOD_NOARG("routes6", rpc_luci2_network_routes6),
732 static struct ubus_object_type luci2_network_type =
733 UBUS_OBJECT_TYPE("luci-rpc-luci2-network", luci2_network_methods);
735 static struct ubus_object network_obj = {
736 .name = "luci2.network",
737 .type = &luci2_network_type,
738 .methods = luci2_network_methods,
739 .n_methods = ARRAY_SIZE(luci2_network_methods),
742 cursor = uci_alloc_context();
745 return UBUS_STATUS_UNKNOWN_ERROR;
747 rv |= ubus_add_object(ctx, &system_obj);
748 rv |= ubus_add_object(ctx, &network_obj);