OpenVPN 3 Core Library
Loading...
Searching...
No Matches
sitnl.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8// Copyright (C) 2018-2022 Antonio Quartulli <antonio@openvpn.net>
9//
10// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
11//
12
13
14#pragma once
15
16#include <errno.h>
17#include <string.h>
18#include <unistd.h>
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <linux/netlink.h>
22#include <linux/rtnetlink.h>
23
25#include <openvpn/addr/ip.hpp>
26#include <openvpn/addr/ipv4.hpp>
27#include <openvpn/addr/ipv6.hpp>
29
30
31#ifndef OPENVPN_LOG_RTNL
32#ifdef DEBUG_RTNL
33#define OPENVPN_LOG_RTNL(_x) OPENVPN_LOG(_x)
34#else
35#define OPENVPN_LOG_RTNL(_x)
36#endif
37#endif
38
40
41#define SNDBUF_SIZE (1024 * 2)
42#define RCVBUF_SIZE (1024 * 4)
43
44#define SITNL_ADDATTR(_msg, _max_size, _attr, _data, _size) \
45 { \
46 if (sitnl_addattr(_msg, _max_size, _attr, _data, _size) < 0) \
47 { \
48 goto err; \
49 } \
50 }
51
52#define NLMSG_TAIL(nmsg) \
53 ((struct rtattr *)(((uint8_t *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
54
55/* this class contains only static members */
56class SITNL
57{
58 private:
63 {
64 struct nlmsghdr n;
65 struct ifinfomsg i;
66 char buf[256];
67 };
68
73 {
74 struct nlmsghdr n;
75 struct ifaddrmsg i;
76 char buf[256];
77 };
78
83 {
84 struct nlmsghdr n;
85 struct rtmsg r;
86 char buf[256];
87 };
88
89 typedef int (*sitnl_parse_reply_cb)(struct nlmsghdr *msg, void *arg);
90
94 static int
95 sitnl_addattr(struct nlmsghdr *n, int maxlen, uint16_t type, const void *data, uint16_t alen)
96 {
97 uint16_t len = RTA_LENGTH(alen);
98 struct rtattr *rta;
99
100 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen)
101 {
102 OPENVPN_LOG(__func__ << ": rtnl: message exceeded bound of " << maxlen);
103 return -EMSGSIZE;
104 }
105
106 rta = NLMSG_TAIL(n);
107 rta->rta_type = type;
108 rta->rta_len = len;
109
110 if (!data)
111 {
112 memset(RTA_DATA(rta), 0, alen);
113 }
114 else
115 {
116 memcpy(RTA_DATA(rta), data, alen);
117 }
118
119 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
120
121 return 0;
122 }
123
127 static int
129 {
130 int sndbuf = SNDBUF_SIZE;
131 int rcvbuf = RCVBUF_SIZE;
132 int fd;
133
134 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
135 if (fd < 0)
136 {
137 OPENVPN_LOG(__func__ << ": cannot open netlink socket");
138 return fd;
139 }
140
141 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0)
142 {
143 OPENVPN_LOG(__func__ << ": SO_SNDBUF");
144 close(fd);
145 return -1;
146 }
147
148 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0)
149 {
150 OPENVPN_LOG(__func__ << ": SO_RCVBUF");
151 close(fd);
152 return -1;
153 }
154
155 return fd;
156 }
157
161 static int
162 sitnl_bind(int fd, uint32_t groups)
163 {
164 socklen_t addr_len;
165 struct sockaddr_nl local = {};
166
167 local.nl_family = AF_NETLINK;
168 local.nl_groups = groups;
169
170 if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0)
171 {
172 OPENVPN_LOG(__func__ << ": cannot bind netlink socket");
173 return -errno;
174 }
175
176 addr_len = sizeof(local);
177 if (getsockname(fd, (struct sockaddr *)&local, &addr_len) < 0)
178 {
179 OPENVPN_LOG(__func__ << ": cannot getsockname");
180 return -errno;
181 }
182
183 if (addr_len != sizeof(local))
184 {
185 OPENVPN_LOG(__func__ << ": wrong address length " << addr_len);
186 return -EINVAL;
187 }
188
189 if (local.nl_family != AF_NETLINK)
190 {
191 OPENVPN_LOG(__func__ << ": wrong address family " << local.nl_family);
192 return -EINVAL;
193 }
194
195 return 0;
196 }
197
221 static int
222 sitnl_send(struct nlmsghdr *payload, pid_t peer, unsigned int groups, sitnl_parse_reply_cb cb, void *arg_cb)
223 {
224 int ret = 0;
225 const size_t buf_len = 16 * 1024;
226 struct sockaddr_nl nladdr = {
227 .nl_family = AF_NETLINK,
228 .nl_pid = static_cast<__u32>(peer),
229 .nl_groups = groups,
230 };
231 struct iovec iov = {
232 .iov_base = payload,
233 .iov_len = payload->nlmsg_len,
234 };
235 struct msghdr nlmsg = {
236 .msg_name = &nladdr,
237 .msg_namelen = sizeof(nladdr),
238 .msg_iov = &iov,
239 .msg_iovlen = 1,
240 };
241
242 payload->nlmsg_seq = static_cast<__u32>(time(NULL));
243
244 /* request ACK if no cb is used */
245 if (!cb)
246 {
247 payload->nlmsg_flags |= NLM_F_ACK;
248 }
249
250 /* resources that need cleaning on out */
251 void *buf = NULL;
252 int fd = sitnl_socket();
253 if (fd < 0)
254 {
255 OPENVPN_LOG(__func__ << ": can't open rtnl socket");
256 return -errno;
257 }
258
259 if (sitnl_bind(fd, 0) < 0)
260 {
261 OPENVPN_LOG(__func__ << ": can't bind rtnl socket");
262 ret = -errno;
263 goto out;
264 }
265
266 if (sendmsg(fd, &nlmsg, 0) < 0)
267 {
268 OPENVPN_LOG(__func__ << ": rtnl: error on sendmsg()");
269 ret = -errno;
270 goto out;
271 }
272
273 /* prepare buffer to store RTNL replies */
274 buf = calloc(1, buf_len);
275 if (!buf)
276 {
277 ret = -ENOMEM;
278 goto out;
279 }
280
281 iov.iov_base = buf;
282
283 while (1)
284 {
285 /*
286 * iov_len is modified by recvmsg(), therefore has to be initialized before
287 * using it again
288 */
289 OPENVPN_LOG_RTNL(__func__ << ": checking for received messages");
290 iov.iov_len = buf_len;
291 ssize_t rcv_len = recvmsg(fd, &nlmsg, 0);
292 OPENVPN_LOG_RTNL(__func__ << ": rtnl: received " << rcv_len << " bytes");
293 if (rcv_len < 0)
294 {
295 if ((errno == EINTR) || (errno == EAGAIN))
296 {
297 OPENVPN_LOG(__func__ << ": interrupted call");
298 continue;
299 }
300 OPENVPN_LOG(__func__ << ": rtnl: error on recvmsg()");
301 ret = -errno;
302 goto out;
303 }
304
305 if (rcv_len == 0)
306 {
307 OPENVPN_LOG(__func__ << ": rtnl: socket reached unexpected EOF");
308 ret = -EIO;
309 goto out;
310 }
311
312 if (nlmsg.msg_namelen != sizeof(nladdr))
313 {
314 OPENVPN_LOG(__func__ << ": sender address length: "
315 << nlmsg.msg_namelen << " (expected " << sizeof(nladdr)
316 << ")");
317 ret = -EIO;
318 goto out;
319 }
320
321 struct nlmsghdr *h = (struct nlmsghdr *)buf;
322 while (rcv_len >= static_cast<ssize_t>(sizeof(*h)))
323 {
324 const auto len = h->nlmsg_len;
325 const auto data_len = len - sizeof(*h);
326
327 if ((sizeof(*h) > len) || (len > rcv_len))
328 {
329 if (nlmsg.msg_flags & MSG_TRUNC)
330 {
331 OPENVPN_LOG(__func__ << ": truncated message");
332 ret = -EIO;
333 goto out;
334 }
335 OPENVPN_LOG(__func__ << ": malformed message: len=" << len);
336 ret = -EIO;
337 goto out;
338 }
339
340 if (h->nlmsg_type == NLMSG_DONE)
341 {
342 goto out;
343 }
344
345 if (h->nlmsg_type == NLMSG_ERROR)
346 {
347 if (data_len < sizeof(struct nlmsgerr))
348 {
349 OPENVPN_LOG(__func__ << ": ERROR truncated");
350 ret = -EIO;
351 goto out;
352 }
353
354 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
355 if (!err->error)
356 {
357 ret = 0;
358 if (cb)
359 ret = cb(h, arg_cb);
360 }
361 else
362 {
363 OPENVPN_LOG(__func__ << ": rtnl: generic error: "
364 << strerror(-err->error)
365 << " (" << err->error << ")");
366 ret = err->error;
367 }
368 goto out;
369 }
370
371 if (cb)
372 {
373 ret = cb(h, arg_cb);
374 }
375 else
376 {
377 OPENVPN_LOG(__func__ << ": RTNL: unexpected reply");
378 }
379
380 rcv_len -= NLMSG_ALIGN(len);
381 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
382 }
383
384 if (nlmsg.msg_flags & MSG_TRUNC)
385 {
386 OPENVPN_LOG(__func__ << ": message truncated");
387 continue;
388 }
389
390 if (rcv_len)
391 {
392 OPENVPN_LOG(__func__ << ": rtnl: " << rcv_len
393 << " not parsed bytes");
394 ret = -1;
395 goto out;
396 }
397
398 // continue reading multipart message
399 if (!(h->nlmsg_flags & NLM_F_MULTI))
400 goto out;
401 }
402 out:
403 close(fd);
404 free(buf);
405
406 return ret;
407 }
408
409 /* store the route entry resulting from the query */
410 typedef struct
411 {
412 sa_family_t family;
414 std::string iface;
415 std::string iface_to_ignore;
419 } route_res_t;
420
421 static int
422 sitnl_route_save(struct nlmsghdr *n, void *arg)
423 {
424 route_res_t *res = (route_res_t *)arg;
425 struct rtmsg *r = (struct rtmsg *)NLMSG_DATA(n);
426 struct rtattr *rta = RTM_RTA(r);
427 auto len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
428 int ifindex = 0;
429 int metric = 0;
430
431 IP::Addr gw;
432
433 IP::Route route;
434 switch (res->family)
435 {
436 case AF_INET:
437 route = IP::Route("0.0.0.0/0");
438 break;
439 case AF_INET6:
440 route = IP::Route("::/0");
441 break;
442 }
443
444 while (RTA_OK(rta, len))
445 {
446 switch (rta->rta_type)
447 {
448 case RTA_OIF:
449 /* route interface */
450 ifindex = *(unsigned int *)RTA_DATA(rta);
451 break;
452 case RTA_DST:
453 /* route prefix */
454 {
455 const unsigned char *bytestr = (unsigned char *)RTA_DATA(rta);
456 switch (res->family)
457 {
458 case AF_INET:
459 route = IP::Route(IP::Addr::from_ipv4(IPv4::Addr::from_bytes_net(bytestr)), r->rtm_dst_len);
460 route.validate_prefix_length("SITNL route4");
461 break;
462 case AF_INET6:
463 route = IP::Route(IP::Addr::from_ipv6(IPv6::Addr::from_byte_string(bytestr)), r->rtm_dst_len);
464 route.validate_prefix_length("SITNL route6");
465 break;
466 }
467 }
468 break;
469 case RTA_PRIORITY:
470 metric = *(unsigned int *)RTA_DATA(rta);
471 break;
472 case RTA_GATEWAY:
473 /* GW for the route */
474 {
475 const unsigned char *bytestr = (unsigned char *)RTA_DATA(rta);
476 switch (res->family)
477 {
478 case AF_INET:
480 break;
481 case AF_INET6:
483 break;
484 }
485 }
486 break;
487 }
488
489 rta = RTA_NEXT(rta, len);
490 }
491
492 OPENVPN_LOG_RTNL(__func__ << ": ROUTE " << route.to_string()
493 << " metric=" << metric
494 << " ifindex=" << ifindex
495 << " proto=" << int(r->rtm_protocol)
496 << " scope=" << int(r->rtm_scope)
497 << " type=" << int(r->rtm_type)
498 << " table=" << int(r->rtm_table));
499
500 if (!gw.defined() || ifindex <= 0)
501 {
502 return 0;
503 }
504 else
505 {
506 OPENVPN_LOG_RTNL(__func__ << ": RTA_GATEWAY " << gw.to_string());
507 }
508
509 if (!route.contains(res->dst))
510 {
511 OPENVPN_LOG_RTNL(__func__ << ": Ignore gw for unmatched route " << route.to_string());
512 return 0;
513 }
514
515 char iface[IFNAMSIZ];
516 if (!if_indextoname(ifindex, iface))
517 {
518 OPENVPN_LOG(__func__ << ": rtnl: can't get ifname for index "
519 << ifindex);
520 return -1;
521 }
522
523 if (res->iface_to_ignore == iface)
524 {
525 OPENVPN_LOG_RTNL(__func__ << ": Ignore gw " << gw.to_string()
526 << " on " << iface);
527 return 0;
528 }
529
530 // skip if gw's route prefix is shorter
531 if (r->rtm_dst_len < res->prefix_len)
532 {
533 OPENVPN_LOG_RTNL(__func__ << ": Ignore gw " << gw.to_string()
534 << " with shorter route prefix " << route.to_string());
535 return 0;
536 }
537
538 // skip if gw's route metric is higher
539 if ((metric > res->metric) && (res->metric != -1))
540 {
541 OPENVPN_LOG_RTNL(__func__ << ": Ignore gw " << gw.to_string()
542 << " with higher metrics " << metric);
543 return 0;
544 }
545
546 res->iface = iface;
547 res->gw = gw;
548 res->metric = metric;
549 res->prefix_len = r->rtm_dst_len;
550
551 OPENVPN_LOG_RTNL(__func__ << ": Use gw " << gw.to_string()
552 << " route " << route.to_string()
553 << " metric " << metric);
554
555 return 0;
556 }
557
568 static int
569 sitnl_route_best_gw(const std::string &iface_to_ignore,
570 const IP::Route &route,
571 IP::Addr &best_gw,
572 std::string &best_iface)
573 {
574 struct sitnl_route_req req = {};
575 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
576 req.n.nlmsg_type = RTM_GETROUTE;
577 req.n.nlmsg_flags = NLM_F_REQUEST;
578
579 route_res_t res;
580 res.metric = -1;
581 res.prefix_len = -1;
582
583 int ret = -EINVAL;
584
585 if (!is_safe_conversion<unsigned char>(route.addr.family()))
586 return -EINVAL;
587 res.family = req.r.rtm_family = static_cast<unsigned char>(route.addr.family());
588
589 if (!is_safe_conversion<decltype(req.r.rtm_dst_len)>(route.prefix_len))
590 return -EINVAL;
591 req.r.rtm_dst_len = static_cast<decltype(req.r.rtm_dst_len)>(route.prefix_len);
592
593 if (route.addr.family() == AF_INET)
594 {
595 req.n.nlmsg_flags |= NLM_F_DUMP;
596 }
597
598 res.iface_to_ignore = iface_to_ignore;
599 res.dst = route;
600
601 {
602 unsigned char bytestr[IP::Addr::V6_SIZE / 8];
603 route.addr.to_byte_string_variable(bytestr);
604
605 if (!is_safe_conversion<uint16_t>(route.addr.size_bytes()))
606 return -EINVAL;
607 SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, bytestr, static_cast<uint16_t>(route.addr.size_bytes()));
608 }
609
610 ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &res);
611 if (ret >= 0)
612 {
613 /* save result in output variables */
614 best_gw = std::move(res.gw);
615 best_iface = std::move(res.iface);
616
617 OPENVPN_LOG(__func__ << " result: via " << best_gw << " dev " << best_iface);
618 }
619 else
620 {
621 OPENVPN_LOG(__func__ << ": failed to retrieve route, err=" << ret);
622 }
623
624 err:
625 return ret;
626 }
627
628 /* state info for sitnl_iface_addr_save() */
629 typedef struct
630 {
631 sa_family_t family;
632 __u32 ifindex;
635
636 static int
637 sitnl_iface_addr_save(struct nlmsghdr *n, void *arg)
638 {
640 struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(n);
641 struct rtattr *rta = IFA_RTA(ifa);
642 auto len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
643 IP::Route route;
644 struct ifaddrmsg save = {};
645
646 while (RTA_OK(rta, len))
647 {
648 switch (rta->rta_type)
649 {
650 case IFA_ADDRESS:
651 /* interface address */
652 {
653 const unsigned char *bytestr = (unsigned char *)RTA_DATA(rta);
654 switch (res->family)
655 {
656 case AF_INET:
657 route = IP::Route(IP::Addr::from_ipv4(IPv4::Addr::from_bytes_net(bytestr)), ifa->ifa_prefixlen);
658 save = *ifa;
659 OPENVPN_LOG_RTNL(__func__ << ": ADD4 " << route.to_string()
660 << " family=" << int(ifa->ifa_family)
661 << " prefixlen=" << int(ifa->ifa_prefixlen)
662 << " flags=" << int(ifa->ifa_flags)
663 << " scope=" << int(ifa->ifa_scope)
664 << " index=" << int(ifa->ifa_index));
665 break;
666 case AF_INET6:
667 route = IP::Route(IP::Addr::from_ipv6(IPv6::Addr::from_byte_string(bytestr)), ifa->ifa_prefixlen);
668 save = *ifa;
669 OPENVPN_LOG_RTNL(__func__ << ": ADDR6 " << route.to_string()
670 << " family=" << int(ifa->ifa_family)
671 << " prefixlen=" << int(ifa->ifa_prefixlen)
672 << " flags=" << int(ifa->ifa_flags)
673 << " scope=" << int(ifa->ifa_scope)
674 << " index=" << int(ifa->ifa_index));
675 break;
676 }
677 }
678 break;
679 }
680
681 rta = RTA_NEXT(rta, len);
682 }
683
684 if (!res->route.defined() && save.ifa_index == res->ifindex)
685 {
686 res->route = std::move(route);
687 OPENVPN_LOG_RTNL(__func__ << ": MATCH " << res->route.to_string() << " ifindex=" << save.ifa_index);
688 }
689 return 0;
690 }
691
699 static int
700 sitnl_iface_addr(const int ifindex,
701 const int family,
702 IP::Route &route)
703 {
704 struct sitnl_route_req req = {};
705 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
706 req.n.nlmsg_type = RTM_GETADDR;
707 req.n.nlmsg_flags = NLM_F_REQUEST;
708
710 res.ifindex = ifindex;
711
712 if (!is_safe_conversion<unsigned char>(family))
713 return -EINVAL;
714 res.family = req.r.rtm_family = static_cast<unsigned char>(family);
715
716 req.n.nlmsg_flags |= NLM_F_DUMP;
717
718 const auto ret = sitnl_send(&req.n, 0, 0, sitnl_iface_addr_save, &res);
719 if (ret == 0 && res.route.defined())
720 {
721 /* save result in output variables */
722 route = res.route;
723
724 OPENVPN_LOG(__func__ << " result: route " << res.route.to_string()
725 << " ifindex=" << res.ifindex);
726 }
727 else
728 {
729 OPENVPN_LOG(__func__ << ": failed to retrieve addr, err=" << ret);
730 }
731
732 return ret;
733 }
734
735 static int
736 sitnl_addr_set(const unsigned short cmd,
737 const unsigned short flags,
738 const std::string &iface,
739 const IP::Addr &local,
740 const IP::Addr &remote,
741 unsigned char prefixlen,
742 const IP::Addr &broadcast)
743 {
744 struct sitnl_addr_req req = {};
745 int ret = -EINVAL;
746
747 if (iface.empty())
748 {
749 OPENVPN_LOG(__func__ << ": passed empty interface");
750 return -EINVAL;
751 }
752
753 if (local.unspecified())
754 {
755 OPENVPN_LOG(__func__ << ": passed zero IP address");
756 return -EINVAL;
757 }
758
759 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
760 req.n.nlmsg_type = cmd;
761 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
762
763 if (!is_safe_conversion<decltype(req.i.ifa_family)>(local.family()))
764 return -EINVAL;
765 req.i.ifa_family = static_cast<decltype(req.i.ifa_family)>(local.family());
766 req.i.ifa_index = if_nametoindex(iface.c_str());
767 if (req.i.ifa_index == 0)
768 {
769 OPENVPN_LOG(__func__ << ": cannot get ifindex for " << iface << " "
770 << strerror(errno));
771 return -ENOENT;
772 }
773
774 /* if no prefixlen has been specified, assume host address */
775 if (prefixlen == 0)
776 {
777 if (!is_safe_conversion<decltype(prefixlen)>(local.size()))
778 return -EINVAL;
779 prefixlen = static_cast<decltype(prefixlen)>(local.size());
780 }
781 req.i.ifa_prefixlen = prefixlen;
782
783 {
784 unsigned char bytestr[IP::Addr::V6_SIZE / 8];
785
786 local.to_byte_string_variable(bytestr);
787 if (!is_safe_conversion<uint16_t>(local.size_bytes()))
788 return -EINVAL;
789 SITNL_ADDATTR(&req.n, sizeof(req), IFA_LOCAL, bytestr, static_cast<uint16_t>(local.size_bytes()));
790
791 if (remote.specified())
792 {
793 remote.to_byte_string_variable(bytestr);
794 if (!is_safe_conversion<uint16_t>(remote.size_bytes()))
795 return -EINVAL;
796 SITNL_ADDATTR(&req.n, sizeof(req), IFA_ADDRESS, bytestr, static_cast<uint16_t>(remote.size_bytes()));
797 }
798
799 if (broadcast.specified())
800 {
801 broadcast.to_byte_string_variable(bytestr);
802 if (!is_safe_conversion<uint16_t>(broadcast.size_bytes()))
803 return -EINVAL;
804 SITNL_ADDATTR(&req.n, sizeof(req), IFA_BROADCAST, bytestr, static_cast<uint16_t>(broadcast.size_bytes()));
805 }
806 }
807
808 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
809 if ((ret < 0) && (errno == EEXIST))
810 {
811 ret = 0;
812 }
813
814 /* for SITNL_ADDATTR */
815 err:
816 return ret;
817 }
818
819 static int
820 sitnl_addr_ptp_add(const std::string &iface,
821 const IP::Addr &local,
822 const IP::Addr &remote)
823 {
825 NLM_F_CREATE | NLM_F_REPLACE,
826 iface,
827 local,
828 remote,
829 0,
831 }
832
833 static int
834 sitnl_addr_ptp_del(const std::string &iface, const IP::Addr &local)
835 {
837 0,
838 iface,
839 local,
841 0,
843 }
844
845 static int
846 sitnl_route_set(const unsigned short cmd,
847 const unsigned short flags,
848 const std::string &iface,
849 const IP::Route &route,
850 const IP::Addr &gw,
851 const enum rt_class_t table,
852 const int metric,
853 const enum rt_scope_t scope,
854 const unsigned char protocol,
855 const unsigned char type)
856 {
857 struct sitnl_route_req req = {};
858 int ret = -1;
859
860 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
861 req.n.nlmsg_type = cmd;
862 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
863
864 if (!is_safe_conversion<decltype(req.r.rtm_family)>(route.addr.family()))
865 return -1;
866 req.r.rtm_family = static_cast<decltype(req.r.rtm_family)>(route.addr.family());
867 req.r.rtm_scope = scope;
868 req.r.rtm_protocol = protocol;
869 req.r.rtm_type = type;
870 if (!is_safe_conversion<decltype(req.r.rtm_dst_len)>(route.prefix_len))
871 return -1;
872 req.r.rtm_dst_len = static_cast<decltype(req.r.rtm_dst_len)>(route.prefix_len);
873
874 if (table < 256)
875 {
876 req.r.rtm_table = static_cast<decltype(req.r.rtm_table)>(table);
877 }
878 else
879 {
880 req.r.rtm_table = RT_TABLE_UNSPEC;
881 SITNL_ADDATTR(&req.n, sizeof(req), RTA_TABLE, &table, 4);
882 }
883
884 {
885 unsigned char bytestr[IP::Addr::V6_SIZE / 8];
886
887 route.addr.to_byte_string_variable(bytestr);
888 if (!is_safe_conversion<uint16_t>(route.addr.size_bytes()))
889 return -1;
890 SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, bytestr, static_cast<uint16_t>(route.addr.size_bytes()));
891
892 if (gw.specified())
893 {
894 gw.to_byte_string_variable(bytestr);
895 if (!is_safe_conversion<uint16_t>(gw.size_bytes()))
896 return -1;
897 SITNL_ADDATTR(&req.n, sizeof(req), RTA_GATEWAY, bytestr, static_cast<uint16_t>(gw.size_bytes()));
898 }
899 }
900
901 if (!iface.empty())
902 {
903 int ifindex = if_nametoindex(iface.c_str());
904 if (ifindex == 0)
905 {
906 OPENVPN_LOG(__func__ << ": rtnl: cannot get ifindex for " << iface);
907 return -ENOENT;
908 }
909
910 SITNL_ADDATTR(&req.n, sizeof(req), RTA_OIF, &ifindex, 4);
911 }
912
913 if (metric > 0)
914 {
915 SITNL_ADDATTR(&req.n, sizeof(req), RTA_PRIORITY, &metric, 4);
916 }
917
918 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
919 if ((ret < 0) && (errno == EEXIST))
920 {
921 ret = 0;
922 }
923
924 /* for SITNL_ADDATTR */
925 err:
926 return ret;
927 }
928
929 static int
930 sitnl_addr_add(const std::string &iface,
931 const IP::Addr &addr,
932 unsigned char prefixlen,
933 const IP::Addr &broadcast)
934 {
936 NLM_F_CREATE | NLM_F_REPLACE,
937 iface,
938 addr,
940 prefixlen,
941 broadcast);
942 }
943
944 static int
945 sitnl_addr_del(const std::string &iface, const IP::Addr &addr, unsigned char prefixlen)
946 {
948 0,
949 iface,
950 addr,
952 prefixlen,
954 }
955
956 static int
958 const IP::Addr &gw,
959 const std::string &iface,
960 const uint32_t table,
961 const int metric)
962 {
963 return sitnl_route_set(RTM_NEWROUTE,
964 NLM_F_CREATE,
965 iface,
966 route,
967 gw,
968 (enum rt_class_t)(!table ? RT_TABLE_MAIN : table),
969 metric,
970 RT_SCOPE_UNIVERSE,
971 RTPROT_BOOT,
972 RTN_UNICAST);
973 }
974
975 static int
977 const IP::Addr &gw,
978 const std::string &iface,
979 const uint32_t table,
980 const int metric)
981 {
982 return sitnl_route_set(RTM_DELROUTE,
983 0,
984 iface,
985 route,
986 gw,
987 (enum rt_class_t)(!table ? RT_TABLE_MAIN : table),
988 metric,
989 RT_SCOPE_NOWHERE,
990 0,
991 0);
992 }
993
994 public:
995 static int
997 IPv6::Addr &best_gw6,
998 std::string &best_iface,
999 const std::string &iface_to_ignore = "")
1000 {
1001 IP::Addr best_gw;
1002
1003 OPENVPN_LOG(__func__ << " query IPv6: " << route);
1004
1005 const auto ret = sitnl_route_best_gw(iface_to_ignore,
1007 best_gw,
1008 best_iface);
1009 if (ret == 0)
1010 {
1011 best_gw6 = best_gw.to_ipv6();
1012 }
1013
1014 return ret;
1015 }
1016
1017 static int
1019 IPv4::Addr &best_gw4,
1020 std::string &best_iface,
1021 const std::string &iface_to_ignore = "")
1022 {
1023 IP::Addr best_gw;
1024
1025 OPENVPN_LOG(__func__ << " query IPv4: " << route);
1026
1027 const auto ret = sitnl_route_best_gw(iface_to_ignore,
1029 best_gw,
1030 best_iface);
1031 if (ret == 0)
1032 {
1033 best_gw4 = best_gw.to_ipv4();
1034 }
1035
1036 return ret;
1037 }
1038
1046 static IP::Route
1047 net_iface_addr(const std::string &iface,
1048 const int family)
1049 {
1050 unsigned int ifindex = if_nametoindex(iface.c_str());
1051 if (ifindex)
1052 {
1053 IP::Route route;
1054 const auto ret = sitnl_iface_addr(ifindex, family, route);
1055 if (ret == 0)
1056 return route;
1057 }
1058 return IP::Route();
1059 }
1060
1068 static int
1069 net_iface_new(const std::string &iface, const std::string &type)
1070 {
1071 struct sitnl_link_req req = {};
1072 struct rtattr *tail = NULL;
1073
1074 if (iface.empty())
1075 {
1076 OPENVPN_LOG(__func__ << ": passed empty interface");
1077 return -EINVAL;
1078 }
1079
1080 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1081 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
1082 req.n.nlmsg_type = RTM_NEWLINK;
1083
1084 if (!is_safe_conversion<uint16_t>(iface.length() + 1))
1085 return -1;
1086 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_IFNAME, iface.c_str(), static_cast<uint16_t>(iface.length() + 1));
1087 tail = NLMSG_TAIL(&req.n);
1088 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
1089 if (!is_safe_conversion<uint16_t>(type.length() + 1))
1090 return -1;
1091 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_INFO_KIND, type.c_str(), static_cast<uint16_t>(type.length() + 1));
1092 if (!is_safe_conversion<decltype(tail->rta_len)>((uint8_t *)NLMSG_TAIL(&req.n) - (uint8_t *)tail))
1093 return -1;
1094 tail->rta_len = static_cast<decltype(tail->rta_len)>((uint8_t *)NLMSG_TAIL(&req.n) - (uint8_t *)tail);
1095
1096 req.i.ifi_family = AF_PACKET;
1097 req.i.ifi_index = 0;
1098
1099 OPENVPN_LOG(__func__ << ": add " << iface << " type " << type);
1100
1101 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1102 /* for SITNL_ADDATTR */
1103 err:
1104 return -1;
1105 }
1106
1107 static int
1108 net_iface_del(const std::string &iface)
1109 {
1110 struct sitnl_link_req req = {};
1111 int ifindex;
1112
1113 if (iface.empty())
1114 {
1115 OPENVPN_LOG(__func__ << ": passed empty interface");
1116 return -EINVAL;
1117 }
1118
1119 ifindex = if_nametoindex(iface.c_str());
1120 if (ifindex == 0)
1121 {
1122 OPENVPN_LOG(__func__ << ": rtnl: cannot get ifindex for " << iface
1123 << ": " << strerror(errno));
1124 return -ENOENT;
1125 }
1126
1127 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1128 req.n.nlmsg_flags = NLM_F_REQUEST;
1129 req.n.nlmsg_type = RTM_DELLINK;
1130
1131 req.i.ifi_family = AF_PACKET;
1132 req.i.ifi_index = ifindex;
1133
1134 OPENVPN_LOG(__func__ << ": del " << iface);
1135
1136 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1137 }
1138
1139 static int
1140 net_iface_up(std::string &iface, bool up)
1141 {
1142 struct sitnl_link_req req = {};
1143 int ifindex;
1144
1145 if (iface.empty())
1146 {
1147 OPENVPN_LOG(__func__ << ": passed empty interface");
1148 return -EINVAL;
1149 }
1150
1151 ifindex = if_nametoindex(iface.c_str());
1152 if (ifindex == 0)
1153 {
1154 OPENVPN_LOG(__func__ << ": rtnl: cannot get ifindex for " << iface
1155 << ": " << strerror(errno));
1156 return -ENOENT;
1157 }
1158
1159 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1160 req.n.nlmsg_flags = NLM_F_REQUEST;
1161 req.n.nlmsg_type = RTM_NEWLINK;
1162
1163 req.i.ifi_family = AF_PACKET;
1164 req.i.ifi_index = ifindex;
1165 req.i.ifi_change |= IFF_UP;
1166 if (up)
1167 {
1168 req.i.ifi_flags |= IFF_UP;
1169 }
1170 else
1171 {
1172 req.i.ifi_flags &= ~IFF_UP;
1173 }
1174
1175 OPENVPN_LOG(__func__ << ": set " << iface << " " << (up ? "up" : "down"));
1176
1177 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1178 }
1179
1180 static int
1181 net_iface_mtu_set(std::string &iface, uint32_t mtu)
1182 {
1183 struct sitnl_link_req req = {};
1184 int ifindex;
1185
1186 if (iface.empty())
1187 {
1188 OPENVPN_LOG(__func__ << ": passed empty interface");
1189 return -EINVAL;
1190 }
1191
1192 ifindex = if_nametoindex(iface.c_str());
1193 if (ifindex == 0)
1194 {
1195 OPENVPN_LOG(__func__ << ": rtnl: cannot get ifindex for " << iface);
1196 return -1;
1197 }
1198
1199 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1200 req.n.nlmsg_flags = NLM_F_REQUEST;
1201 req.n.nlmsg_type = RTM_NEWLINK;
1202
1203 req.i.ifi_family = AF_PACKET;
1204 req.i.ifi_index = ifindex;
1205
1206 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_MTU, &mtu, 4);
1207
1208 OPENVPN_LOG(__func__ << ": mtu " << mtu << " for " << iface);
1209
1210 err:
1211 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1212 }
1213
1214 static int
1215 net_addr_add(const std::string &iface,
1216 const IPv4::Addr &addr,
1217 const unsigned char prefixlen,
1218 const IPv4::Addr &broadcast)
1219 {
1220 OPENVPN_LOG(__func__ << ": " << addr << "/" << +prefixlen
1221 << " brd " << broadcast
1222 << " dev " << iface);
1223
1224 return sitnl_addr_add(iface,
1225 IP::Addr::from_ipv4(addr),
1226 prefixlen,
1227 IP::Addr::from_ipv4(broadcast));
1228 }
1229
1230 static int
1231 net_addr_add(const std::string &iface,
1232 const IPv6::Addr &addr,
1233 const unsigned char prefixlen)
1234 {
1235 OPENVPN_LOG(__func__ << ": " << addr << "/" << +prefixlen
1236 << " dev " << iface);
1237
1238 return sitnl_addr_add(iface,
1239 IP::Addr::from_ipv6(addr),
1240 prefixlen,
1242 }
1243
1244 static int
1245 net_addr_del(const std::string &iface,
1246 const IPv4::Addr &addr,
1247 const unsigned char prefixlen)
1248 {
1249 OPENVPN_LOG(__func__ << ": " << addr << "/" << +prefixlen
1250 << " dev " << iface);
1251
1252 return sitnl_addr_del(iface,
1253 IP::Addr::from_ipv4(addr),
1254 prefixlen);
1255 }
1256
1257 static int
1258 net_addr_del(const std::string &iface,
1259 const IPv6::Addr &addr,
1260 const unsigned char prefixlen)
1261 {
1262 OPENVPN_LOG(__func__ << ": " << addr << "/" << +prefixlen
1263 << " dev " << iface);
1264
1265 return sitnl_addr_del(iface,
1266 IP::Addr::from_ipv6(addr),
1267 prefixlen);
1268 }
1269
1270 static int
1271 net_addr_ptp_add(const std::string &iface,
1272 const IPv4::Addr &local,
1273 const IPv4::Addr &remote)
1274 {
1275 OPENVPN_LOG(__func__ << ": " << local
1276 << " peer " << remote
1277 << " dev " << iface);
1278
1279 return sitnl_addr_ptp_add(iface,
1280 IP::Addr::from_ipv4(local),
1281 IP::Addr::from_ipv4(remote));
1282 }
1283
1284 static int
1285 net_addr_ptp_del(const std::string &iface,
1286 const IPv4::Addr &local,
1287 const IPv4::Addr &remote)
1288 {
1289 OPENVPN_LOG(__func__ << ": " << local
1290 << " dev " << iface);
1291
1292 return sitnl_addr_ptp_del(iface,
1293 IP::Addr::from_ipv4(local));
1294 }
1295
1296 static int
1298 const IPv4::Addr &gw,
1299 const std::string &iface,
1300 const uint32_t table,
1301 const int metric)
1302 {
1303 OPENVPN_LOG(__func__ << ": " << route
1304 << " via " << gw
1305 << " dev " << iface
1306 << " table " << table
1307 << " metric " << metric);
1308
1311 iface,
1312 table,
1313 metric);
1314 }
1315
1316 static int
1318 const IPv6::Addr &gw,
1319 const std::string &iface,
1320 const uint32_t table,
1321 const int metric)
1322 {
1323 OPENVPN_LOG(__func__ << ": " << route
1324 << " via " << gw
1325 << " dev " << iface
1326 << " table " << table
1327 << " metric " << metric);
1328
1331 iface,
1332 table,
1333 metric);
1334 }
1335
1336 static int
1338 const IPv4::Addr &gw,
1339 const std::string &iface,
1340 const uint32_t table,
1341 const int metric)
1342 {
1343 OPENVPN_LOG(__func__ << ": " << route << " via " << gw << " dev " << iface
1344 << " table " << table << " metric " << metric);
1345
1348 iface,
1349 table,
1350 metric);
1351 }
1352
1353 static int
1355 const IPv6::Addr &gw,
1356 const std::string &iface,
1357 const uint32_t table,
1358 const int metric)
1359 {
1360 OPENVPN_LOG(__func__ << ": " << route
1361 << " via " << gw
1362 << " dev " << iface
1363 << " table " << table
1364 << " metric " << metric);
1365
1368 iface,
1369 table,
1370 metric);
1371 }
1372};
1373} // namespace openvpn::TunNetlink
bool specified() const
Definition ip.hpp:811
Version version() const
Definition ip.hpp:895
std::string to_string() const
Definition ip.hpp:528
unsigned int size() const
Definition ip.hpp:1016
unsigned int size_bytes() const
Definition ip.hpp:1022
const IPv4::Addr & to_ipv4() const
Definition ip.hpp:276
bool defined() const
Definition ip.hpp:872
const IPv6::Addr & to_ipv6() const
Definition ip.hpp:296
int family() const
Definition ip.hpp:931
static Addr from_ipv6(IPv6::Addr addr)
Definition ip.hpp:268
static Addr from_ipv4(IPv4::Addr addr)
Definition ip.hpp:260
void to_byte_string_variable(unsigned char *bytestr) const
Definition ip.hpp:429
static Addr from_zero(const Version v)
Definition ip.hpp:450
bool unspecified() const
Definition ip.hpp:806
void validate_prefix_length(const TITLE &title)
Definition route.hpp:91
std::string to_string() const
Definition route.hpp:237
unsigned int prefix_len
Definition route.hpp:38
bool defined() const
Definition route.hpp:134
bool contains(const ADDR &a) const
Definition route.hpp:208
static Addr from_bytes_net(const unsigned char *bytes)
Definition ipv4.hpp:160
static Addr from_byte_string(const unsigned char *bytestr)
Definition ipv6.hpp:254
#define OPENVPN_LOG(args)
RouteType< IP::Addr > Route
Definition route.hpp:357
bool is_safe_conversion(InT inVal)
Returns true if the given value can be contained by the out type.
#define RTM_DELADDR
Definition net-route.h:201
#define RTA_DST
Definition net-route.h:224
#define RTM_NEWADDR
Definition net-route.h:200
#define RTA_GATEWAY
Definition net-route.h:225
#define NLMSG_TAIL(nmsg)
Definition sitnl.hpp:52
#define OPENVPN_LOG_RTNL(_x)
Definition sitnl.hpp:35
#define SITNL_ADDATTR(_msg, _max_size, _attr, _data, _size)
Definition sitnl.hpp:44
#define RCVBUF_SIZE
Definition sitnl.hpp:42
#define SNDBUF_SIZE
Definition sitnl.hpp:41
const auto metric
reroute_gw flags
std::string ret
static std::stringstream out
Definition test_path.cpp:10
#define msg(flags,...)