rpcd-mod-luci: Return array of addresses in getHostHints
Update luci-rpc's getHostHints method to return two string arrays for
each host, `ipaddrs` and `ip6addrs`, each containing the host's IPv4
and IPv6 addresses, respectively. Each array is sorted by a priority
derived from the source from which the address was discovered. The
current address sources and their priority is as follows (a
higher (larger) priority is listed first):
- neighbor table entries: 10
- /etc/ethers entries: 50
- DHCP leasefile: 100
- RRDNS queries: 100
- getifaddrs(): 200
- UCI static leases: 200
The existing `ipv4` and `ipv6` string fields for each host in
`getHostHints` has been removed. Downstream users of getHostHints
still need to be updated.
Fixes: #4838
Signed-off-by: Niels Widger <niels@qacafe.com>
[squash commits, reformat fixes tag]
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
(cherry picked from commit a5195e7825
)
This commit is contained in:
parent
127b896a52
commit
87bcf9e923
1 changed files with 156 additions and 39 deletions
|
@ -1135,10 +1135,48 @@ rpc_luci_get_wireless_devices(struct ubus_context *ctx,
|
||||||
struct host_hint {
|
struct host_hint {
|
||||||
struct avl_node avl;
|
struct avl_node avl;
|
||||||
char *hostname;
|
char *hostname;
|
||||||
struct in_addr ip;
|
struct avl_tree ipaddrs;
|
||||||
struct in6_addr ip6;
|
struct avl_tree ip6addrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* used to ignore priority with avl_find_element */
|
||||||
|
#define HOST_HINT_PRIO_IGNORE -1
|
||||||
|
|
||||||
|
/* higher (larger) priority addresses are listed first */
|
||||||
|
#define HOST_HINT_PRIO_NL 10 /* neighbor table */
|
||||||
|
#define HOST_HINT_PRIO_ETHER 50 /* /etc/ethers */
|
||||||
|
#define HOST_HINT_PRIO_LEASEFILE 100 /* dhcp leasefile */
|
||||||
|
#define HOST_HINT_PRIO_RRDNS 100 /* rrdns */
|
||||||
|
#define HOST_HINT_PRIO_IFADDRS 200 /* getifaddrs() */
|
||||||
|
#define HOST_HINT_PRIO_STATIC_LEASE 200 /* uci static leases */
|
||||||
|
|
||||||
|
struct host_hint_addr {
|
||||||
|
struct avl_node avl;
|
||||||
|
int af;
|
||||||
|
int prio;
|
||||||
|
union {
|
||||||
|
struct in_addr in;
|
||||||
|
struct in6_addr in6;
|
||||||
|
} addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
host_hint_addr_avl_cmp(const void *k1, const void *k2, void *ptr)
|
||||||
|
{
|
||||||
|
struct host_hint_addr *a1 = (struct host_hint_addr *)k1;
|
||||||
|
struct host_hint_addr *a2 = (struct host_hint_addr *)k2;
|
||||||
|
|
||||||
|
if (a1->prio != a2->prio &&
|
||||||
|
a1->prio != HOST_HINT_PRIO_IGNORE &&
|
||||||
|
a2->prio != HOST_HINT_PRIO_IGNORE)
|
||||||
|
return a1->prio < a2->prio ? 1 : -1;
|
||||||
|
|
||||||
|
if (a1->af != a2->af)
|
||||||
|
return a1->af < a2->af ? -1 : 1;
|
||||||
|
|
||||||
|
return memcmp(&a1->addr, &a2->addr, sizeof(a1->addr));
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nl_cb_done(struct nl_msg *msg, void *arg)
|
nl_cb_done(struct nl_msg *msg, void *arg)
|
||||||
{
|
{
|
||||||
|
@ -1174,12 +1212,69 @@ rpc_luci_get_host_hint(struct reply_context *rctx, struct ether_addr *ea)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
hint->avl.key = strcpy(p, mac);
|
hint->avl.key = strcpy(p, mac);
|
||||||
|
avl_init(&hint->ipaddrs, host_hint_addr_avl_cmp, false, NULL);
|
||||||
|
avl_init(&hint->ip6addrs, host_hint_addr_avl_cmp, false, NULL);
|
||||||
avl_insert(&rctx->avl, &hint->avl);
|
avl_insert(&rctx->avl, &hint->avl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hint;
|
return hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rpc_luci_add_host_hint_addr(struct host_hint *hint, int af, int prio, void *addr)
|
||||||
|
{
|
||||||
|
struct host_hint_addr e, *a;
|
||||||
|
struct avl_tree *addrs = af == AF_INET ? &hint->ipaddrs : &hint->ip6addrs;
|
||||||
|
|
||||||
|
if (!addr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&e, 0, sizeof(e));
|
||||||
|
e.af = af;
|
||||||
|
/* ignore prio when comparing against existing addresses */
|
||||||
|
e.prio = HOST_HINT_PRIO_IGNORE;
|
||||||
|
|
||||||
|
if (af == AF_INET)
|
||||||
|
memcpy(&e.addr.in, (struct in_addr *)addr, sizeof(e.addr.in));
|
||||||
|
else
|
||||||
|
memcpy(&e.addr.in6, (struct in6_addr *)addr, sizeof(e.addr.in6));
|
||||||
|
|
||||||
|
a = avl_find_element(addrs, &e, a, avl);
|
||||||
|
|
||||||
|
if (a) {
|
||||||
|
/* update prio of existing address if higher */
|
||||||
|
if (prio <= a->prio)
|
||||||
|
return;
|
||||||
|
|
||||||
|
avl_delete(addrs, &a->avl);
|
||||||
|
a->prio = prio;
|
||||||
|
avl_insert(addrs, &a->avl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = calloc(1, sizeof(*a));
|
||||||
|
|
||||||
|
if (!a)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memcpy(a, &e, sizeof(*a));
|
||||||
|
a->prio = prio;
|
||||||
|
a->avl.key = a;
|
||||||
|
avl_insert(addrs, &a->avl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rpc_luci_add_host_hint_ipaddr(struct host_hint *hint, int prio, struct in_addr *addr)
|
||||||
|
{
|
||||||
|
return rpc_luci_add_host_hint_addr(hint, AF_INET, prio, (void *)addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rpc_luci_add_host_hint_ip6addr(struct host_hint *hint, int prio, struct in6_addr *addr)
|
||||||
|
{
|
||||||
|
return rpc_luci_add_host_hint_addr(hint, AF_INET6, prio, (void *)addr);
|
||||||
|
}
|
||||||
|
|
||||||
static int nl_cb_dump_neigh(struct nl_msg *msg, void *arg)
|
static int nl_cb_dump_neigh(struct nl_msg *msg, void *arg)
|
||||||
{
|
{
|
||||||
struct reply_context *rctx = arg;
|
struct reply_context *rctx = arg;
|
||||||
|
@ -1213,9 +1308,9 @@ static int nl_cb_dump_neigh(struct nl_msg *msg, void *arg)
|
||||||
return NL_SKIP;
|
return NL_SKIP;
|
||||||
|
|
||||||
if (nd->ndm_family == AF_INET)
|
if (nd->ndm_family == AF_INET)
|
||||||
hint->ip = *(struct in_addr *)dst;
|
rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_NL, (struct in_addr *)dst);
|
||||||
else
|
else
|
||||||
hint->ip6 = *(struct in6_addr *)dst;
|
rpc_luci_add_host_hint_ip6addr(hint, HOST_HINT_PRIO_NL, (struct in6_addr *)dst);
|
||||||
|
|
||||||
return NL_SKIP;
|
return NL_SKIP;
|
||||||
}
|
}
|
||||||
|
@ -1298,8 +1393,7 @@ rpc_luci_get_host_hints_ether(struct reply_context *rctx)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (inet_pton(AF_INET, p, &in) == 1) {
|
if (inet_pton(AF_INET, p, &in) == 1) {
|
||||||
if (hint->ip.s_addr == 0)
|
rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_ETHER, &in);
|
||||||
hint->ip = in;
|
|
||||||
}
|
}
|
||||||
else if (*p && !hint->hostname) {
|
else if (*p && !hint->hostname) {
|
||||||
hint->hostname = strdup(p);
|
hint->hostname = strdup(p);
|
||||||
|
@ -1315,13 +1409,13 @@ rpc_luci_get_host_hints_uci(struct reply_context *rctx)
|
||||||
struct uci_ptr ptr = { .package = "dhcp" };
|
struct uci_ptr ptr = { .package = "dhcp" };
|
||||||
struct uci_context *uci = NULL;
|
struct uci_context *uci = NULL;
|
||||||
struct uci_package *pkg = NULL;
|
struct uci_package *pkg = NULL;
|
||||||
struct in6_addr empty = {};
|
|
||||||
struct lease_entry *lease;
|
struct lease_entry *lease;
|
||||||
struct host_hint *hint;
|
struct host_hint *hint;
|
||||||
struct uci_element *e, *l;
|
struct uci_element *e, *l;
|
||||||
struct uci_section *s;
|
struct uci_section *s;
|
||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
char *p, *n;
|
char *p, *n;
|
||||||
|
int i;
|
||||||
|
|
||||||
uci = uci_alloc_context();
|
uci = uci_alloc_context();
|
||||||
|
|
||||||
|
@ -1379,8 +1473,8 @@ rpc_luci_get_host_hints_uci(struct reply_context *rctx)
|
||||||
if (!hint)
|
if (!hint)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (hint->ip.s_addr == 0 && in.s_addr != 0)
|
if (in.s_addr != 0)
|
||||||
hint->ip = in;
|
rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_STATIC_LEASE, &in);
|
||||||
|
|
||||||
if (n && !hint->hostname)
|
if (n && !hint->hostname)
|
||||||
hint->hostname = strdup(n);
|
hint->hostname = strdup(n);
|
||||||
|
@ -1393,8 +1487,8 @@ rpc_luci_get_host_hints_uci(struct reply_context *rctx)
|
||||||
if (!hint)
|
if (!hint)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (hint->ip.s_addr == 0 && in.s_addr != 0)
|
if (in.s_addr != 0)
|
||||||
hint->ip = in;
|
rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_STATIC_LEASE, &in);
|
||||||
|
|
||||||
if (n && !hint->hostname)
|
if (n && !hint->hostname)
|
||||||
hint->hostname = strdup(n);
|
hint->hostname = strdup(n);
|
||||||
|
@ -1410,11 +1504,12 @@ rpc_luci_get_host_hints_uci(struct reply_context *rctx)
|
||||||
if (!hint)
|
if (!hint)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (lease->af == AF_INET && lease->n_addr && hint->ip.s_addr == 0)
|
for (i = 0; i < lease->n_addr; i++) {
|
||||||
hint->ip = lease->addr[0].in;
|
if (lease->af == AF_INET)
|
||||||
else if (lease->af == AF_INET6 && lease->n_addr &&
|
rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_LEASEFILE, &lease->addr[i].in);
|
||||||
!memcmp(&hint->ip6, &empty, sizeof(empty)))
|
else if (lease->af == AF_INET6)
|
||||||
hint->ip6 = lease->addr[0].in6;
|
rpc_luci_add_host_hint_ip6addr(hint, HOST_HINT_PRIO_LEASEFILE, &lease->addr[i].in6);
|
||||||
|
}
|
||||||
|
|
||||||
if (lease->hostname && !hint->hostname)
|
if (lease->hostname && !hint->hostname)
|
||||||
hint->hostname = strdup(lease->hostname);
|
hint->hostname = strdup(lease->hostname);
|
||||||
|
@ -1493,12 +1588,11 @@ rpc_luci_get_host_hints_ifaddrs(struct reply_context *rctx)
|
||||||
hint = rpc_luci_get_host_hint(rctx, &device->ea);
|
hint = rpc_luci_get_host_hint(rctx, &device->ea);
|
||||||
|
|
||||||
if (hint) {
|
if (hint) {
|
||||||
if (hint->ip.s_addr == 0 && device->in.s_addr != 0)
|
if (device->in.s_addr != 0)
|
||||||
hint->ip = device->in;
|
rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_IFADDRS, &device->in);
|
||||||
|
|
||||||
if (memcmp(&hint->ip6, &empty_in6, sizeof(empty_in6)) == 0 &&
|
if (memcmp(&device->in6, &empty_in6, sizeof(empty_in6)) != 0)
|
||||||
memcmp(&device->in6, &empty_in6, sizeof(empty_in6)) != 0)
|
rpc_luci_add_host_hint_ip6addr(hint, HOST_HINT_PRIO_IFADDRS, &device->in6);
|
||||||
hint->ip6 = device->in6;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1527,7 +1621,8 @@ rpc_luci_get_host_hints_rrdns_cb(struct ubus_request *req, int type,
|
||||||
|
|
||||||
if (inet_pton(AF_INET6, blobmsg_name(cur), &in6) == 1) {
|
if (inet_pton(AF_INET6, blobmsg_name(cur), &in6) == 1) {
|
||||||
avl_for_each_element(&rctx->avl, hint, avl) {
|
avl_for_each_element(&rctx->avl, hint, avl) {
|
||||||
if (!memcmp(&hint->ip6, &in6, sizeof(in6))) {
|
rpc_luci_add_host_hint_ip6addr(hint, HOST_HINT_PRIO_RRDNS, &in6);
|
||||||
|
if (!avl_is_empty(&hint->ip6addrs)) {
|
||||||
if (hint->hostname)
|
if (hint->hostname)
|
||||||
free(hint->hostname);
|
free(hint->hostname);
|
||||||
|
|
||||||
|
@ -1538,7 +1633,8 @@ rpc_luci_get_host_hints_rrdns_cb(struct ubus_request *req, int type,
|
||||||
}
|
}
|
||||||
else if (inet_pton(AF_INET, blobmsg_name(cur), &in) == 1) {
|
else if (inet_pton(AF_INET, blobmsg_name(cur), &in) == 1) {
|
||||||
avl_for_each_element(&rctx->avl, hint, avl) {
|
avl_for_each_element(&rctx->avl, hint, avl) {
|
||||||
if (!memcmp(&hint->ip, &in, sizeof(in))) {
|
rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_RRDNS, &in);
|
||||||
|
if (!avl_is_empty(&hint->ipaddrs)) {
|
||||||
if (hint->hostname)
|
if (hint->hostname)
|
||||||
free(hint->hostname);
|
free(hint->hostname);
|
||||||
|
|
||||||
|
@ -1560,6 +1656,7 @@ rpc_luci_get_host_hints_rrdns(struct reply_context *rctx)
|
||||||
char buf[INET6_ADDRSTRLEN];
|
char buf[INET6_ADDRSTRLEN];
|
||||||
struct blob_buf req = {};
|
struct blob_buf req = {};
|
||||||
struct host_hint *hint;
|
struct host_hint *hint;
|
||||||
|
struct host_hint_addr *addr;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
void *a;
|
void *a;
|
||||||
|
|
||||||
|
@ -1568,17 +1665,21 @@ rpc_luci_get_host_hints_rrdns(struct reply_context *rctx)
|
||||||
a = blobmsg_open_array(&req, "addrs");
|
a = blobmsg_open_array(&req, "addrs");
|
||||||
|
|
||||||
avl_for_each_element(&rctx->avl, hint, avl) {
|
avl_for_each_element(&rctx->avl, hint, avl) {
|
||||||
if (hint->ip.s_addr != 0) {
|
avl_for_each_element(&hint->ipaddrs, addr, avl) {
|
||||||
inet_ntop(AF_INET, &hint->ip, buf, sizeof(buf));
|
if (addr->addr.in.s_addr != 0) {
|
||||||
|
inet_ntop(AF_INET, &addr->addr.in, buf, sizeof(buf));
|
||||||
blobmsg_add_string(&req, NULL, buf);
|
blobmsg_add_string(&req, NULL, buf);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
else if (memcmp(&hint->ip6, &empty_in6, sizeof(empty_in6))) {
|
}
|
||||||
inet_ntop(AF_INET6, &hint->ip6, buf, sizeof(buf));
|
avl_for_each_element(&hint->ip6addrs, addr, avl) {
|
||||||
|
if (memcmp(&addr->addr.in6, &empty_in6, sizeof(empty_in6))) {
|
||||||
|
inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf));
|
||||||
blobmsg_add_string(&req, NULL, buf);
|
blobmsg_add_string(&req, NULL, buf);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
blobmsg_close_array(&req, a);
|
blobmsg_close_array(&req, a);
|
||||||
|
|
||||||
|
@ -1601,24 +1702,40 @@ static int
|
||||||
rpc_luci_get_host_hints_finish(struct reply_context *rctx)
|
rpc_luci_get_host_hints_finish(struct reply_context *rctx)
|
||||||
{
|
{
|
||||||
struct host_hint *hint, *nexthint;
|
struct host_hint *hint, *nexthint;
|
||||||
|
struct host_hint_addr *addr, *nextaddr;
|
||||||
char buf[INET6_ADDRSTRLEN];
|
char buf[INET6_ADDRSTRLEN];
|
||||||
struct in6_addr in6 = {};
|
struct in6_addr in6 = {};
|
||||||
struct in_addr in = {};
|
void *o, *a;
|
||||||
void *o;
|
|
||||||
|
|
||||||
avl_remove_all_elements(&rctx->avl, hint, avl, nexthint) {
|
avl_remove_all_elements(&rctx->avl, hint, avl, nexthint) {
|
||||||
o = blobmsg_open_table(&rctx->blob, hint->avl.key);
|
o = blobmsg_open_table(&rctx->blob, hint->avl.key);
|
||||||
|
|
||||||
if (memcmp(&hint->ip, &in, sizeof(in))) {
|
a = blobmsg_open_array(&rctx->blob, "ipaddrs");
|
||||||
inet_ntop(AF_INET, &hint->ip, buf, sizeof(buf));
|
|
||||||
blobmsg_add_string(&rctx->blob, "ipv4", buf);
|
avl_remove_all_elements(&hint->ipaddrs, addr, avl, nextaddr) {
|
||||||
|
if (addr->addr.in.s_addr != 0) {
|
||||||
|
inet_ntop(AF_INET, &addr->addr.in, buf, sizeof(buf));
|
||||||
|
blobmsg_add_string(&rctx->blob, NULL, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(&hint->ip6, &in6, sizeof(in6))) {
|
free(addr);
|
||||||
inet_ntop(AF_INET6, &hint->ip6, buf, sizeof(buf));
|
|
||||||
blobmsg_add_string(&rctx->blob, "ipv6", buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blobmsg_close_array(&rctx->blob, a);
|
||||||
|
|
||||||
|
a = blobmsg_open_array(&rctx->blob, "ip6addrs");
|
||||||
|
|
||||||
|
avl_remove_all_elements(&hint->ip6addrs, addr, avl, nextaddr) {
|
||||||
|
if (memcmp(&addr->addr.in6, &in6, sizeof(in6))) {
|
||||||
|
inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf));
|
||||||
|
blobmsg_add_string(&rctx->blob, NULL, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
blobmsg_close_array(&rctx->blob, a);
|
||||||
|
|
||||||
if (hint->hostname)
|
if (hint->hostname)
|
||||||
blobmsg_add_string(&rctx->blob, "name", hint->hostname);
|
blobmsg_add_string(&rctx->blob, "name", hint->hostname);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue