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