OpenVPN
networking_sitnl.c
Go to the documentation of this file.
1/*
2 * Simplified Interface To NetLink
3 *
4 * Copyright (C) 2016-2025 Antonio Quartulli <a@unstable.cc>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program (see the file COPYING included with this
17 * distribution); if not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#ifdef TARGET_LINUX
25
26#include "syshead.h"
27
28#include "dco.h"
29#include "errlevel.h"
30#include "buffer.h"
31#include "misc.h"
32#include "networking.h"
33#include "proto.h"
34
35#include <errno.h>
36#include <string.h>
37#include <unistd.h>
38#include <sys/types.h>
39#include <sys/socket.h>
40#include <linux/netlink.h>
41#include <linux/rtnetlink.h>
42
43#define SNDBUF_SIZE (1024 * 2)
44#define RCVBUF_SIZE (1024 * 4)
45
46#define SITNL_ADDATTR(_msg, _max_size, _attr, _data, _size) \
47 { \
48 if (sitnl_addattr(_msg, _max_size, _attr, _data, _size) < 0) \
49 { \
50 goto err; \
51 } \
52 }
53
54#define SITNL_NEST(_msg, _max_size, _attr) \
55 ({ \
56 struct rtattr *_nest = sitnl_nlmsg_tail(_msg); \
57 SITNL_ADDATTR(_msg, _max_size, _attr, NULL, 0); \
58 _nest; \
59 })
60
61#define SITNL_NEST_END(_msg, _nest) \
62 { \
63 _nest->rta_len = (void *)sitnl_nlmsg_tail(_msg) - (void *)_nest; \
64 }
65
66/* This function was originally implemented as a macro, but compiling with
67 * gcc and -O3 was getting confused about the math and thus raising
68 * security warnings on subsequent memcpy() calls.
69 *
70 * Converting the macro to a function was not enough, because gcc was still
71 * inlining it and falling in the same math trap.
72 *
73 * The only way out to avoid any warning/error is to force the function to
74 * not be inline'd.
75 */
76static __attribute__((noinline)) void *
77sitnl_nlmsg_tail(const struct nlmsghdr *nlh)
78{
79 return (unsigned char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len);
80}
81
86typedef union
87{
88 in_addr_t ipv4;
89 struct in6_addr ipv6;
91
95struct sitnl_link_req
96{
97 struct nlmsghdr n;
98 struct ifinfomsg i;
99 char buf[256];
100};
101
105struct sitnl_addr_req
106{
107 struct nlmsghdr n;
108 struct ifaddrmsg i;
109 char buf[256];
110};
111
115struct sitnl_route_req
116{
117 struct nlmsghdr n;
118 struct rtmsg r;
119 char buf[256];
120};
121
122typedef int (*sitnl_parse_reply_cb)(struct nlmsghdr *msg, void *arg);
123
127struct sitnl_route_data_cb
128{
129 unsigned int iface;
131};
132
136static int
137sitnl_addattr(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen)
138{
139 int len = RTA_LENGTH(alen);
140 struct rtattr *rta;
141
142 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen)
143 {
144 msg(M_WARN, "%s: rtnl: message exceeded bound of %d", __func__, maxlen);
145 return -EMSGSIZE;
146 }
147
148 rta = sitnl_nlmsg_tail(n);
149 rta->rta_type = type;
150 rta->rta_len = len;
151
152 if (!data)
153 {
154 memset(RTA_DATA(rta), 0, alen);
155 }
156 else
157 {
158 memcpy(RTA_DATA(rta), data, alen);
159 }
160
161 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
162
163 return 0;
164}
165
169static int
170sitnl_socket(void)
171{
172 int sndbuf = SNDBUF_SIZE;
173 int rcvbuf = RCVBUF_SIZE;
174 int fd;
175
176 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
177 if (fd < 0)
178 {
179 msg(M_WARN, "%s: cannot open netlink socket", __func__);
180 return fd;
181 }
182
183 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0)
184 {
185 msg(M_WARN | M_ERRNO, "%s: SO_SNDBUF", __func__);
186 close(fd);
187 return -1;
188 }
189
190 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0)
191 {
192 msg(M_WARN | M_ERRNO, "%s: SO_RCVBUF", __func__);
193 close(fd);
194 return -1;
195 }
196
197 return fd;
198}
199
203static int
204sitnl_bind(int fd, uint32_t groups)
205{
206 socklen_t addr_len;
207 struct sockaddr_nl local;
208
209 CLEAR(local);
210
211 local.nl_family = AF_NETLINK;
212 local.nl_groups = groups;
213
214 if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0)
215 {
216 msg(M_WARN | M_ERRNO, "%s: cannot bind netlink socket", __func__);
217 return -errno;
218 }
219
220 addr_len = sizeof(local);
221 if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0)
222 {
223 msg(M_WARN | M_ERRNO, "%s: cannot getsockname", __func__);
224 return -errno;
225 }
226
227 if (addr_len != sizeof(local))
228 {
229 msg(M_WARN, "%s: wrong address length %d", __func__, addr_len);
230 return -EINVAL;
231 }
232
233 if (local.nl_family != AF_NETLINK)
234 {
235 msg(M_WARN, "%s: wrong address family %d", __func__, local.nl_family);
236 return -EINVAL;
237 }
238
239 return 0;
240}
241
245static int
246sitnl_send(struct nlmsghdr *payload, pid_t peer, unsigned int groups, sitnl_parse_reply_cb cb,
247 void *arg_cb)
248{
249 int len, rem_len, fd, ret, rcv_len;
250 struct sockaddr_nl nladdr;
251 struct nlmsgerr *err;
252 struct nlmsghdr *h;
253 unsigned int seq;
254 char buf[1024 * 16];
255 struct iovec iov = {
256 .iov_base = payload,
257 .iov_len = payload->nlmsg_len,
258 };
259 struct msghdr nlmsg = {
260 .msg_name = &nladdr,
261 .msg_namelen = sizeof(nladdr),
262 .msg_iov = &iov,
263 .msg_iovlen = 1,
264 };
265
266 CLEAR(nladdr);
267
268 nladdr.nl_family = AF_NETLINK;
269 nladdr.nl_pid = peer;
270 nladdr.nl_groups = groups;
271
272 payload->nlmsg_seq = seq = time(NULL);
273
274 /* no need to send reply */
275 if (!cb)
276 {
277 payload->nlmsg_flags |= NLM_F_ACK;
278 }
279
280 fd = sitnl_socket();
281 if (fd < 0)
282 {
283 msg(M_WARN | M_ERRNO, "%s: can't open rtnl socket", __func__);
284 return -errno;
285 }
286
287 ret = sitnl_bind(fd, 0);
288 if (ret < 0)
289 {
290 msg(M_WARN | M_ERRNO, "%s: can't bind rtnl socket", __func__);
291 ret = -errno;
292 goto out;
293 }
294
295 ret = sendmsg(fd, &nlmsg, 0);
296 if (ret < 0)
297 {
298 msg(M_WARN | M_ERRNO, "%s: rtnl: error on sendmsg()", __func__);
299 ret = -errno;
300 goto out;
301 }
302
303 /* prepare buffer to store RTNL replies */
304 memset(buf, 0, sizeof(buf));
305 iov.iov_base = buf;
306
307 while (1)
308 {
309 /*
310 * iov_len is modified by recvmsg(), therefore has to be initialized before
311 * using it again
312 */
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);
317 if (rcv_len < 0)
318 {
319 if ((errno == EINTR) || (errno == EAGAIN))
320 {
321 msg(D_RTNL, "%s: interrupted call", __func__);
322 continue;
323 }
324 msg(M_WARN | M_ERRNO, "%s: rtnl: error on recvmsg()", __func__);
325 ret = -errno;
326 goto out;
327 }
328
329 if (rcv_len == 0)
330 {
331 msg(M_WARN, "%s: rtnl: socket reached unexpected EOF", __func__);
332 ret = -EIO;
333 goto out;
334 }
335
336 if (nlmsg.msg_namelen != sizeof(nladdr))
337 {
338 msg(M_WARN, "%s: sender address length: %u (expected %zu)", __func__, nlmsg.msg_namelen,
339 sizeof(nladdr));
340 ret = -EIO;
341 goto out;
342 }
343
344 h = (struct nlmsghdr *)buf;
345 while (rcv_len >= (int)sizeof(*h))
346 {
347 len = h->nlmsg_len;
348 rem_len = len - sizeof(*h);
349
350 if ((rem_len < 0) || (len > rcv_len))
351 {
352 if (nlmsg.msg_flags & MSG_TRUNC)
353 {
354 msg(M_WARN, "%s: truncated message", __func__);
355 ret = -EIO;
356 goto out;
357 }
358 msg(M_WARN, "%s: malformed message: len=%d", __func__, len);
359 ret = -EIO;
360 goto out;
361 }
362
363 /* if (((int)nladdr.nl_pid != peer) || (h->nlmsg_pid != nladdr.nl_pid)
364 * || (h->nlmsg_seq != seq))
365 * {
366 * rcv_len -= NLMSG_ALIGN(len);
367 * h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
368 * msg(M_DEBUG, "%s: skipping unrelated message. nl_pid:%d (peer:%d)
369 * nl_msg_pid:%d nl_seq:%d seq:%d",
370 * __func__, (int)nladdr.nl_pid, peer, h->nlmsg_pid,
371 * h->nlmsg_seq, seq);
372 * continue;
373 * }
374 */
375
376 if (h->nlmsg_type == NLMSG_DONE)
377 {
378 ret = 0;
379 goto out;
380 }
381
382 if (h->nlmsg_type == NLMSG_ERROR)
383 {
384 err = (struct nlmsgerr *)NLMSG_DATA(h);
385 if (rem_len < (int)sizeof(struct nlmsgerr))
386 {
387 msg(M_WARN, "%s: ERROR truncated", __func__);
388 ret = -EIO;
389 }
390 else
391 {
392 if (!err->error)
393 {
394 ret = 0;
395 if (cb)
396 {
397 int r = cb(h, arg_cb);
398 if (r <= 0)
399 {
400 ret = r;
401 }
402 }
403 }
404 else
405 {
406 msg(M_WARN, "%s: rtnl: generic error (%d): %s", __func__, err->error,
407 strerror(-err->error));
408 ret = err->error;
409 }
410 }
411 goto out;
412 }
413
414 if (cb)
415 {
416 int r = cb(h, arg_cb);
417 if (r <= 0)
418 {
419 ret = r;
420 goto out;
421 }
422 }
423 else
424 {
425 msg(M_WARN, "%s: RTNL: unexpected reply", __func__);
426 }
427
428 rcv_len -= NLMSG_ALIGN(len);
429 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
430 }
431
432 if (nlmsg.msg_flags & MSG_TRUNC)
433 {
434 msg(M_WARN, "%s: message truncated", __func__);
435 continue;
436 }
437
438 if (rcv_len)
439 {
440 msg(M_WARN, "%s: rtnl: %d not parsed bytes", __func__, rcv_len);
441 ret = -1;
442 goto out;
443 }
444 }
445out:
446 close(fd);
447
448 return ret;
449}
450
451typedef struct
452{
453 int addr_size;
455 char iface[IFNAMSIZ];
456 bool default_only;
457 unsigned int table;
458} route_res_t;
459
460static int
461sitnl_route_save(struct nlmsghdr *n, void *arg)
462{
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;
468 void *gw = NULL;
469
470 /* filter-out non-zero dst prefixes */
471 if (res->default_only && r->rtm_dst_len != 0)
472 {
473 return 1;
474 }
475
476 /* route table, ignored with RTA_TABLE */
477 table = r->rtm_table;
478
479 while (RTA_OK(rta, len))
480 {
481 switch (rta->rta_type)
482 {
483 /* route interface */
484 case RTA_OIF:
485 ifindex = *(unsigned int *)RTA_DATA(rta);
486 break;
487
488 /* route prefix */
489 case RTA_DST:
490 break;
491
492 /* GW for the route */
493 case RTA_GATEWAY:
494 gw = RTA_DATA(rta);
495 break;
496
497 /* route table */
498 case RTA_TABLE:
499 table = *(unsigned int *)RTA_DATA(rta);
500 break;
501 }
502
503 rta = RTA_NEXT(rta, len);
504 }
505
506 /* filter out any route not coming from the selected table */
507 if (res->table && res->table != table)
508 {
509 return 1;
510 }
511
512 if (!if_indextoname(ifindex, res->iface))
513 {
514 msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifname for index %d", __func__, ifindex);
515 return -1;
516 }
517
518 if (gw)
519 {
520 memcpy(&res->gw, gw, res->addr_size);
521 }
522
523 return 0;
524}
525
526static int
527sitnl_route_best_gw(sa_family_t af_family, const inet_address_t *dst, void *best_gw,
528 char *best_iface)
529{
530 struct sitnl_route_req req;
531 route_res_t res;
532 int ret = -EINVAL;
533
534 ASSERT(best_gw);
535 ASSERT(best_iface);
536
537 CLEAR(req);
538 CLEAR(res);
539
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;
543
544 req.r.rtm_family = af_family;
545
546 switch (af_family)
547 {
548 case AF_INET:
549 res.addr_size = sizeof(in_addr_t);
550 /*
551 * kernel can't return 0.0.0.0/8 host route, dump all
552 * the routes and filter for 0.0.0.0/0 in cb()
553 */
554 if (!dst || !dst->ipv4)
555 {
556 req.n.nlmsg_flags |= NLM_F_DUMP;
557 res.default_only = true;
558 res.table = RT_TABLE_MAIN;
559 }
560 else
561 {
562 req.r.rtm_dst_len = 32;
563 }
564 break;
565
566 case AF_INET6:
567 res.addr_size = sizeof(struct in6_addr);
568 /* kernel can return ::/128 host route */
569 req.r.rtm_dst_len = 128;
570 break;
571
572 default:
573 /* unsupported */
574 return -EINVAL;
575 }
576
577 SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, dst, res.addr_size);
578
579 ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &res);
580 if (ret < 0)
581 {
582 goto err;
583 }
584
585 /* save result in output variables */
586 memcpy(best_gw, &res.gw, res.addr_size);
587 strncpy(best_iface, res.iface, IFNAMSIZ);
588err:
589 return ret;
590}
591
592/* used by iproute2 implementation too */
593int
594net_route_v6_best_gw(openvpn_net_ctx_t *ctx, const struct in6_addr *dst, struct in6_addr *best_gw,
595 char *best_iface)
596{
597 inet_address_t dst_v6 = { 0 };
598 char buf[INET6_ADDRSTRLEN];
599 int ret;
600
601 if (dst)
602 {
603 dst_v6.ipv6 = *dst;
604 }
605
606 msg(D_ROUTE, "%s query: dst %s", __func__, inet_ntop(AF_INET6, &dst_v6.ipv6, buf, sizeof(buf)));
607
608 ret = sitnl_route_best_gw(AF_INET6, &dst_v6, best_gw, best_iface);
609 if (ret < 0)
610 {
611 return ret;
612 }
613
614 msg(D_ROUTE, "%s result: via %s dev %s", __func__,
615 inet_ntop(AF_INET6, best_gw, buf, sizeof(buf)), best_iface);
616
617 return ret;
618}
619
620/* used by iproute2 implementation too */
621int
622net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst, in_addr_t *best_gw,
623 char *best_iface)
624{
625 inet_address_t dst_v4 = { 0 };
626 char buf[INET_ADDRSTRLEN];
627 int ret;
628
629 if (dst)
630 {
631 dst_v4.ipv4 = htonl(*dst);
632 }
633
634 msg(D_ROUTE, "%s query: dst %s", __func__, inet_ntop(AF_INET, &dst_v4.ipv4, buf, sizeof(buf)));
635
636 ret = sitnl_route_best_gw(AF_INET, &dst_v4, best_gw, best_iface);
637 if (ret < 0)
638 {
639 return ret;
640 }
641
642 msg(D_ROUTE, "%s result: via %s dev %s", __func__,
643 inet_ntop(AF_INET, best_gw, buf, sizeof(buf)), best_iface);
644
645 /* result is expected in Host Order */
646 *best_gw = ntohl(*best_gw);
647
648 return ret;
649}
650
651#ifdef ENABLE_SITNL
652
653int
654net_iface_up(openvpn_net_ctx_t *ctx, const char *iface, bool up)
655{
656 struct sitnl_link_req req;
657 int ifindex;
658
659 CLEAR(req);
660
661 if (!iface)
662 {
663 msg(M_WARN, "%s: passed NULL interface", __func__);
664 return -EINVAL;
665 }
666
667 ifindex = if_nametoindex(iface);
668 if (ifindex == 0)
669 {
670 msg(M_WARN, "%s: rtnl: cannot get ifindex for %s: %s", __func__, iface, strerror(errno));
671 return -ENOENT;
672 }
673
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;
677
678 req.i.ifi_family = AF_PACKET;
679 req.i.ifi_index = ifindex;
680 req.i.ifi_change |= IFF_UP;
681 if (up)
682 {
683 req.i.ifi_flags |= IFF_UP;
684 }
685 else
686 {
687 req.i.ifi_flags &= ~IFF_UP;
688 }
689
690 msg(M_INFO, "%s: set %s %s", __func__, iface, up ? "up" : "down");
691
692 return sitnl_send(&req.n, 0, 0, NULL, NULL);
693}
694
695int
696net_iface_mtu_set(openvpn_net_ctx_t *ctx, const char *iface, uint32_t mtu)
697{
698 struct sitnl_link_req req;
699 int ifindex, ret = -1;
700
701 CLEAR(req);
702
703 ifindex = if_nametoindex(iface);
704 if (ifindex == 0)
705 {
706 msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__, iface);
707 return -1;
708 }
709
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;
713
714 req.i.ifi_family = AF_PACKET;
715 req.i.ifi_index = ifindex;
716
717 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_MTU, &mtu, 4);
718
719 msg(M_INFO, "%s: mtu %u for %s", __func__, mtu, iface);
720
721 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
722err:
723 return ret;
724}
725
726int
727net_addr_ll_set(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface, uint8_t *addr)
728{
729 struct sitnl_link_req req;
730 int ifindex, ret = -1;
731
732 CLEAR(req);
733
734 ifindex = if_nametoindex(iface);
735 if (ifindex == 0)
736 {
737 msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__, iface);
738 return -1;
739 }
740
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;
744
745 req.i.ifi_family = AF_PACKET;
746 req.i.ifi_index = ifindex;
747
748 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_ADDRESS, addr, OPENVPN_ETH_ALEN);
749
750 msg(M_INFO, "%s: lladdr " MAC_FMT " for %s", __func__, MAC_PRINT_ARG(addr), iface);
751
752 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
753err:
754 return ret;
755}
756
757static int
758sitnl_addr_set(int cmd, uint32_t flags, int ifindex, sa_family_t af_family,
759 const inet_address_t *local, const inet_address_t *remote, int prefixlen)
760{
761 struct sitnl_addr_req req;
762 uint32_t size;
763 int ret = -EINVAL;
764
765 CLEAR(req);
766
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;
770
771 req.i.ifa_index = ifindex;
772 req.i.ifa_family = af_family;
773
774 switch (af_family)
775 {
776 case AF_INET:
777 size = sizeof(struct in_addr);
778 break;
779
780 case AF_INET6:
781 size = sizeof(struct in6_addr);
782 break;
783
784 default:
785 msg(M_WARN, "%s: rtnl: unknown address family %d", __func__, af_family);
786 return -EINVAL;
787 }
788
789 /* if no prefixlen has been specified, assume host address */
790 if (prefixlen == 0)
791 {
792 prefixlen = size * 8;
793 }
794 req.i.ifa_prefixlen = prefixlen;
795
796 if (remote)
797 {
798 SITNL_ADDATTR(&req.n, sizeof(req), IFA_ADDRESS, remote, size);
799 }
800
801 if (local)
802 {
803 SITNL_ADDATTR(&req.n, sizeof(req), IFA_LOCAL, local, size);
804 }
805
806 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
807 if (ret == -EEXIST)
808 {
809 ret = 0;
810 }
811err:
812 return ret;
813}
814
815static int
816sitnl_addr_ptp_add(sa_family_t af_family, const char *iface, const inet_address_t *local,
817 const inet_address_t *remote)
818{
819 int ifindex;
820
821 switch (af_family)
822 {
823 case AF_INET:
824 case AF_INET6:
825 break;
826
827 default:
828 return -EINVAL;
829 }
830
831 if (!iface)
832 {
833 msg(M_WARN, "%s: passed NULL interface", __func__);
834 return -EINVAL;
835 }
836
837 ifindex = if_nametoindex(iface);
838 if (ifindex == 0)
839 {
840 msg(M_WARN, "%s: cannot get ifindex for %s: %s", __func__, np(iface), strerror(errno));
841 return -ENOENT;
842 }
843
844 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex, af_family, local,
845 remote, 0);
846}
847
848static int
849sitnl_addr_ptp_del(sa_family_t af_family, const char *iface, const inet_address_t *local)
850{
851 int ifindex;
852
853 switch (af_family)
854 {
855 case AF_INET:
856 case AF_INET6:
857 break;
858
859 default:
860 return -EINVAL;
861 }
862
863 if (!iface)
864 {
865 msg(M_WARN, "%s: passed NULL interface", __func__);
866 return -EINVAL;
867 }
868
869 ifindex = if_nametoindex(iface);
870 if (ifindex == 0)
871 {
872 msg(M_WARN | M_ERRNO, "%s: cannot get ifindex for %s", __func__, iface);
873 return -ENOENT;
874 }
875
876 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, local, NULL, 0);
877}
878
879static int
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)
883{
884 struct sitnl_route_req req;
885 int ret = -1, size;
886
887 CLEAR(req);
888
889 switch (af_family)
890 {
891 case AF_INET:
892 size = sizeof(in_addr_t);
893 break;
894
895 case AF_INET6:
896 size = sizeof(struct in6_addr);
897 break;
898
899 default:
900 return -EINVAL;
901 }
902
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;
906
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;
912
913 if (table < 256)
914 {
915 req.r.rtm_table = table;
916 }
917 else
918 {
919 req.r.rtm_table = RT_TABLE_UNSPEC;
920 SITNL_ADDATTR(&req.n, sizeof(req), RTA_TABLE, &table, 4);
921 }
922
923 if (dst)
924 {
925 SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, dst, size);
926 }
927
928 if (gw)
929 {
930 SITNL_ADDATTR(&req.n, sizeof(req), RTA_GATEWAY, gw, size);
931 }
932
933 if (ifindex > 0)
934 {
935 SITNL_ADDATTR(&req.n, sizeof(req), RTA_OIF, &ifindex, 4);
936 }
937
938 if (metric > 0)
939 {
940 SITNL_ADDATTR(&req.n, sizeof(req), RTA_PRIORITY, &metric, 4);
941 }
942
943 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
944err:
945 return ret;
946}
947
948static int
949sitnl_addr_add(sa_family_t af_family, const char *iface, const inet_address_t *addr, int prefixlen)
950{
951 int ifindex;
952
953 switch (af_family)
954 {
955 case AF_INET:
956 case AF_INET6:
957 break;
958
959 default:
960 return -EINVAL;
961 }
962
963 if (!iface)
964 {
965 msg(M_WARN, "%s: passed NULL interface", __func__);
966 return -EINVAL;
967 }
968
969 ifindex = if_nametoindex(iface);
970 if (ifindex == 0)
971 {
972 msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__, iface);
973 return -ENOENT;
974 }
975
976 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex, af_family, addr, NULL,
977 prefixlen);
978}
979
980static int
981sitnl_addr_del(sa_family_t af_family, const char *iface, inet_address_t *addr, int prefixlen)
982{
983 int ifindex;
984
985 switch (af_family)
986 {
987 case AF_INET:
988 case AF_INET6:
989 break;
990
991 default:
992 return -EINVAL;
993 }
994
995 if (!iface)
996 {
997 msg(M_WARN, "%s: passed NULL interface", __func__);
998 return -EINVAL;
999 }
1000
1001 ifindex = if_nametoindex(iface);
1002 if (ifindex == 0)
1003 {
1004 msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__, iface);
1005 return -ENOENT;
1006 }
1007
1008 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, addr, NULL, prefixlen);
1009}
1010
1011int
1012net_addr_v4_add(openvpn_net_ctx_t *ctx, const char *iface, const in_addr_t *addr, int prefixlen)
1013{
1014 inet_address_t addr_v4 = { 0 };
1015 char buf[INET_ADDRSTRLEN];
1016
1017 if (!addr)
1018 {
1019 return -EINVAL;
1020 }
1021
1022 addr_v4.ipv4 = htonl(*addr);
1023
1024 msg(M_INFO, "%s: %s/%d dev %s", __func__, inet_ntop(AF_INET, &addr_v4.ipv4, buf, sizeof(buf)),
1025 prefixlen, iface);
1026
1027 return sitnl_addr_add(AF_INET, iface, &addr_v4, prefixlen);
1028}
1029
1030int
1031net_addr_v6_add(openvpn_net_ctx_t *ctx, const char *iface, const struct in6_addr *addr,
1032 int prefixlen)
1033{
1034 inet_address_t addr_v6 = { 0 };
1035 char buf[INET6_ADDRSTRLEN];
1036
1037 if (!addr)
1038 {
1039 return -EINVAL;
1040 }
1041
1042 addr_v6.ipv6 = *addr;
1043
1044 msg(M_INFO, "%s: %s/%d dev %s", __func__, inet_ntop(AF_INET6, &addr_v6.ipv6, buf, sizeof(buf)),
1045 prefixlen, iface);
1046
1047 return sitnl_addr_add(AF_INET6, iface, &addr_v6, prefixlen);
1048}
1049
1050int
1051net_addr_v4_del(openvpn_net_ctx_t *ctx, const char *iface, const in_addr_t *addr, int prefixlen)
1052{
1053 inet_address_t addr_v4 = { 0 };
1054 char buf[INET_ADDRSTRLEN];
1055
1056 if (!addr)
1057 {
1058 return -EINVAL;
1059 }
1060
1061 addr_v4.ipv4 = htonl(*addr);
1062
1063 msg(M_INFO, "%s: %s dev %s", __func__, inet_ntop(AF_INET, &addr_v4.ipv4, buf, sizeof(buf)),
1064 iface);
1065
1066 return sitnl_addr_del(AF_INET, iface, &addr_v4, prefixlen);
1067}
1068
1069int
1070net_addr_v6_del(openvpn_net_ctx_t *ctx, const char *iface, const struct in6_addr *addr,
1071 int prefixlen)
1072{
1073 inet_address_t addr_v6 = { 0 };
1074 char buf[INET6_ADDRSTRLEN];
1075
1076 if (!addr)
1077 {
1078 return -EINVAL;
1079 }
1080
1081 addr_v6.ipv6 = *addr;
1082
1083 msg(M_INFO, "%s: %s/%d dev %s", __func__, inet_ntop(AF_INET6, &addr_v6.ipv6, buf, sizeof(buf)),
1084 prefixlen, iface);
1085
1086 return sitnl_addr_del(AF_INET6, iface, &addr_v6, prefixlen);
1087}
1088
1089int
1090net_addr_ptp_v4_add(openvpn_net_ctx_t *ctx, const char *iface, const in_addr_t *local,
1091 const in_addr_t *remote)
1092{
1093 inet_address_t local_v4 = { 0 };
1094 inet_address_t remote_v4 = { 0 };
1095 char buf1[INET_ADDRSTRLEN];
1096 char buf2[INET_ADDRSTRLEN];
1097
1098 if (!local)
1099 {
1100 return -EINVAL;
1101 }
1102
1103 local_v4.ipv4 = htonl(*local);
1104
1105 if (remote)
1106 {
1107 remote_v4.ipv4 = htonl(*remote);
1108 }
1109
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);
1113
1114 return sitnl_addr_ptp_add(AF_INET, iface, &local_v4, &remote_v4);
1115}
1116
1117int
1118net_addr_ptp_v4_del(openvpn_net_ctx_t *ctx, const char *iface, const in_addr_t *local,
1119 const in_addr_t *remote)
1120{
1121 inet_address_t local_v4 = { 0 };
1122 char buf[INET6_ADDRSTRLEN];
1123
1124
1125 if (!local)
1126 {
1127 return -EINVAL;
1128 }
1129
1130 local_v4.ipv4 = htonl(*local);
1131
1132 msg(M_INFO, "%s: %s dev %s", __func__, inet_ntop(AF_INET, &local_v4.ipv4, buf, sizeof(buf)),
1133 iface);
1134
1135 return sitnl_addr_ptp_del(AF_INET, iface, &local_v4);
1136}
1137
1138static int
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)
1141{
1142 enum rt_scope_t scope = RT_SCOPE_UNIVERSE;
1143 int ifindex = 0;
1144
1145 if (iface)
1146 {
1147 ifindex = if_nametoindex(iface);
1148 if (ifindex == 0)
1149 {
1150 msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifindex for %s", __func__, iface);
1151 return -ENOENT;
1152 }
1153 }
1154
1155 if (table == 0)
1156 {
1157 table = RT_TABLE_MAIN;
1158 }
1159
1160 if (!gw && iface)
1161 {
1162 scope = RT_SCOPE_LINK;
1163 }
1164
1165 return sitnl_route_set(RTM_NEWROUTE, NLM_F_CREATE, ifindex, af_family, dst, prefixlen, gw,
1166 table, metric, scope, RTPROT_BOOT, RTN_UNICAST);
1167}
1168
1169int
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)
1172{
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];
1177
1178 if (dst)
1179 {
1180 dst_be = htonl(*dst);
1181 dst_ptr = &dst_be;
1182 }
1183
1184 if (gw)
1185 {
1186 gw_be = htonl(*gw);
1187 gw_ptr = &gw_be;
1188 }
1189
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);
1193
1194 return sitnl_route_add(iface, AF_INET, dst_ptr, prefixlen, gw_ptr, table, metric);
1195}
1196
1197int
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)
1200{
1201 inet_address_t dst_v6 = { 0 };
1202 inet_address_t gw_v6 = { 0 };
1203 char dst_str[INET6_ADDRSTRLEN];
1204 char gw_str[INET6_ADDRSTRLEN];
1205
1206 if (dst)
1207 {
1208 dst_v6.ipv6 = *dst;
1209 }
1210
1211 if (gw)
1212 {
1213 gw_v6.ipv6 = *gw;
1214 }
1215
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);
1219
1220 return sitnl_route_add(iface, AF_INET6, dst, prefixlen, gw, table, metric);
1221}
1222
1223static int
1224sitnl_route_del(const char *iface, sa_family_t af_family, inet_address_t *dst, int prefixlen,
1225 inet_address_t *gw, uint32_t table, int metric)
1226{
1227 int ifindex = 0;
1228
1229 if (iface)
1230 {
1231 ifindex = if_nametoindex(iface);
1232 if (ifindex == 0)
1233 {
1234 msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifindex for %s", __func__, iface);
1235 return -ENOENT;
1236 }
1237 }
1238
1239 if (table == 0)
1240 {
1241 table = RT_TABLE_MAIN;
1242 }
1243
1244 return sitnl_route_set(RTM_DELROUTE, 0, ifindex, af_family, dst, prefixlen, gw, table, metric,
1245 RT_SCOPE_NOWHERE, 0, 0);
1246}
1247
1248int
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)
1251{
1252 inet_address_t dst_v4 = { 0 };
1253 inet_address_t gw_v4 = { 0 };
1254 char dst_str[INET_ADDRSTRLEN];
1255 char gw_str[INET_ADDRSTRLEN];
1256
1257 if (dst)
1258 {
1259 dst_v4.ipv4 = htonl(*dst);
1260 }
1261
1262 if (gw)
1263 {
1264 gw_v4.ipv4 = htonl(*gw);
1265 }
1266
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);
1270
1271 return sitnl_route_del(iface, AF_INET, &dst_v4, prefixlen, &gw_v4, table, metric);
1272}
1273
1274int
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)
1277{
1278 inet_address_t dst_v6 = { 0 };
1279 inet_address_t gw_v6 = { 0 };
1280 char dst_str[INET6_ADDRSTRLEN];
1281 char gw_str[INET6_ADDRSTRLEN];
1282
1283 if (dst)
1284 {
1285 dst_v6.ipv6 = *dst;
1286 }
1287
1288 if (gw)
1289 {
1290 gw_v6.ipv6 = *gw;
1291 }
1292
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);
1296
1297 return sitnl_route_del(iface, AF_INET6, &dst_v6, prefixlen, &gw_v6, table, metric);
1298}
1299
1300
1301int
1302net_iface_new(openvpn_net_ctx_t *ctx, const char *iface, const char *type, void *arg)
1303{
1304 struct sitnl_link_req req = {};
1305 int ret = -1;
1306
1307 ASSERT(iface);
1308
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;
1312
1313 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_IFNAME, iface, strlen(iface) + 1);
1314
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)
1318 if (arg && (strcmp(type, OVPN_FAMILY_NAME) == 0))
1319 {
1320 dco_context_t *dco = arg;
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);
1324 }
1325#endif
1326 SITNL_NEST_END(&req.n, linkinfo);
1327
1328 req.i.ifi_family = AF_PACKET;
1329
1330 msg(D_ROUTE, "%s: add %s type %s", __func__, iface, type);
1331
1332 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
1333err:
1334 return ret;
1335}
1336
1337static int
1338sitnl_parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, int len,
1339 unsigned short flags)
1340{
1341 unsigned short type;
1342
1343 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
1344
1345 while (RTA_OK(rta, len))
1346 {
1347 type = rta->rta_type & ~flags;
1348
1349 if ((type <= max) && (!tb[type]))
1350 {
1351 tb[type] = rta;
1352 }
1353
1354 rta = RTA_NEXT(rta, len);
1355 }
1356
1357 if (len)
1358 {
1359 msg(D_ROUTE, "%s: %d bytes not parsed! (rta_len=%d)", __func__, len, rta->rta_len);
1360 }
1361
1362 return 0;
1363}
1364
1365static int
1366sitnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
1367{
1368 return sitnl_parse_rtattr_flags(tb, max, rta, len, 0);
1369}
1370
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))
1373
1374static int
1375sitnl_type_save(struct nlmsghdr *n, void *arg)
1376{
1377 char *type = arg;
1378 struct ifinfomsg *ifi = NLMSG_DATA(n);
1379 struct rtattr *tb[IFLA_MAX + 1];
1380 int ret;
1381
1382 ret = sitnl_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
1383 if (ret < 0)
1384 {
1385 return ret;
1386 }
1387
1388 if (tb[IFLA_LINKINFO])
1389 {
1390 struct rtattr *tb_link[IFLA_INFO_MAX + 1];
1391
1392 ret = sitnl_parse_rtattr_nested(tb_link, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
1393 if (ret < 0)
1394 {
1395 return ret;
1396 }
1397
1398 if (!tb_link[IFLA_INFO_KIND])
1399 {
1400 return -ENOENT;
1401 }
1402
1403 strncpynt(type, RTA_DATA(tb_link[IFLA_INFO_KIND]), IFACE_TYPE_LEN_MAX);
1404 }
1405
1406 return 0;
1407}
1408
1409int
1410net_iface_type(openvpn_net_ctx_t *ctx, const char *iface, char type[IFACE_TYPE_LEN_MAX])
1411{
1412 struct sitnl_link_req req = {};
1413 int ifindex = if_nametoindex(iface);
1414
1415 if (!ifindex)
1416 {
1417 return -errno;
1418 }
1419
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;
1423
1424 req.i.ifi_family = AF_PACKET;
1425 req.i.ifi_index = ifindex;
1426
1427 memset(type, 0, IFACE_TYPE_LEN_MAX);
1428
1429 int ret = sitnl_send(&req.n, 0, 0, sitnl_type_save, type);
1430 if (ret < 0)
1431 {
1432 msg(D_ROUTE, "%s: cannot retrieve iface %s: %s (%d)", __func__, iface, strerror(-ret), ret);
1433 return ret;
1434 }
1435
1436 msg(D_ROUTE, "%s: type of %s: %s", __func__, iface, type);
1437
1438 return 0;
1439}
1440
1441int
1442net_iface_del(openvpn_net_ctx_t *ctx, const char *iface)
1443{
1444 struct sitnl_link_req req = {};
1445 int ifindex = if_nametoindex(iface);
1446
1447 if (!ifindex)
1448 {
1449 return -errno;
1450 }
1451
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;
1455
1456 req.i.ifi_family = AF_PACKET;
1457 req.i.ifi_index = ifindex;
1458
1459 msg(D_ROUTE, "%s: delete %s", __func__, iface);
1460
1461 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1462}
1463
1464#endif /* !ENABLE_SITNL */
1465
1466#endif /* TARGET_LINUX */
static void strncpynt(char *dest, const char *src, size_t maxlen)
Definition buffer.h:361
void * dco_context_t
Definition dco.h:261
#define D_RTNL
Definition errlevel.h:111
#define M_INFO
Definition errlevel.h:54
#define D_ROUTE
Definition errlevel.h:79
#define MAC_PRINT_ARG(_mac)
Definition misc.h:222
#define MAC_FMT
Definition misc.h:220
static const char * np(const char *str)
Definition multi-auth.c:146
void * openvpn_net_iface_t
Definition networking.h:39
#define IFACE_TYPE_LEN_MAX
Definition networking.h:25
void * openvpn_net_ctx_t
Definition networking.h:38
#define CLEAR(x)
Definition basic.h:32
#define msg(flags,...)
Definition error.h:150
#define ASSERT(x)
Definition error.h:217
#define M_WARN
Definition error.h:90
#define M_ERRNO
Definition error.h:93
#define OVPN_FAMILY_NAME
#define OPENVPN_ETH_ALEN
Definition proto.h:52
unsigned short sa_family_t
Definition syshead.h:396
__attribute__((unused))
Definition test.c:42
static char * iface
char ** res
struct in6_addr ipv6
Definition openvpn-msg.h:64
struct in_addr ipv4
Definition openvpn-msg.h:63