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);
184 rpc_luci2_process_list(struct ubus_context *ctx, struct ubus_object *obj,
185 struct ubus_request_data *req, const char *method,
186 struct blob_attr *msg)
191 char *pid, *ppid, *user, *stat, *vsz, *pvsz, *pcpu, *cmd;
193 if (!(top = popen("/bin/busybox top -bn1", "r")))
194 return rpc_errno_status();
196 blob_buf_init(&buf, 0);
197 c = blobmsg_open_array(&buf, "processes");
199 while (fgets(line, sizeof(line) - 1, top))
201 pid = strtok(line, " ");
203 if (*pid < '0' || *pid > '9')
206 ppid = strtok(NULL, " ");
207 user = strtok(NULL, " ");
208 stat = strtok(NULL, " ");
221 vsz = strtok(stat + 4, " ");
222 pvsz = strtok(NULL, " ");
223 pcpu = strtok(NULL, " ");
224 cmd = strtok(NULL, "\n");
229 d = blobmsg_open_table(&buf, NULL);
231 blobmsg_add_u32(&buf, "pid", atoi(pid));
232 blobmsg_add_u32(&buf, "ppid", atoi(ppid));
233 blobmsg_add_string(&buf, "user", user);
234 blobmsg_add_string(&buf, "stat", stat);
235 blobmsg_add_u32(&buf, "vsize", atoi(vsz) * 1024);
236 blobmsg_add_u32(&buf, "vsize_percent", atoi(pvsz));
237 blobmsg_add_u32(&buf, "cpu_percent", atoi(pcpu));
238 blobmsg_add_string(&buf, "command", cmd);
240 blobmsg_close_table(&buf, d);
244 blobmsg_close_array(&buf, c);
246 ubus_send_reply(ctx, req, buf.head);
252 dnsmasq_leasefile(void)
255 struct uci_package *p;
256 struct uci_element *e;
257 struct uci_section *s;
258 struct uci_ptr ptr = {
261 .option = "leasefile"
264 uci_load(cursor, ptr.package, &p);
269 uci_foreach_element(&p->sections, e)
271 s = uci_to_section(e);
273 if (strcmp(s->type, "dnsmasq"))
276 ptr.section = e->name;
277 uci_lookup_ptr(cursor, &ptr, NULL, true);
281 if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
282 leases = fopen(ptr.o->v.string, "r");
284 uci_unload(cursor, p);
290 rpc_luci2_network_leases(struct ubus_context *ctx, struct ubus_object *obj,
291 struct ubus_request_data *req, const char *method,
292 struct blob_attr *msg)
297 char *ts, *mac, *addr, *name;
298 time_t now = time(NULL);
300 blob_buf_init(&buf, 0);
301 c = blobmsg_open_array(&buf, "leases");
303 leases = dnsmasq_leasefile();
308 while (fgets(line, sizeof(line) - 1, leases))
310 ts = strtok(line, " \t");
311 mac = strtok(NULL, " \t");
312 addr = strtok(NULL, " \t");
313 name = strtok(NULL, " \t");
315 if (!ts || !mac || !addr || !name)
318 if (strchr(addr, ':'))
321 d = blobmsg_open_table(&buf, NULL);
323 blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
324 blobmsg_add_string(&buf, "macaddr", mac);
325 blobmsg_add_string(&buf, "ipaddr", addr);
327 if (strcmp(name, "*"))
328 blobmsg_add_string(&buf, "hostname", name);
330 blobmsg_close_table(&buf, d);
336 blobmsg_close_array(&buf, c);
337 ubus_send_reply(ctx, req, buf.head);
343 rpc_luci2_network_leases6(struct ubus_context *ctx, struct ubus_object *obj,
344 struct ubus_request_data *req, const char *method,
345 struct blob_attr *msg)
350 char *ts, *mac, *addr, *name, *duid;
351 time_t now = time(NULL);
353 blob_buf_init(&buf, 0);
354 c = blobmsg_open_array(&buf, "leases");
356 leases = fopen("/tmp/hosts/6relayd", "r");
360 while (fgets(line, sizeof(line) - 1, leases))
362 if (strncmp(line, "# ", 2))
365 strtok(line + 2, " \t"); /* iface */
367 duid = strtok(NULL, " \t");
369 strtok(NULL, " \t"); /* iaid */
371 name = strtok(NULL, " \t");
372 ts = strtok(NULL, " \t");
374 strtok(NULL, " \t"); /* id */
375 strtok(NULL, " \t"); /* length */
377 addr = strtok(NULL, " \t\n");
382 d = blobmsg_open_table(&buf, NULL);
384 blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
385 blobmsg_add_string(&buf, "duid", duid);
386 blobmsg_add_string(&buf, "ip6addr", addr);
388 if (strcmp(name, "-"))
389 blobmsg_add_string(&buf, "hostname", name);
391 blobmsg_close_array(&buf, d);
398 leases = dnsmasq_leasefile();
403 while (fgets(line, sizeof(line) - 1, leases))
405 ts = strtok(line, " \t");
406 mac = strtok(NULL, " \t");
407 addr = strtok(NULL, " \t");
408 name = strtok(NULL, " \t");
409 duid = strtok(NULL, " \t\n");
411 if (!ts || !mac || !addr || !duid)
414 if (!strchr(addr, ':'))
417 d = blobmsg_open_table(&buf, NULL);
419 blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
420 blobmsg_add_string(&buf, "macaddr", mac);
421 blobmsg_add_string(&buf, "ip6addr", addr);
423 if (strcmp(name, "*"))
424 blobmsg_add_string(&buf, "hostname", name);
426 if (strcmp(duid, "*"))
427 blobmsg_add_string(&buf, "duid", name);
429 blobmsg_close_table(&buf, d);
436 blobmsg_close_array(&buf, c);
437 ubus_send_reply(ctx, req, buf.head);
443 rpc_luci2_network_ct_count(struct ubus_context *ctx, struct ubus_object *obj,
444 struct ubus_request_data *req, const char *method,
445 struct blob_attr *msg)
450 blob_buf_init(&buf, 0);
452 if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_count", "r")) != NULL)
454 if (fgets(line, sizeof(line) - 1, f))
455 blobmsg_add_u32(&buf, "count", atoi(line));
460 if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_max", "r")) != NULL)
462 if (fgets(line, sizeof(line) - 1, f))
463 blobmsg_add_u32(&buf, "limit", atoi(line));
468 ubus_send_reply(ctx, req, buf.head);
474 rpc_luci2_network_ct_table(struct ubus_context *ctx, struct ubus_object *obj,
475 struct ubus_request_data *req, const char *method,
476 struct blob_attr *msg)
484 blob_buf_init(&buf, 0);
485 c = blobmsg_open_array(&buf, "entries");
487 if ((f = fopen("/proc/net/nf_conntrack", "r")) != NULL)
489 while (fgets(line, sizeof(line) - 1, f))
491 d = blobmsg_open_table(&buf, NULL);
492 memset(seen, 0, sizeof(seen));
494 for (i = 0, p = strtok(line, " "); p; i++, p = strtok(NULL, " "))
497 blobmsg_add_u8(&buf, "ipv6", !strcmp(p, "ipv6"));
499 blobmsg_add_u32(&buf, "protocol", atoi(p));
501 blobmsg_add_u32(&buf, "expires", atoi(p));
507 if (!seen[0] && !strncmp(p, "src=", 4))
509 blobmsg_add_string(&buf, "src", p + 4);
512 else if (!seen[1] && !strncmp(p, "dst=", 4))
514 blobmsg_add_string(&buf, "dest", p + 4);
517 else if (!seen[2] && !strncmp(p, "sport=", 6))
519 blobmsg_add_u32(&buf, "sport", atoi(p + 6));
522 else if (!seen[3] && !strncmp(p, "dport=", 6))
524 blobmsg_add_u32(&buf, "dport", atoi(p + 6));
527 else if (!strncmp(p, "packets=", 8))
529 blobmsg_add_u32(&buf,
530 seen[4] ? "tx_packets" : "rx_packets",
534 else if (!strncmp(p, "bytes=", 6))
536 blobmsg_add_u32(&buf,
537 seen[5] ? "tx_bytes" : "rx_bytes",
544 blobmsg_close_table(&buf, d);
550 blobmsg_close_array(&buf, c);
551 ubus_send_reply(ctx, req, buf.head);
557 rpc_luci2_network_arp_table(struct ubus_context *ctx, struct ubus_object *obj,
558 struct ubus_request_data *req, const char *method,
559 struct blob_attr *msg)
563 char *addr, *mac, *dev, line[128];
565 blob_buf_init(&buf, 0);
566 c = blobmsg_open_array(&buf, "entries");
568 if ((f = fopen("/proc/net/arp", "r")) != NULL)
570 /* skip header line */
571 fgets(line, sizeof(line) - 1, f);
573 while (fgets(line, sizeof(line) - 1, f))
575 addr = strtok(line, " \t");
577 strtok(NULL, " \t"); /* HW type */
578 strtok(NULL, " \t"); /* Flags */
580 mac = strtok(NULL, " \t");
582 strtok(NULL, " \t"); /* Mask */
584 dev = strtok(NULL, " \t\n");
589 d = blobmsg_open_table(&buf, NULL);
590 blobmsg_add_string(&buf, "ipaddr", addr);
591 blobmsg_add_string(&buf, "macaddr", mac);
592 blobmsg_add_string(&buf, "device", dev);
593 blobmsg_close_table(&buf, d);
599 blobmsg_close_array(&buf, c);
600 ubus_send_reply(ctx, req, buf.head);
606 put_hexaddr(const char *name, const char *s, const char *m)
610 char as[sizeof("255.255.255.255/32\0")];
612 a.s_addr = strtoul(s, NULL, 16);
613 inet_ntop(AF_INET, &a, as, sizeof(as));
617 for (a.s_addr = ntohl(strtoul(m, NULL, 16)), bits = 0;
618 a.s_addr & 0x80000000;
622 sprintf(as + strlen(as), "/%u", bits);
625 blobmsg_add_string(&buf, name, as);
629 rpc_luci2_network_routes(struct ubus_context *ctx, struct ubus_object *obj,
630 struct ubus_request_data *req, const char *method,
631 struct blob_attr *msg)
635 char *dst, *dmask, *next, *metric, *device;
639 if (!(routes = fopen("/proc/net/route", "r")))
640 return rpc_errno_status();
642 blob_buf_init(&buf, 0);
643 c = blobmsg_open_array(&buf, "routes");
645 /* skip header line */
646 fgets(line, sizeof(line) - 1, routes);
648 while (fgets(line, sizeof(line) - 1, routes))
650 device = strtok(line, "\t ");
651 dst = strtok(NULL, "\t ");
652 next = strtok(NULL, "\t ");
654 strtok(NULL, "\t "); /* flags */
655 strtok(NULL, "\t "); /* refcount */
656 strtok(NULL, "\t "); /* usecount */
658 metric = strtok(NULL, "\t ");
659 dmask = strtok(NULL, "\t ");
664 d = blobmsg_open_table(&buf, NULL);
666 put_hexaddr("target", dst, dmask);
667 put_hexaddr("nexthop", next, NULL);
669 n = strtoul(metric, NULL, 10);
670 blobmsg_add_u32(&buf, "metric", n);
672 blobmsg_add_string(&buf, "device", device);
674 blobmsg_close_table(&buf, d);
677 blobmsg_close_array(&buf, c);
680 ubus_send_reply(ctx, req, buf.head);
685 put_hex6addr(const char *name, const char *s, const char *m)
689 char as[INET6_ADDRSTRLEN + sizeof("/128")];
692 (((x) <= '9') ? ((x) - '0') : \
693 (((x) <= 'F') ? ((x) - 'A' + 10) : \
696 for (i = 0; i < 16; i++, s += 2)
697 a.s6_addr[i] = (16 * hex(*s)) + hex(*(s+1));
699 inet_ntop(AF_INET6, &a, as, sizeof(as));
702 sprintf(as + strlen(as), "/%lu", strtoul(m, NULL, 16));
704 blobmsg_add_string(&buf, name, as);
708 rpc_luci2_network_routes6(struct ubus_context *ctx, struct ubus_object *obj,
709 struct ubus_request_data *req, const char *method,
710 struct blob_attr *msg)
714 char *src, *smask, *dst, *dmask, *next, *metric, *flags, *device;
718 if (!(routes = fopen("/proc/net/ipv6_route", "r")))
719 return rpc_errno_status();
721 blob_buf_init(&buf, 0);
722 c = blobmsg_open_array(&buf, "routes");
724 while (fgets(line, sizeof(line) - 1, routes))
726 dst = strtok(line, " ");
727 dmask = strtok(NULL, " ");
728 src = strtok(NULL, " ");
729 smask = strtok(NULL, " ");
730 next = strtok(NULL, " ");
731 metric = strtok(NULL, " ");
733 strtok(NULL, " "); /* refcount */
734 strtok(NULL, " "); /* usecount */
736 flags = strtok(NULL, " ");
737 device = strtok(NULL, " \n");
742 n = strtoul(flags, NULL, 16);
747 d = blobmsg_open_table(&buf, NULL);
749 put_hex6addr("target", dst, dmask);
750 put_hex6addr("source", src, smask);
751 put_hex6addr("nexthop", next, NULL);
753 n = strtoul(metric, NULL, 16);
754 blobmsg_add_u32(&buf, "metric", n);
756 blobmsg_add_string(&buf, "device", device);
758 blobmsg_close_table(&buf, d);
761 blobmsg_close_array(&buf, c);
764 ubus_send_reply(ctx, req, buf.head);
769 int rpc_luci2_api_init(struct ubus_context *ctx)
773 static const struct ubus_method luci2_system_methods[] = {
774 UBUS_METHOD_NOARG("syslog", rpc_luci2_system_log),
775 UBUS_METHOD_NOARG("dmesg", rpc_luci2_system_dmesg),
776 UBUS_METHOD_NOARG("process_list", rpc_luci2_process_list)
779 static struct ubus_object_type luci2_system_type =
780 UBUS_OBJECT_TYPE("luci-rpc-luci2-system", luci2_system_methods);
782 static struct ubus_object system_obj = {
783 .name = "luci2.system",
784 .type = &luci2_system_type,
785 .methods = luci2_system_methods,
786 .n_methods = ARRAY_SIZE(luci2_system_methods),
790 static const struct ubus_method luci2_network_methods[] = {
791 UBUS_METHOD_NOARG("conntrack_count", rpc_luci2_network_ct_count),
792 UBUS_METHOD_NOARG("conntrack_table", rpc_luci2_network_ct_table),
793 UBUS_METHOD_NOARG("arp_table", rpc_luci2_network_arp_table),
794 UBUS_METHOD_NOARG("dhcp_leases", rpc_luci2_network_leases),
795 UBUS_METHOD_NOARG("dhcp6_leases", rpc_luci2_network_leases6),
796 UBUS_METHOD_NOARG("routes", rpc_luci2_network_routes),
797 UBUS_METHOD_NOARG("routes6", rpc_luci2_network_routes6),
800 static struct ubus_object_type luci2_network_type =
801 UBUS_OBJECT_TYPE("luci-rpc-luci2-network", luci2_network_methods);
803 static struct ubus_object network_obj = {
804 .name = "luci2.network",
805 .type = &luci2_network_type,
806 .methods = luci2_network_methods,
807 .n_methods = ARRAY_SIZE(luci2_network_methods),
810 cursor = uci_alloc_context();
813 return UBUS_STATUS_UNKNOWN_ERROR;
815 rv |= ubus_add_object(ctx, &system_obj);
816 rv |= ubus_add_object(ctx, &network_obj);