Merge pull request #2043 from freifunk-gluon/iface-type
Fix tunnel interface detection in respondd nodeinfo
This commit is contained in:
commit
892405b9e0
@ -62,38 +62,40 @@
|
|||||||
|
|
||||||
static struct babelhelper_ctx bhelper_ctx = {};
|
static struct babelhelper_ctx bhelper_ctx = {};
|
||||||
|
|
||||||
static void obtain_if_addr(const char *ifname, char *lladdr) {
|
static bool get_linklocal_address(const char *ifname, char lladdr[INET6_ADDRSTRLEN]) {
|
||||||
struct ifaddrs *ifaddr, *ifa;
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
int family, n;
|
bool ret = false;
|
||||||
|
|
||||||
if (getifaddrs(&ifaddr) == -1) {
|
if (getifaddrs(&ifaddr) == -1) {
|
||||||
perror("getifaddrs");
|
perror("getifaddrs");
|
||||||
exit(EXIT_FAILURE);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
||||||
if (ifa->ifa_addr == NULL)
|
if (!ifa->ifa_addr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
family = ifa->ifa_addr->sa_family;
|
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||||
|
continue;
|
||||||
|
|
||||||
if ( (family == AF_INET6) && ( ! strncmp(ifname, ifa->ifa_name, strlen(ifname)) ) ) {
|
if (strcmp(ifname, ifa->ifa_name) != 0)
|
||||||
char lhost[INET6_ADDRSTRLEN];
|
continue;
|
||||||
struct in6_addr *address = &((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr;
|
|
||||||
if (inet_ntop(AF_INET6, address, lhost, INET6_ADDRSTRLEN) == NULL) {
|
|
||||||
fprintf(stderr, "obtain_if_addr: could not convert ip to string\n");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! strncmp("fe80:", lhost, 5) ) {
|
const struct in6_addr *address = &((const struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
|
||||||
snprintf( lladdr, NI_MAXHOST, "%s", lhost );
|
if (!IN6_IS_ADDR_LINKLOCAL(address))
|
||||||
goto cleanup;
|
continue;
|
||||||
}
|
|
||||||
|
if (!inet_ntop(AF_INET6, address, lladdr, INET6_ADDRSTRLEN)) {
|
||||||
|
perror("inet_ntop");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
|
||||||
freeifaddrs(ifaddr);
|
freeifaddrs(ifaddr);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -154,29 +156,32 @@ free:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool interface_file_exists(const char *ifname, const char *name) {
|
|
||||||
const char *format = "/sys/class/net/%s/%s";
|
|
||||||
char path[strlen(format) + strlen(ifname) + strlen(name)+1];
|
|
||||||
snprintf(path, sizeof(path), format, ifname, name);
|
|
||||||
|
|
||||||
return !access(path, F_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mesh_add_if(const char *ifname, struct json_object *wireless,
|
static void mesh_add_if(const char *ifname, struct json_object *wireless,
|
||||||
struct json_object *tunnel, struct json_object *other) {
|
struct json_object *tunnel, struct json_object *other) {
|
||||||
char str_ip[NI_MAXHOST] = {};
|
char str_ip[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
obtain_if_addr(ifname, str_ip);
|
if (!get_linklocal_address(ifname, str_ip))
|
||||||
|
return;
|
||||||
|
|
||||||
struct json_object *address = json_object_new_string(str_ip);
|
struct json_object *address = json_object_new_string(str_ip);
|
||||||
|
|
||||||
if (interface_file_exists(ifname, "wireless"))
|
/* In case of VLAN and bridge interfaces, we want the lower interface
|
||||||
json_object_array_add(wireless, address);
|
* to determine the interface type (but not for the interface address) */
|
||||||
else if (interface_file_exists(ifname, "tun_flags"))
|
char lowername[IF_NAMESIZE];
|
||||||
json_object_array_add(tunnel, address);
|
gluonutil_get_interface_lower(lowername, ifname);
|
||||||
else
|
|
||||||
json_object_array_add(other, address);
|
|
||||||
|
|
||||||
|
switch(gluonutil_get_interface_type(lowername)) {
|
||||||
|
case GLUONUTIL_INTERFACE_TYPE_WIRELESS:
|
||||||
|
json_object_array_add(wireless, address);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLUONUTIL_INTERFACE_TYPE_TUNNEL:
|
||||||
|
json_object_array_add(tunnel, address);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
json_object_array_add(other, address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -193,24 +198,26 @@ static bool handle_neighbour(char **data, void *obj) {
|
|||||||
if (data[REACH])
|
if (data[REACH])
|
||||||
json_object_object_add(neigh, "reachability", json_object_new_double(strtod(data[REACH], NULL)));
|
json_object_object_add(neigh, "reachability", json_object_new_double(strtod(data[REACH], NULL)));
|
||||||
|
|
||||||
struct json_object *nif = 0;
|
if (!data[IF])
|
||||||
if (data[IF] && !json_object_object_get_ex(obj, data[IF], &nif)) {
|
return true;
|
||||||
char str_ip[NI_MAXHOST] = {};
|
|
||||||
obtain_if_addr( (const char*)data[IF], str_ip );
|
struct json_object *nif;
|
||||||
|
if (!json_object_object_get_ex(obj, data[IF], &nif)) {
|
||||||
|
char str_ip[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
nif = json_object_new_object();
|
nif = json_object_new_object();
|
||||||
|
|
||||||
json_object_object_add(nif, "ll-addr", json_object_new_string(str_ip));
|
if (get_linklocal_address(data[IF], str_ip))
|
||||||
|
json_object_object_add(nif, "ll-addr", json_object_new_string(str_ip));
|
||||||
|
|
||||||
json_object_object_add(nif, "protocol", json_object_new_string("babel"));
|
json_object_object_add(nif, "protocol", json_object_new_string("babel"));
|
||||||
json_object_object_add(obj, data[IF], nif);
|
json_object_object_add(obj, data[IF], nif);
|
||||||
|
|
||||||
}
|
json_object_object_add(nif, "neighbours", json_object_new_object());
|
||||||
struct json_object *neighborcollector = 0;
|
|
||||||
if (!json_object_object_get_ex(nif, "neighbours", &neighborcollector)) {
|
|
||||||
neighborcollector = json_object_new_object();
|
|
||||||
json_object_object_add(nif, "neighbours", neighborcollector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct json_object *neighborcollector;
|
||||||
|
json_object_object_get_ex(nif, "neighbours", &neighborcollector);
|
||||||
json_object_object_add(neighborcollector, data[ADDRESS], neigh);
|
json_object_object_add(neighborcollector, data[ADDRESS], neigh);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -277,6 +284,13 @@ static void blobmsg_handle_list(struct blob_attr *attr, int len, bool array, str
|
|||||||
free(proto);
|
free(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_if_not_empty(struct json_object *obj, const char *key, struct json_object *val) {
|
||||||
|
if (json_object_array_length(val))
|
||||||
|
json_object_object_add(obj, key, val);
|
||||||
|
else
|
||||||
|
json_object_put(val);
|
||||||
|
}
|
||||||
|
|
||||||
static void receive_call_result_data(struct ubus_request *req, int type, struct blob_attr *msg) {
|
static void receive_call_result_data(struct ubus_request *req, int type, struct blob_attr *msg) {
|
||||||
struct json_object *ret = json_object_new_object();
|
struct json_object *ret = json_object_new_object();
|
||||||
struct json_object *wireless = json_object_new_array();
|
struct json_object *wireless = json_object_new_array();
|
||||||
@ -298,9 +312,9 @@ static void receive_call_result_data(struct ubus_request *req, int type, struct
|
|||||||
|
|
||||||
blobmsg_handle_list(blobmsg_data(msg), blobmsg_data_len(msg), false, wireless, tunnel, other);
|
blobmsg_handle_list(blobmsg_data(msg), blobmsg_data_len(msg), false, wireless, tunnel, other);
|
||||||
|
|
||||||
json_object_object_add(ret, "wireless", wireless);
|
add_if_not_empty(ret, "wireless", wireless);
|
||||||
json_object_object_add(ret, "tunnel", tunnel);
|
add_if_not_empty(ret, "tunnel", tunnel);
|
||||||
json_object_object_add(ret, "other", other);
|
add_if_not_empty(ret, "other", other);
|
||||||
|
|
||||||
*((struct json_object**)(req->priv)) = ret;
|
*((struct json_object**)(req->priv)) = ret;
|
||||||
}
|
}
|
||||||
|
@ -131,35 +131,23 @@ static void mesh_add_subif(const char *ifname, struct json_object *wireless,
|
|||||||
struct json_object *tunnel, struct json_object *other) {
|
struct json_object *tunnel, struct json_object *other) {
|
||||||
struct json_object *address = gluonutil_wrap_and_free_string(gluonutil_get_interface_address(ifname));
|
struct json_object *address = gluonutil_wrap_and_free_string(gluonutil_get_interface_address(ifname));
|
||||||
|
|
||||||
char lowername[IFNAMSIZ];
|
|
||||||
strncpy(lowername, ifname, sizeof(lowername)-1);
|
|
||||||
lowername[sizeof(lowername)-1] = 0;
|
|
||||||
|
|
||||||
const char *format = "/sys/class/net/%s/lower_*";
|
|
||||||
char pattern[strlen(format) + IFNAMSIZ];
|
|
||||||
|
|
||||||
/* In case of VLAN and bridge interfaces, we want the lower interface
|
/* In case of VLAN and bridge interfaces, we want the lower interface
|
||||||
* to determine the interface type (but not for the interface address) */
|
* to determine the interface type (but not for the interface address) */
|
||||||
while (true) {
|
char lowername[IF_NAMESIZE];
|
||||||
snprintf(pattern, sizeof(pattern), format, lowername);
|
gluonutil_get_interface_lower(lowername, ifname);
|
||||||
size_t pattern_len = strlen(pattern);
|
|
||||||
|
|
||||||
glob_t lower;
|
switch(gluonutil_get_interface_type(lowername)) {
|
||||||
if (glob(pattern, GLOB_NOSORT, NULL, &lower))
|
case GLUONUTIL_INTERFACE_TYPE_WIRELESS:
|
||||||
break;
|
|
||||||
|
|
||||||
strncpy(lowername, lower.gl_pathv[0] + pattern_len - 1, sizeof(lowername)-1);
|
|
||||||
|
|
||||||
globfree(&lower);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interface_file_exists(lowername, "wireless"))
|
|
||||||
json_object_array_add(wireless, address);
|
json_object_array_add(wireless, address);
|
||||||
else if (interface_file_exists(lowername, "tun_flags"))
|
break;
|
||||||
json_object_array_add(tunnel, address);
|
|
||||||
else
|
|
||||||
json_object_array_add(other, address);
|
|
||||||
|
|
||||||
|
case GLUONUTIL_INTERFACE_TYPE_TUNNEL:
|
||||||
|
json_object_array_add(tunnel, address);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
json_object_array_add(other, address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct json_object * get_mesh_subifs(const char *ifname) {
|
static struct json_object * get_mesh_subifs(const char *ifname) {
|
||||||
|
@ -28,13 +28,16 @@
|
|||||||
|
|
||||||
#include <json-c/json.h>
|
#include <json-c/json.h>
|
||||||
#include <uci.h>
|
#include <uci.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges two JSON objects
|
* Merges two JSON objects
|
||||||
@ -129,6 +132,74 @@ char * gluonutil_get_interface_address(const char *ifname) {
|
|||||||
return gluonutil_read_line(path);
|
return gluonutil_read_line(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gluonutil_get_interface_lower(char out[IF_NAMESIZE], const char *ifname) {
|
||||||
|
strncpy(out, ifname, IF_NAMESIZE-1);
|
||||||
|
out[IF_NAMESIZE-1] = 0;
|
||||||
|
|
||||||
|
const char *format = "/sys/class/net/%s/lower_*";
|
||||||
|
char pattern[strlen(format) + IF_NAMESIZE];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
snprintf(pattern, sizeof(pattern), format, out);
|
||||||
|
size_t pattern_len = strlen(pattern);
|
||||||
|
|
||||||
|
glob_t lower;
|
||||||
|
if (glob(pattern, GLOB_NOSORT, NULL, &lower) != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
strncpy(out, lower.gl_pathv[0] + pattern_len - 1, IF_NAMESIZE-1);
|
||||||
|
|
||||||
|
globfree(&lower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum gluonutil_interface_type lookup_interface_type(const char *devtype) {
|
||||||
|
if (strcmp(devtype, "wlan") == 0)
|
||||||
|
return GLUONUTIL_INTERFACE_TYPE_WIRELESS;
|
||||||
|
|
||||||
|
if (strcmp(devtype, "l2tpeth") == 0 || strcmp(devtype, "wireguard") == 0)
|
||||||
|
return GLUONUTIL_INTERFACE_TYPE_TUNNEL;
|
||||||
|
|
||||||
|
/* Regular wired interfaces do not set DEVTYPE, so if this point is
|
||||||
|
* reached, we have something different */
|
||||||
|
return GLUONUTIL_INTERFACE_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum gluonutil_interface_type gluonutil_get_interface_type(const char *ifname) {
|
||||||
|
const char *pattern = "/sys/class/net/%s/%s";
|
||||||
|
|
||||||
|
/* Default to wired type when no DEVTYPE is set */
|
||||||
|
enum gluonutil_interface_type ret = GLUONUTIL_INTERFACE_TYPE_WIRED;
|
||||||
|
char *line = NULL, path[PATH_MAX];
|
||||||
|
size_t buflen = 0;
|
||||||
|
ssize_t len;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), pattern, ifname, "tun_flags");
|
||||||
|
if (access(path, F_OK) == 0)
|
||||||
|
return GLUONUTIL_INTERFACE_TYPE_TUNNEL;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), pattern, ifname, "uevent");
|
||||||
|
f = fopen(path, "r");
|
||||||
|
if (!f)
|
||||||
|
return GLUONUTIL_INTERFACE_TYPE_UNKNOWN;
|
||||||
|
|
||||||
|
while ((len = getline(&line, &buflen, f)) >= 0) {
|
||||||
|
if (len == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (line[len-1] == '\n')
|
||||||
|
line[len-1] = '\0';
|
||||||
|
|
||||||
|
if (strncmp(line, "DEVTYPE=", 8) == 0) {
|
||||||
|
ret = lookup_interface_type(line+8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct json_object * gluonutil_wrap_string(const char *str) {
|
struct json_object * gluonutil_wrap_string(const char *str) {
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#ifndef _LIBGLUON_LIBGLUON_H_
|
#ifndef _LIBGLUON_LIBGLUON_H_
|
||||||
#define _LIBGLUON_LIBGLUON_H_
|
#define _LIBGLUON_LIBGLUON_H_
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@ -34,7 +35,18 @@
|
|||||||
char * gluonutil_read_line(const char *filename);
|
char * gluonutil_read_line(const char *filename);
|
||||||
char * gluonutil_get_sysconfig(const char *key);
|
char * gluonutil_get_sysconfig(const char *key);
|
||||||
char * gluonutil_get_node_id(void);
|
char * gluonutil_get_node_id(void);
|
||||||
|
|
||||||
|
enum gluonutil_interface_type {
|
||||||
|
GLUONUTIL_INTERFACE_TYPE_UNKNOWN,
|
||||||
|
GLUONUTIL_INTERFACE_TYPE_WIRED,
|
||||||
|
GLUONUTIL_INTERFACE_TYPE_WIRELESS,
|
||||||
|
GLUONUTIL_INTERFACE_TYPE_TUNNEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void gluonutil_get_interface_lower(char out[IF_NAMESIZE], const char *ifname);
|
||||||
char * gluonutil_get_interface_address(const char *ifname);
|
char * gluonutil_get_interface_address(const char *ifname);
|
||||||
|
enum gluonutil_interface_type gluonutil_get_interface_type(const char *ifname);
|
||||||
|
|
||||||
bool gluonutil_get_node_prefix6(struct in6_addr *prefix);
|
bool gluonutil_get_node_prefix6(struct in6_addr *prefix);
|
||||||
|
|
||||||
struct json_object * gluonutil_wrap_string(const char *str);
|
struct json_object * gluonutil_wrap_string(const char *str);
|
||||||
|
Loading…
Reference in New Issue
Block a user