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 using sitnl_parse_reply_cb = int (*)(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 */
411 {
412 sa_family_t family;
414 std::string iface;
415 std::string iface_to_ignore;
419 };
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
505 OPENVPN_LOG_RTNL(__func__ << ": RTA_GATEWAY " << gw.to_string());
506
507
508 if (!route.contains(res->dst))
509 {
510 OPENVPN_LOG_RTNL(__func__ << ": Ignore gw for unmatched route " << route.to_string());
511 return 0;
512 }
513
514 char iface[IFNAMSIZ];
515 if (!if_indextoname(ifindex, iface))
516 {
517 OPENVPN_LOG(__func__ << ": rtnl: can't get ifname for index "
518 << ifindex);
519 return -1;
520 }
521
522 if (res->iface_to_ignore == iface)
523 {
524 OPENVPN_LOG_RTNL(__func__ << ": Ignore gw " << gw.to_string()
525 << " on " << iface);
526 return 0;
527 }
528
529 // skip if gw's route prefix is shorter
530 if (r->rtm_dst_len < res->prefix_len)
531 {
532 OPENVPN_LOG_RTNL(__func__ << ": Ignore gw " << gw.to_string()
533 << " with shorter route prefix " << route.to_string());
534 return 0;
535 }
536
537 // skip if gw's route metric is higher
538 if ((metric > res->metric) && (res->metric != -1))
539 {
540 OPENVPN_LOG_RTNL(__func__ << ": Ignore gw " << gw.to_string()
541 << " with higher metrics " << metric);
542 return 0;
543 }
544
545 res->iface = iface;
546 res->gw = gw;
547 res->metric = metric;
548 res->prefix_len = r->rtm_dst_len;
549
550 OPENVPN_LOG_RTNL(__func__ << ": Use gw " << gw.to_string()
551 << " route " << route.to_string()
552 << " metric " << metric);
553
554 return 0;
555 }
556
567 static int
568 sitnl_route_best_gw(const std::string &iface_to_ignore,
569 const IP::Route &route,
570 IP::Addr &best_gw,
571 std::string &best_iface)
572 {
573 struct sitnl_route_req req = {};
574 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
575 req.n.nlmsg_type = RTM_GETROUTE;
576 req.n.nlmsg_flags = NLM_F_REQUEST;
577
578 route_res_t res;
579 res.metric = -1;
580 res.prefix_len = -1;
581
582 int ret = -EINVAL;
583
584 if (!is_safe_conversion<unsigned char>(route.addr.family()))
585 return -EINVAL;
586 res.family = req.r.rtm_family = static_cast<unsigned char>(route.addr.family());
587
588 if (!is_safe_conversion<decltype(req.r.rtm_dst_len)>(route.prefix_len))
589 return -EINVAL;
590 req.r.rtm_dst_len = static_cast<decltype(req.r.rtm_dst_len)>(route.prefix_len);
591
592 if (route.addr.family() == AF_INET)
593 {
594 req.n.nlmsg_flags |= NLM_F_DUMP;
595 }
596
597 res.iface_to_ignore = iface_to_ignore;
598 res.dst = route;
599
600 {
601 unsigned char bytestr[IP::Addr::V6_SIZE / 8];
602 route.addr.to_byte_string_variable(bytestr);
603
604 if (!is_safe_conversion<uint16_t>(route.addr.size_bytes()))
605 return -EINVAL;
606 SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, bytestr, static_cast<uint16_t>(route.addr.size_bytes()));
607 }
608
609 ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &res);
610 if (ret >= 0)
611 {
612 /* save result in output variables */
613 best_gw = std::move(res.gw);
614 best_iface = std::move(res.iface);
615
616 OPENVPN_LOG(__func__ << " result: via " << best_gw << " dev " << best_iface);
617 }
618 else
619 {
620 OPENVPN_LOG(__func__ << ": failed to retrieve route, err=" << ret);
621 }
622
623 err:
624 return ret;
625 }
626
627 /* state info for sitnl_iface_addr_save() */
629 {
630 sa_family_t family;
631 __u32 ifindex;
633 };
634
635 static int
636 sitnl_iface_addr_save(struct nlmsghdr *n, void *arg)
637 {
639 struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(n);
640 struct rtattr *rta = IFA_RTA(ifa);
641 auto len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
642 IP::Route route;
643 struct ifaddrmsg save = {};
644
645 while (RTA_OK(rta, len))
646 {
647 switch (rta->rta_type)
648 {
649 case IFA_ADDRESS:
650 /* interface address */
651 {
652 const unsigned char *bytestr = (unsigned char *)RTA_DATA(rta);
653 switch (res->family)
654 {
655 case AF_INET:
656 route = IP::Route(IP::Addr::from_ipv4(IPv4::Addr::from_bytes_net(bytestr)), ifa->ifa_prefixlen);
657 save = *ifa;
658 OPENVPN_LOG_RTNL(__func__ << ": ADD4 " << route.to_string()
659 << " family=" << int(ifa->ifa_family)
660 << " prefixlen=" << int(ifa->ifa_prefixlen)
661 << " flags=" << int(ifa->ifa_flags)
662 << " scope=" << int(ifa->ifa_scope)
663 << " index=" << int(ifa->ifa_index));
664 break;
665 case AF_INET6:
666 route = IP::Route(IP::Addr::from_ipv6(IPv6::Addr::from_byte_string(bytestr)), ifa->ifa_prefixlen);
667 save = *ifa;
668 OPENVPN_LOG_RTNL(__func__ << ": ADDR6 " << route.to_string()
669 << " family=" << int(ifa->ifa_family)
670 << " prefixlen=" << int(ifa->ifa_prefixlen)
671 << " flags=" << int(ifa->ifa_flags)
672 << " scope=" << int(ifa->ifa_scope)
673 << " index=" << int(ifa->ifa_index));
674 break;
675 }
676 }
677 break;
678 }
679
680 rta = RTA_NEXT(rta, len);
681 }
682
683 if (!res->route.defined() && save.ifa_index == res->ifindex)
684 {
685 res->route = std::move(route);
686 OPENVPN_LOG_RTNL(__func__ << ": MATCH " << res->route.to_string() << " ifindex=" << save.ifa_index);
687 }
688 return 0;
689 }
690
698 static int
699 sitnl_iface_addr(const int ifindex,
700 const int family,
701 IP::Route &route)
702 {
703 struct sitnl_route_req req = {};
704 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
705 req.n.nlmsg_type = RTM_GETADDR;
706 req.n.nlmsg_flags = NLM_F_REQUEST;
707
709 res.ifindex = ifindex;
710
711 if (!is_safe_conversion<unsigned char>(family))
712 return -EINVAL;
713 res.family = req.r.rtm_family = static_cast<unsigned char>(family);
714
715 req.n.nlmsg_flags |= NLM_F_DUMP;
716
717 const auto ret = sitnl_send(&req.n, 0, 0, sitnl_iface_addr_save, &res);
718 if (ret == 0 && res.route.defined())
719 {
720 /* save result in output variables */
721 route = res.route;
722
723 OPENVPN_LOG(__func__ << " result: route " << res.route.to_string()
724 << " ifindex=" << res.ifindex);
725 }
726 else
727 {
728 OPENVPN_LOG(__func__ << ": failed to retrieve addr, err=" << ret);
729 }
730
731 return ret;
732 }
733
734 static int
735 sitnl_addr_set(const unsigned short cmd,
736 const unsigned short flags,
737 const std::string &iface,
738 const IP::Addr &local,
739 const IP::Addr &remote,
740 unsigned char prefixlen,
741 const IP::Addr &broadcast)
742 {
743 struct sitnl_addr_req req = {};
744 int ret = -EINVAL;
745
746 if (iface.empty())
747 {
748 OPENVPN_LOG(__func__ << ": passed empty interface");
749 return -EINVAL;
750 }
751
752 if (local.unspecified())
753 {
754 OPENVPN_LOG(__func__ << ": passed zero IP address");
755 return -EINVAL;
756 }
757
758 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
759 req.n.nlmsg_type = cmd;
760 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
761
762 if (!is_safe_conversion<decltype(req.i.ifa_family)>(local.family()))
763 return -EINVAL;
764 req.i.ifa_family = static_cast<decltype(req.i.ifa_family)>(local.family());
765 req.i.ifa_index = if_nametoindex(iface.c_str());
766 if (req.i.ifa_index == 0)
767 {
768 OPENVPN_LOG(__func__ << ": cannot get ifindex for " << iface << " "
769 << strerror(errno));
770 return -ENOENT;
771 }
772
773 /* if no prefixlen has been specified, assume host address */
774 if (prefixlen == 0)
775 {
776 if (!is_safe_conversion<decltype(prefixlen)>(local.size()))
777 return -EINVAL;
778 prefixlen = static_cast<decltype(prefixlen)>(local.size());
779 }
780 req.i.ifa_prefixlen = prefixlen;
781
782 {
783 unsigned char bytestr[IP::Addr::V6_SIZE / 8];
784
785 local.to_byte_string_variable(bytestr);
786 if (!is_safe_conversion<uint16_t>(local.size_bytes()))
787 return -EINVAL;
788 SITNL_ADDATTR(&req.n, sizeof(req), IFA_LOCAL, bytestr, static_cast<uint16_t>(local.size_bytes()));
789
790 if (remote.specified())
791 {
792 remote.to_byte_string_variable(bytestr);
793 if (!is_safe_conversion<uint16_t>(remote.size_bytes()))
794 return -EINVAL;
795 SITNL_ADDATTR(&req.n, sizeof(req), IFA_ADDRESS, bytestr, static_cast<uint16_t>(remote.size_bytes()));
796 }
797
798 if (broadcast.specified())
799 {
800 broadcast.to_byte_string_variable(bytestr);
801 if (!is_safe_conversion<uint16_t>(broadcast.size_bytes()))
802 return -EINVAL;
803 SITNL_ADDATTR(&req.n, sizeof(req), IFA_BROADCAST, bytestr, static_cast<uint16_t>(broadcast.size_bytes()));
804 }
805 }
806
807 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
808 if ((ret < 0) && (errno == EEXIST))
809 {
810 ret = 0;
811 }
812
813 /* for SITNL_ADDATTR */
814 err:
815 return ret;
816 }
817
818 static int
819 sitnl_addr_ptp_add(const std::string &iface,
820 const IP::Addr &local,
821 const IP::Addr &remote)
822 {
824 NLM_F_CREATE | NLM_F_REPLACE,
825 iface,
826 local,
827 remote,
828 0,
830 }
831
832 static int
833 sitnl_addr_ptp_del(const std::string &iface, const IP::Addr &local)
834 {
836 0,
837 iface,
838 local,
840 0,
842 }
843
844 static int
845 sitnl_route_set(const unsigned short cmd,
846 const unsigned short flags,
847 const std::string &iface,
848 const IP::Route &route,
849 const IP::Addr &gw,
850 const enum rt_class_t table,
851 const int metric,
852 const enum rt_scope_t scope,
853 const unsigned char protocol,
854 const unsigned char type)
855 {
856 struct sitnl_route_req req = {};
857 int ret = -1;
858
859 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
860 req.n.nlmsg_type = cmd;
861 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
862
863 if (!is_safe_conversion<decltype(req.r.rtm_family)>(route.addr.family()))
864 return -1;
865 req.r.rtm_family = static_cast<decltype(req.r.rtm_family)>(route.addr.family());
866 req.r.rtm_scope = scope;
867 req.r.rtm_protocol = protocol;
868 req.r.rtm_type = type;
869 if (!is_safe_conversion<decltype(req.r.rtm_dst_len)>(route.prefix_len))
870 return -1;
871 req.r.rtm_dst_len = static_cast<decltype(req.r.rtm_dst_len)>(route.prefix_len);
872
873 if (table < 256)
874 {
875 req.r.rtm_table = static_cast<decltype(req.r.rtm_table)>(table);
876 }
877 else
878 {
879 req.r.rtm_table = RT_TABLE_UNSPEC;
880 SITNL_ADDATTR(&req.n, sizeof(req), RTA_TABLE, &table, 4);
881 }
882
883 {
884 unsigned char bytestr[IP::Addr::V6_SIZE / 8];
885
886 route.addr.to_byte_string_variable(bytestr);
887 if (!is_safe_conversion<uint16_t>(route.addr.size_bytes()))
888 return -1;
889 SITNL_ADDATTR(&req.n, sizeof(req), RTA_DST, bytestr, static_cast<uint16_t>(route.addr.size_bytes()));
890
891 if (gw.specified())
892 {
893 gw.to_byte_string_variable(bytestr);
894 if (!is_safe_conversion<uint16_t>(gw.size_bytes()))
895 return -1;
896 SITNL_ADDATTR(&req.n, sizeof(req), RTA_GATEWAY, bytestr, static_cast<uint16_t>(gw.size_bytes()));
897 }
898 }
899
900 if (!iface.empty())
901 {
902 int ifindex = if_nametoindex(iface.c_str());
903 if (ifindex == 0)
904 {
905 OPENVPN_LOG(__func__ << ": rtnl: cannot get ifindex for " << iface);
906 return -ENOENT;
907 }
908
909 SITNL_ADDATTR(&req.n, sizeof(req), RTA_OIF, &ifindex, 4);
910 }
911
912 if (metric > 0)
913 {
914 SITNL_ADDATTR(&req.n, sizeof(req), RTA_PRIORITY, &metric, 4);
915 }
916
917 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
918 if ((ret < 0) && (errno == EEXIST))
919 {
920 ret = 0;
921 }
922
923 /* for SITNL_ADDATTR */
924 err:
925 return ret;
926 }
927
928 static int
929 sitnl_addr_add(const std::string &iface,
930 const IP::Addr &addr,
931 unsigned char prefixlen,
932 const IP::Addr &broadcast)
933 {
935 NLM_F_CREATE | NLM_F_REPLACE,
936 iface,
937 addr,
939 prefixlen,
940 broadcast);
941 }
942
943 static int
944 sitnl_addr_del(const std::string &iface, const IP::Addr &addr, unsigned char prefixlen)
945 {
947 0,
948 iface,
949 addr,
951 prefixlen,
953 }
954
955 static int
957 const IP::Addr &gw,
958 const std::string &iface,
959 const uint32_t table,
960 const int metric)
961 {
962 return sitnl_route_set(RTM_NEWROUTE,
963 NLM_F_CREATE,
964 iface,
965 route,
966 gw,
967 (enum rt_class_t)(!table ? RT_TABLE_MAIN : table),
968 metric,
969 RT_SCOPE_UNIVERSE,
970 RTPROT_BOOT,
971 RTN_UNICAST);
972 }
973
974 static int
976 const IP::Addr &gw,
977 const std::string &iface,
978 const uint32_t table,
979 const int metric)
980 {
981 return sitnl_route_set(RTM_DELROUTE,
982 0,
983 iface,
984 route,
985 gw,
986 (enum rt_class_t)(!table ? RT_TABLE_MAIN : table),
987 metric,
988 RT_SCOPE_NOWHERE,
989 0,
990 0);
991 }
992
993 public:
994 static int
996 IPv6::Addr &best_gw6,
997 std::string &best_iface,
998 const std::string &iface_to_ignore = "")
999 {
1000 IP::Addr best_gw;
1001
1002 OPENVPN_LOG(__func__ << " query IPv6: " << route);
1003
1004 const auto ret = sitnl_route_best_gw(iface_to_ignore,
1006 best_gw,
1007 best_iface);
1008 if (ret == 0)
1009 {
1010 best_gw6 = best_gw.to_ipv6();
1011 }
1012
1013 return ret;
1014 }
1015
1016 static int
1018 IPv4::Addr &best_gw4,
1019 std::string &best_iface,
1020 const std::string &iface_to_ignore = "")
1021 {
1022 IP::Addr best_gw;
1023
1024 OPENVPN_LOG(__func__ << " query IPv4: " << route);
1025
1026 const auto ret = sitnl_route_best_gw(iface_to_ignore,
1028 best_gw,
1029 best_iface);
1030 if (ret == 0)
1031 {
1032 best_gw4 = best_gw.to_ipv4();
1033 }
1034
1035 return ret;
1036 }
1037
1045 static IP::Route
1046 net_iface_addr(const std::string &iface,
1047 const int family)
1048 {
1049 unsigned int ifindex = if_nametoindex(iface.c_str());
1050 if (ifindex)
1051 {
1052 IP::Route route;
1053 const auto ret = sitnl_iface_addr(ifindex, family, route);
1054 if (ret == 0)
1055 return route;
1056 }
1057 return IP::Route();
1058 }
1059
1067 static int
1068 net_iface_new(const std::string &iface, const std::string &type)
1069 {
1070 struct sitnl_link_req req = {};
1071 struct rtattr *tail = NULL;
1072
1073 if (iface.empty())
1074 {
1075 OPENVPN_LOG(__func__ << ": passed empty interface");
1076 return -EINVAL;
1077 }
1078
1079 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1080 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
1081 req.n.nlmsg_type = RTM_NEWLINK;
1082
1083 if (!is_safe_conversion<uint16_t>(iface.length() + 1))
1084 return -1;
1085 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_IFNAME, iface.c_str(), static_cast<uint16_t>(iface.length() + 1));
1086 tail = NLMSG_TAIL(&req.n);
1087 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
1088 if (!is_safe_conversion<uint16_t>(type.length() + 1))
1089 return -1;
1090 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_INFO_KIND, type.c_str(), static_cast<uint16_t>(type.length() + 1));
1091 if (!is_safe_conversion<decltype(tail->rta_len)>((uint8_t *)NLMSG_TAIL(&req.n) - (uint8_t *)tail))
1092 return -1;
1093 tail->rta_len = static_cast<decltype(tail->rta_len)>((uint8_t *)NLMSG_TAIL(&req.n) - (uint8_t *)tail);
1094
1095 req.i.ifi_family = AF_PACKET;
1096 req.i.ifi_index = 0;
1097
1098 OPENVPN_LOG(__func__ << ": add " << iface << " type " << type);
1099
1100 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1101 /* for SITNL_ADDATTR */
1102 err:
1103 return -1;
1104 }
1105
1106 static int
1107 net_iface_del(const std::string &iface)
1108 {
1109 struct sitnl_link_req req = {};
1110 int ifindex;
1111
1112 if (iface.empty())
1113 {
1114 OPENVPN_LOG(__func__ << ": passed empty interface");
1115 return -EINVAL;
1116 }
1117
1118 ifindex = if_nametoindex(iface.c_str());
1119 if (ifindex == 0)
1120 {
1121 OPENVPN_LOG(__func__ << ": rtnl: cannot get ifindex for " << iface
1122 << ": " << strerror(errno));
1123 return -ENOENT;
1124 }
1125
1126 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1127 req.n.nlmsg_flags = NLM_F_REQUEST;
1128 req.n.nlmsg_type = RTM_DELLINK;
1129
1130 req.i.ifi_family = AF_PACKET;
1131 req.i.ifi_index = ifindex;
1132
1133 OPENVPN_LOG(__func__ << ": del " << iface);
1134
1135 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1136 }
1137
1138 static int
1139 net_iface_up(std::string &iface, bool up)
1140 {
1141 struct sitnl_link_req req = {};
1142 int ifindex;
1143
1144 if (iface.empty())
1145 {
1146 OPENVPN_LOG(__func__ << ": passed empty interface");
1147 return -EINVAL;
1148 }
1149
1150 ifindex = if_nametoindex(iface.c_str());
1151 if (ifindex == 0)
1152 {
1153 OPENVPN_LOG(__func__ << ": rtnl: cannot get ifindex for " << iface
1154 << ": " << strerror(errno));
1155 return -ENOENT;
1156 }
1157
1158 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1159 req.n.nlmsg_flags = NLM_F_REQUEST;
1160 req.n.nlmsg_type = RTM_NEWLINK;
1161
1162 req.i.ifi_family = AF_PACKET;
1163 req.i.ifi_index = ifindex;
1164 req.i.ifi_change |= IFF_UP;
1165 if (up)
1166 {
1167 req.i.ifi_flags |= IFF_UP;
1168 }
1169 else
1170 {
1171 req.i.ifi_flags &= ~IFF_UP;
1172 }
1173
1174 OPENVPN_LOG(__func__ << ": set " << iface << " " << (up ? "up" : "down"));
1175
1176 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1177 }
1178
1179 static int
1180 net_iface_mtu_set(std::string &iface, uint32_t mtu)
1181 {
1182 struct sitnl_link_req req = {};
1183 int ifindex;
1184
1185 if (iface.empty())
1186 {
1187 OPENVPN_LOG(__func__ << ": passed empty interface");
1188 return -EINVAL;
1189 }
1190
1191 ifindex = if_nametoindex(iface.c_str());
1192 if (ifindex == 0)
1193 {
1194 OPENVPN_LOG(__func__ << ": rtnl: cannot get ifindex for " << iface);
1195 return -1;
1196 }
1197
1198 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
1199 req.n.nlmsg_flags = NLM_F_REQUEST;
1200 req.n.nlmsg_type = RTM_NEWLINK;
1201
1202 req.i.ifi_family = AF_PACKET;
1203 req.i.ifi_index = ifindex;
1204
1205 SITNL_ADDATTR(&req.n, sizeof(req), IFLA_MTU, &mtu, 4);
1206
1207 OPENVPN_LOG(__func__ << ": mtu " << mtu << " for " << iface);
1208
1209 err:
1210 return sitnl_send(&req.n, 0, 0, NULL, NULL);
1211 }
1212
1213 static int
1214 net_addr_add(const std::string &iface,
1215 const IPv4::Addr &addr,
1216 const unsigned char prefixlen,
1217 const IPv4::Addr &broadcast)
1218 {
1219 OPENVPN_LOG(__func__ << ": " << addr << "/" << +prefixlen
1220 << " brd " << broadcast
1221 << " dev " << iface);
1222
1223 return sitnl_addr_add(iface,
1224 IP::Addr::from_ipv4(addr),
1225 prefixlen,
1226 IP::Addr::from_ipv4(broadcast));
1227 }
1228
1229 static int
1230 net_addr_add(const std::string &iface,
1231 const IPv6::Addr &addr,
1232 const unsigned char prefixlen)
1233 {
1234 OPENVPN_LOG(__func__ << ": " << addr << "/" << +prefixlen
1235 << " dev " << iface);
1236
1237 return sitnl_addr_add(iface,
1238 IP::Addr::from_ipv6(addr),
1239 prefixlen,
1241 }
1242
1243 static int
1244 net_addr_del(const std::string &iface,
1245 const IPv4::Addr &addr,
1246 const unsigned char prefixlen)
1247 {
1248 OPENVPN_LOG(__func__ << ": " << addr << "/" << +prefixlen
1249 << " dev " << iface);
1250
1251 return sitnl_addr_del(iface,
1252 IP::Addr::from_ipv4(addr),
1253 prefixlen);
1254 }
1255
1256 static int
1257 net_addr_del(const std::string &iface,
1258 const IPv6::Addr &addr,
1259 const unsigned char prefixlen)
1260 {
1261 OPENVPN_LOG(__func__ << ": " << addr << "/" << +prefixlen
1262 << " dev " << iface);
1263
1264 return sitnl_addr_del(iface,
1265 IP::Addr::from_ipv6(addr),
1266 prefixlen);
1267 }
1268
1269 static int
1270 net_addr_ptp_add(const std::string &iface,
1271 const IPv4::Addr &local,
1272 const IPv4::Addr &remote)
1273 {
1274 OPENVPN_LOG(__func__ << ": " << local
1275 << " peer " << remote
1276 << " dev " << iface);
1277
1278 return sitnl_addr_ptp_add(iface,
1279 IP::Addr::from_ipv4(local),
1280 IP::Addr::from_ipv4(remote));
1281 }
1282
1283 static int
1284 net_addr_ptp_del(const std::string &iface,
1285 const IPv4::Addr &local,
1286 const IPv4::Addr &remote)
1287 {
1288 OPENVPN_LOG(__func__ << ": " << local
1289 << " dev " << iface);
1290
1291 return sitnl_addr_ptp_del(iface,
1292 IP::Addr::from_ipv4(local));
1293 }
1294
1295 static int
1297 const IPv4::Addr &gw,
1298 const std::string &iface,
1299 const uint32_t table,
1300 const int metric)
1301 {
1302 OPENVPN_LOG(__func__ << ": " << route
1303 << " via " << gw
1304 << " dev " << iface
1305 << " table " << table
1306 << " metric " << metric);
1307
1310 iface,
1311 table,
1312 metric);
1313 }
1314
1315 static int
1317 const IPv6::Addr &gw,
1318 const std::string &iface,
1319 const uint32_t table,
1320 const int metric)
1321 {
1322 OPENVPN_LOG(__func__ << ": " << route
1323 << " via " << gw
1324 << " dev " << iface
1325 << " table " << table
1326 << " metric " << metric);
1327
1330 iface,
1331 table,
1332 metric);
1333 }
1334
1335 static int
1337 const IPv4::Addr &gw,
1338 const std::string &iface,
1339 const uint32_t table,
1340 const int metric)
1341 {
1342 OPENVPN_LOG(__func__ << ": " << route << " via " << gw << " dev " << iface
1343 << " table " << table << " metric " << metric);
1344
1347 iface,
1348 table,
1349 metric);
1350 }
1351
1352 static int
1354 const IPv6::Addr &gw,
1355 const std::string &iface,
1356 const uint32_t table,
1357 const int metric)
1358 {
1359 OPENVPN_LOG(__func__ << ": " << route
1360 << " via " << gw
1361 << " dev " << iface
1362 << " table " << table
1363 << " metric " << metric);
1364
1367 iface,
1368 table,
1369 metric);
1370 }
1371};
1372} // 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:235
unsigned int prefix_len
Definition route.hpp:38
bool defined() const
Definition route.hpp:134
bool contains(const ADDR &a) const
Definition route.hpp:207
static Addr from_bytes_net(const unsigned char *bytes)
Definition ipv4.hpp:157
static Addr from_byte_string(const unsigned char *bytestr)
Definition ipv6.hpp:251
#define OPENVPN_LOG(args)
RouteType< IP::Addr > Route
Definition route.hpp:354
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,...)