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);
95struct sitnl_link_req {
104struct sitnl_addr_req {
113struct sitnl_route_req {
119typedef int (*sitnl_parse_reply_cb)(
struct nlmsghdr *
msg,
void *arg);
124struct sitnl_route_data_cb {
133sitnl_addattr(
struct nlmsghdr *n,
int maxlen,
int type,
const void *data,
136 int len = RTA_LENGTH(alen);
139 if ((
int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen)
141 msg(
M_WARN,
"%s: rtnl: message exceeded bound of %d", __func__,
146 rta = sitnl_nlmsg_tail(n);
147 rta->rta_type = type;
152 memset(RTA_DATA(rta), 0, alen);
156 memcpy(RTA_DATA(rta), data, alen);
159 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
170 int sndbuf = SNDBUF_SIZE;
171 int rcvbuf = RCVBUF_SIZE;
174 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
177 msg(
M_WARN,
"%s: cannot open netlink socket", __func__);
181 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
sizeof(sndbuf)) < 0)
188 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
sizeof(rcvbuf)) < 0)
202sitnl_bind(
int fd, uint32_t groups)
205 struct sockaddr_nl local;
209 local.nl_family = AF_NETLINK;
210 local.nl_groups = groups;
212 if (bind(fd, (
struct sockaddr *)&local,
sizeof(local)) < 0)
218 addr_len =
sizeof(local);
219 if (getsockname(fd, (
struct sockaddr *)&local, &addr_len) < 0)
225 if (addr_len !=
sizeof(local))
227 msg(
M_WARN,
"%s: wrong address length %d", __func__, addr_len);
231 if (local.nl_family != AF_NETLINK)
233 msg(
M_WARN,
"%s: wrong address family %d", __func__, local.nl_family);
244sitnl_send(
struct nlmsghdr *payload, pid_t peer,
unsigned int groups,
245 sitnl_parse_reply_cb cb,
void *arg_cb)
247 int len, rem_len, fd, ret, rcv_len;
248 struct sockaddr_nl nladdr;
249 struct nlmsgerr *err;
256 .iov_len = payload->nlmsg_len,
258 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)",
339 __func__, nlmsg.msg_namelen,
sizeof(nladdr));
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);
375 if (h->nlmsg_type == NLMSG_DONE)
381 if (h->nlmsg_type == NLMSG_ERROR)
383 err = (
struct nlmsgerr *)NLMSG_DATA(h);
384 if (rem_len < (
int)
sizeof(
struct nlmsgerr))
386 msg(
M_WARN,
"%s: ERROR truncated", __func__);
396 int r = cb(h, arg_cb);
405 msg(
M_WARN,
"%s: rtnl: generic error (%d): %s",
406 __func__, err->error, strerror(-err->error));
415 int r = cb(h, arg_cb);
424 msg(
M_WARN,
"%s: RTNL: unexpected reply", __func__);
427 rcv_len -= NLMSG_ALIGN(len);
428 h = (
struct nlmsghdr *)((
char *)h + NLMSG_ALIGN(len));
431 if (nlmsg.msg_flags & MSG_TRUNC)
433 msg(
M_WARN,
"%s: message truncated", __func__);
439 msg(
M_WARN,
"%s: rtnl: %d not parsed bytes", __func__, rcv_len);
453 char iface[IFNAMSIZ];
459sitnl_route_save(
struct nlmsghdr *n,
void *arg)
461 route_res_t *res = arg;
462 struct rtmsg *r = NLMSG_DATA(n);
463 struct rtattr *rta = RTM_RTA(r);
464 int len = n->nlmsg_len - NLMSG_LENGTH(
sizeof(*r));
465 unsigned int table, ifindex = 0;
469 if (res->default_only && r->rtm_dst_len != 0)
475 table = r->rtm_table;
477 while (RTA_OK(rta, len))
479 switch (rta->rta_type)
483 ifindex = *(
unsigned int *)RTA_DATA(rta);
497 table = *(
unsigned int *)RTA_DATA(rta);
501 rta = RTA_NEXT(rta, len);
505 if (res->table && res->table != table)
510 if (!if_indextoname(ifindex, res->iface))
519 memcpy(&res->gw, gw, res->addr_size);
527 void *best_gw,
char *best_iface)
529 struct sitnl_route_req req;
539 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
540 req.n.nlmsg_type = RTM_GETROUTE;
541 req.n.nlmsg_flags = NLM_F_REQUEST;
543 req.r.rtm_family = af_family;
548 res.addr_size =
sizeof(in_addr_t);
553 if (!dst || !dst->
ipv4)
555 req.n.nlmsg_flags |= NLM_F_DUMP;
556 res.default_only =
true;
557 res.table = RT_TABLE_MAIN;
561 req.r.rtm_dst_len = 32;
566 res.addr_size =
sizeof(
struct in6_addr);
568 req.r.rtm_dst_len = 128;
576 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst, res.addr_size);
578 ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &res);
585 memcpy(best_gw, &res.gw, res.addr_size);
586 strncpy(best_iface, res.iface, IFNAMSIZ);
595 struct in6_addr *best_gw,
char *best_iface)
598 char buf[INET6_ADDRSTRLEN];
607 inet_ntop(AF_INET6, &dst_v6.
ipv6, buf,
sizeof(buf)));
609 ret = sitnl_route_best_gw(AF_INET6, &dst_v6, best_gw, best_iface);
615 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
616 inet_ntop(AF_INET6, best_gw, buf,
sizeof(buf)), best_iface);
625 in_addr_t *best_gw,
char *best_iface)
628 char buf[INET_ADDRSTRLEN];
633 dst_v4.
ipv4 = htonl(*dst);
637 inet_ntop(AF_INET, &dst_v4.
ipv4, buf,
sizeof(buf)));
639 ret = sitnl_route_best_gw(AF_INET, &dst_v4, best_gw, best_iface);
645 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
646 inet_ntop(AF_INET, best_gw, buf,
sizeof(buf)), best_iface);
649 *best_gw = ntohl(*best_gw);
659 struct sitnl_link_req req;
666 msg(
M_WARN,
"%s: passed NULL interface", __func__);
670 ifindex = if_nametoindex(
iface);
673 msg(
M_WARN,
"%s: rtnl: cannot get ifindex for %s: %s", __func__,
iface,
678 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
679 req.n.nlmsg_flags = NLM_F_REQUEST;
680 req.n.nlmsg_type = RTM_NEWLINK;
682 req.i.ifi_family = AF_PACKET;
683 req.i.ifi_index = ifindex;
684 req.i.ifi_change |= IFF_UP;
687 req.i.ifi_flags |= IFF_UP;
691 req.i.ifi_flags &= ~IFF_UP;
694 msg(
M_INFO,
"%s: set %s %s", __func__,
iface, up ?
"up" :
"down");
696 return sitnl_send(&req.n, 0, 0, NULL, NULL);
703 struct sitnl_link_req req;
704 int ifindex, ret = -1;
708 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);
736 struct sitnl_link_req req;
737 int ifindex, ret = -1;
741 ifindex = if_nametoindex(
iface);
749 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
750 req.n.nlmsg_flags = NLM_F_REQUEST;
751 req.n.nlmsg_type = RTM_NEWLINK;
753 req.i.ifi_family = AF_PACKET;
754 req.i.ifi_index = ifindex;
761 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
767sitnl_addr_set(
int cmd, uint32_t flags,
int ifindex,
sa_family_t af_family,
771 struct sitnl_addr_req req;
777 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
778 req.n.nlmsg_type = cmd;
779 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
781 req.i.ifa_index = ifindex;
782 req.i.ifa_family = af_family;
787 size =
sizeof(
struct in_addr);
791 size =
sizeof(
struct in6_addr);
795 msg(
M_WARN,
"%s: rtnl: unknown address family %d", __func__,
803 prefixlen = size * 8;
805 req.i.ifa_prefixlen = prefixlen;
809 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_ADDRESS, remote, size);
814 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_LOCAL, local, size);
817 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
845 msg(
M_WARN,
"%s: passed NULL interface", __func__);
849 ifindex = if_nametoindex(
iface);
857 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex,
858 af_family, local, remote, 0);
879 msg(
M_WARN,
"%s: passed NULL interface", __func__);
883 ifindex = if_nametoindex(
iface);
890 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, local, NULL, 0);
894sitnl_route_set(
int cmd, uint32_t flags,
int ifindex,
sa_family_t af_family,
895 const void *dst,
int prefixlen,
896 const void *gw,
enum rt_class_t table,
int metric,
897 enum rt_scope_t scope,
int protocol,
int type)
899 struct sitnl_route_req req;
907 size =
sizeof(in_addr_t);
911 size =
sizeof(
struct in6_addr);
918 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
919 req.n.nlmsg_type = cmd;
920 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
922 req.r.rtm_family = af_family;
923 req.r.rtm_scope = scope;
924 req.r.rtm_protocol = protocol;
925 req.r.rtm_type = type;
926 req.r.rtm_dst_len = prefixlen;
930 req.r.rtm_table = table;
934 req.r.rtm_table = RT_TABLE_UNSPEC;
935 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_TABLE, &table, 4);
940 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst, size);
945 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_GATEWAY, gw, size);
950 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_OIF, &ifindex, 4);
955 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_PRIORITY, &metric, 4);
958 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
981 msg(
M_WARN,
"%s: passed NULL interface", __func__);
985 ifindex = if_nametoindex(
iface);
993 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex,
994 af_family, addr, NULL, prefixlen);
1015 msg(
M_WARN,
"%s: passed NULL interface", __func__);
1019 ifindex = if_nametoindex(
iface);
1027 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, addr, NULL,
1033 const in_addr_t *addr,
int prefixlen)
1036 char buf[INET_ADDRSTRLEN];
1043 addr_v4.
ipv4 = htonl(*addr);
1045 msg(
M_INFO,
"%s: %s/%d dev %s", __func__,
1046 inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)), prefixlen,
iface);
1048 return sitnl_addr_add(AF_INET,
iface, &addr_v4, prefixlen);
1053 const struct in6_addr *addr,
int prefixlen)
1056 char buf[INET6_ADDRSTRLEN];
1063 addr_v6.
ipv6 = *addr;
1065 msg(
M_INFO,
"%s: %s/%d dev %s", __func__,
1066 inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)), prefixlen,
iface);
1068 return sitnl_addr_add(AF_INET6,
iface, &addr_v6, prefixlen);
1073 const in_addr_t *addr,
int prefixlen)
1076 char buf[INET_ADDRSTRLEN];
1083 addr_v4.
ipv4 = htonl(*addr);
1086 inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)),
iface);
1088 return sitnl_addr_del(AF_INET,
iface, &addr_v4, prefixlen);
1093 const struct in6_addr *addr,
int prefixlen)
1096 char buf[INET6_ADDRSTRLEN];
1103 addr_v6.
ipv6 = *addr;
1105 msg(
M_INFO,
"%s: %s/%d dev %s", __func__,
1106 inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)), prefixlen,
iface);
1108 return sitnl_addr_del(AF_INET6,
iface, &addr_v6, prefixlen);
1113 const in_addr_t *local,
const in_addr_t *remote)
1117 char buf1[INET_ADDRSTRLEN];
1118 char buf2[INET_ADDRSTRLEN];
1125 local_v4.
ipv4 = htonl(*local);
1129 remote_v4.
ipv4 = htonl(*remote);
1132 msg(
M_INFO,
"%s: %s peer %s dev %s", __func__,
1133 inet_ntop(AF_INET, &local_v4.
ipv4, buf1,
sizeof(buf1)),
1134 inet_ntop(AF_INET, &remote_v4.
ipv4, buf2,
sizeof(buf2)),
iface);
1136 return sitnl_addr_ptp_add(AF_INET,
iface, &local_v4, &remote_v4);
1141 const in_addr_t *local,
const in_addr_t *remote)
1144 char buf[INET6_ADDRSTRLEN];
1152 local_v4.
ipv4 = htonl(*local);
1155 inet_ntop(AF_INET, &local_v4.
ipv4, buf,
sizeof(buf)),
iface);
1157 return sitnl_addr_ptp_del(AF_INET,
iface, &local_v4);
1162 int prefixlen,
const void *gw, uint32_t table,
int metric)
1164 enum rt_scope_t scope = RT_SCOPE_UNIVERSE;
1169 ifindex = if_nametoindex(
iface);
1180 table = RT_TABLE_MAIN;
1185 scope = RT_SCOPE_LINK;
1188 return sitnl_route_set(RTM_NEWROUTE, NLM_F_CREATE, ifindex,
1189 af_family, dst, prefixlen, gw, table, metric, scope,
1190 RTPROT_BOOT, RTN_UNICAST);
1195 const in_addr_t *gw,
const char *
iface,
1196 uint32_t table,
int metric)
1198 in_addr_t *dst_ptr = NULL, *gw_ptr = NULL;
1199 in_addr_t dst_be = 0, gw_be = 0;
1200 char dst_str[INET_ADDRSTRLEN];
1201 char gw_str[INET_ADDRSTRLEN];
1205 dst_be = htonl(*dst);
1215 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1216 inet_ntop(AF_INET, &dst_be, dst_str,
sizeof(dst_str)),
1217 prefixlen, inet_ntop(AF_INET, &gw_be, gw_str,
sizeof(gw_str)),
1220 return sitnl_route_add(
iface, AF_INET, dst_ptr, prefixlen, gw_ptr, table,
1226 int prefixlen,
const struct in6_addr *gw,
1227 const char *
iface, uint32_t table,
int metric)
1231 char dst_str[INET6_ADDRSTRLEN];
1232 char gw_str[INET6_ADDRSTRLEN];
1244 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1245 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)),
1246 prefixlen, inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
1249 return sitnl_route_add(
iface, AF_INET6, dst, prefixlen, gw, table,
1262 ifindex = if_nametoindex(
iface);
1273 table = RT_TABLE_MAIN;
1276 return sitnl_route_set(RTM_DELROUTE, 0, ifindex, af_family, dst, prefixlen,
1277 gw, table, metric, RT_SCOPE_NOWHERE, 0, 0);
1282 const in_addr_t *gw,
const char *
iface, uint32_t table,
1287 char dst_str[INET_ADDRSTRLEN];
1288 char gw_str[INET_ADDRSTRLEN];
1292 dst_v4.
ipv4 = htonl(*dst);
1297 gw_v4.
ipv4 = htonl(*gw);
1300 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1301 inet_ntop(AF_INET, &dst_v4.
ipv4, dst_str,
sizeof(dst_str)),
1302 prefixlen, inet_ntop(AF_INET, &gw_v4.
ipv4, gw_str,
sizeof(gw_str)),
1305 return sitnl_route_del(
iface, AF_INET, &dst_v4, prefixlen, &gw_v4, table,
1311 int prefixlen,
const struct in6_addr *gw,
1312 const char *
iface, uint32_t table,
int metric)
1316 char dst_str[INET6_ADDRSTRLEN];
1317 char gw_str[INET6_ADDRSTRLEN];
1329 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1330 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)),
1331 prefixlen, inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
1334 return sitnl_route_del(
iface, AF_INET6, &dst_v6, prefixlen, &gw_v6,
1343 struct sitnl_link_req req = { };
1348 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1349 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
1350 req.n.nlmsg_type = RTM_NEWLINK;
1352 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_IFNAME,
iface, strlen(
iface) + 1);
1354 struct rtattr *linkinfo = SITNL_NEST(&req.n,
sizeof(req), IFLA_LINKINFO);
1355 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_INFO_KIND, type, strlen(type) + 1);
1356#if defined(ENABLE_DCO)
1357 if (arg && (strcmp(type,
"ovpn-dco") == 0))
1360 struct rtattr *data = SITNL_NEST(&req.n,
sizeof(req), IFLA_INFO_DATA);
1363 SITNL_NEST_END(&req.n, data);
1366 SITNL_NEST_END(&req.n, linkinfo);
1368 req.i.ifi_family = AF_PACKET;
1372 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
1378sitnl_parse_rtattr_flags(
struct rtattr *tb[],
int max,
struct rtattr *rta,
1379 int len,
unsigned short flags)
1381 unsigned short type;
1383 memset(tb, 0,
sizeof(
struct rtattr *) * (max + 1));
1385 while (RTA_OK(rta, len))
1387 type = rta->rta_type & ~flags;
1389 if ((type <= max) && (!tb[type]))
1394 rta = RTA_NEXT(rta, len);
1399 msg(
D_ROUTE,
"%s: %d bytes not parsed! (rta_len=%d)", __func__, len,
1407sitnl_parse_rtattr(
struct rtattr *tb[],
int max,
struct rtattr *rta,
int len)
1409 return sitnl_parse_rtattr_flags(tb, max, rta, len, 0);
1412#define sitnl_parse_rtattr_nested(tb, max, rta) \
1413 (sitnl_parse_rtattr_flags(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta), \
1417sitnl_type_save(
struct nlmsghdr *n,
void *arg)
1420 struct ifinfomsg *ifi = NLMSG_DATA(n);
1421 struct rtattr *tb[IFLA_MAX + 1];
1424 ret = sitnl_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
1430 if (tb[IFLA_LINKINFO])
1432 struct rtattr *tb_link[IFLA_INFO_MAX + 1];
1434 ret = sitnl_parse_rtattr_nested(tb_link, IFLA_INFO_MAX,
1441 if (!tb_link[IFLA_INFO_KIND])
1456 struct sitnl_link_req req = { };
1457 int ifindex = if_nametoindex(
iface);
1464 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1465 req.n.nlmsg_flags = NLM_F_REQUEST;
1466 req.n.nlmsg_type = RTM_GETLINK;
1468 req.i.ifi_family = AF_PACKET;
1469 req.i.ifi_index = ifindex;
1473 int ret = sitnl_send(&req.n, 0, 0, sitnl_type_save, type);
1476 msg(
D_ROUTE,
"%s: cannot retrieve iface %s: %s (%d)", __func__,
iface,
1477 strerror(-ret), ret);
1489 struct sitnl_link_req req = { };
1490 int ifindex = if_nametoindex(
iface);
1497 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1498 req.n.nlmsg_flags = NLM_F_REQUEST;
1499 req.n.nlmsg_type = RTM_DELLINK;
1501 req.i.ifi_family = AF_PACKET;
1502 req.i.ifi_index = ifindex;
1506 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