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