+static void netlink_getlink(int fd) {
+ static const struct {
+ struct nlmsghdr nlm;
+ struct ifinfomsg ifi;
+ } msg = {
+ .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifi)),
+ .nlm.nlmsg_type = RTM_GETLINK,
+ .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+ .nlm.nlmsg_seq = 1,
+ .ifi.ifi_family = AF_UNSPEC,
+ };
+ send(fd, &msg, msg.nlm.nlmsg_len, 0);
+}
+
+static void netlink_getaddr(int fd) {
+ static const struct {
+ struct nlmsghdr nlm;
+ struct ifaddrmsg ifa;
+ } msg = {
+ .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifa)),
+ .nlm.nlmsg_type = RTM_GETADDR,
+ .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+ .nlm.nlmsg_seq = 2,
+ .ifa.ifa_family = AF_UNSPEC,
+ };
+ send(fd, &msg, msg.nlm.nlmsg_len, 0);
+}
+
+static void netlink_parse_link(meshlink_handle_t *mesh, const struct nlmsghdr *nlm) {
+ const struct ifinfomsg *ifi = (const struct ifinfomsg *)(nlm + 1);
+
+ if(ifi->ifi_flags & IFF_UP && ifi->ifi_flags & IFF_MULTICAST) {
+ logger(mesh, MESHLINK_INFO, "iface %d active\n", ifi->ifi_index);
+ } else {
+ logger(mesh, MESHLINK_INFO, "iface %d inactive\n", ifi->ifi_index);
+ }
+}
+
+static void netlink_parse_addr(meshlink_handle_t *mesh, const struct nlmsghdr *nlm) {
+ const struct ifaddrmsg *ifa = (const struct ifaddrmsg *)(nlm + 1);
+ const uint8_t *ptr = (const uint8_t *)(ifa + 1);
+ size_t len = nlm->nlmsg_len - (ptr - (const uint8_t *)nlm);
+
+ while(len >= sizeof(struct rtattr)) {
+ const struct rtattr *rta = (const struct rtattr *)ptr;
+
+ if(rta->rta_len <= 0 || rta->rta_len > len) {
+ break;
+ }
+
+ if(rta->rta_type == IFA_ADDRESS) {
+ char dest[40] = "?";
+
+ if(rta->rta_len == 8) {
+ inet_ntop(AF_INET, ptr + 4, dest, sizeof dest);
+ } else if(rta->rta_len == 20) {
+ inet_ntop(AF_INET6, ptr + 4, dest, sizeof dest);
+ }
+
+ logger(mesh, MESHLINK_INFO, "iface %d address %s %s\n", ifa->ifa_index, dest, nlm->nlmsg_type == RTM_NEWADDR ? "new" : "del");
+ }
+
+ unsigned short rta_len = (rta->rta_len + 3) & ~3;
+ ptr += rta_len;
+ len -= rta_len;
+ }
+}
+
+static void netlink_parse(meshlink_handle_t *mesh, const void *data, size_t len) {
+ const uint8_t *ptr = data;
+
+ while(len >= sizeof(struct nlmsghdr)) {
+ const struct nlmsghdr *nlm = (const struct nlmsghdr *)ptr;
+
+ if(nlm->nlmsg_len > len) {
+ break;
+ }
+
+ switch(nlm->nlmsg_type) {
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ netlink_parse_link(mesh, nlm);
+ break;
+
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ netlink_parse_addr(mesh, nlm);
+ }
+
+ ptr += nlm->nlmsg_len;
+ len -= nlm->nlmsg_len;
+ }
+}
+