39#include <sys/socket.h>
40#include <linux/netlink.h>
41#include <linux/rtnetlink.h>
43#define SNDBUF_SIZE (1024 * 2)
44#define RCVBUF_SIZE (1024 * 4)
46#define SITNL_ADDATTR(_msg, _max_size, _attr, _data, _size) \
48 if (sitnl_addattr(_msg, _max_size, _attr, _data, _size) < 0) \
54#define SITNL_NEST(_msg, _max_size, _attr) \
56 struct rtattr *_nest = sitnl_nlmsg_tail(_msg); \
57 SITNL_ADDATTR(_msg, _max_size, _attr, NULL, 0); \
61#define SITNL_NEST_END(_msg, _nest) \
63 _nest->rta_len = (void *)sitnl_nlmsg_tail(_msg) - (void *)_nest; \
77sitnl_nlmsg_tail(
const struct nlmsghdr *nlh)
79 return (
unsigned char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len);
115struct sitnl_route_req
122typedef int (*sitnl_parse_reply_cb)(
struct nlmsghdr *
msg,
void *arg);
127struct sitnl_route_data_cb
137sitnl_addattr(
struct nlmsghdr *n,
int maxlen,
int type,
const void *data,
int alen)
139 int len = RTA_LENGTH(alen);
142 if ((
int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen)
144 msg(
M_WARN,
"%s: rtnl: message exceeded bound of %d", __func__, maxlen);
148 rta = sitnl_nlmsg_tail(n);
149 rta->rta_type = type;
154 memset(RTA_DATA(rta), 0, alen);
158 memcpy(RTA_DATA(rta), data, alen);
161 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
172 int sndbuf = SNDBUF_SIZE;
173 int rcvbuf = RCVBUF_SIZE;
176 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
179 msg(
M_WARN,
"%s: cannot open netlink socket", __func__);
183 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
sizeof(sndbuf)) < 0)
190 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
sizeof(rcvbuf)) < 0)
204sitnl_bind(
int fd, uint32_t groups)
207 struct sockaddr_nl local;
211 local.nl_family = AF_NETLINK;
212 local.nl_groups = groups;
214 if (bind(fd, (
struct sockaddr *)&local,
sizeof(local)) < 0)
220 addr_len =
sizeof(local);
221 if (getsockname(fd, (
struct sockaddr *)&local, &addr_len) < 0)
227 if (addr_len !=
sizeof(local))
229 msg(
M_WARN,
"%s: wrong address length %d", __func__, addr_len);
233 if (local.nl_family != AF_NETLINK)
235 msg(
M_WARN,
"%s: wrong address family %d", __func__, local.nl_family);
246sitnl_send(
struct nlmsghdr *payload, pid_t peer,
unsigned int groups, sitnl_parse_reply_cb cb,
249 int len, rem_len, fd, ret, rcv_len;
250 struct sockaddr_nl nladdr;
251 struct nlmsgerr *err;
257 .iov_len = payload->nlmsg_len,
259 struct msghdr nlmsg = {
261 .msg_namelen =
sizeof(nladdr),
268 nladdr.nl_family = AF_NETLINK;
269 nladdr.nl_pid = peer;
270 nladdr.nl_groups = groups;
272 payload->nlmsg_seq = seq = time(NULL);
277 payload->nlmsg_flags |= NLM_F_ACK;
287 ret = sitnl_bind(fd, 0);
295 ret = sendmsg(fd, &nlmsg, 0);
304 memset(buf, 0,
sizeof(buf));
313 msg(
D_RTNL,
"%s: checking for received messages", __func__);
314 iov.iov_len =
sizeof(buf);
315 rcv_len = recvmsg(fd, &nlmsg, 0);
316 msg(
D_RTNL,
"%s: rtnl: received %d bytes", __func__, rcv_len);
319 if ((errno == EINTR) || (errno == EAGAIN))
321 msg(
D_RTNL,
"%s: interrupted call", __func__);
331 msg(
M_WARN,
"%s: rtnl: socket reached unexpected EOF", __func__);
336 if (nlmsg.msg_namelen !=
sizeof(nladdr))
338 msg(
M_WARN,
"%s: sender address length: %u (expected %zu)", __func__, nlmsg.msg_namelen,
344 h = (
struct nlmsghdr *)buf;
345 while (rcv_len >= (
int)
sizeof(*h))
348 rem_len = len -
sizeof(*h);
350 if ((rem_len < 0) || (len > rcv_len))
352 if (nlmsg.msg_flags & MSG_TRUNC)
354 msg(
M_WARN,
"%s: truncated message", __func__);
358 msg(
M_WARN,
"%s: malformed message: len=%d", __func__, len);
376 if (h->nlmsg_type == NLMSG_DONE)
382 if (h->nlmsg_type == NLMSG_ERROR)
384 err = (
struct nlmsgerr *)NLMSG_DATA(h);
385 if (rem_len < (
int)
sizeof(
struct nlmsgerr))
387 msg(
M_WARN,
"%s: ERROR truncated", __func__);
397 int r = cb(h, arg_cb);
406 msg(
M_WARN,
"%s: rtnl: generic error (%d): %s", __func__, err->error,
407 strerror(-err->error));
416 int r = cb(h, arg_cb);
425 msg(
M_WARN,
"%s: RTNL: unexpected reply", __func__);
428 rcv_len -= NLMSG_ALIGN(len);
429 h = (
struct nlmsghdr *)((
char *)h + NLMSG_ALIGN(len));
432 if (nlmsg.msg_flags & MSG_TRUNC)
434 msg(
M_WARN,
"%s: message truncated", __func__);
440 msg(
M_WARN,
"%s: rtnl: %d not parsed bytes", __func__, rcv_len);
455 char iface[IFNAMSIZ];
461sitnl_route_save(
struct nlmsghdr *n,
void *arg)
463 route_res_t *
res = arg;
464 struct rtmsg *r = NLMSG_DATA(n);
465 struct rtattr *rta = RTM_RTA(r);
466 int len = n->nlmsg_len - NLMSG_LENGTH(
sizeof(*r));
467 unsigned int table, ifindex = 0;
471 if (
res->default_only && r->rtm_dst_len != 0)
477 table = r->rtm_table;
479 while (RTA_OK(rta, len))
481 switch (rta->rta_type)
485 ifindex = *(
unsigned int *)RTA_DATA(rta);
499 table = *(
unsigned int *)RTA_DATA(rta);
503 rta = RTA_NEXT(rta, len);
507 if (
res->table &&
res->table != table)
512 if (!if_indextoname(ifindex,
res->iface))
514 msg(
M_WARN |
M_ERRNO,
"%s: rtnl: can't get ifname for index %d", __func__, ifindex);
520 memcpy(&
res->gw, gw,
res->addr_size);
530 struct sitnl_route_req req;
540 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
541 req.n.nlmsg_type = RTM_GETROUTE;
542 req.n.nlmsg_flags = NLM_F_REQUEST;
544 req.r.rtm_family = af_family;
549 res.addr_size =
sizeof(in_addr_t);
554 if (!dst || !dst->
ipv4)
556 req.n.nlmsg_flags |= NLM_F_DUMP;
557 res.default_only =
true;
558 res.table = RT_TABLE_MAIN;
562 req.r.rtm_dst_len = 32;
567 res.addr_size =
sizeof(
struct in6_addr);
569 req.r.rtm_dst_len = 128;
577 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst,
res.addr_size);
579 ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &
res);
586 memcpy(best_gw, &
res.gw,
res.addr_size);
587 strncpy(best_iface,
res.iface, IFNAMSIZ);
594net_route_v6_best_gw(
openvpn_net_ctx_t *ctx,
const struct in6_addr *dst,
struct in6_addr *best_gw,
598 char buf[INET6_ADDRSTRLEN];
606 msg(
D_ROUTE,
"%s query: dst %s", __func__, inet_ntop(AF_INET6, &dst_v6.
ipv6, buf,
sizeof(buf)));
608 ret = sitnl_route_best_gw(AF_INET6, &dst_v6, best_gw, best_iface);
614 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
615 inet_ntop(AF_INET6, best_gw, buf,
sizeof(buf)), best_iface);
622net_route_v4_best_gw(
openvpn_net_ctx_t *ctx,
const in_addr_t *dst, in_addr_t *best_gw,
626 char buf[INET_ADDRSTRLEN];
631 dst_v4.
ipv4 = htonl(*dst);
634 msg(
D_ROUTE,
"%s query: dst %s", __func__, inet_ntop(AF_INET, &dst_v4.
ipv4, buf,
sizeof(buf)));
636 ret = sitnl_route_best_gw(AF_INET, &dst_v4, best_gw, best_iface);
642 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
643 inet_ntop(AF_INET, best_gw, buf,
sizeof(buf)), best_iface);
646 *best_gw = ntohl(*best_gw);
656 struct sitnl_link_req req;
663 msg(
M_WARN,
"%s: passed NULL interface", __func__);
667 ifindex = if_nametoindex(
iface);
670 msg(
M_WARN,
"%s: rtnl: cannot get ifindex for %s: %s", __func__,
iface, strerror(errno));
674 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
675 req.n.nlmsg_flags = NLM_F_REQUEST;
676 req.n.nlmsg_type = RTM_NEWLINK;
678 req.i.ifi_family = AF_PACKET;
679 req.i.ifi_index = ifindex;
680 req.i.ifi_change |= IFF_UP;
683 req.i.ifi_flags |= IFF_UP;
687 req.i.ifi_flags &= ~IFF_UP;
690 msg(
M_INFO,
"%s: set %s %s", __func__,
iface, up ?
"up" :
"down");
692 return sitnl_send(&req.n, 0, 0, NULL, NULL);
698 struct sitnl_link_req req;
699 int ifindex, ret = -1;
703 ifindex = if_nametoindex(
iface);
710 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
711 req.n.nlmsg_flags = NLM_F_REQUEST;
712 req.n.nlmsg_type = RTM_NEWLINK;
714 req.i.ifi_family = AF_PACKET;
715 req.i.ifi_index = ifindex;
717 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_MTU, &mtu, 4);
721 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
729 struct sitnl_link_req req;
730 int ifindex, ret = -1;
734 ifindex = if_nametoindex(
iface);
741 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
742 req.n.nlmsg_flags = NLM_F_REQUEST;
743 req.n.nlmsg_type = RTM_NEWLINK;
745 req.i.ifi_family = AF_PACKET;
746 req.i.ifi_index = ifindex;
752 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
758sitnl_addr_set(
int cmd, uint32_t flags,
int ifindex,
sa_family_t af_family,
761 struct sitnl_addr_req req;
767 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
768 req.n.nlmsg_type = cmd;
769 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
771 req.i.ifa_index = ifindex;
772 req.i.ifa_family = af_family;
777 size =
sizeof(
struct in_addr);
781 size =
sizeof(
struct in6_addr);
785 msg(
M_WARN,
"%s: rtnl: unknown address family %d", __func__, af_family);
792 prefixlen = size * 8;
794 req.i.ifa_prefixlen = prefixlen;
798 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_ADDRESS, remote, size);
803 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_LOCAL, local, size);
806 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
833 msg(
M_WARN,
"%s: passed NULL interface", __func__);
837 ifindex = if_nametoindex(
iface);
840 msg(
M_WARN,
"%s: cannot get ifindex for %s: %s", __func__,
np(
iface), strerror(errno));
844 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex, af_family, local,
865 msg(
M_WARN,
"%s: passed NULL interface", __func__);
869 ifindex = if_nametoindex(
iface);
876 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, local, NULL, 0);
880sitnl_route_set(
int cmd, uint32_t flags,
int ifindex,
sa_family_t af_family,
const void *dst,
881 int prefixlen,
const void *gw,
enum rt_class_t table,
int metric,
882 enum rt_scope_t scope,
int protocol,
int type)
884 struct sitnl_route_req req;
892 size =
sizeof(in_addr_t);
896 size =
sizeof(
struct in6_addr);
903 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
904 req.n.nlmsg_type = cmd;
905 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
907 req.r.rtm_family = af_family;
908 req.r.rtm_scope = scope;
909 req.r.rtm_protocol = protocol;
910 req.r.rtm_type = type;
911 req.r.rtm_dst_len = prefixlen;
915 req.r.rtm_table = table;
919 req.r.rtm_table = RT_TABLE_UNSPEC;
920 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_TABLE, &table, 4);
925 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst, size);
930 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_GATEWAY, gw, size);
935 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_OIF, &ifindex, 4);
940 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_PRIORITY, &metric, 4);
943 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
965 msg(
M_WARN,
"%s: passed NULL interface", __func__);
969 ifindex = if_nametoindex(
iface);
976 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex, af_family, addr, NULL,
997 msg(
M_WARN,
"%s: passed NULL interface", __func__);
1001 ifindex = if_nametoindex(
iface);
1008 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, addr, NULL, prefixlen);
1015 char buf[INET_ADDRSTRLEN];
1022 addr_v4.
ipv4 = htonl(*addr);
1024 msg(
M_INFO,
"%s: %s/%d dev %s", __func__, inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)),
1027 return sitnl_addr_add(AF_INET,
iface, &addr_v4, prefixlen);
1035 char buf[INET6_ADDRSTRLEN];
1042 addr_v6.
ipv6 = *addr;
1044 msg(
M_INFO,
"%s: %s/%d dev %s", __func__, inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)),
1047 return sitnl_addr_add(AF_INET6,
iface, &addr_v6, prefixlen);
1054 char buf[INET_ADDRSTRLEN];
1061 addr_v4.
ipv4 = htonl(*addr);
1063 msg(
M_INFO,
"%s: %s dev %s", __func__, inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)),
1066 return sitnl_addr_del(AF_INET,
iface, &addr_v4, prefixlen);
1074 char buf[INET6_ADDRSTRLEN];
1081 addr_v6.
ipv6 = *addr;
1083 msg(
M_INFO,
"%s: %s/%d dev %s", __func__, inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)),
1086 return sitnl_addr_del(AF_INET6,
iface, &addr_v6, prefixlen);
1091 const in_addr_t *remote)
1095 char buf1[INET_ADDRSTRLEN];
1096 char buf2[INET_ADDRSTRLEN];
1103 local_v4.
ipv4 = htonl(*local);
1107 remote_v4.
ipv4 = htonl(*remote);
1110 msg(
M_INFO,
"%s: %s peer %s dev %s", __func__,
1111 inet_ntop(AF_INET, &local_v4.
ipv4, buf1,
sizeof(buf1)),
1112 inet_ntop(AF_INET, &remote_v4.
ipv4, buf2,
sizeof(buf2)),
iface);
1114 return sitnl_addr_ptp_add(AF_INET,
iface, &local_v4, &remote_v4);
1119 const in_addr_t *remote)
1122 char buf[INET6_ADDRSTRLEN];
1130 local_v4.
ipv4 = htonl(*local);
1132 msg(
M_INFO,
"%s: %s dev %s", __func__, inet_ntop(AF_INET, &local_v4.
ipv4, buf,
sizeof(buf)),
1135 return sitnl_addr_ptp_del(AF_INET,
iface, &local_v4);
1139sitnl_route_add(
const char *
iface,
sa_family_t af_family,
const void *dst,
int prefixlen,
1140 const void *gw, uint32_t table,
int metric)
1142 enum rt_scope_t scope = RT_SCOPE_UNIVERSE;
1147 ifindex = if_nametoindex(
iface);
1157 table = RT_TABLE_MAIN;
1162 scope = RT_SCOPE_LINK;
1165 return sitnl_route_set(RTM_NEWROUTE, NLM_F_CREATE, ifindex, af_family, dst, prefixlen, gw,
1166 table, metric, scope, RTPROT_BOOT, RTN_UNICAST);
1170net_route_v4_add(
openvpn_net_ctx_t *ctx,
const in_addr_t *dst,
int prefixlen,
const in_addr_t *gw,
1171 const char *
iface, uint32_t table,
int metric)
1173 in_addr_t *dst_ptr = NULL, *gw_ptr = NULL;
1174 in_addr_t dst_be = 0, gw_be = 0;
1175 char dst_str[INET_ADDRSTRLEN];
1176 char gw_str[INET_ADDRSTRLEN];
1180 dst_be = htonl(*dst);
1190 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1191 inet_ntop(AF_INET, &dst_be, dst_str,
sizeof(dst_str)), prefixlen,
1192 inet_ntop(AF_INET, &gw_be, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1194 return sitnl_route_add(
iface, AF_INET, dst_ptr, prefixlen, gw_ptr, table, metric);
1198net_route_v6_add(
openvpn_net_ctx_t *ctx,
const struct in6_addr *dst,
int prefixlen,
1199 const struct in6_addr *gw,
const char *
iface, uint32_t table,
int metric)
1203 char dst_str[INET6_ADDRSTRLEN];
1204 char gw_str[INET6_ADDRSTRLEN];
1216 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1217 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)), prefixlen,
1218 inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1220 return sitnl_route_add(
iface, AF_INET6, dst, prefixlen, gw, table, metric);
1231 ifindex = if_nametoindex(
iface);
1241 table = RT_TABLE_MAIN;
1244 return sitnl_route_set(RTM_DELROUTE, 0, ifindex, af_family, dst, prefixlen, gw, table, metric,
1245 RT_SCOPE_NOWHERE, 0, 0);
1249net_route_v4_del(
openvpn_net_ctx_t *ctx,
const in_addr_t *dst,
int prefixlen,
const in_addr_t *gw,
1250 const char *
iface, uint32_t table,
int metric)
1254 char dst_str[INET_ADDRSTRLEN];
1255 char gw_str[INET_ADDRSTRLEN];
1259 dst_v4.
ipv4 = htonl(*dst);
1264 gw_v4.
ipv4 = htonl(*gw);
1267 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1268 inet_ntop(AF_INET, &dst_v4.
ipv4, dst_str,
sizeof(dst_str)), prefixlen,
1269 inet_ntop(AF_INET, &gw_v4.
ipv4, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1271 return sitnl_route_del(
iface, AF_INET, &dst_v4, prefixlen, &gw_v4, table, metric);
1275net_route_v6_del(
openvpn_net_ctx_t *ctx,
const struct in6_addr *dst,
int prefixlen,
1276 const struct in6_addr *gw,
const char *
iface, uint32_t table,
int metric)
1280 char dst_str[INET6_ADDRSTRLEN];
1281 char gw_str[INET6_ADDRSTRLEN];
1293 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1294 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)), prefixlen,
1295 inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
np(
iface), table, metric);
1297 return sitnl_route_del(
iface, AF_INET6, &dst_v6, prefixlen, &gw_v6, table, metric);
1304 struct sitnl_link_req req = {};
1309 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1310 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
1311 req.n.nlmsg_type = RTM_NEWLINK;
1313 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_IFNAME,
iface, strlen(
iface) + 1);
1315 struct rtattr *linkinfo = SITNL_NEST(&req.n,
sizeof(req), IFLA_LINKINFO);
1316 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_INFO_KIND, type, strlen(type) + 1);
1317#if defined(ENABLE_DCO)
1321 struct rtattr *data = SITNL_NEST(&req.n,
sizeof(req), IFLA_INFO_DATA);
1322 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_OVPN_MODE, &dco->ifmode,
sizeof(uint8_t));
1323 SITNL_NEST_END(&req.n, data);
1326 SITNL_NEST_END(&req.n, linkinfo);
1328 req.i.ifi_family = AF_PACKET;
1332 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
1338sitnl_parse_rtattr_flags(
struct rtattr *tb[],
int max,
struct rtattr *rta,
int len,
1339 unsigned short flags)
1341 unsigned short type;
1343 memset(tb, 0,
sizeof(
struct rtattr *) * (max + 1));
1345 while (RTA_OK(rta, len))
1347 type = rta->rta_type & ~flags;
1349 if ((type <= max) && (!tb[type]))
1354 rta = RTA_NEXT(rta, len);
1359 msg(
D_ROUTE,
"%s: %d bytes not parsed! (rta_len=%d)", __func__, len, rta->rta_len);
1366sitnl_parse_rtattr(
struct rtattr *tb[],
int max,
struct rtattr *rta,
int len)
1368 return sitnl_parse_rtattr_flags(tb, max, rta, len, 0);
1371#define sitnl_parse_rtattr_nested(tb, max, rta) \
1372 (sitnl_parse_rtattr_flags(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta), NLA_F_NESTED))
1375sitnl_type_save(
struct nlmsghdr *n,
void *arg)
1378 struct ifinfomsg *ifi = NLMSG_DATA(n);
1379 struct rtattr *tb[IFLA_MAX + 1];
1382 ret = sitnl_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
1388 if (tb[IFLA_LINKINFO])
1390 struct rtattr *tb_link[IFLA_INFO_MAX + 1];
1392 ret = sitnl_parse_rtattr_nested(tb_link, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
1398 if (!tb_link[IFLA_INFO_KIND])
1412 struct sitnl_link_req req = {};
1413 int ifindex = if_nametoindex(
iface);
1420 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1421 req.n.nlmsg_flags = NLM_F_REQUEST;
1422 req.n.nlmsg_type = RTM_GETLINK;
1424 req.i.ifi_family = AF_PACKET;
1425 req.i.ifi_index = ifindex;
1429 int ret = sitnl_send(&req.n, 0, 0, sitnl_type_save, type);
1432 msg(
D_ROUTE,
"%s: cannot retrieve iface %s: %s (%d)", __func__,
iface, strerror(-ret), ret);
1444 struct sitnl_link_req req = {};
1445 int ifindex = if_nametoindex(
iface);
1452 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1453 req.n.nlmsg_flags = NLM_F_REQUEST;
1454 req.n.nlmsg_type = RTM_DELLINK;
1456 req.i.ifi_family = AF_PACKET;
1457 req.i.ifi_index = ifindex;
1461 return sitnl_send(&req.n, 0, 0, NULL, NULL);
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
unsigned short sa_family_t