OpenVPN
networking_sitnl.c
Go to the documentation of this file.
1/*
2 * Simplified Interface To NetLink
3 *
4 * Copyright (C) 2016-2024 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, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#ifdef TARGET_LINUX
26
27#include "syshead.h"
28
29#include "dco.h"
30#include "errlevel.h"
31#include "buffer.h"
32#include "misc.h"
33#include "networking.h"
34#include "proto.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 in_addr_t ipv4;
89 struct in6_addr ipv6;
91
95struct sitnl_link_req {
96 struct nlmsghdr n;
97 struct ifinfomsg i;
98 char buf[256];
99};
100
104struct sitnl_addr_req {
105 struct nlmsghdr n;
106 struct ifaddrmsg i;
107 char buf[256];
108};
109
113struct sitnl_route_req {
114 struct nlmsghdr n;
115 struct rtmsg r;
116 char buf[256];
117};
118
119typedef int (*sitnl_parse_reply_cb)(struct nlmsghdr *msg, void *arg);
120
124struct sitnl_route_data_cb {
125 unsigned int iface;
127};
128
132static int
133sitnl_addattr(struct nlmsghdr *n, int maxlen, int type, const void *data,
134 int alen)
135{
136 int len = RTA_LENGTH(alen);
137 struct rtattr *rta;
138
139 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen)
140 {
141 msg(M_WARN, "%s: rtnl: message exceeded bound of %d", __func__,
142 maxlen);
143 return -EMSGSIZE;
144 }
145
146 rta = sitnl_nlmsg_tail(n);
147 rta->rta_type = type;
148 rta->rta_len = len;
149
150 if (!data)
151 {
152 memset(RTA_DATA(rta), 0, alen);
153 }
154 else
155 {
156 memcpy(RTA_DATA(rta), data, alen);
157 }
158
159 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
160
161 return 0;
162}
163
167static int
168sitnl_socket(void)
169{
170 int sndbuf = SNDBUF_SIZE;
171 int rcvbuf = RCVBUF_SIZE;
172 int fd;
173
174 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
175 if (fd < 0)
176 {
177 msg(M_WARN, "%s: cannot open netlink socket", __func__);
178 return fd;
179 }
180
181 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0)
182 {
183 msg(M_WARN | M_ERRNO, "%s: SO_SNDBUF", __func__);
184 close(fd);
185 return -1;
186 }
187
188 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0)
189 {
190 msg(M_WARN | M_ERRNO, "%s: SO_RCVBUF", __func__);
191 close(fd);
192 return -1;
193 }
194
195 return fd;
196}
197
201static int
202sitnl_bind(int fd, uint32_t groups)
203{
204 socklen_t addr_len;
205 struct sockaddr_nl local;
206
207 CLEAR(local);
208
209 local.nl_family = AF_NETLINK;
210 local.nl_groups = groups;
211
212 if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0)
213 {
214 msg(M_WARN | M_ERRNO, "%s: cannot bind netlink socket", __func__);
215 return -errno;
216 }
217
218 addr_len = sizeof(local);
219 if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0)
220 {
221 msg(M_WARN | M_ERRNO, "%s: cannot getsockname", __func__);
222 return -errno;
223 }
224
225 if (addr_len != sizeof(local))
226 {
227 msg(M_WARN, "%s: wrong address length %d", __func__, addr_len);
228 return -EINVAL;
229 }
230
231 if (local.nl_family != AF_NETLINK)
232 {
233 msg(M_WARN, "%s: wrong address family %d", __func__, local.nl_family);
234 return -EINVAL;
235 }
236
237 return 0;
238}
239
243static int
244sitnl_send(struct nlmsghdr *payload, pid_t peer, unsigned int groups,
245 sitnl_parse_reply_cb cb, void *arg_cb)
246{
247 int len, rem_len, fd, ret, rcv_len;
248 struct sockaddr_nl nladdr;
249 struct nlmsgerr *err;
250 struct nlmsghdr *h;
251 unsigned int seq;
252 char buf[1024 * 16];
253 struct iovec iov =
254 {
255 .iov_base = payload,
256 .iov_len = payload->nlmsg_len,
257 };
258 struct msghdr nlmsg =
259 {
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)",
339 __func__, nlmsg.msg_namelen, 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) nl_msg_pid:%d nl_seq:%d seq:%d",
369 * __func__, (int)nladdr.nl_pid, peer, h->nlmsg_pid,
370 * h->nlmsg_seq, seq);
371 * continue;
372 * }
373 */
374
375 if (h->nlmsg_type == NLMSG_DONE)
376 {
377 ret = 0;
378 goto out;
379 }
380
381 if (h->nlmsg_type == NLMSG_ERROR)
382 {
383 err = (struct nlmsgerr *)NLMSG_DATA(h);
384 if (rem_len < (int)sizeof(struct nlmsgerr))
385 {
386 msg(M_WARN, "%s: ERROR truncated", __func__);
387 ret = -EIO;
388 }
389 else
390 {
391 if (!err->error)
392 {
393 ret = 0;
394 if (cb)
395 {
396 int r = cb(h, arg_cb);
397 if (r <= 0)
398 {
399 ret = r;
400 }
401 }
402 }
403 else
404 {
405 msg(M_WARN, "%s: rtnl: generic error (%d): %s",
406 __func__, err->error, strerror(-err->error));
407 ret = err->error;
408 }
409 }
410 goto out;
411 }
412
413 if (cb)
414 {
415 int r = cb(h, arg_cb);
416 if (r <= 0)
417 {
418 ret = r;
419 goto out;
420 }
421 }
422 else
423 {
424 msg(M_WARN, "%s: RTNL: unexpected reply", __func__);
425 }
426
427 rcv_len -= NLMSG_ALIGN(len);
428 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
429 }
430
431 if (nlmsg.msg_flags & MSG_TRUNC)
432 {
433 msg(M_WARN, "%s: message truncated", __func__);
434 continue;
435 }
436
437 if (rcv_len)
438 {
439 msg(M_WARN, "%s: rtnl: %d not parsed bytes", __func__, rcv_len);
440 ret = -1;
441 goto out;
442 }
443 }
444out:
445 close(fd);
446
447 return ret;
448}
449
450typedef struct {
451 int addr_size;
453 char iface[IFNAMSIZ];
454 bool default_only;
455 unsigned int table;
456} route_res_t;
457
458static int
459sitnl_route_save(struct nlmsghdr *n, void *arg)
460{
461 route_res_t *res = arg;
462 struct rtmsg *r = NLMSG_DATA(n);
463 struct rtattr *rta = RTM_RTA(r);
464 int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
465 unsigned int table, ifindex = 0;
466 void *gw = NULL;
467
468 /* filter-out non-zero dst prefixes */
469 if (res->default_only && r->rtm_dst_len != 0)
470 {
471 return 1;
472 }
473
474 /* route table, ignored with RTA_TABLE */
475 table = r->rtm_table;
476
477 while (RTA_OK(rta, len))
478 {
479 switch (rta->rta_type)
480 {
481 /* route interface */
482 case RTA_OIF:
483 ifindex = *(unsigned int *)RTA_DATA(rta);
484 break;
485
486 /* route prefix */
487 case RTA_DST:
488 break;
489
490 /* GW for the route */
491 case RTA_GATEWAY:
492 gw = RTA_DATA(rta);
493 break;
494
495 /* route table */
496 case RTA_TABLE:
497 table = *(unsigned int *)RTA_DATA(rta);
498 break;
499 }
500
501 rta = RTA_NEXT(rta, len);
502 }
503
504 /* filter out any route not coming from the selected table */
505 if (res->table && res->table != table)
506 {
507 return 1;
508 }
509
510 if (!if_indextoname(ifindex, res->iface))
511 {
512 msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifname for index %d",
513 __func__, ifindex);
514 return -1;
515 }
516
517 if (gw)
518 {
519 memcpy(&res->gw, gw, res->addr_size);
520 }
521
522 return 0;
523}
524
525static int
526sitnl_route_best_gw(sa_family_t af_family, const inet_address_t *dst,
527 void *best_gw, char *best_iface)
528{
529 struct sitnl_route_req req;
530 route_res_t res;
531 int ret = -EINVAL;
532
533 ASSERT(best_gw);
534 ASSERT(best_iface);
535
536 CLEAR(req);
537 CLEAR(res);
538
539 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
540 req.n.nlmsg_type = RTM_GETROUTE;
541 req.n.nlmsg_flags = NLM_F_REQUEST;
542
543 req.r.rtm_family = af_family;
544
545 switch (af_family)
546 {
547 case AF_INET:
548 res.addr_size = sizeof(in_addr_t);
549 /*
550 * kernel can't return 0.0.0.0/8 host route, dump all
551 * the routes and filter for 0.0.0.0/0 in cb()
552 */
553 if (!dst || !dst->ipv4)
554 {
555 req.n.nlmsg_flags |= NLM_F_DUMP;
556 res.default_only = true;
557 res.table = RT_TABLE_MAIN;
558 }
559 else
560 {
561 req.r.rtm_dst_len = 32;
562 }
563 break;
564
565 case AF_INET6:
566 res.addr_size = sizeof(struct in6_addr);
567 /* kernel can return ::/128 host route */
568 req.r.rtm_dst_len = 128;
569 break;
570
571 default:
572 /* unsupported */
573 return -EINVAL;
574 }
575
576 SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, dst, res.addr_size);
577
578 ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &res);
579 if (ret < 0)
580 {
581 goto err;
582 }
583
584 /* save result in output variables */
585 memcpy(best_gw, &res.gw, res.addr_size);
586 strncpy(best_iface, res.iface, IFNAMSIZ);
587err:
588 return ret;
589
590}
591
592/* used by iproute2 implementation too */
593int
594net_route_v6_best_gw(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
595 struct in6_addr *best_gw, 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__,
607 inet_ntop(AF_INET6, &dst_v6.ipv6, buf, sizeof(buf)));
608
609 ret = sitnl_route_best_gw(AF_INET6, &dst_v6, best_gw, best_iface);
610 if (ret < 0)
611 {
612 return ret;
613 }
614
615 msg(D_ROUTE, "%s result: via %s dev %s", __func__,
616 inet_ntop(AF_INET6, best_gw, buf, sizeof(buf)), best_iface);
617
618 return ret;
619
620}
621
622/* used by iproute2 implementation too */
623int
624net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
625 in_addr_t *best_gw, char *best_iface)
626{
627 inet_address_t dst_v4 = {0};
628 char buf[INET_ADDRSTRLEN];
629 int ret;
630
631 if (dst)
632 {
633 dst_v4.ipv4 = htonl(*dst);
634 }
635
636 msg(D_ROUTE, "%s query: dst %s", __func__,
637 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,
674 strerror(errno));
675 return -ENOENT;
676 }
677
678 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
679 req.n.nlmsg_flags = NLM_F_REQUEST;
680 req.n.nlmsg_type = RTM_NEWLINK;
681
682 req.i.ifi_family = AF_PACKET;
683 req.i.ifi_index = ifindex;
684 req.i.ifi_change |= IFF_UP;
685 if (up)
686 {
687 req.i.ifi_flags |= IFF_UP;
688 }
689 else
690 {
691 req.i.ifi_flags &= ~IFF_UP;
692 }
693
694 msg(M_INFO, "%s: set %s %s", __func__, iface, up ? "up" : "down");
695
696 return sitnl_send(&req.n, 0, 0, NULL, NULL);
697}
698
699int
700net_iface_mtu_set(openvpn_net_ctx_t *ctx, const char *iface,
701 uint32_t mtu)
702{
703 struct sitnl_link_req req;
704 int ifindex, ret = -1;
705
706 CLEAR(req);
707
708 ifindex = if_nametoindex(iface);
709 if (ifindex == 0)
710 {
711 msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__,
712 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,
734 uint8_t *addr)
735{
736 struct sitnl_link_req req;
737 int ifindex, ret = -1;
738
739 CLEAR(req);
740
741 ifindex = if_nametoindex(iface);
742 if (ifindex == 0)
743 {
744 msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__,
745 iface);
746 return -1;
747 }
748
749 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
750 req.n.nlmsg_flags = NLM_F_REQUEST;
751 req.n.nlmsg_type = RTM_NEWLINK;
752
753 req.i.ifi_family = AF_PACKET;
754 req.i.ifi_index = ifindex;
755
756 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_ADDRESS, addr, OPENVPN_ETH_ALEN);
757
758 msg(M_INFO, "%s: lladdr " MAC_FMT " for %s", __func__, MAC_PRINT_ARG(addr),
759 iface);
760
761 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
762err:
763 return ret;
764}
765
766static int
767sitnl_addr_set(int cmd, uint32_t flags, int ifindex, sa_family_t af_family,
768 const inet_address_t *local, const inet_address_t *remote,
769 int prefixlen)
770{
771 struct sitnl_addr_req req;
772 uint32_t size;
773 int ret = -EINVAL;
774
775 CLEAR(req);
776
777 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
778 req.n.nlmsg_type = cmd;
779 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
780
781 req.i.ifa_index = ifindex;
782 req.i.ifa_family = af_family;
783
784 switch (af_family)
785 {
786 case AF_INET:
787 size = sizeof(struct in_addr);
788 break;
789
790 case AF_INET6:
791 size = sizeof(struct in6_addr);
792 break;
793
794 default:
795 msg(M_WARN, "%s: rtnl: unknown address family %d", __func__,
796 af_family);
797 return -EINVAL;
798 }
799
800 /* if no prefixlen has been specified, assume host address */
801 if (prefixlen == 0)
802 {
803 prefixlen = size * 8;
804 }
805 req.i.ifa_prefixlen = prefixlen;
806
807 if (remote)
808 {
809 SITNL_ADDATTR(&req.n, sizeof(req), IFA_ADDRESS, remote, size);
810 }
811
812 if (local)
813 {
814 SITNL_ADDATTR(&req.n, sizeof(req), IFA_LOCAL, local, size);
815 }
816
817 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
818 if (ret == -EEXIST)
819 {
820 ret = 0;
821 }
822err:
823 return ret;
824}
825
826static int
827sitnl_addr_ptp_add(sa_family_t af_family, const char *iface,
828 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),
853 strerror(errno));
854 return -ENOENT;
855 }
856
857 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex,
858 af_family, local, remote, 0);
859}
860
861static int
862sitnl_addr_ptp_del(sa_family_t af_family, const char *iface,
863 const inet_address_t *local)
864{
865 int ifindex;
866
867 switch (af_family)
868 {
869 case AF_INET:
870 case AF_INET6:
871 break;
872
873 default:
874 return -EINVAL;
875 }
876
877 if (!iface)
878 {
879 msg(M_WARN, "%s: passed NULL interface", __func__);
880 return -EINVAL;
881 }
882
883 ifindex = if_nametoindex(iface);
884 if (ifindex == 0)
885 {
886 msg(M_WARN | M_ERRNO, "%s: cannot get ifindex for %s", __func__, iface);
887 return -ENOENT;
888 }
889
890 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, local, NULL, 0);
891}
892
893static int
894sitnl_route_set(int cmd, uint32_t flags, int ifindex, sa_family_t af_family,
895 const void *dst, int prefixlen,
896 const void *gw, enum rt_class_t table, int metric,
897 enum rt_scope_t scope, int protocol, int type)
898{
899 struct sitnl_route_req req;
900 int ret = -1, size;
901
902 CLEAR(req);
903
904 switch (af_family)
905 {
906 case AF_INET:
907 size = sizeof(in_addr_t);
908 break;
909
910 case AF_INET6:
911 size = sizeof(struct in6_addr);
912 break;
913
914 default:
915 return -EINVAL;
916 }
917
918 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
919 req.n.nlmsg_type = cmd;
920 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
921
922 req.r.rtm_family = af_family;
923 req.r.rtm_scope = scope;
924 req.r.rtm_protocol = protocol;
925 req.r.rtm_type = type;
926 req.r.rtm_dst_len = prefixlen;
927
928 if (table < 256)
929 {
930 req.r.rtm_table = table;
931 }
932 else
933 {
934 req.r.rtm_table = RT_TABLE_UNSPEC;
935 SITNL_ADDATTR(&req.n, sizeof(req), RTA_TABLE, &table, 4);
936 }
937
938 if (dst)
939 {
940 SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, dst, size);
941 }
942
943 if (gw)
944 {
945 SITNL_ADDATTR(&req.n, sizeof(req), RTA_GATEWAY, gw, size);
946 }
947
948 if (ifindex > 0)
949 {
950 SITNL_ADDATTR(&req.n, sizeof(req), RTA_OIF, &ifindex, 4);
951 }
952
953 if (metric > 0)
954 {
955 SITNL_ADDATTR(&req.n, sizeof(req), RTA_PRIORITY, &metric, 4);
956 }
957
958 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
959err:
960 return ret;
961}
962
963static int
964sitnl_addr_add(sa_family_t af_family, const char *iface,
965 const inet_address_t *addr, int prefixlen)
966{
967 int ifindex;
968
969 switch (af_family)
970 {
971 case AF_INET:
972 case AF_INET6:
973 break;
974
975 default:
976 return -EINVAL;
977 }
978
979 if (!iface)
980 {
981 msg(M_WARN, "%s: passed NULL interface", __func__);
982 return -EINVAL;
983 }
984
985 ifindex = if_nametoindex(iface);
986 if (ifindex == 0)
987 {
988 msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__,
989 iface);
990 return -ENOENT;
991 }
992
993 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex,
994 af_family, addr, NULL, prefixlen);
995}
996
997static int
998sitnl_addr_del(sa_family_t af_family, const char *iface, inet_address_t *addr,
999 int prefixlen)
1000{
1001 int ifindex;
1002
1003 switch (af_family)
1004 {
1005 case AF_INET:
1006 case AF_INET6:
1007 break;
1008
1009 default:
1010 return -EINVAL;
1011 }
1012
1013 if (!iface)
1014 {
1015 msg(M_WARN, "%s: passed NULL interface", __func__);
1016 return -EINVAL;
1017 }
1018
1019 ifindex = if_nametoindex(iface);
1020 if (ifindex == 0)
1021 {
1022 msg(M_WARN | M_ERRNO, "%s: rtnl: cannot get ifindex for %s", __func__,
1023 iface);
1024 return -ENOENT;
1025 }
1026
1027 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, addr, NULL,
1028 prefixlen);
1029}
1030
1031int
1032net_addr_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
1033 const in_addr_t *addr, int prefixlen)
1034{
1035 inet_address_t addr_v4 = { 0 };
1036 char buf[INET_ADDRSTRLEN];
1037
1038 if (!addr)
1039 {
1040 return -EINVAL;
1041 }
1042
1043 addr_v4.ipv4 = htonl(*addr);
1044
1045 msg(M_INFO, "%s: %s/%d dev %s", __func__,
1046 inet_ntop(AF_INET, &addr_v4.ipv4, buf, sizeof(buf)), prefixlen, iface);
1047
1048 return sitnl_addr_add(AF_INET, iface, &addr_v4, prefixlen);
1049}
1050
1051int
1052net_addr_v6_add(openvpn_net_ctx_t *ctx, const char *iface,
1053 const struct in6_addr *addr, int prefixlen)
1054{
1055 inet_address_t addr_v6 = { 0 };
1056 char buf[INET6_ADDRSTRLEN];
1057
1058 if (!addr)
1059 {
1060 return -EINVAL;
1061 }
1062
1063 addr_v6.ipv6 = *addr;
1064
1065 msg(M_INFO, "%s: %s/%d dev %s", __func__,
1066 inet_ntop(AF_INET6, &addr_v6.ipv6, buf, sizeof(buf)), prefixlen, iface);
1067
1068 return sitnl_addr_add(AF_INET6, iface, &addr_v6, prefixlen);
1069}
1070
1071int
1072net_addr_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
1073 const in_addr_t *addr, int prefixlen)
1074{
1075 inet_address_t addr_v4 = { 0 };
1076 char buf[INET_ADDRSTRLEN];
1077
1078 if (!addr)
1079 {
1080 return -EINVAL;
1081 }
1082
1083 addr_v4.ipv4 = htonl(*addr);
1084
1085 msg(M_INFO, "%s: %s dev %s", __func__,
1086 inet_ntop(AF_INET, &addr_v4.ipv4, buf, sizeof(buf)), iface);
1087
1088 return sitnl_addr_del(AF_INET, iface, &addr_v4, prefixlen);
1089}
1090
1091int
1092net_addr_v6_del(openvpn_net_ctx_t *ctx, const char *iface,
1093 const struct in6_addr *addr, int prefixlen)
1094{
1095 inet_address_t addr_v6 = { 0 };
1096 char buf[INET6_ADDRSTRLEN];
1097
1098 if (!addr)
1099 {
1100 return -EINVAL;
1101 }
1102
1103 addr_v6.ipv6 = *addr;
1104
1105 msg(M_INFO, "%s: %s/%d dev %s", __func__,
1106 inet_ntop(AF_INET6, &addr_v6.ipv6, buf, sizeof(buf)), prefixlen, iface);
1107
1108 return sitnl_addr_del(AF_INET6, iface, &addr_v6, prefixlen);
1109}
1110
1111int
1112net_addr_ptp_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
1113 const in_addr_t *local, const in_addr_t *remote)
1114{
1115 inet_address_t local_v4 = { 0 };
1116 inet_address_t remote_v4 = { 0 };
1117 char buf1[INET_ADDRSTRLEN];
1118 char buf2[INET_ADDRSTRLEN];
1119
1120 if (!local)
1121 {
1122 return -EINVAL;
1123 }
1124
1125 local_v4.ipv4 = htonl(*local);
1126
1127 if (remote)
1128 {
1129 remote_v4.ipv4 = htonl(*remote);
1130 }
1131
1132 msg(M_INFO, "%s: %s peer %s dev %s", __func__,
1133 inet_ntop(AF_INET, &local_v4.ipv4, buf1, sizeof(buf1)),
1134 inet_ntop(AF_INET, &remote_v4.ipv4, buf2, sizeof(buf2)), iface);
1135
1136 return sitnl_addr_ptp_add(AF_INET, iface, &local_v4, &remote_v4);
1137}
1138
1139int
1140net_addr_ptp_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
1141 const in_addr_t *local, const in_addr_t *remote)
1142{
1143 inet_address_t local_v4 = { 0 };
1144 char buf[INET6_ADDRSTRLEN];
1145
1146
1147 if (!local)
1148 {
1149 return -EINVAL;
1150 }
1151
1152 local_v4.ipv4 = htonl(*local);
1153
1154 msg(M_INFO, "%s: %s dev %s", __func__,
1155 inet_ntop(AF_INET, &local_v4.ipv4, buf, sizeof(buf)), iface);
1156
1157 return sitnl_addr_ptp_del(AF_INET, iface, &local_v4);
1158}
1159
1160static int
1161sitnl_route_add(const char *iface, sa_family_t af_family, const void *dst,
1162 int prefixlen, const void *gw, uint32_t table, int metric)
1163{
1164 enum rt_scope_t scope = RT_SCOPE_UNIVERSE;
1165 int ifindex = 0;
1166
1167 if (iface)
1168 {
1169 ifindex = if_nametoindex(iface);
1170 if (ifindex == 0)
1171 {
1172 msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifindex for %s",
1173 __func__, iface);
1174 return -ENOENT;
1175 }
1176 }
1177
1178 if (table == 0)
1179 {
1180 table = RT_TABLE_MAIN;
1181 }
1182
1183 if (!gw && iface)
1184 {
1185 scope = RT_SCOPE_LINK;
1186 }
1187
1188 return sitnl_route_set(RTM_NEWROUTE, NLM_F_CREATE, ifindex,
1189 af_family, dst, prefixlen, gw, table, metric, scope,
1190 RTPROT_BOOT, RTN_UNICAST);
1191}
1192
1193int
1194net_route_v4_add(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
1195 const in_addr_t *gw, const char *iface,
1196 uint32_t table, int metric)
1197{
1198 in_addr_t *dst_ptr = NULL, *gw_ptr = NULL;
1199 in_addr_t dst_be = 0, gw_be = 0;
1200 char dst_str[INET_ADDRSTRLEN];
1201 char gw_str[INET_ADDRSTRLEN];
1202
1203 if (dst)
1204 {
1205 dst_be = htonl(*dst);
1206 dst_ptr = &dst_be;
1207 }
1208
1209 if (gw)
1210 {
1211 gw_be = htonl(*gw);
1212 gw_ptr = &gw_be;
1213 }
1214
1215 msg(D_ROUTE, "%s: %s/%d via %s dev %s table %d metric %d", __func__,
1216 inet_ntop(AF_INET, &dst_be, dst_str, sizeof(dst_str)),
1217 prefixlen, inet_ntop(AF_INET, &gw_be, gw_str, sizeof(gw_str)),
1218 np(iface), table, metric);
1219
1220 return sitnl_route_add(iface, AF_INET, dst_ptr, prefixlen, gw_ptr, table,
1221 metric);
1222}
1223
1224int
1225net_route_v6_add(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
1226 int prefixlen, const struct in6_addr *gw,
1227 const char *iface, uint32_t table, int metric)
1228{
1229 inet_address_t dst_v6 = { 0 };
1230 inet_address_t gw_v6 = { 0 };
1231 char dst_str[INET6_ADDRSTRLEN];
1232 char gw_str[INET6_ADDRSTRLEN];
1233
1234 if (dst)
1235 {
1236 dst_v6.ipv6 = *dst;
1237 }
1238
1239 if (gw)
1240 {
1241 gw_v6.ipv6 = *gw;
1242 }
1243
1244 msg(D_ROUTE, "%s: %s/%d via %s dev %s table %d metric %d", __func__,
1245 inet_ntop(AF_INET6, &dst_v6.ipv6, dst_str, sizeof(dst_str)),
1246 prefixlen, inet_ntop(AF_INET6, &gw_v6.ipv6, gw_str, sizeof(gw_str)),
1247 np(iface), table, metric);
1248
1249 return sitnl_route_add(iface, AF_INET6, dst, prefixlen, gw, table,
1250 metric);
1251}
1252
1253static int
1254sitnl_route_del(const char *iface, sa_family_t af_family, inet_address_t *dst,
1255 int prefixlen, inet_address_t *gw, uint32_t table,
1256 int metric)
1257{
1258 int ifindex = 0;
1259
1260 if (iface)
1261 {
1262 ifindex = if_nametoindex(iface);
1263 if (ifindex == 0)
1264 {
1265 msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifindex for %s",
1266 __func__, iface);
1267 return -ENOENT;
1268 }
1269 }
1270
1271 if (table == 0)
1272 {
1273 table = RT_TABLE_MAIN;
1274 }
1275
1276 return sitnl_route_set(RTM_DELROUTE, 0, ifindex, af_family, dst, prefixlen,
1277 gw, table, metric, RT_SCOPE_NOWHERE, 0, 0);
1278}
1279
1280int
1281net_route_v4_del(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
1282 const in_addr_t *gw, const char *iface, uint32_t table,
1283 int metric)
1284{
1285 inet_address_t dst_v4 = { 0 };
1286 inet_address_t gw_v4 = { 0 };
1287 char dst_str[INET_ADDRSTRLEN];
1288 char gw_str[INET_ADDRSTRLEN];
1289
1290 if (dst)
1291 {
1292 dst_v4.ipv4 = htonl(*dst);
1293 }
1294
1295 if (gw)
1296 {
1297 gw_v4.ipv4 = htonl(*gw);
1298 }
1299
1300 msg(D_ROUTE, "%s: %s/%d via %s dev %s table %d metric %d", __func__,
1301 inet_ntop(AF_INET, &dst_v4.ipv4, dst_str, sizeof(dst_str)),
1302 prefixlen, inet_ntop(AF_INET, &gw_v4.ipv4, gw_str, sizeof(gw_str)),
1303 np(iface), table, metric);
1304
1305 return sitnl_route_del(iface, AF_INET, &dst_v4, prefixlen, &gw_v4, table,
1306 metric);
1307}
1308
1309int
1310net_route_v6_del(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
1311 int prefixlen, const struct in6_addr *gw,
1312 const char *iface, uint32_t table, int metric)
1313{
1314 inet_address_t dst_v6 = { 0 };
1315 inet_address_t gw_v6 = { 0 };
1316 char dst_str[INET6_ADDRSTRLEN];
1317 char gw_str[INET6_ADDRSTRLEN];
1318
1319 if (dst)
1320 {
1321 dst_v6.ipv6 = *dst;
1322 }
1323
1324 if (gw)
1325 {
1326 gw_v6.ipv6 = *gw;
1327 }
1328
1329 msg(D_ROUTE, "%s: %s/%d via %s dev %s table %d metric %d", __func__,
1330 inet_ntop(AF_INET6, &dst_v6.ipv6, dst_str, sizeof(dst_str)),
1331 prefixlen, inet_ntop(AF_INET6, &gw_v6.ipv6, gw_str, sizeof(gw_str)),
1332 np(iface), table, metric);
1333
1334 return sitnl_route_del(iface, AF_INET6, &dst_v6, prefixlen, &gw_v6,
1335 table, metric);
1336}
1337
1338
1339int
1340net_iface_new(openvpn_net_ctx_t *ctx, const char *iface, const char *type,
1341 void *arg)
1342{
1343 struct sitnl_link_req req = { };
1344 int ret = -1;
1345
1346 ASSERT(iface);
1347
1348 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1349 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
1350 req.n.nlmsg_type = RTM_NEWLINK;
1351
1352 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_IFNAME, iface, strlen(iface) + 1);
1353
1354 struct rtattr *linkinfo = SITNL_NEST(&req.n, sizeof(req), IFLA_LINKINFO);
1355 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_INFO_KIND, type, strlen(type) + 1);
1356#if defined(ENABLE_DCO)
1357 if (arg && (strcmp(type, "ovpn-dco") == 0))
1358 {
1359 dco_context_t *dco = arg;
1360 struct rtattr *data = SITNL_NEST(&req.n, sizeof(req), IFLA_INFO_DATA);
1361 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_OVPN_MODE, &dco->ifmode,
1362 sizeof(uint8_t));
1363 SITNL_NEST_END(&req.n, data);
1364 }
1365#endif
1366 SITNL_NEST_END(&req.n, linkinfo);
1367
1368 req.i.ifi_family = AF_PACKET;
1369
1370 msg(D_ROUTE, "%s: add %s type %s", __func__, iface, type);
1371
1372 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
1373err:
1374 return ret;
1375}
1376
1377static int
1378sitnl_parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
1379 int len, unsigned short flags)
1380{
1381 unsigned short type;
1382
1383 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
1384
1385 while (RTA_OK(rta, len))
1386 {
1387 type = rta->rta_type & ~flags;
1388
1389 if ((type <= max) && (!tb[type]))
1390 {
1391 tb[type] = rta;
1392 }
1393
1394 rta = RTA_NEXT(rta, len);
1395 }
1396
1397 if (len)
1398 {
1399 msg(D_ROUTE, "%s: %d bytes not parsed! (rta_len=%d)", __func__, len,
1400 rta->rta_len);
1401 }
1402
1403 return 0;
1404}
1405
1406static int
1407sitnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
1408{
1409 return sitnl_parse_rtattr_flags(tb, max, rta, len, 0);
1410}
1411
1412#define sitnl_parse_rtattr_nested(tb, max, rta) \
1413 (sitnl_parse_rtattr_flags(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta), \
1414 NLA_F_NESTED))
1415
1416static int
1417sitnl_type_save(struct nlmsghdr *n, void *arg)
1418{
1419 char *type = arg;
1420 struct ifinfomsg *ifi = NLMSG_DATA(n);
1421 struct rtattr *tb[IFLA_MAX + 1];
1422 int ret;
1423
1424 ret = sitnl_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
1425 if (ret < 0)
1426 {
1427 return ret;
1428 }
1429
1430 if (tb[IFLA_LINKINFO])
1431 {
1432 struct rtattr *tb_link[IFLA_INFO_MAX + 1];
1433
1434 ret = sitnl_parse_rtattr_nested(tb_link, IFLA_INFO_MAX,
1435 tb[IFLA_LINKINFO]);
1436 if (ret < 0)
1437 {
1438 return ret;
1439 }
1440
1441 if (!tb_link[IFLA_INFO_KIND])
1442 {
1443 return -ENOENT;
1444 }
1445
1446 strncpynt(type, RTA_DATA(tb_link[IFLA_INFO_KIND]), IFACE_TYPE_LEN_MAX);
1447 }
1448
1449 return 0;
1450}
1451
1452int
1453net_iface_type(openvpn_net_ctx_t *ctx, const char *iface,
1454 char type[IFACE_TYPE_LEN_MAX])
1455{
1456 struct sitnl_link_req req = { };
1457 int ifindex = if_nametoindex(iface);
1458
1459 if (!ifindex)
1460 {
1461 return -errno;
1462 }
1463
1464 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1465 req.n.nlmsg_flags = NLM_F_REQUEST;
1466 req.n.nlmsg_type = RTM_GETLINK;
1467
1468 req.i.ifi_family = AF_PACKET;
1469 req.i.ifi_index = ifindex;
1470
1471 memset(type, 0, IFACE_TYPE_LEN_MAX);
1472
1473 int ret = sitnl_send(&req.n, 0, 0, sitnl_type_save, type);
1474 if (ret < 0)
1475 {
1476 msg(D_ROUTE, "%s: cannot retrieve iface %s: %s (%d)", __func__, iface,
1477 strerror(-ret), ret);
1478 return ret;
1479 }
1480
1481 msg(D_ROUTE, "%s: type of %s: %s", __func__, iface, type);
1482
1483 return 0;
1484}
1485
1486int
1487net_iface_del(openvpn_net_ctx_t *ctx, const char *iface)
1488{
1489 struct sitnl_link_req req = { };
1490 int ifindex = if_nametoindex(iface);
1491
1492 if (!ifindex)
1493 {
1494 return -errno;
1495 }
1496
1497 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1498 req.n.nlmsg_flags = NLM_F_REQUEST;
1499 req.n.nlmsg_type = RTM_DELLINK;
1500
1501 req.i.ifi_family = AF_PACKET;
1502 req.i.ifi_index = ifindex;
1503
1504 msg(D_ROUTE, "%s: delete %s", __func__, iface);
1505
1506 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1507}
1508
1509#endif /* !ENABLE_SITNL */
1510
1511#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:267
#define D_RTNL
Definition errlevel.h:112
#define M_INFO
Definition errlevel.h:55
#define D_ROUTE
Definition errlevel.h:80
#define MAC_PRINT_ARG(_mac)
Definition misc.h:227
#define MAC_FMT
Definition misc.h:225
static const char * np(const char *str)
Definition multi-auth.c:146
void * openvpn_net_iface_t
Definition networking.h:40
#define IFACE_TYPE_LEN_MAX
Definition networking.h:26
void * openvpn_net_ctx_t
Definition networking.h:39
#define CLEAR(x)
Definition basic.h:33
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
#define M_ERRNO
Definition error.h:94
@ IFLA_OVPN_MODE
#define OPENVPN_ETH_ALEN
Definition proto.h:53
unsigned short sa_family_t
Definition syshead.h:395
__attribute__((unused))
Definition test.c:42
static char * iface
struct in6_addr ipv6
Definition openvpn-msg.h:59
struct in_addr ipv4
Definition openvpn-msg.h:58