123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866 |
- /*
- * luci - LuCI core functions plugin for rpcd
- *
- * Copyright (C) 2019 Jo-Philipp Wich <jo@mein.io>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <string.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <unistd.h>
- #include <ctype.h>
- #include <dlfcn.h>
- #include <time.h>
- #include <ifaddrs.h>
- #include <net/if.h>
- #include <arpa/inet.h>
- #include <sys/types.h>
- #include <netinet/ether.h>
- #include <linux/rtnetlink.h>
- #include <linux/if_packet.h>
- #include <netlink/msg.h>
- #include <netlink/attr.h>
- #include <netlink/socket.h>
- #include <libubus.h>
- #include <libubox/avl.h>
- #include <libubox/avl-cmp.h>
- #include <libubox/usock.h>
- #include <libubox/uloop.h>
- #include <uci.h>
- #include <iwinfo.h>
- #include <rpcd/plugin.h>
- static struct blob_buf blob;
- struct reply_context {
- struct ubus_context *context;
- struct ubus_request_data request;
- struct uloop_timeout timeout;
- struct blob_buf blob;
- struct avl_tree avl;
- int pending;
- };
- struct invoke_context {
- struct ubus_request request;
- struct uloop_timeout timeout;
- struct ubus_context *context;
- void (*cb)(struct ubus_request *, int, struct blob_attr *);
- void *priv;
- };
- static const char **iw_modenames;
- static struct iwinfo_ops *(*iw_backend)(const char *);
- static void (*iw_close)(void);
- static void
- invoke_data_cb(struct ubus_request *req, int type, struct blob_attr *msg)
- {
- struct invoke_context *ictx =
- container_of(req, struct invoke_context, request);
- if (ictx->cb != NULL)
- ictx->cb(req, type, msg);
- ictx->cb = NULL;
- }
- static void
- invoke_done_cb(struct ubus_request *req, int ret)
- {
- struct invoke_context *ictx =
- container_of(req, struct invoke_context, request);
- if (ictx->cb != NULL)
- ictx->cb(req, -1, NULL);
- uloop_timeout_cancel(&ictx->timeout);
- free(ictx);
- }
- static void
- invoke_timeout_cb(struct uloop_timeout *timeout)
- {
- struct invoke_context *ictx =
- container_of(timeout, struct invoke_context, timeout);
- if (ictx->cb != NULL)
- ictx->cb(&ictx->request, -1, NULL);
- ubus_abort_request(ictx->context, &ictx->request);
- free(ictx);
- }
- static struct reply_context *
- defer_request(struct ubus_context *ctx, struct ubus_request_data *req)
- {
- struct reply_context *rctx;
- rctx = calloc(1, sizeof(*rctx));
- if (!rctx)
- return NULL;
- rctx->context = ctx;
- blob_buf_init(&rctx->blob, 0);
- ubus_defer_request(ctx, req, &rctx->request);
- return rctx;
- }
- static int
- finish_request(struct reply_context *rctx, int status)
- {
- if (status == UBUS_STATUS_OK)
- ubus_send_reply(rctx->context, &rctx->request, rctx->blob.head);
- ubus_complete_deferred_request(rctx->context, &rctx->request, status);
- blob_buf_free(&rctx->blob);
- free(rctx);
- return status;
- }
- static bool
- invoke_ubus(struct ubus_context *ctx, const char *object, const char *method,
- struct blob_buf *req,
- void (*cb)(struct ubus_request *, int, struct blob_attr *),
- void *priv)
- {
- struct invoke_context *ictx;
- struct blob_buf empty = {};
- uint32_t id;
- bool rv;
- if (ubus_lookup_id(ctx, object, &id))
- return false;
- if (req == NULL) {
- blob_buf_init(&empty, 0);
- req = ∅
- }
- ictx = calloc(1, sizeof(*ictx));
- if (ictx == NULL)
- return false;
- ictx->context = ctx;
- rv = !ubus_invoke_async(ctx, id, method, req->head, &ictx->request);
- if (rv) {
- ictx->cb = cb;
- ictx->request.priv = priv;
- ictx->request.data_cb = invoke_data_cb;
- ictx->request.complete_cb = invoke_done_cb;
- ubus_complete_request_async(ctx, &ictx->request);
- ictx->timeout.cb = invoke_timeout_cb;
- uloop_timeout_set(&ictx->timeout, 2000);
- }
- else {
- if (cb != NULL)
- cb(&ictx->request, -1, NULL);
- free(ictx);
- }
- if (req == &empty)
- blob_buf_free(req);
- return rv;
- }
- static char *
- readstr(const char *fmt, ...)
- {
- static char data[128];
- char path[128];
- va_list ap;
- size_t n;
- FILE *f;
- va_start(ap, fmt);
- vsnprintf(path, sizeof(path), fmt, ap);
- va_end(ap);
- data[0] = 0;
- f = fopen(path, "r");
- if (f != NULL) {
- n = fread(data, 1, sizeof(data) - 1, f);
- data[n] = 0;
- while (n > 0 && isspace(data[n-1]))
- data[--n] = 0;
- fclose(f);
- }
- return data;
- }
- static char *
- ea2str(struct ether_addr *ea)
- {
- static char mac[18];
- if (!ea)
- return NULL;
- snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
- ea->ether_addr_octet[0], ea->ether_addr_octet[1],
- ea->ether_addr_octet[2], ea->ether_addr_octet[3],
- ea->ether_addr_octet[4], ea->ether_addr_octet[5]);
- return mac;
- }
- static char *
- sa2str(struct sockaddr *sa)
- {
- static char buf[INET6_ADDRSTRLEN];
- union {
- struct sockaddr_in6 *in6;
- struct sockaddr_in *in;
- struct sockaddr_ll *ll;
- struct sockaddr *sa;
- } s;
- s.sa = sa;
- if (s.sa->sa_family == AF_INET)
- inet_ntop(sa->sa_family, &s.in->sin_addr, buf, sizeof(buf));
- else if (s.sa->sa_family == AF_INET6)
- inet_ntop(sa->sa_family, &s.in6->sin6_addr, buf, sizeof(buf));
- else if (s.sa->sa_family == AF_PACKET)
- strcpy(buf, ea2str((struct ether_addr *)s.ll->sll_addr));
- else
- buf[0] = 0;
- return buf;
- }
- static struct ether_addr *
- duid2ea(const char *duid)
- {
- static struct ether_addr ea;
- const char *p = NULL;
- size_t len;
- if (!duid)
- return NULL;
- for (len = 0; duid[len]; len++)
- if (!isxdigit(duid[len]))
- return NULL;
- #define hex(x) \
- (((x) <= '9') ? ((x) - '0') : \
- (((x) <= 'F') ? ((x) - 'A' + 10) : \
- ((x) - 'a' + 10)))
- switch (len) {
- case 28:
- if (!strncmp(duid, "00010001", 8))
- p = duid + 16;
- break;
- case 20:
- if (!strncmp(duid, "00030001", 8))
- p = duid + 8;
- break;
- case 12:
- p = duid;
- break;
- }
- if (!p)
- return NULL;
- ea.ether_addr_octet[0] = hex(p[0]) * 16 + hex(p[1]);
- ea.ether_addr_octet[1] = hex(p[2]) * 16 + hex(p[3]);
- ea.ether_addr_octet[2] = hex(p[4]) * 16 + hex(p[5]);
- ea.ether_addr_octet[3] = hex(p[6]) * 16 + hex(p[7]);
- ea.ether_addr_octet[4] = hex(p[8]) * 16 + hex(p[9]);
- ea.ether_addr_octet[5] = hex(p[10]) * 16 + hex(p[11]);
- return &ea;
- }
- static struct {
- time_t now;
- size_t num, off;
- struct {
- FILE *fh;
- bool odhcpd;
- } *files;
- } lease_state = { };
- struct lease_entry {
- int af, n_addr;
- char buf[512];
- int32_t expire;
- struct ether_addr mac;
- char *hostname;
- char *duid;
- union {
- struct in_addr in;
- struct in6_addr in6;
- } addr[10];
- };
- static bool
- add_leasefile(const char *path, bool is_odhcpd)
- {
- void *ptr;
- FILE *fh;
- fh = fopen(path, "r");
- if (!fh)
- return false;
- ptr = realloc(lease_state.files, sizeof(*lease_state.files) * (lease_state.num + 1));
- if (!ptr) {
- fclose(fh);
- return false;
- }
- lease_state.files = ptr;
- lease_state.files[lease_state.num].fh = fh;
- lease_state.files[lease_state.num].odhcpd = is_odhcpd;
- lease_state.num++;
- return true;
- }
- static bool
- find_leasefiles(struct uci_context *uci, bool is_odhcpd)
- {
- struct uci_ptr ptr = { .package = "dhcp" };
- struct uci_package *pkg = NULL;
- struct uci_section *s;
- struct uci_element *e;
- bool found = false;
- pkg = uci_lookup_package(uci, ptr.package);
- if (!pkg) {
- uci_load(uci, ptr.package, &pkg);
- if (!pkg)
- return NULL;
- }
- uci_foreach_element(&pkg->sections, e) {
- s = uci_to_section(e);
- if (strcmp(s->type, is_odhcpd ? "odhcpd" : "dnsmasq"))
- continue;
- ptr.flags = 0;
- ptr.section = s->e.name;
- ptr.s = NULL;
- ptr.option = "leasefile";
- ptr.o = NULL;
- if (uci_lookup_ptr(uci, &ptr, NULL, true) || ptr.o == NULL)
- continue;
- if (ptr.o->type != UCI_TYPE_STRING)
- continue;
- if (add_leasefile(ptr.o->v.string, is_odhcpd))
- found = true;
- }
- return found;
- }
- static void
- lease_close(void)
- {
- while (lease_state.num > 0)
- fclose(lease_state.files[--lease_state.num].fh);
- free(lease_state.files);
- lease_state.files = NULL;
- lease_state.num = 0;
- lease_state.off = 0;
- }
- static void
- lease_open(void)
- {
- struct uci_context *uci;
- lease_close();
- uci = uci_alloc_context();
- if (!uci)
- return;
- lease_state.now = time(NULL);
- if (!find_leasefiles(uci, false))
- add_leasefile("/tmp/dhcp.leases", false);
- if (!find_leasefiles(uci, true))
- add_leasefile("/tmp/hosts/odhcpd", true);
- uci_free_context(uci);
- }
- static struct lease_entry *
- lease_next(void)
- {
- static struct lease_entry e;
- struct ether_addr *ea;
- char *p;
- int n;
- memset(&e, 0, sizeof(e));
- while (lease_state.off < lease_state.num) {
- while (fgets(e.buf, sizeof(e.buf), lease_state.files[lease_state.off].fh)) {
- if (lease_state.files[lease_state.off].odhcpd) {
- strtok(e.buf, " \t\n"); /* # */
- strtok(NULL, " \t\n"); /* iface */
- e.duid = strtok(NULL, " \t\n"); /* duid */
- if (!e.duid)
- continue;
- p = strtok(NULL, " \t\n"); /* iaid */
- if (p)
- e.af = strcmp(p, "ipv4") ? AF_INET6 : AF_INET;
- else
- continue;
- e.hostname = strtok(NULL, " \t\n"); /* name */
- if (!e.hostname)
- continue;
- p = strtok(NULL, " \t\n"); /* ts */
- if (!p)
- continue;
- n = strtol(p, NULL, 10);
- if (n > lease_state.now)
- e.expire = n - lease_state.now;
- else if (n >= 0)
- e.expire = 0;
- else
- e.expire = -1;
- strtok(NULL, " \t\n"); /* id */
- strtok(NULL, " \t\n"); /* length */
- for (e.n_addr = 0, p = strtok(NULL, "/ \t\n");
- e.n_addr < ARRAY_SIZE(e.addr) && p != NULL;
- p = strtok(NULL, "/ \t\n")) {
- if (inet_pton(e.af, p, &e.addr[e.n_addr].in6))
- e.n_addr++;
- }
- ea = duid2ea(e.duid);
- if (ea)
- e.mac = *ea;
- if (!strcmp(e.hostname, "-"))
- e.hostname = NULL;
- if (!strcmp(e.duid, "-"))
- e.duid = NULL;
- }
- else {
- p = strtok(e.buf, " \t\n");
- if (!p)
- continue;
- n = strtol(p, NULL, 10);
- if (n > lease_state.now)
- e.expire = n - lease_state.now;
- else if (n > 0)
- e.expire = 0;
- else
- e.expire = -1;
- p = strtok(NULL, " \t\n");
- if (!p)
- continue;
- ea = ether_aton(p);
- p = strtok(NULL, " \t\n");
- if (p && inet_pton(AF_INET6, p, &e.addr[0].in6)) {
- e.af = AF_INET6;
- e.n_addr = 1;
- }
- else if (p && inet_pton(AF_INET, p, &e.addr[0].in)) {
- e.af = AF_INET;
- e.n_addr = 1;
- }
- else {
- continue;
- }
- if (!ea && e.af != AF_INET6)
- continue;
- e.hostname = strtok(NULL, " \t\n");
- e.duid = strtok(NULL, " \t\n");
- if (!e.hostname || !e.duid)
- continue;
- if (!strcmp(e.hostname, "*"))
- e.hostname = NULL;
- if (!strcmp(e.duid, "*"))
- e.duid = NULL;
- if (!ea && e.duid)
- ea = duid2ea(e.duid);
- if (ea)
- e.mac = *ea;
- }
- return &e;
- }
- lease_state.off++;
- }
- return NULL;
- }
- static void
- rpc_luci_parse_network_device_sys(const char *name, struct ifaddrs *ifaddr)
- {
- char link[64], buf[512], *p;
- unsigned int ifa_flags = 0;
- struct sockaddr_ll *sll;
- struct ifaddrs *ifa;
- struct dirent *e;
- void *o, *o2, *a;
- ssize_t len;
- uint64_t v;
- int n, af;
- DIR *d;
- const char *stats[] = {
- "rx_bytes", "tx_bytes", "tx_errors", "rx_errors", "tx_packets",
- "rx_packets", "multicast", "collisions", "rx_dropped", "tx_dropped"
- };
- o = blobmsg_open_table(&blob, name);
- blobmsg_add_string(&blob, "name", name);
- snprintf(buf, sizeof(buf), "/sys/class/net/%s/brif", name);
- d = opendir(buf);
- if (d) {
- blobmsg_add_u8(&blob, "bridge", 1);
- a = blobmsg_open_array(&blob, "ports");
- while (true) {
- e = readdir(d);
- if (e == NULL)
- break;
- if (strcmp(e->d_name, ".") && strcmp(e->d_name, ".."))
- blobmsg_add_string(&blob, NULL, e->d_name);
- }
- blobmsg_close_array(&blob, a);
- closedir(d);
- p = readstr("/sys/class/net/%s/bridge/bridge_id", name);
- blobmsg_add_string(&blob, "id", p);
- p = readstr("/sys/class/net/%s/bridge/stp_state", name);
- blobmsg_add_u8(&blob, "stp", strcmp(p, "0") ? 1 : 0);
- }
- snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", name);
- len = readlink(buf, link, sizeof(link) - 1);
- if (len > 0) {
- link[len] = 0;
- blobmsg_add_string(&blob, "master", basename(link));
- }
- p = readstr("/sys/class/net/%s/phy80211/index", name);
- blobmsg_add_u8(&blob, "wireless", *p ? 1 : 0);
- p = readstr("/sys/class/net/%s/operstate", name);
- blobmsg_add_u8(&blob, "up", !strcmp(p, "up") || !strcmp(p, "unknown"));
- n = atoi(readstr("/sys/class/net/%s/mtu", name));
- if (n > 0)
- blobmsg_add_u32(&blob, "mtu", n);
- n = atoi(readstr("/sys/class/net/%s/tx_queue_len", name));
- if (n > 0)
- blobmsg_add_u32(&blob, "qlen", n);
- p = readstr("/sys/class/net/%s/master", name);
- if (*p)
- blobmsg_add_string(&blob, "master", p);
- p = strstr(readstr("/sys/class/net/%s/uevent", name), "DEVTYPE=");
- if (p) {
- for (n = 0, p += strlen("DEVTYPE=");; n++) {
- if (p[n] == '\0' || p[n] == '\n') {
- p[n] = 0;
- blobmsg_add_string(&blob, "devtype", p);
- break;
- }
- }
- }
- else {
- blobmsg_add_string(&blob, "devtype", "ethernet");
- }
- for (af = AF_INET; af != 0; af = (af == AF_INET) ? AF_INET6 : 0) {
- a = blobmsg_open_array(&blob,
- (af == AF_INET) ? "ipaddrs" : "ip6addrs");
- for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != af)
- continue;
- if (strcmp(ifa->ifa_name, name))
- continue;
- o2 = blobmsg_open_table(&blob, NULL);
- blobmsg_add_string(&blob, "address",
- sa2str(ifa->ifa_addr));
- blobmsg_add_string(&blob, "netmask",
- sa2str(ifa->ifa_netmask));
- if (ifa->ifa_dstaddr && (ifa->ifa_flags & IFF_POINTOPOINT))
- blobmsg_add_string(&blob, "remote",
- sa2str(ifa->ifa_dstaddr));
- else if (ifa->ifa_broadaddr && (ifa->ifa_flags & IFF_BROADCAST))
- blobmsg_add_string(&blob, "broadcast",
- sa2str(ifa->ifa_broadaddr));
- blobmsg_close_table(&blob, o2);
- ifa_flags |= ifa->ifa_flags;
- }
- blobmsg_close_array(&blob, a);
- }
- for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_PACKET)
- continue;
- if (strcmp(ifa->ifa_name, name))
- continue;
- sll = (struct sockaddr_ll *)ifa->ifa_addr;
- if (sll->sll_hatype == 1)
- blobmsg_add_string(&blob, "mac", sa2str(ifa->ifa_addr));
- blobmsg_add_u32(&blob, "type", sll->sll_hatype);
- blobmsg_add_u32(&blob, "ifindex", sll->sll_ifindex);
- ifa_flags |= ifa->ifa_flags;
- n = atoi(readstr("/sys/class/net/%s/iflink", name));
- if (n != sll->sll_ifindex) {
- for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_PACKET)
- continue;
- sll = (struct sockaddr_ll *)ifa->ifa_addr;
- if (sll->sll_ifindex != n)
- continue;
- blobmsg_add_string(&blob, "parent", ifa->ifa_name);
- break;
- }
- }
- break;
- }
- o2 = blobmsg_open_table(&blob, "stats");
- for (n = 0; n < ARRAY_SIZE(stats); n++) {
- v = strtoull(readstr("/sys/class/net/%s/statistics/%s",
- name, stats[n]), NULL, 10);
- blobmsg_add_u64(&blob, stats[n], v);
- }
- blobmsg_close_table(&blob, o2);
- o2 = blobmsg_open_table(&blob, "flags");
- blobmsg_add_u8(&blob, "up", ifa_flags & IFF_UP);
- blobmsg_add_u8(&blob, "broadcast", ifa_flags & IFF_BROADCAST);
- blobmsg_add_u8(&blob, "promisc", ifa_flags & IFF_PROMISC);
- blobmsg_add_u8(&blob, "loopback", ifa_flags & IFF_LOOPBACK);
- blobmsg_add_u8(&blob, "noarp", ifa_flags & IFF_NOARP);
- blobmsg_add_u8(&blob, "multicast", ifa_flags & IFF_MULTICAST);
- blobmsg_add_u8(&blob, "pointtopoint", ifa_flags & IFF_POINTOPOINT);
- blobmsg_close_table(&blob, o2);
- blobmsg_close_table(&blob, o);
- }
- static int
- rpc_luci_get_network_devices(struct ubus_context *ctx,
- struct ubus_object *obj,
- struct ubus_request_data *req,
- const char *method,
- struct blob_attr *msg)
- {
- struct ifaddrs *ifaddr;
- struct dirent *e;
- DIR *d;
- blob_buf_init(&blob, 0);
- d = opendir("/sys/class/net");
- if (d != NULL) {
- if (getifaddrs(&ifaddr) == 1)
- ifaddr = NULL;
- while (true) {
- e = readdir(d);
- if (e == NULL)
- break;
- if (strcmp(e->d_name, ".") && strcmp(e->d_name, ".."))
- rpc_luci_parse_network_device_sys(e->d_name, ifaddr);
- }
- if (ifaddr != NULL)
- freeifaddrs(ifaddr);
- closedir(d);
- }
- ubus_send_reply(ctx, req, blob.head);
- return 0;
- }
- static void
- iw_call_str(int (*method)(const char *, char *), const char *dev,
- struct blob_buf *blob, const char *field)
- {
- char buf[IWINFO_BUFSIZE] = {};
- if (method(dev, buf) == 0)
- blobmsg_add_string(blob, field, buf);
- }
- static void
- iw_call_num(int (*method)(const char *, int *), const char *dev,
- struct blob_buf *blob, const char *field)
- {
- int val = 0;
- if (method(dev, &val) == 0)
- blobmsg_add_u32(blob, field, val);
- }
- static bool rpc_luci_get_iwinfo(struct blob_buf *buf, const char *devname,
- bool phy_only)
- {
- struct iwinfo_crypto_entry crypto = {};
- struct iwinfo_hardware_id ids = {};
- const struct iwinfo_ops *iw;
- void *iwlib = NULL;
- void *o, *o2, *a;
- glob_t paths;
- int nret, i;
- if (!iw_backend || !iw_close || !iw_modenames) {
- if (glob("/usr/lib/libiwinfo.so*", 0, NULL, &paths) != 0)
- return false;
- for (i = 0; i < paths.gl_pathc && !iwlib; i++)
- iwlib = dlopen(paths.gl_pathv[i], RTLD_LAZY | RTLD_LOCAL);
- globfree(&paths);
- if (!iwlib)
- return false;
- iw_backend = dlsym(iwlib, "iwinfo_backend");
- iw_close = dlsym(iwlib, "iwinfo_close");
- iw_modenames = dlsym(iwlib, "IWINFO_OPMODE_NAMES");
- if (!iw_backend || !iw_close || !iw_modenames)
- return false;
- }
- iw = iw_backend(devname);
- if (!iw)
- return false;
- o = blobmsg_open_table(buf, "iwinfo");
- iw_call_num(iw->signal, devname, buf, "signal");
- iw_call_num(iw->noise, devname, buf, "noise");
- iw_call_num(iw->channel, devname, buf, "channel");
- iw_call_str(iw->country, devname, buf, "country");
- iw_call_str(iw->phyname, devname, buf, "phy");
- iw_call_num(iw->txpower, devname, buf, "txpower");
- iw_call_num(iw->txpower_offset, devname, buf, "txpower_offset");
- iw_call_num(iw->frequency, devname, buf, "frequency");
- iw_call_num(iw->frequency_offset, devname, buf, "frequency_offset");
- if (!iw->hwmodelist(devname, &nret)) {
- a = blobmsg_open_array(buf, "hwmodes");
- if (nret & IWINFO_80211_AC)
- blobmsg_add_string(buf, NULL, "ac");
- if (nret & IWINFO_80211_A)
- blobmsg_add_string(buf, NULL, "a");
- if (nret & IWINFO_80211_B)
- blobmsg_add_string(buf, NULL, "b");
- if (nret & IWINFO_80211_G)
- blobmsg_add_string(buf, NULL, "g");
- if (nret & IWINFO_80211_N)
- blobmsg_add_string(buf, NULL, "n");
- blobmsg_close_array(buf, a);
- }
- if (!iw->htmodelist(devname, &nret)) {
- a = blobmsg_open_array(buf, "htmodes");
- if (nret & IWINFO_HTMODE_HT20)
- blobmsg_add_string(buf, NULL, "HT20");
- if (nret & IWINFO_HTMODE_HT40)
- blobmsg_add_string(buf, NULL, "HT40");
- if (nret & IWINFO_HTMODE_VHT20)
- blobmsg_add_string(buf, NULL, "VHT20");
- if (nret & IWINFO_HTMODE_VHT40)
- blobmsg_add_string(buf, NULL, "VHT40");
- if (nret & IWINFO_HTMODE_VHT80)
- blobmsg_add_string(buf, NULL, "VHT80");
- if (nret & IWINFO_HTMODE_VHT80_80)
- blobmsg_add_string(buf, NULL, "VHT80+80");
- if (nret & IWINFO_HTMODE_VHT160)
- blobmsg_add_string(buf, NULL, "VHT160");
- blobmsg_close_array(buf, a);
- }
- if (!iw->hardware_id(devname, (char *)&ids)) {
- o2 = blobmsg_open_table(buf, "hardware");
- a = blobmsg_open_array(buf, "id");
- blobmsg_add_u32(buf, NULL, ids.vendor_id);
- blobmsg_add_u32(buf, NULL, ids.device_id);
- blobmsg_add_u32(buf, NULL, ids.subsystem_vendor_id);
- blobmsg_add_u32(buf, NULL, ids.subsystem_device_id);
- blobmsg_close_array(buf, a);
- iw_call_str(iw->hardware_name, devname, buf, "name");
- blobmsg_close_table(buf, o2);
- }
- if (!phy_only) {
- iw_call_num(iw->quality, devname, buf, "quality");
- iw_call_num(iw->quality_max, devname, buf, "quality_max");
- iw_call_num(iw->bitrate, devname, buf, "bitrate");
- if (!iw->mode(devname, &nret))
- blobmsg_add_string(buf, "mode", iw_modenames[nret]);
- iw_call_str(iw->ssid, devname, buf, "ssid");
- iw_call_str(iw->bssid, devname, buf, "bssid");
- if (!iw->encryption(devname, (char *)&crypto)) {
- o2 = blobmsg_open_table(buf, "encryption");
- blobmsg_add_u8(buf, "enabled", crypto.enabled);
- if (crypto.enabled) {
- if (!crypto.wpa_version) {
- a = blobmsg_open_array(buf, "wep");
- if (crypto.auth_algs & IWINFO_AUTH_OPEN)
- blobmsg_add_string(buf, NULL, "open");
- if (crypto.auth_algs & IWINFO_AUTH_SHARED)
- blobmsg_add_string(buf, NULL, "shared");
- blobmsg_close_array(buf, a);
- }
- else {
- a = blobmsg_open_array(buf, "wpa");
- for (nret = 1; nret <= 3; nret++)
- if (crypto.wpa_version & (1 << (nret - 1)))
- blobmsg_add_u32(buf, NULL, nret);
- blobmsg_close_array(buf, a);
- a = blobmsg_open_array(buf, "authentication");
- if (crypto.auth_suites & IWINFO_KMGMT_PSK)
- blobmsg_add_string(buf, NULL, "psk");
- if (crypto.auth_suites & IWINFO_KMGMT_8021x)
- blobmsg_add_string(buf, NULL, "802.1x");
- if (crypto.auth_suites & IWINFO_KMGMT_SAE)
- blobmsg_add_string(buf, NULL, "sae");
- if (crypto.auth_suites & IWINFO_KMGMT_OWE)
- blobmsg_add_string(buf, NULL, "owe");
- if (!crypto.auth_suites ||
- (crypto.auth_suites & IWINFO_KMGMT_NONE))
- blobmsg_add_string(buf, NULL, "none");
- blobmsg_close_array(buf, a);
- }
- a = blobmsg_open_array(buf, "ciphers");
- nret = crypto.pair_ciphers | crypto.group_ciphers;
- if (nret & IWINFO_CIPHER_WEP40)
- blobmsg_add_string(buf, NULL, "wep-40");
- if (nret & IWINFO_CIPHER_WEP104)
- blobmsg_add_string(buf, NULL, "wep-104");
- if (nret & IWINFO_CIPHER_TKIP)
- blobmsg_add_string(buf, NULL, "tkip");
- if (nret & IWINFO_CIPHER_CCMP)
- blobmsg_add_string(buf, NULL, "ccmp");
- if (nret & IWINFO_CIPHER_WRAP)
- blobmsg_add_string(buf, NULL, "wrap");
- if (nret & IWINFO_CIPHER_AESOCB)
- blobmsg_add_string(buf, NULL, "aes-ocb");
- if (nret & IWINFO_CIPHER_CKIP)
- blobmsg_add_string(buf, NULL, "ckip");
- if (!nret || (nret & IWINFO_CIPHER_NONE))
- blobmsg_add_string(buf, NULL, "none");
- blobmsg_close_array(buf, a);
- }
- blobmsg_close_table(buf, o2);
- }
- }
- blobmsg_close_table(buf, o);
- iw_close();
- return true;
- }
- static void rpc_luci_get_wireless_devices_cb(struct ubus_request *req,
- int type, struct blob_attr *msg)
- {
- struct blob_attr *wifi, *cur, *iface, *cur2;
- struct reply_context *rctx = req->priv;
- const char *name, *first_ifname;
- int rem, rem2, rem3, rem4;
- void *o, *a, *o2;
- blob_for_each_attr(wifi, msg, rem) {
- if (blobmsg_type(wifi) != BLOBMSG_TYPE_TABLE ||
- blobmsg_name(wifi) == NULL)
- continue;
- o = blobmsg_open_table(&rctx->blob, blobmsg_name(wifi));
- rem2 = blobmsg_data_len(wifi);
- first_ifname = NULL;
- __blob_for_each_attr(cur, blobmsg_data(wifi), rem2) {
- name = blobmsg_name(cur);
- if (!name || !strcmp(name, "iwinfo")) {
- continue;
- }
- else if (!strcmp(name, "interfaces")) {
- if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY)
- continue;
- a = blobmsg_open_array(&rctx->blob, "interfaces");
- rem3 = blobmsg_data_len(cur);
- __blob_for_each_attr(iface, blobmsg_data(cur), rem3) {
- if (blobmsg_type(iface) != BLOBMSG_TYPE_TABLE)
- continue;
- o2 = blobmsg_open_table(&rctx->blob, NULL);
- rem4 = blobmsg_data_len(iface);
- name = NULL;
- __blob_for_each_attr(cur2, blobmsg_data(iface), rem4) {
- if (!strcmp(blobmsg_name(cur2), "ifname"))
- name = blobmsg_get_string(cur2);
- else if (!strcmp(blobmsg_name(cur2), "iwinfo"))
- continue;
- blobmsg_add_blob(&rctx->blob, cur2);
- }
- if (name)
- if (rpc_luci_get_iwinfo(&rctx->blob, name, false))
- first_ifname = first_ifname ? first_ifname : name;
- blobmsg_close_table(&rctx->blob, o2);
- }
- blobmsg_close_array(&rctx->blob, a);
- }
- else {
- blobmsg_add_blob(&rctx->blob, cur);
- }
- }
- rpc_luci_get_iwinfo(&rctx->blob,
- first_ifname ? first_ifname : blobmsg_name(wifi),
- true);
- blobmsg_close_table(&rctx->blob, o);
- }
- finish_request(rctx, UBUS_STATUS_OK);
- }
- static int
- rpc_luci_get_wireless_devices(struct ubus_context *ctx,
- struct ubus_object *obj,
- struct ubus_request_data *req,
- const char *method,
- struct blob_attr *msg)
- {
- struct reply_context *rctx = defer_request(ctx, req);
- if (!rctx)
- return UBUS_STATUS_UNKNOWN_ERROR;
- if (!invoke_ubus(ctx, "network.wireless", "status", NULL,
- rpc_luci_get_wireless_devices_cb, rctx))
- return finish_request(rctx, UBUS_STATUS_NOT_FOUND);
- return UBUS_STATUS_OK;
- }
- struct host_hint {
- struct avl_node avl;
- char *hostname;
- struct in_addr ip;
- struct in6_addr ip6;
- };
- static int
- nl_cb_done(struct nl_msg *msg, void *arg)
- {
- struct reply_context *rctx = arg;
- rctx->pending = 0;
- return NL_STOP;
- }
- static int
- nl_cb_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
- {
- struct reply_context *rctx = arg;
- rctx->pending = 0;
- return NL_STOP;
- }
- static struct host_hint *
- rpc_luci_get_host_hint(struct reply_context *rctx, struct ether_addr *ea)
- {
- struct host_hint *hint;
- char *p, *mac;
- if (!ea)
- return NULL;
- mac = ea2str(ea);
- hint = avl_find_element(&rctx->avl, mac, hint, avl);
- if (!hint) {
- hint = calloc_a(sizeof(*hint), &p, strlen(mac) + 1);
- if (!hint)
- return NULL;
- hint->avl.key = strcpy(p, mac);
- avl_insert(&rctx->avl, &hint->avl);
- }
- return hint;
- }
- static int nl_cb_dump_neigh(struct nl_msg *msg, void *arg)
- {
- struct reply_context *rctx = arg;
- struct ether_addr *mac;
- struct in6_addr *dst;
- struct nlmsghdr *hdr = nlmsg_hdr(msg);
- struct ndmsg *nd = NLMSG_DATA(hdr);
- struct nlattr *tb[NDA_MAX+1];
- struct host_hint *hint;
- rctx->pending = !!(hdr->nlmsg_flags & NLM_F_MULTI);
- if (hdr->nlmsg_type != RTM_NEWNEIGH ||
- (nd->ndm_family != AF_INET && nd->ndm_family != AF_INET6))
- return NL_SKIP;
- if (!(nd->ndm_state & (0xFF & ~NUD_NOARP)))
- return NL_SKIP;
- nlmsg_parse(hdr, sizeof(*nd), tb, NDA_MAX, NULL);
- mac = tb[NDA_LLADDR] ? RTA_DATA(tb[NDA_LLADDR]) : NULL;
- dst = tb[NDA_DST] ? RTA_DATA(tb[NDA_DST]) : NULL;
- if (!mac || !dst)
- return NL_SKIP;
- hint = rpc_luci_get_host_hint(rctx, mac);
- if (!hint)
- return NL_SKIP;
- if (nd->ndm_family == AF_INET)
- hint->ip = *(struct in_addr *)dst;
- else
- hint->ip6 = *(struct in6_addr *)dst;
- return NL_SKIP;
- }
- static void
- rpc_luci_get_host_hints_nl(struct reply_context *rctx)
- {
- struct nl_sock *sock = NULL;
- struct nl_msg *msg = NULL;
- struct nl_cb *cb = NULL;
- struct ndmsg ndm = {};
- sock = nl_socket_alloc();
- if (!sock)
- goto out;
- if (nl_connect(sock, NETLINK_ROUTE))
- goto out;
- cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (!cb)
- goto out;
- msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
- if (!msg)
- goto out;
- nlmsg_append(msg, &ndm, sizeof(ndm), 0);
- nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, nl_cb_dump_neigh, rctx);
- nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_cb_done, rctx);
- nl_cb_err(cb, NL_CB_CUSTOM, nl_cb_error, rctx);
- avl_init(&rctx->avl, avl_strcmp, false, NULL);
- rctx->pending = 1;
- nl_send_auto_complete(sock, msg);
- while (rctx->pending)
- nl_recvmsgs(sock, cb);
- out:
- if (sock)
- nl_socket_free(sock);
- if (cb)
- nl_cb_put(cb);
- if (msg)
- nlmsg_free(msg);
- }
- static void
- rpc_luci_get_host_hints_ether(struct reply_context *rctx)
- {
- struct host_hint *hint;
- struct in_addr in;
- char buf[512], *p;
- FILE *f;
- f = fopen("/etc/ethers", "r");
- if (!f)
- return;
- while (fgets(buf, sizeof(buf), f)) {
- p = strtok(buf, " \t\n");
- hint = rpc_luci_get_host_hint(rctx, p ? ether_aton(p) : NULL);
- if (!hint)
- continue;
- p = strtok(NULL, " \t\n");
- if (!p)
- continue;
- if (inet_pton(AF_INET, p, &in) == 1) {
- if (hint->ip.s_addr == 0)
- hint->ip = in;
- }
- else if (*p && !hint->hostname) {
- hint->hostname = strdup(p);
- }
- }
- fclose(f);
- }
- static void
- rpc_luci_get_host_hints_uci(struct reply_context *rctx)
- {
- struct uci_ptr ptr = { .package = "dhcp" };
- struct uci_context *uci = NULL;
- struct uci_package *pkg = NULL;
- struct in6_addr empty = {};
- struct lease_entry *lease;
- struct host_hint *hint;
- struct uci_element *e, *l;
- struct uci_section *s;
- struct in_addr in;
- char *p, *n;
- uci = uci_alloc_context();
- if (!uci)
- goto out;
- uci_load(uci, ptr.package, &pkg);
- if (!pkg)
- goto out;
- uci_foreach_element(&pkg->sections, e)
- {
- s = uci_to_section(e);
- if (strcmp(s->type, "host"))
- continue;
- ptr.section = s->e.name;
- ptr.s = NULL;
- ptr.option = "ip";
- ptr.o = NULL;
- if (!uci_lookup_ptr(uci, &ptr, NULL, true) && ptr.o != NULL &&
- ptr.o->type != UCI_TYPE_STRING)
- n = ptr.o->v.string;
- else
- n = NULL;
- if (!n || inet_pton(AF_INET, n, &in) != 1)
- in.s_addr = 0;
- ptr.option = "name";
- ptr.o = NULL;
- if (!uci_lookup_ptr(uci, &ptr, NULL, true) && ptr.o != NULL &&
- ptr.o->type == UCI_TYPE_STRING)
- n = ptr.o->v.string;
- else
- n = NULL;
- ptr.option = "mac";
- ptr.o = NULL;
- if (uci_lookup_ptr(uci, &ptr, NULL, true) || ptr.o == NULL)
- continue;
- if (ptr.o->type == UCI_TYPE_STRING) {
- for (p = strtok(ptr.o->v.string, " \t");
- p != NULL;
- p = strtok(NULL, " \t")) {
- hint = rpc_luci_get_host_hint(rctx, ether_aton(p));
- if (!hint)
- continue;
- if (hint->ip.s_addr == 0 && in.s_addr != 0)
- hint->ip = in;
- if (n && !hint->hostname)
- hint->hostname = strdup(n);
- }
- }
- else if (ptr.o->type == UCI_TYPE_LIST) {
- uci_foreach_element(&ptr.o->v.list, l) {
- hint = rpc_luci_get_host_hint(rctx, ether_aton(l->name));
- if (!hint)
- continue;
- if (hint->ip.s_addr == 0 && in.s_addr != 0)
- hint->ip = in;
- if (n && !hint->hostname)
- hint->hostname = strdup(n);
- }
- }
- }
- lease_open();
- while ((lease = lease_next()) != NULL) {
- hint = rpc_luci_get_host_hint(rctx, &lease->mac);
- if (!hint)
- continue;
- if (lease->af == AF_INET && lease->n_addr && hint->ip.s_addr == 0)
- hint->ip = lease->addr[0].in;
- else if (lease->af == AF_INET6 && lease->n_addr &&
- !memcmp(&hint->ip6, &empty, sizeof(empty)))
- hint->ip6 = lease->addr[0].in6;
- if (lease->hostname && !hint->hostname)
- hint->hostname = strdup(lease->hostname);
- }
- lease_close();
- out:
- if (uci)
- uci_free_context(uci);
- }
- static void
- rpc_luci_get_host_hints_ifaddrs(struct reply_context *rctx)
- {
- struct ether_addr empty_ea = {};
- struct in6_addr empty_in6 = {};
- struct ifaddrs *ifaddr, *ifa;
- struct sockaddr_ll *sll;
- struct avl_tree devices;
- struct host_hint *hint;
- struct {
- struct avl_node avl;
- struct ether_addr ea;
- struct in6_addr in6;
- struct in_addr in;
- } *device, *nextdevice;
- char *p;
- avl_init(&devices, avl_strcmp, false, NULL);
- if (getifaddrs(&ifaddr) == -1)
- return;
- for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (!ifa->ifa_addr)
- continue;
- device = avl_find_element(&devices, ifa->ifa_name, device, avl);
- if (!device) {
- device = calloc_a(sizeof(*device), &p, strlen(ifa->ifa_name) + 1);
- if (!device)
- continue;
- device->avl.key = strcpy(p, ifa->ifa_name);
- avl_insert(&devices, &device->avl);
- }
- switch (ifa->ifa_addr->sa_family) {
- case AF_PACKET:
- sll = (struct sockaddr_ll *)ifa->ifa_addr;
- if (sll->sll_halen == 6)
- memcpy(&device->ea, sll->sll_addr, 6);
- break;
- case AF_INET6:
- device->in6 = ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
- break;
- case AF_INET:
- device->in = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
- break;
- }
- }
- freeifaddrs(ifaddr);
- avl_remove_all_elements(&devices, device, avl, nextdevice) {
- if (memcmp(&device->ea, &empty_ea, sizeof(empty_ea)) &&
- (memcmp(&device->in6, &empty_in6, sizeof(empty_in6)) ||
- device->in.s_addr != 0)) {
- hint = rpc_luci_get_host_hint(rctx, &device->ea);
- if (hint) {
- if (hint->ip.s_addr == 0 && device->in.s_addr != 0)
- hint->ip = device->in;
- if (memcmp(&hint->ip6, &empty_in6, sizeof(empty_in6)) == 0 &&
- memcmp(&device->in6, &empty_in6, sizeof(empty_in6)) != 0)
- hint->ip6 = device->in6;
- }
- }
- free(device);
- }
- }
- static int
- rpc_luci_get_host_hints_finish(struct reply_context *rctx);
- static void
- rpc_luci_get_host_hints_rrdns_cb(struct ubus_request *req, int type,
- struct blob_attr *msg)
- {
- struct reply_context *rctx = req->priv;
- struct host_hint *hint;
- struct blob_attr *cur;
- struct in6_addr in6;
- struct in_addr in;
- int rem;
- if (msg) {
- blob_for_each_attr(cur, msg, rem) {
- if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
- continue;
- if (inet_pton(AF_INET6, blobmsg_name(cur), &in6) == 1) {
- avl_for_each_element(&rctx->avl, hint, avl) {
- if (!memcmp(&hint->ip6, &in6, sizeof(in6))) {
- if (hint->hostname)
- free(hint->hostname);
- hint->hostname = strdup(blobmsg_get_string(cur));
- break;
- }
- }
- }
- else if (inet_pton(AF_INET, blobmsg_name(cur), &in) == 1) {
- avl_for_each_element(&rctx->avl, hint, avl) {
- if (!memcmp(&hint->ip, &in, sizeof(in))) {
- if (hint->hostname)
- free(hint->hostname);
- hint->hostname = strdup(blobmsg_get_string(cur));
- break;
- }
- }
- }
- }
- }
- rpc_luci_get_host_hints_finish(rctx);
- }
- static void
- rpc_luci_get_host_hints_rrdns(struct reply_context *rctx)
- {
- struct in6_addr empty_in6 = {};
- char buf[INET6_ADDRSTRLEN];
- struct blob_buf req = {};
- struct host_hint *hint;
- int n = 0;
- void *a;
- blob_buf_init(&req, 0);
- a = blobmsg_open_array(&req, "addrs");
- avl_for_each_element(&rctx->avl, hint, avl) {
- if (hint->ip.s_addr != 0) {
- inet_ntop(AF_INET, &hint->ip, buf, sizeof(buf));
- blobmsg_add_string(&req, NULL, buf);
- n++;
- }
- else if (memcmp(&hint->ip6, &empty_in6, sizeof(empty_in6))) {
- inet_ntop(AF_INET6, &hint->ip6, buf, sizeof(buf));
- blobmsg_add_string(&req, NULL, buf);
- n++;
- }
- }
- blobmsg_close_array(&req, a);
- if (n > 0) {
- blobmsg_add_u32(&req, "timeout", 250);
- blobmsg_add_u32(&req, "limit", n);
- if (!invoke_ubus(rctx->context, "network.rrdns", "lookup", &req,
- rpc_luci_get_host_hints_rrdns_cb, rctx))
- rpc_luci_get_host_hints_finish(rctx);
- }
- else {
- rpc_luci_get_host_hints_finish(rctx);
- }
- blob_buf_free(&req);
- }
- static int
- rpc_luci_get_host_hints_finish(struct reply_context *rctx)
- {
- struct host_hint *hint, *nexthint;
- char buf[INET6_ADDRSTRLEN];
- struct in6_addr in6 = {};
- struct in_addr in = {};
- void *o;
- avl_remove_all_elements(&rctx->avl, hint, avl, nexthint) {
- o = blobmsg_open_table(&rctx->blob, hint->avl.key);
- if (memcmp(&hint->ip, &in, sizeof(in))) {
- inet_ntop(AF_INET, &hint->ip, buf, sizeof(buf));
- blobmsg_add_string(&rctx->blob, "ipv4", buf);
- }
- if (memcmp(&hint->ip6, &in6, sizeof(in6))) {
- inet_ntop(AF_INET6, &hint->ip6, buf, sizeof(buf));
- blobmsg_add_string(&rctx->blob, "ipv6", buf);
- }
- if (hint->hostname)
- blobmsg_add_string(&rctx->blob, "name", hint->hostname);
- blobmsg_close_table(&rctx->blob, o);
- if (hint->hostname)
- free(hint->hostname);
- free(hint);
- }
- return finish_request(rctx, UBUS_STATUS_OK);
- }
- static int
- rpc_luci_get_host_hints(struct ubus_context *ctx, struct ubus_object *obj,
- struct ubus_request_data *req, const char *method,
- struct blob_attr *msg)
- {
- struct reply_context *rctx = defer_request(ctx, req);
- if (!rctx)
- return UBUS_STATUS_UNKNOWN_ERROR;
- rpc_luci_get_host_hints_nl(rctx);
- rpc_luci_get_host_hints_uci(rctx);
- rpc_luci_get_host_hints_ether(rctx);
- rpc_luci_get_host_hints_ifaddrs(rctx);
- rpc_luci_get_host_hints_rrdns(rctx);
- return UBUS_STATUS_OK;
- }
- static int
- rpc_luci_get_duid_hints(struct ubus_context *ctx, struct ubus_object *obj,
- struct ubus_request_data *req, const char *method,
- struct blob_attr *msg)
- {
- struct { struct avl_node avl; } *e, *next;
- char s[INET6_ADDRSTRLEN], *p;
- struct ether_addr empty = {};
- struct lease_entry *lease;
- struct avl_tree avl;
- void *o, *a;
- int n;
- avl_init(&avl, avl_strcmp, false, NULL);
- blob_buf_init(&blob, 0);
- lease_open();
- while ((lease = lease_next()) != NULL) {
- if (lease->af != AF_INET6 || lease->duid == NULL)
- continue;
- e = avl_find_element(&avl, lease->duid, e, avl);
- if (e)
- continue;
- e = calloc_a(sizeof(*e), &p, strlen(lease->duid) + 1);
- if (!e)
- continue;
- o = blobmsg_open_table(&blob, lease->duid);
- inet_ntop(AF_INET6, &lease->addr[0].in6, s, sizeof(s));
- blobmsg_add_string(&blob, "ip6addr", s);
- a = blobmsg_open_array(&blob, "ip6addrs");
- for (n = 0; n < lease->n_addr; n++) {
- inet_ntop(AF_INET6, &lease->addr[n].in6, s, sizeof(s));
- blobmsg_add_string(&blob, NULL, s);
- }
- blobmsg_close_array(&blob, a);
- if (lease->hostname)
- blobmsg_add_string(&blob, "hostname", lease->hostname);
- if (memcmp(&lease->mac, &empty, sizeof(empty)))
- blobmsg_add_string(&blob, "macaddr", ea2str(&lease->mac));
- blobmsg_close_table(&blob, o);
- e->avl.key = strcpy(p, lease->duid);
- avl_insert(&avl, &e->avl);
- }
- lease_close();
- avl_remove_all_elements(&avl, e, avl, next) {
- free(e);
- }
- ubus_send_reply(ctx, req, blob.head);
- return UBUS_STATUS_OK;
- }
- static int
- rpc_luci_get_board_json(struct ubus_context *ctx, struct ubus_object *obj,
- struct ubus_request_data *req, const char *method,
- struct blob_attr *msg)
- {
- blob_buf_init(&blob, 0);
- if (!blobmsg_add_json_from_file(&blob, "/etc/board.json"))
- return UBUS_STATUS_UNKNOWN_ERROR;
- ubus_send_reply(ctx, req, blob.head);
- return UBUS_STATUS_OK;
- }
- enum {
- RPC_L_FAMILY,
- __RPC_L_MAX,
- };
- static const struct blobmsg_policy rpc_get_leases_policy[__RPC_L_MAX] = {
- [RPC_L_FAMILY] = { .name = "family", .type = BLOBMSG_TYPE_INT32 }
- };
- static int
- rpc_luci_get_dhcp_leases(struct ubus_context *ctx, struct ubus_object *obj,
- struct ubus_request_data *req, const char *method,
- struct blob_attr *msg)
- {
- struct blob_attr *tb[__RPC_L_MAX];
- struct ether_addr emptymac = {};
- struct lease_entry *lease;
- char s[INET6_ADDRSTRLEN];
- int af, family = 0;
- void *a, *a2, *o;
- int n;
- blobmsg_parse(rpc_get_leases_policy, __RPC_L_MAX, tb,
- blob_data(msg), blob_len(msg));
- switch (tb[RPC_L_FAMILY] ? blobmsg_get_u32(tb[RPC_L_FAMILY]) : 0) {
- case 0:
- family = 0;
- break;
- case 4:
- family = AF_INET;
- break;
- case 6:
- family = AF_INET6;
- break;
- default:
- return UBUS_STATUS_INVALID_ARGUMENT;
- }
- blob_buf_init(&blob, 0);
- for (af = family ? family : AF_INET;
- af != 0;
- af = (family == 0) ? (af == AF_INET ? AF_INET6 : 0) : 0) {
- a = blobmsg_open_array(&blob, (af == AF_INET) ? "dhcp_leases"
- : "dhcp6_leases");
- lease_open();
- while ((lease = lease_next()) != NULL) {
- if (lease->af != af)
- continue;
- o = blobmsg_open_table(&blob, NULL);
- if (lease->expire == -1)
- blobmsg_add_u8(&blob, "expires", 0);
- else
- blobmsg_add_u32(&blob, "expires", lease->expire);
- if (lease->hostname)
- blobmsg_add_string(&blob, "hostname", lease->hostname);
- if (memcmp(&lease->mac, &emptymac, sizeof(emptymac)))
- blobmsg_add_string(&blob, "macaddr", ea2str(&lease->mac));
- if (lease->duid)
- blobmsg_add_string(&blob, "duid", lease->duid);
- inet_ntop(lease->af, &lease->addr[0].in6, s, sizeof(s));
- blobmsg_add_string(&blob, (af == AF_INET) ? "ipaddr" : "ip6addr",
- s);
- if (af == AF_INET6) {
- a2 = blobmsg_open_array(&blob, "ip6addrs");
- for (n = 0; n < lease->n_addr; n++) {
- inet_ntop(lease->af, &lease->addr[n].in6, s, sizeof(s));
- blobmsg_add_string(&blob, NULL, s);
- }
- blobmsg_close_array(&blob, a2);
- }
- blobmsg_close_table(&blob, o);
- }
- lease_close();
- blobmsg_close_array(&blob, a);
- }
- ubus_send_reply(ctx, req, blob.head);
- return UBUS_STATUS_OK;
- }
- static int
- rpc_luci_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
- {
- static const struct ubus_method luci_methods[] = {
- UBUS_METHOD_NOARG("getNetworkDevices", rpc_luci_get_network_devices),
- UBUS_METHOD_NOARG("getWirelessDevices", rpc_luci_get_wireless_devices),
- UBUS_METHOD_NOARG("getHostHints", rpc_luci_get_host_hints),
- UBUS_METHOD_NOARG("getDUIDHints", rpc_luci_get_duid_hints),
- UBUS_METHOD_NOARG("getBoardJSON", rpc_luci_get_board_json),
- UBUS_METHOD("getDHCPLeases", rpc_luci_get_dhcp_leases, rpc_get_leases_policy)
- };
- static struct ubus_object_type luci_type =
- UBUS_OBJECT_TYPE("rpcd-luci", luci_methods);
- static struct ubus_object obj = {
- .name = "luci-rpc",
- .type = &luci_type,
- .methods = luci_methods,
- .n_methods = ARRAY_SIZE(luci_methods),
- };
- return ubus_add_object(ctx, &obj);
- }
- struct rpc_plugin rpc_plugin = {
- .init = rpc_luci_api_init
- };
|