40#include <sys/socket.h>
41#include <linux/netlink.h>
42#include <linux/rtnetlink.h>
44#define SNDBUF_SIZE (1024 * 2)
45#define RCVBUF_SIZE (1024 * 4)
47#define SITNL_ADDATTR(_msg, _max_size, _attr, _data, _size) \
49 if (sitnl_addattr(_msg, _max_size, _attr, _data, _size) < 0) \
55#define SITNL_NEST(_msg, _max_size, _attr) \
57 struct rtattr *_nest = sitnl_nlmsg_tail(_msg); \
58 SITNL_ADDATTR(_msg, _max_size, _attr, NULL, 0); \
62#define SITNL_NEST_END(_msg, _nest) \
64 _nest->rta_len = (void *)sitnl_nlmsg_tail(_msg) - (void *)_nest; \
78sitnl_nlmsg_tail(
const struct nlmsghdr *nlh)
80 return (
unsigned char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len);
116struct sitnl_route_req
123typedef int (*sitnl_parse_reply_cb)(
struct nlmsghdr *
msg,
void *arg);
128struct sitnl_route_data_cb
134#if defined(__GNUC__) || defined(__clang__)
135#pragma GCC diagnostic push
136#pragma GCC diagnostic ignored "-Wconversion"
143sitnl_addattr(
struct nlmsghdr *n,
int maxlen,
int type,
const void *data,
int alen)
145 int len = RTA_LENGTH(alen);
148 if ((
int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen)
150 msg(
M_WARN,
"%s: rtnl: message exceeded bound of %d", __func__, maxlen);
154 rta = sitnl_nlmsg_tail(n);
155 rta->rta_type = type;
160 memset(RTA_DATA(rta), 0, alen);
164 memcpy(RTA_DATA(rta), data, alen);
167 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
178 int sndbuf = SNDBUF_SIZE;
179 int rcvbuf = RCVBUF_SIZE;
182 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
185 msg(
M_WARN,
"%s: cannot open netlink socket", __func__);
189 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
sizeof(sndbuf)) < 0)
196 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
sizeof(rcvbuf)) < 0)
210sitnl_bind(
int fd, uint32_t groups)
213 struct sockaddr_nl local;
217 local.nl_family = AF_NETLINK;
218 local.nl_groups = groups;
220 if (bind(fd, (
struct sockaddr *)&local,
sizeof(local)) < 0)
226 addr_len =
sizeof(local);
227 if (getsockname(fd, (
struct sockaddr *)&local, &addr_len) < 0)
233 if (addr_len !=
sizeof(local))
235 msg(
M_WARN,
"%s: wrong address length %d", __func__, addr_len);
239 if (local.nl_family != AF_NETLINK)
241 msg(
M_WARN,
"%s: wrong address family %d", __func__, local.nl_family);
252sitnl_send(
struct nlmsghdr *payload, pid_t peer,
unsigned int groups, sitnl_parse_reply_cb cb,
255 int len, rem_len, fd, ret, rcv_len;
256 struct sockaddr_nl nladdr;
257 struct nlmsgerr *err;
263 .iov_len = payload->nlmsg_len,
265 struct msghdr nlmsg = {
267 .msg_namelen =
sizeof(nladdr),
274 nladdr.nl_family = AF_NETLINK;
275 nladdr.nl_pid = peer;
276 nladdr.nl_groups = groups;
278 payload->nlmsg_seq = seq = time(NULL);
283 payload->nlmsg_flags |= NLM_F_ACK;
293 ret = sitnl_bind(fd, 0);
301 ret = sendmsg(fd, &nlmsg, 0);
310 memset(buf, 0,
sizeof(buf));
319 msg(
D_RTNL,
"%s: checking for received messages", __func__);
320 iov.iov_len =
sizeof(buf);
321 rcv_len = recvmsg(fd, &nlmsg, 0);
322 msg(
D_RTNL,
"%s: rtnl: received %d bytes", __func__, rcv_len);
325 if ((errno == EINTR) || (errno == EAGAIN))
327 msg(
D_RTNL,
"%s: interrupted call", __func__);
337 msg(
M_WARN,
"%s: rtnl: socket reached unexpected EOF", __func__);
342 if (nlmsg.msg_namelen !=
sizeof(nladdr))
344 msg(
M_WARN,
"%s: sender address length: %u (expected %zu)", __func__, nlmsg.msg_namelen,
350 h = (
struct nlmsghdr *)buf;
351 while (rcv_len >= (
int)
sizeof(*h))
354 rem_len = len -
sizeof(*h);
356 if ((rem_len < 0) || (len > rcv_len))
358 if (nlmsg.msg_flags & MSG_TRUNC)
360 msg(
M_WARN,
"%s: truncated message", __func__);
364 msg(
M_WARN,
"%s: malformed message: len=%d", __func__, len);
382 if (h->nlmsg_type == NLMSG_DONE)
388 if (h->nlmsg_type == NLMSG_ERROR)
390 err = (
struct nlmsgerr *)NLMSG_DATA(h);
391 if (rem_len < (
int)
sizeof(
struct nlmsgerr))
393 msg(
M_WARN,
"%s: ERROR truncated", __func__);
403 int r = cb(h, arg_cb);
412 msg(
M_WARN,
"%s: rtnl: generic error (%d): %s", __func__, err->error,
413 strerror(-err->error));
422 int r = cb(h, arg_cb);
431 msg(
M_WARN,
"%s: RTNL: unexpected reply", __func__);
434 rcv_len -= NLMSG_ALIGN(len);
435 h = (
struct nlmsghdr *)((
char *)h + NLMSG_ALIGN(len));
438 if (nlmsg.msg_flags & MSG_TRUNC)
440 msg(
M_WARN,
"%s: message truncated", __func__);
446 msg(
M_WARN,
"%s: rtnl: %d not parsed bytes", __func__, rcv_len);
461 char iface[IFNAMSIZ];
467sitnl_route_save(
struct nlmsghdr *n,
void *arg)
469 route_res_t *
res = arg;
470 struct rtmsg *r = NLMSG_DATA(n);
471 struct rtattr *rta = RTM_RTA(r);
472 int len = n->nlmsg_len - NLMSG_LENGTH(
sizeof(*r));
473 unsigned int table, ifindex = 0;
477 if (
res->default_only && r->rtm_dst_len != 0)
483 table = r->rtm_table;
485 while (RTA_OK(rta, len))
487 switch (rta->rta_type)
491 ifindex = *(
unsigned int *)RTA_DATA(rta);
505 table = *(
unsigned int *)RTA_DATA(rta);
509 rta = RTA_NEXT(rta, len);
513 if (
res->table &&
res->table != table)
518 if (!if_indextoname(ifindex,
res->iface))
520 msg(
M_WARN |
M_ERRNO,
"%s: rtnl: can't get ifname for index %d", __func__, ifindex);
526 memcpy(&
res->gw, gw,
res->addr_size);
536 struct sitnl_route_req req;
546 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
547 req.n.nlmsg_type = RTM_GETROUTE;
548 req.n.nlmsg_flags = NLM_F_REQUEST;
550 req.r.rtm_family = af_family;
555 res.addr_size =
sizeof(in_addr_t);
560 if (!dst || !dst->
ipv4)
562 req.n.nlmsg_flags |= NLM_F_DUMP;
563 res.default_only =
true;
564 res.table = RT_TABLE_MAIN;
568 req.r.rtm_dst_len = 32;
573 res.addr_size =
sizeof(
struct in6_addr);
575 req.r.rtm_dst_len = 128;
583 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst,
res.addr_size);
585 ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &
res);
592 memcpy(best_gw, &
res.gw,
res.addr_size);
593 strncpy(best_iface,
res.iface, IFNAMSIZ);
600net_route_v6_best_gw(
openvpn_net_ctx_t *ctx,
const struct in6_addr *dst,
struct in6_addr *best_gw,
604 char buf[INET6_ADDRSTRLEN];
612 msg(
D_ROUTE,
"%s query: dst %s", __func__, inet_ntop(AF_INET6, &dst_v6.
ipv6, buf,
sizeof(buf)));
614 ret = sitnl_route_best_gw(AF_INET6, &dst_v6, best_gw, best_iface);
620 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
621 inet_ntop(AF_INET6, best_gw, buf,
sizeof(buf)), best_iface);
628net_route_v4_best_gw(
openvpn_net_ctx_t *ctx,
const in_addr_t *dst, in_addr_t *best_gw,
632 char buf[INET_ADDRSTRLEN];
637 dst_v4.
ipv4 = htonl(*dst);
640 msg(
D_ROUTE,
"%s query: dst %s", __func__, inet_ntop(AF_INET, &dst_v4.
ipv4, buf,
sizeof(buf)));
642 ret = sitnl_route_best_gw(AF_INET, &dst_v4, best_gw, best_iface);
648 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
649 inet_ntop(AF_INET, best_gw, buf,
sizeof(buf)), best_iface);
652 *best_gw = ntohl(*best_gw);
662 struct sitnl_link_req req;
669 msg(
M_WARN,
"%s: passed NULL interface", __func__);
673 ifindex = if_nametoindex(
iface);
676 msg(
M_WARN,
"%s: rtnl: cannot get ifindex for %s: %s", __func__,
iface, strerror(errno));
680 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
681 req.n.nlmsg_flags = NLM_F_REQUEST;
682 req.n.nlmsg_type = RTM_NEWLINK;
684 req.i.ifi_family = AF_PACKET;
685 req.i.ifi_index = ifindex;
686 req.i.ifi_change |= IFF_UP;
689 req.i.ifi_flags |= IFF_UP;
693 req.i.ifi_flags &= ~IFF_UP;
696 msg(
M_INFO,
"%s: set %s %s", __func__,
iface, up ?
"up" :
"down");
698 return sitnl_send(&req.n, 0, 0, NULL, NULL);
704 struct sitnl_link_req req;
705 int ifindex, ret = -1;
709 ifindex = if_nametoindex(
iface);
716 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
717 req.n.nlmsg_flags = NLM_F_REQUEST;
718 req.n.nlmsg_type = RTM_NEWLINK;
720 req.i.ifi_family = AF_PACKET;
721 req.i.ifi_index = ifindex;
723 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_MTU, &mtu, 4);
727 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
735 struct sitnl_link_req req;
736 int ifindex, ret = -1;
740 ifindex = if_nametoindex(
iface);
747 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
748 req.n.nlmsg_flags = NLM_F_REQUEST;
749 req.n.nlmsg_type = RTM_NEWLINK;
751 req.i.ifi_family = AF_PACKET;
752 req.i.ifi_index = ifindex;
758 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
764sitnl_addr_set(
int cmd, uint32_t flags,
int ifindex,
sa_family_t af_family,
767 struct sitnl_addr_req req;
773 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
774 req.n.nlmsg_type = cmd;
775 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
777 req.i.ifa_index = ifindex;
778 req.i.ifa_family = af_family;
783 size =
sizeof(
struct in_addr);
787 size =
sizeof(
struct in6_addr);
791 msg(
M_WARN,
"%s: rtnl: unknown address family %d", __func__, af_family);
798 prefixlen = size * 8;
800 req.i.ifa_prefixlen = prefixlen;
804 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_ADDRESS, remote, size);
809 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_LOCAL, local, size);
812 if (af_family == AF_INET && local && !remote && prefixlen <= 30)
816 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_BROADCAST, &broadcast, size);
819 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
846 msg(
M_WARN,
"%s: passed NULL interface", __func__);
850 ifindex = if_nametoindex(
iface);
853 msg(
M_WARN,
"%s: cannot get ifindex for %s: %s", __func__,
np(
iface), strerror(errno));
857 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex, af_family, local,
878 msg(
M_WARN,
"%s: passed NULL interface", __func__);
882 ifindex = if_nametoindex(
iface);
889 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, local, NULL, 0);
893sitnl_route_set(
int cmd, uint32_t flags,
int ifindex,
sa_family_t af_family,
const void *dst,
894 int prefixlen,
const void *gw,
enum rt_class_t table,
int metric,
895 enum rt_scope_t scope,
int protocol,
int type)
897 struct sitnl_route_req req;
905 size =
sizeof(in_addr_t);
909 size =
sizeof(
struct in6_addr);
916 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
917 req.n.nlmsg_type = cmd;
918 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
920 req.r.rtm_family = af_family;
921 req.r.rtm_scope = scope;
922 req.r.rtm_protocol = protocol;
923 req.r.rtm_type = type;
924 req.r.rtm_dst_len = prefixlen;
928 req.r.rtm_table = table;
932 req.r.rtm_table = RT_TABLE_UNSPEC;
933 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_TABLE, &table, 4);
938 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst, size);
943 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_GATEWAY, gw, size);
948 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_OIF, &ifindex, 4);
953 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_PRIORITY, &metric, 4);
956 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
978 msg(
M_WARN,
"%s: passed NULL interface", __func__);
982 ifindex = if_nametoindex(
iface);
989 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex, af_family, addr, NULL,
1010 msg(
M_WARN,
"%s: passed NULL interface", __func__);
1014 ifindex = if_nametoindex(
iface);
1021 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, addr, NULL, prefixlen);
1028 char buf[INET_ADDRSTRLEN];
1035 addr_v4.
ipv4 = htonl(*addr);
1037 msg(
M_INFO,
"%s: %s/%d dev %s", __func__, inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)),
1040 return sitnl_addr_add(AF_INET,
iface, &addr_v4, prefixlen);
1048 char buf[INET6_ADDRSTRLEN];
1055 addr_v6.
ipv6 = *addr;
1057 msg(
M_INFO,
"%s: %s/%d dev %s", __func__, inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)),
1060 return sitnl_addr_add(AF_INET6,
iface, &addr_v6, prefixlen);
1067 char buf[INET_ADDRSTRLEN];
1074 addr_v4.
ipv4 = htonl(*addr);
1076 msg(
M_INFO,
"%s: %s dev %s", __func__, inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)),
1079 return sitnl_addr_del(AF_INET,
iface, &addr_v4, prefixlen);
1087 char buf[INET6_ADDRSTRLEN];
1094 addr_v6.
ipv6 = *addr;
1096 msg(
M_INFO,
"%s: %s/%d dev %s", __func__, inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)),
1099 return sitnl_addr_del(AF_INET6,
iface, &addr_v6, prefixlen);
1104 const in_addr_t *remote)
1108 char buf1[INET_ADDRSTRLEN];
1109 char buf2[INET_ADDRSTRLEN];
1116 local_v4.
ipv4 = htonl(*local);
1120 remote_v4.
ipv4 = htonl(*remote);
1123 msg(
M_INFO,
"%s: %s peer %s dev %s", __func__,
1124 inet_ntop(AF_INET, &local_v4.
ipv4, buf1,
sizeof(buf1)),
1125 inet_ntop(AF_INET, &remote_v4.
ipv4, buf2,
sizeof(buf2)),
iface);
1127 return sitnl_addr_ptp_add(AF_INET,
iface, &local_v4, &remote_v4);
1132 const in_addr_t *remote)
1135 char buf[INET6_ADDRSTRLEN];
1143 local_v4.
ipv4 = htonl(*local);
1145 msg(
M_INFO,
"%s: %s dev %s", __func__, inet_ntop(AF_INET, &local_v4.
ipv4, buf,
sizeof(buf)),
1148 return sitnl_addr_ptp_del(AF_INET,
iface, &local_v4);
1152sitnl_route_add(
const char *
iface,
sa_family_t af_family,
const void *dst,
int prefixlen,
1153 const void *gw, uint32_t table,
int metric)
1155 enum rt_scope_t scope = RT_SCOPE_UNIVERSE;
1160 ifindex = if_nametoindex(
iface);
1170 table = RT_TABLE_MAIN;
1175 scope = RT_SCOPE_LINK;
1178 return sitnl_route_set(RTM_NEWROUTE, NLM_F_CREATE, ifindex, af_family, dst, prefixlen, gw,
1179 table, metric, scope, RTPROT_BOOT, RTN_UNICAST);
1183net_route_v4_add(
openvpn_net_ctx_t *ctx,
const in_addr_t *dst,
int prefixlen,
const in_addr_t *gw,
1184 const char *
iface, uint32_t table,
int metric)
1186 in_addr_t *dst_ptr = NULL, *gw_ptr = NULL;
1187 in_addr_t dst_be = 0, gw_be = 0;
1188 char dst_str[INET_ADDRSTRLEN];
1189 char gw_str[INET_ADDRSTRLEN];
1193 dst_be = htonl(*dst);
1203 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1204 inet_ntop(AF_INET, &dst_be, dst_str,
sizeof(dst_str)), prefixlen,
1205 inet_ntop(AF_INET, &gw_be, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1207 return sitnl_route_add(
iface, AF_INET, dst_ptr, prefixlen, gw_ptr, table, metric);
1211net_route_v6_add(
openvpn_net_ctx_t *ctx,
const struct in6_addr *dst,
int prefixlen,
1212 const struct in6_addr *gw,
const char *
iface, uint32_t table,
int metric)
1216 char dst_str[INET6_ADDRSTRLEN];
1217 char gw_str[INET6_ADDRSTRLEN];
1229 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1230 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)), prefixlen,
1231 inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1233 return sitnl_route_add(
iface, AF_INET6, dst, prefixlen, gw, table, metric);
1244 ifindex = if_nametoindex(
iface);
1254 table = RT_TABLE_MAIN;
1257 return sitnl_route_set(RTM_DELROUTE, 0, ifindex, af_family, dst, prefixlen, gw, table, metric,
1258 RT_SCOPE_NOWHERE, 0, 0);
1262net_route_v4_del(
openvpn_net_ctx_t *ctx,
const in_addr_t *dst,
int prefixlen,
const in_addr_t *gw,
1263 const char *
iface, uint32_t table,
int metric)
1267 char dst_str[INET_ADDRSTRLEN];
1268 char gw_str[INET_ADDRSTRLEN];
1272 dst_v4.
ipv4 = htonl(*dst);
1277 gw_v4.
ipv4 = htonl(*gw);
1280 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1281 inet_ntop(AF_INET, &dst_v4.
ipv4, dst_str,
sizeof(dst_str)), prefixlen,
1282 inet_ntop(AF_INET, &gw_v4.
ipv4, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1284 return sitnl_route_del(
iface, AF_INET, &dst_v4, prefixlen, &gw_v4, table, metric);
1288net_route_v6_del(
openvpn_net_ctx_t *ctx,
const struct in6_addr *dst,
int prefixlen,
1289 const struct in6_addr *gw,
const char *
iface, uint32_t table,
int metric)
1293 char dst_str[INET6_ADDRSTRLEN];
1294 char gw_str[INET6_ADDRSTRLEN];
1306 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1307 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)), prefixlen,
1308 inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1310 return sitnl_route_del(
iface, AF_INET6, &dst_v6, prefixlen, &gw_v6, table, metric);
1317 struct sitnl_link_req req = {};
1322 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1323 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
1324 req.n.nlmsg_type = RTM_NEWLINK;
1326 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_IFNAME,
iface, strlen(
iface) + 1);
1328 struct rtattr *linkinfo = SITNL_NEST(&req.n,
sizeof(req), IFLA_LINKINFO);
1329 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_INFO_KIND, type, strlen(type) + 1);
1330#if defined(ENABLE_DCO)
1334 struct rtattr *data = SITNL_NEST(&req.n,
sizeof(req), IFLA_INFO_DATA);
1335 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_OVPN_MODE, &dco->ifmode,
sizeof(uint8_t));
1336 SITNL_NEST_END(&req.n, data);
1339 SITNL_NEST_END(&req.n, linkinfo);
1341 req.i.ifi_family = AF_PACKET;
1345 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
1351sitnl_parse_rtattr_flags(
struct rtattr *tb[],
int max,
struct rtattr *rta,
int len,
1352 unsigned short flags)
1354 unsigned short type;
1356 memset(tb, 0,
sizeof(
struct rtattr *) * (max + 1));
1358 while (RTA_OK(rta, len))
1360 type = rta->rta_type & ~flags;
1362 if ((type <= max) && (!tb[type]))
1367 rta = RTA_NEXT(rta, len);
1372 msg(
D_ROUTE,
"%s: %d bytes not parsed! (rta_len=%d)", __func__, len, rta->rta_len);
1379sitnl_parse_rtattr(
struct rtattr *tb[],
int max,
struct rtattr *rta,
int len)
1381 return sitnl_parse_rtattr_flags(tb, max, rta, len, 0);
1384#define sitnl_parse_rtattr_nested(tb, max, rta) \
1385 (sitnl_parse_rtattr_flags(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta), NLA_F_NESTED))
1388sitnl_type_save(
struct nlmsghdr *n,
void *arg)
1391 struct ifinfomsg *ifi = NLMSG_DATA(n);
1392 struct rtattr *tb[IFLA_MAX + 1];
1395 ret = sitnl_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
1401 if (tb[IFLA_LINKINFO])
1403 struct rtattr *tb_link[IFLA_INFO_MAX + 1];
1405 ret = sitnl_parse_rtattr_nested(tb_link, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
1411 if (!tb_link[IFLA_INFO_KIND])
1425 struct sitnl_link_req req = {};
1426 int ifindex = if_nametoindex(
iface);
1433 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1434 req.n.nlmsg_flags = NLM_F_REQUEST;
1435 req.n.nlmsg_type = RTM_GETLINK;
1437 req.i.ifi_family = AF_PACKET;
1438 req.i.ifi_index = ifindex;
1442 int ret = sitnl_send(&req.n, 0, 0, sitnl_type_save, type);
1445 msg(
D_ROUTE,
"%s: cannot retrieve iface %s: %s (%d)", __func__,
iface, strerror(-ret), ret);
1457 struct sitnl_link_req req = {};
1458 int ifindex = if_nametoindex(
iface);
1465 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1466 req.n.nlmsg_flags = NLM_F_REQUEST;
1467 req.n.nlmsg_type = RTM_DELLINK;
1469 req.i.ifi_family = AF_PACKET;
1470 req.i.ifi_index = ifindex;
1474 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1477#if defined(__GNUC__) || defined(__clang__)
1478#pragma GCC diagnostic pop
static void strncpynt(char *dest, const char *src, size_t maxlen)
#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