41#include <sys/socket.h>
42#include <linux/netlink.h>
43#include <linux/rtnetlink.h>
45#define SNDBUF_SIZE (1024 * 2)
46#define RCVBUF_SIZE (1024 * 4)
48#define SITNL_ADDATTR(_msg, _max_size, _attr, _data, _size) \
50 if (sitnl_addattr(_msg, _max_size, _attr, _data, _size) < 0) \
56#define SITNL_NEST(_msg, _max_size, _attr) \
58 struct rtattr *_nest = sitnl_nlmsg_tail(_msg); \
59 SITNL_ADDATTR(_msg, _max_size, _attr, NULL, 0); \
63#define SITNL_NEST_END(_msg, _nest) \
65 _nest->rta_len = (unsigned short)((void *)sitnl_nlmsg_tail(_msg) - (void *)_nest); \
79sitnl_nlmsg_tail(
const struct nlmsghdr *nlh)
81 return (
unsigned char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len);
117struct sitnl_route_req
124typedef int (*sitnl_parse_reply_cb)(
struct nlmsghdr *
msg,
void *arg);
130sitnl_addattr(
struct nlmsghdr *n,
size_t maxlen,
unsigned short type,
const void *data,
size_t alen)
132 size_t len = RTA_LENGTH(alen);
134 if ((NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen)
136 msg(
M_WARN,
"%s: rtnl: message exceeded bound of %zu", __func__, maxlen);
140 struct rtattr *rta = sitnl_nlmsg_tail(n);
141 rta->rta_type = type;
143 rta->rta_len = (
unsigned short)len;
147 memset(RTA_DATA(rta), 0, alen);
151 memcpy(RTA_DATA(rta), data, alen);
154 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
165 int sndbuf = SNDBUF_SIZE;
166 int rcvbuf = RCVBUF_SIZE;
169 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
172 msg(
M_WARN,
"%s: cannot open netlink socket", __func__);
179 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
sizeof(sndbuf)) < 0)
186 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
sizeof(rcvbuf)) < 0)
200sitnl_bind(
int fd, uint32_t groups, uint32_t *local_pid)
203 struct sockaddr_nl local;
207 local.nl_family = AF_NETLINK;
208 local.nl_groups = groups;
210 if (bind(fd, (
struct sockaddr *)&local,
sizeof(local)) < 0)
216 addr_len =
sizeof(local);
217 if (getsockname(fd, (
struct sockaddr *)&local, &addr_len) < 0)
223 if (addr_len !=
sizeof(local))
225 msg(
M_WARN,
"%s: wrong address length %d", __func__, addr_len);
229 if (local.nl_family != AF_NETLINK)
231 msg(
M_WARN,
"%s: wrong address family %d", __func__, local.nl_family);
241 *local_pid = local.nl_pid;
250sitnl_send(
struct nlmsghdr *payload, pid_t peer,
unsigned int groups, sitnl_parse_reply_cb cb,
254 uint32_t local_pid = 0;
255 struct sockaddr_nl nladdr;
256 struct nlmsgerr *err;
261 .iov_len = payload->nlmsg_len,
263 struct msghdr nlmsg = {
265 .msg_namelen =
sizeof(nladdr),
272 nladdr.nl_family = AF_NETLINK;
273 nladdr.nl_pid = peer;
274 nladdr.nl_groups = groups;
281 static uint32_t sitnl_seq;
284 sitnl_seq = (uint32_t)time(NULL);
286 payload->nlmsg_seq = ++sitnl_seq;
291 payload->nlmsg_flags |= NLM_F_ACK;
301 if (sitnl_bind(fd, 0, &local_pid) < 0)
308 if (sendmsg(fd, &nlmsg, 0) < 0)
316 memset(buf, 0,
sizeof(buf));
325 msg(
D_RTNL,
"%s: checking for received messages", __func__);
326 iov.iov_len =
sizeof(buf);
327 ssize_t rcv_len = recvmsg(fd, &nlmsg, 0);
328 msg(
D_RTNL,
"%s: rtnl: received %zd bytes", __func__, rcv_len);
331 if ((errno == EINTR) || (errno == EAGAIN))
333 msg(
D_RTNL,
"%s: interrupted call", __func__);
343 msg(
M_WARN,
"%s: rtnl: socket reached unexpected EOF", __func__);
348 if (nlmsg.msg_namelen !=
sizeof(nladdr))
350 msg(
M_WARN,
"%s: sender address length: %u (expected %zu)", __func__, nlmsg.msg_namelen,
356 h = (
struct nlmsghdr *)buf;
357 while (rcv_len >= (
int)
sizeof(*h))
359 uint32_t len = h->nlmsg_len;
360 ssize_t rem_len = len -
sizeof(*h);
362 if ((rem_len < 0) || (len > rcv_len))
364 if (nlmsg.msg_flags & MSG_TRUNC)
366 msg(
M_WARN,
"%s: truncated message", __func__);
370 msg(
M_WARN,
"%s: malformed message: len=%u", __func__, len);
381 if ((nladdr.nl_pid != 0) || (h->nlmsg_pid != local_pid)
382 || (h->nlmsg_seq != payload->nlmsg_seq))
385 "%s: skipping unrelated message. nl_pid:%u nlmsg_pid:%u (local:%u) nlmsg_seq:%u (seq:%u)",
386 __func__, nladdr.nl_pid, h->nlmsg_pid, local_pid, h->nlmsg_seq,
388 rcv_len -= NLMSG_ALIGN(len);
389 h = (
struct nlmsghdr *)((
char *)h + NLMSG_ALIGN(len));
393 if (h->nlmsg_type == NLMSG_DONE)
399 if (h->nlmsg_type == NLMSG_ERROR)
401 err = (
struct nlmsgerr *)NLMSG_DATA(h);
402 if (rem_len < (
int)
sizeof(
struct nlmsgerr))
404 msg(
M_WARN,
"%s: ERROR truncated", __func__);
414 int r = cb(h, arg_cb);
423 msg(
M_WARN,
"%s: rtnl: generic error (%d): %s", __func__, err->error,
424 strerror(-err->error));
433 int r = cb(h, arg_cb);
442 msg(
M_WARN,
"%s: RTNL: unexpected reply", __func__);
445 rcv_len -= NLMSG_ALIGN(len);
446 h = (
struct nlmsghdr *)((
char *)h + NLMSG_ALIGN(len));
449 if (nlmsg.msg_flags & MSG_TRUNC)
451 msg(
M_WARN,
"%s: message truncated", __func__);
457 msg(
M_WARN,
"%s: rtnl: %zd not parsed bytes", __func__, rcv_len);
472 char iface[IFNAMSIZ];
478sitnl_route_save(
struct nlmsghdr *n,
void *arg)
480 route_res_t *res = arg;
481 struct rtmsg *r = NLMSG_DATA(n);
482 struct rtattr *rta = RTM_RTA(r);
483 size_t len = n->nlmsg_len - NLMSG_LENGTH(
sizeof(*r));
484 unsigned int table, ifindex = 0;
485 const void *gw = NULL;
488 if (res->default_only && r->rtm_dst_len != 0)
494 table = r->rtm_table;
496 while (RTA_OK(rta, len))
498 switch (rta->rta_type)
502 ifindex = *(
unsigned int *)RTA_DATA(rta);
516 table = *(
unsigned int *)RTA_DATA(rta);
520 rta = RTA_NEXT(rta, len);
524 if (res->table && res->table != table)
529 if (!if_indextoname(ifindex, res->iface))
531 msg(
M_WARN |
M_ERRNO,
"%s: rtnl: can't get ifname for index %d", __func__, ifindex);
537 memcpy(&res->gw, gw, res->addr_size);
547 struct sitnl_route_req req;
557 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
558 req.n.nlmsg_type = RTM_GETROUTE;
559 req.n.nlmsg_flags = NLM_F_REQUEST;
561 ASSERT(af_family <= UCHAR_MAX);
562 req.r.rtm_family = (
unsigned char)af_family;
572 if (!dst || !dst->
ipv4)
574 req.n.nlmsg_flags |= NLM_F_DUMP;
575 res.default_only =
true;
576 res.table = RT_TABLE_MAIN;
580 req.r.rtm_dst_len = 32;
585 res.addr_size =
sizeof(
struct in6_addr);
587 req.r.rtm_dst_len = 128;
595 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst, res.addr_size);
597 ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &res);
604 memcpy(best_gw, &res.gw, res.addr_size);
605 strncpy(best_iface, res.iface, IFNAMSIZ);
612net_route_v6_best_gw(
openvpn_net_ctx_t *ctx,
const struct in6_addr *dst,
struct in6_addr *best_gw,
616 char buf[INET6_ADDRSTRLEN];
624 msg(
D_ROUTE,
"%s query: dst %s", __func__, inet_ntop(AF_INET6, &dst_v6.
ipv6, buf,
sizeof(buf)));
626 ret = sitnl_route_best_gw(AF_INET6, &dst_v6, best_gw, best_iface);
632 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
633 inet_ntop(AF_INET6, best_gw, buf,
sizeof(buf)), best_iface);
644 char buf[INET_ADDRSTRLEN];
649 dst_v4.
ipv4 = htonl(*dst);
652 msg(
D_ROUTE,
"%s query: dst %s", __func__, inet_ntop(AF_INET, &dst_v4.
ipv4, buf,
sizeof(buf)));
654 ret = sitnl_route_best_gw(AF_INET, &dst_v4, best_gw, best_iface);
660 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
661 inet_ntop(AF_INET, best_gw, buf,
sizeof(buf)), best_iface);
664 *best_gw = ntohl(*best_gw);
674 struct sitnl_link_req req;
681 msg(
M_WARN,
"%s: passed NULL interface", __func__);
685 ifindex = if_nametoindex(
iface);
688 msg(
M_WARN,
"%s: rtnl: cannot get ifindex for %s: %s", __func__,
iface, strerror(errno));
692 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
693 req.n.nlmsg_flags = NLM_F_REQUEST;
694 req.n.nlmsg_type = RTM_NEWLINK;
696 req.i.ifi_family = AF_PACKET;
697 req.i.ifi_index = ifindex;
698 req.i.ifi_change |= IFF_UP;
701 req.i.ifi_flags |= IFF_UP;
705 req.i.ifi_flags &= ~IFF_UP;
708 msg(
M_INFO,
"%s: set %s %s", __func__,
iface, up ?
"up" :
"down");
710 return sitnl_send(&req.n, 0, 0, NULL, NULL);
716 struct sitnl_link_req req;
717 int ifindex, ret = -1;
721 ifindex = if_nametoindex(
iface);
728 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
729 req.n.nlmsg_flags = NLM_F_REQUEST;
730 req.n.nlmsg_type = RTM_NEWLINK;
732 req.i.ifi_family = AF_PACKET;
733 req.i.ifi_index = ifindex;
735 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_MTU, &mtu, 4);
739 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
747 struct sitnl_link_req req;
748 int ifindex, ret = -1;
752 ifindex = if_nametoindex(
iface);
759 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
760 req.n.nlmsg_flags = NLM_F_REQUEST;
761 req.n.nlmsg_type = RTM_NEWLINK;
763 req.i.ifi_family = AF_PACKET;
764 req.i.ifi_index = ifindex;
770 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
776sitnl_addr_set(uint16_t cmd, uint16_t flags,
int ifindex,
sa_family_t af_family,
779 struct sitnl_addr_req req;
785 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
786 req.n.nlmsg_type = cmd;
787 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
789 req.i.ifa_index = ifindex;
790 ASSERT(af_family <= UINT8_MAX);
791 req.i.ifa_family = (uint8_t)af_family;
796 size =
sizeof(
struct in_addr);
800 size =
sizeof(
struct in6_addr);
804 msg(
M_WARN,
"%s: rtnl: unknown address family %d", __func__, af_family);
811 prefixlen = size * 8;
813 ASSERT(prefixlen <= UINT8_MAX);
814 req.i.ifa_prefixlen = (uint8_t)prefixlen;
818 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_ADDRESS, remote, size);
823 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_LOCAL, local, size);
826 if (af_family == AF_INET && local && !remote && prefixlen <= 30)
830 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_BROADCAST, &broadcast, size);
833 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
860 msg(
M_WARN,
"%s: passed NULL interface", __func__);
864 ifindex = if_nametoindex(
iface);
867 msg(
M_WARN,
"%s: cannot get ifindex for %s: %s", __func__,
np(
iface), strerror(errno));
871 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex, af_family, local,
892 msg(
M_WARN,
"%s: passed NULL interface", __func__);
896 ifindex = if_nametoindex(
iface);
903 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, local, NULL, 0);
907sitnl_route_set(uint16_t cmd, uint16_t flags,
int ifindex,
sa_family_t af_family,
const void *dst,
908 int prefixlen,
const void *gw,
enum rt_class_t table,
int metric,
909 enum rt_scope_t scope,
unsigned char protocol,
unsigned char type)
911 struct sitnl_route_req req;
923 size =
sizeof(
struct in6_addr);
930 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
931 req.n.nlmsg_type = cmd;
932 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
934 ASSERT(af_family <= UCHAR_MAX);
935 req.r.rtm_family = (
unsigned char)af_family;
936 req.r.rtm_scope = (
unsigned char)scope;
937 req.r.rtm_protocol = protocol;
938 req.r.rtm_type = type;
939 ASSERT(prefixlen >= 0 && prefixlen <= UCHAR_MAX);
940 req.r.rtm_dst_len = (
unsigned char)prefixlen;
942 if (table <= UCHAR_MAX)
944 req.r.rtm_table = (
unsigned char)table;
948 req.r.rtm_table = RT_TABLE_UNSPEC;
949 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_TABLE, &table, 4);
954 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst, size);
959 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_GATEWAY, gw, size);
964 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_OIF, &ifindex, 4);
969 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_PRIORITY, &metric, 4);
972 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
994 msg(
M_WARN,
"%s: passed NULL interface", __func__);
998 ifindex = if_nametoindex(
iface);
1005 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex, af_family, addr, NULL,
1026 msg(
M_WARN,
"%s: passed NULL interface", __func__);
1030 ifindex = if_nametoindex(
iface);
1037 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, addr, NULL, prefixlen);
1044 char buf[INET_ADDRSTRLEN];
1051 addr_v4.
ipv4 = htonl(*addr);
1053 msg(
M_INFO,
"%s: %s/%d dev %s", __func__, inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)),
1056 return sitnl_addr_add(AF_INET,
iface, &addr_v4, prefixlen);
1064 char buf[INET6_ADDRSTRLEN];
1071 addr_v6.
ipv6 = *addr;
1073 msg(
M_INFO,
"%s: %s/%d dev %s", __func__, inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)),
1076 return sitnl_addr_add(AF_INET6,
iface, &addr_v6, prefixlen);
1083 char buf[INET_ADDRSTRLEN];
1090 addr_v4.
ipv4 = htonl(*addr);
1092 msg(
M_INFO,
"%s: %s dev %s", __func__, inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)),
1095 return sitnl_addr_del(AF_INET,
iface, &addr_v4, prefixlen);
1103 char buf[INET6_ADDRSTRLEN];
1110 addr_v6.
ipv6 = *addr;
1112 msg(
M_INFO,
"%s: %s/%d dev %s", __func__, inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)),
1115 return sitnl_addr_del(AF_INET6,
iface, &addr_v6, prefixlen);
1124 char buf1[INET_ADDRSTRLEN];
1125 char buf2[INET_ADDRSTRLEN];
1132 local_v4.
ipv4 = htonl(*local);
1136 remote_v4.
ipv4 = htonl(*remote);
1139 msg(
M_INFO,
"%s: %s peer %s dev %s", __func__,
1140 inet_ntop(AF_INET, &local_v4.
ipv4, buf1,
sizeof(buf1)),
1141 inet_ntop(AF_INET, &remote_v4.
ipv4, buf2,
sizeof(buf2)),
iface);
1143 return sitnl_addr_ptp_add(AF_INET,
iface, &local_v4, &remote_v4);
1151 char buf[INET6_ADDRSTRLEN];
1159 local_v4.
ipv4 = htonl(*local);
1161 msg(
M_INFO,
"%s: %s dev %s", __func__, inet_ntop(AF_INET, &local_v4.
ipv4, buf,
sizeof(buf)),
1164 return sitnl_addr_ptp_del(AF_INET,
iface, &local_v4);
1168sitnl_route_add(
const char *
iface,
sa_family_t af_family,
const void *dst,
int prefixlen,
1169 const void *gw, uint32_t table,
int metric)
1171 enum rt_scope_t scope = RT_SCOPE_UNIVERSE;
1176 ifindex = if_nametoindex(
iface);
1186 table = RT_TABLE_MAIN;
1191 scope = RT_SCOPE_LINK;
1194 return sitnl_route_set(RTM_NEWROUTE, NLM_F_CREATE, ifindex, af_family, dst, prefixlen, gw,
1195 table, metric, scope, RTPROT_BOOT, RTN_UNICAST);
1200 const char *
iface, uint32_t table,
int metric)
1202 const in_addr_t *dst_ptr = NULL, *gw_ptr = NULL;
1204 char dst_str[INET_ADDRSTRLEN];
1205 char gw_str[INET_ADDRSTRLEN];
1209 dst_be = htonl(*dst);
1219 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1220 inet_ntop(AF_INET, &dst_be, dst_str,
sizeof(dst_str)), prefixlen,
1221 inet_ntop(AF_INET, &gw_be, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1223 return sitnl_route_add(
iface, AF_INET, dst_ptr, prefixlen, gw_ptr, table, metric);
1227net_route_v6_add(
openvpn_net_ctx_t *ctx,
const struct in6_addr *dst,
int prefixlen,
1228 const struct in6_addr *gw,
const char *
iface, uint32_t table,
int metric)
1232 char dst_str[INET6_ADDRSTRLEN];
1233 char gw_str[INET6_ADDRSTRLEN];
1245 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1246 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)), prefixlen,
1247 inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1249 return sitnl_route_add(
iface, AF_INET6, dst, prefixlen, gw, table, metric);
1260 ifindex = if_nametoindex(
iface);
1270 table = RT_TABLE_MAIN;
1273 return sitnl_route_set(RTM_DELROUTE, 0, ifindex, af_family, dst, prefixlen, gw, table, metric,
1274 RT_SCOPE_NOWHERE, 0, 0);
1279 const char *
iface, uint32_t table,
int metric)
1283 char dst_str[INET_ADDRSTRLEN];
1284 char gw_str[INET_ADDRSTRLEN];
1288 dst_v4.
ipv4 = htonl(*dst);
1293 gw_v4.
ipv4 = htonl(*gw);
1296 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1297 inet_ntop(AF_INET, &dst_v4.
ipv4, dst_str,
sizeof(dst_str)), prefixlen,
1298 inet_ntop(AF_INET, &gw_v4.
ipv4, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1300 return sitnl_route_del(
iface, AF_INET, &dst_v4, prefixlen, &gw_v4, table, metric);
1304net_route_v6_del(
openvpn_net_ctx_t *ctx,
const struct in6_addr *dst,
int prefixlen,
1305 const struct in6_addr *gw,
const char *
iface, uint32_t table,
int metric)
1309 char dst_str[INET6_ADDRSTRLEN];
1310 char gw_str[INET6_ADDRSTRLEN];
1322 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1323 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)), prefixlen,
1324 inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1326 return sitnl_route_del(
iface, AF_INET6, &dst_v6, prefixlen, &gw_v6, table, metric);
1333 struct sitnl_link_req req = {};
1338 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1339 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
1340 req.n.nlmsg_type = RTM_NEWLINK;
1342 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_IFNAME,
iface, strlen(
iface) + 1);
1344 struct rtattr *linkinfo = SITNL_NEST(&req.n,
sizeof(req), IFLA_LINKINFO);
1345 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_INFO_KIND, type, strlen(type) + 1);
1346#if defined(ENABLE_DCO)
1350 struct rtattr *data = SITNL_NEST(&req.n,
sizeof(req), IFLA_INFO_DATA);
1358 uint8_t ifmode = (uint8_t)dco->ifmode;
1359 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_OVPN_MODE, &ifmode,
sizeof(uint8_t));
1360 SITNL_NEST_END(&req.n, data);
1363 SITNL_NEST_END(&req.n, linkinfo);
1365 req.i.ifi_family = AF_PACKET;
1369 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
1375sitnl_parse_rtattr_flags(
struct rtattr *tb[],
size_t max,
struct rtattr *rta,
size_t len,
1376 unsigned short flags)
1378 unsigned short type;
1380 memset(tb, 0,
sizeof(
struct rtattr *) * (max + 1));
1382 while (RTA_OK(rta, len))
1384 type = rta->rta_type & ~flags;
1386 if ((type <= max) && (!tb[type]))
1391 rta = RTA_NEXT(rta, len);
1396 msg(
D_ROUTE,
"%s: %zu bytes not parsed! (rta_len=%u)", __func__, len, rta->rta_len);
1401sitnl_parse_rtattr(
struct rtattr *tb[],
size_t max,
struct rtattr *rta,
size_t len)
1403 sitnl_parse_rtattr_flags(tb, max, rta, len, 0);
1406#define sitnl_parse_rtattr_nested(tb, max, rta) \
1407 (sitnl_parse_rtattr_flags(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta), NLA_F_NESTED))
1410sitnl_type_save(
struct nlmsghdr *n,
void *arg)
1413 struct ifinfomsg *ifi = NLMSG_DATA(n);
1414 struct rtattr *tb[IFLA_MAX + 1];
1416 sitnl_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
1418 if (tb[IFLA_LINKINFO])
1420 struct rtattr *tb_link[IFLA_INFO_MAX + 1];
1422 sitnl_parse_rtattr_nested(tb_link, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
1424 if (!tb_link[IFLA_INFO_KIND])
1438 struct sitnl_link_req req = {};
1439 int ifindex = if_nametoindex(
iface);
1446 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1447 req.n.nlmsg_flags = NLM_F_REQUEST;
1448 req.n.nlmsg_type = RTM_GETLINK;
1450 req.i.ifi_family = AF_PACKET;
1451 req.i.ifi_index = ifindex;
1455 int ret = sitnl_send(&req.n, 0, 0, sitnl_type_save, type);
1458 msg(
D_ROUTE,
"%s: cannot retrieve iface %s: %s (%d)", __func__,
iface, strerror(-ret), ret);
1470 struct sitnl_link_req req = {};
1471 int ifindex = if_nametoindex(
iface);
1478 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1479 req.n.nlmsg_flags = NLM_F_REQUEST;
1480 req.n.nlmsg_type = RTM_DELLINK;
1482 req.i.ifi_family = AF_PACKET;
1483 req.i.ifi_index = ifindex;
1487 return sitnl_send(&req.n, 0, 0, NULL, NULL);
Buffer management functions and garbage collection.
static void strncpynt(char *dest, const char *src, size_t maxlen)
Like strncpy() but always null-terminates the destination.
void set_cloexec(socket_descriptor_t fd)
#define MAC_PRINT_ARG(_mac)
static const char * np(const char *str)
void * openvpn_net_iface_t
#define IFACE_TYPE_LEN_MAX
static in_addr_t netbits_to_netmask(const int netbits)
unsigned short sa_family_t