OpenVPN 3 Core Library
Loading...
Searching...
No Matches
tunnetlink.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//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#pragma once
13
14#include <sys/ioctl.h>
15#include <fcntl.h>
16#include <net/if.h>
17#include <linux/if_tun.h>
18
28
29namespace openvpn::TunNetlink {
30
31using namespace openvpn::TunLinuxSetup;
32
33struct NetlinkLinkSet : public Action
34{
36
38 {
39 }
40
41 NetlinkLinkSet(std::string dev_arg, bool up_arg, int mtu_arg)
42 : dev(dev_arg),
43 up(up_arg),
44 mtu(mtu_arg)
45 {
46 }
47
49 {
51 ret->dev = dev;
52 ret->up = up;
53 ret->mtu = mtu;
54 return ret;
55 }
56
57 virtual void execute(std::ostream &os) override
58 {
59 if (dev.empty())
60 {
61 os << "Error: can't call NetlinkLinkSet with no interface" << std::endl;
62 return;
63 }
64
66 if (ret)
67 {
68 os << "Error while executing NetlinkLinkSet " << dev << " mtu " << mtu
69 << ": " << ret << std::endl;
70 }
71
73 if (ret)
74 {
75 os << "Error while executing NetlinkLinkSet " << dev << " up " << up
76 << ": " << ret << std::endl;
77 }
78 }
79
80 virtual std::string to_string() const override
81 {
82 std::ostringstream os;
83 os << "netlink iface " << dev << " link set " << up << " mtu " << mtu;
84 return os.str();
85 }
86
87 std::string dev;
88 bool up = true;
90};
91
92struct NetlinkAddr4 : public Action
93{
95
97 {
98 }
99
100 NetlinkAddr4(std::string dev_arg,
101 IPv4::Addr &addr_arg,
102 unsigned char prefixlen_arg,
103 IPv4::Addr &broadcast_arg,
104 bool add_arg)
105 : dev(dev_arg),
106 addr(addr_arg),
107 prefixlen(prefixlen_arg),
108 broadcast(broadcast_arg),
109 add(add_arg)
110 {
111 }
112
114 {
116 ret->dev = dev;
117 ret->addr = addr;
118 ret->prefixlen = prefixlen;
119 ret->broadcast = broadcast;
120 ret->add = add;
121 return ret;
122 }
123
124 virtual void execute(std::ostream &os) override
125 {
126 if (dev.empty())
127 {
128 os << "Error: can't call NetlinkAddr4 with no interface" << std::endl;
129 return;
130 }
131
132 int ret;
133 if (add)
134 {
136 }
137 else
138 {
140 }
141
142 if (ret)
143 {
144 os << "Error while executing NetlinkAddr4(add: " << add << ") "
145 << dev << ": " << ret << std::endl;
146 }
147 }
148
149 virtual std::string to_string() const override
150 {
151 std::ostringstream os;
152 os << "netlink iface " << dev << " " << (add ? "add" : "del") << " "
153 << addr.to_string() << "/" << prefixlen << " broadcast "
154 << broadcast.to_string();
155 return os.str();
156 }
157
158 std::string dev;
160 unsigned char prefixlen = 0;
162 bool add = true;
163};
164
165struct NetlinkAddr6 : public Action
166{
168
170 {
171 }
172
173 NetlinkAddr6(std::string dev_arg,
174 IPv6::Addr &addr_arg,
175 unsigned char prefixlen_arg,
176 bool add_arg)
177 : dev(dev_arg),
178 addr(addr_arg),
179 prefixlen(prefixlen_arg),
180 add(add_arg)
181 {
182 }
183
185 {
187 ret->dev = dev;
188 ret->addr = addr;
189 ret->prefixlen = prefixlen;
190 ret->add = add;
191 return ret;
192 }
193
194 virtual void execute(std::ostream &os) override
195 {
196 if (dev.empty())
197 {
198 os << "Error: can't call NetlinkAddr6 with no interface" << std::endl;
199 return;
200 }
201
202 int ret;
203 if (add)
204 {
206 }
207 else
208 {
210 }
211
212 if (ret)
213 {
214 os << "Error while executing NetlinkAddr6(add: " << add << ") "
215 << dev << ": " << ret << std::endl;
216 }
217 }
218
219 virtual std::string to_string() const override
220 {
221 std::ostringstream os;
222 os << "netlink iface " << dev << " " << (add ? "add" : "del") << " "
223 << addr.to_string() << "/" << prefixlen;
224 return os.str();
225 }
226
227 std::string dev;
229 unsigned char prefixlen = 0;
230 bool add = true;
231};
232
233struct NetlinkAddr4PtP : public Action
234{
236
238 {
239 }
240
241 NetlinkAddr4PtP(std::string dev_arg,
242 IPv4::Addr local_arg,
243 IPv4::Addr remote_arg,
244 bool add_arg)
245 : dev(dev_arg),
246 local(local_arg),
247 remote(remote_arg),
248 add(add_arg)
249 {
250 }
251
253 {
255 ret->dev = dev;
256 ret->local = local;
257 ret->remote = remote;
258 ret->add = add;
259 return ret;
260 }
261
262 virtual void execute(std::ostream &os) override
263 {
264 if (dev.empty())
265 {
266 os << "Error: can't call NetlinkAddr4PtP with no interface" << std::endl;
267 return;
268 }
269
270 int ret;
271 if (add)
272 {
274 }
275 else
276 {
278 }
279
280 if (ret)
281 {
282 os << "Error while executing NetlinkAddr4PtP(add: " << add << ") "
283 << dev << ": " << ret << std::endl;
284 }
285 }
286
287 virtual std::string to_string() const override
288 {
289 return "netlink iface " + dev + " " + (add ? "add" : "del") + " ptp "
290 + local.to_string() + " remote " + remote.to_string();
291 }
292
293 std::string dev;
296 bool add = true;
297};
298
299struct NetlinkRoute4 : public Action
300{
302
304 {
305 }
306
308 int prefixlen_arg,
309 IPv4::Addr &gw_arg,
310 std::string dev_arg,
311 int metric_arg,
312 bool add_arg)
313 : route(dst_arg, prefixlen_arg),
314 gw(gw_arg),
315 dev(dev_arg),
316 metric(metric_arg),
317 add(add_arg)
318 {
319 }
320
322 {
324 ret->route = route;
325 ret->gw = gw;
326 ret->dev = dev;
327 ret->metric = metric;
328 return ret;
329 }
330
331 virtual void execute(std::ostream &os) override
332 {
333 if (dev.empty())
334 {
335 os << "Error: can't call NetlinkRoute4 with no interface" << std::endl;
336 return;
337 }
338
339 int ret;
340 if (add)
341 {
343 }
344 else
345 {
347 }
348
349 if (ret)
350 {
351 os << "Error while executing NetlinkRoute4(add: " << add << ") "
352 << dev << ": " << ret << std::endl;
353 }
354 }
355
356 virtual std::string to_string() const override
357 {
358 std::ostringstream os;
359 os << "netlink route " << (add ? "add" : "del") << " dev " << dev << " "
360 << route << " via " << gw.to_string() << " metric " << metric;
361 return os.str();
362 }
363
366 std::string dev;
367 int metric = -1;
368 bool add = true;
369};
370
371struct NetlinkRoute6 : public Action
372{
374
376 {
377 }
378
380 int prefixlen_arg,
381 IPv6::Addr &gw_arg,
382 std::string dev_arg,
383 int metric_arg,
384 bool add_arg)
385 : route(dst_arg, prefixlen_arg),
386 gw(gw_arg),
387 dev(dev_arg),
388 metric(metric_arg),
389 add(add_arg)
390 {
391 }
392
394 {
396 ret->route = route;
397 ret->gw = gw;
398 ret->dev = dev;
399 ret->metric = metric;
400 return ret;
401 }
402
403 virtual void execute(std::ostream &os) override
404 {
405 if (dev.empty())
406 {
407 os << "Error: can't call NetlinkRoute6 with no interface" << std::endl;
408 return;
409 }
410
411 int ret;
412 if (add)
413 {
415 }
416 else
417 {
419 }
420
421 if (ret)
422 {
423 os << "Error while executing NetlinkRoute6(add: " << add << ") "
424 << dev << ": " << ret << std::endl;
425 }
426 }
427
428 virtual std::string to_string() const override
429 {
430 std::ostringstream os;
431 os << "netlink route " << (add ? "add" : "del") << " dev " << dev << " "
432 << route << " via " << gw.to_string() << " metric " << metric;
433 return os.str();
434 }
435
438 std::string dev;
439 int metric = -1;
440 bool add = true;
441};
442
443enum
444{ // add_del_route flags
445 R_IPv6 = (1 << 0),
446 R_ADD_SYS = (1 << 1),
447 R_ADD_DCO = (1 << 2),
449};
450
459inline int iface_new(std::ostringstream &os, const std::string &dev, const std::string &type)
460{
461 int ret = -1;
462
463 if (dev.empty())
464 {
465 os << "Error: can't call NetlinkLinkNew with no interface" << std::endl;
466 return ret;
467 }
468
469 if (type.empty())
470 {
471 os << "Error: can't call NetlinkLinkNew with no interfacei type" << std::endl;
472 return ret;
473 }
474
475 ret = SITNL::net_iface_new(dev, type);
476 if (ret)
477 {
478 os << "Error while executing NetlinkLinkNew " << dev << ": " << ret << std::endl;
479 }
480
481 return ret;
482}
483
484inline int iface_del(std::ostringstream &os, const std::string &dev)
485{
486 int ret = -1;
487
488 if (dev.empty())
489 {
490 os << "Error: can't call NetlinkLinkDel with no interface" << std::endl;
491 return ret;
492 }
493
495 if (ret)
496 {
497 os << "Error while executing NetlinkLinkDel " << dev << ": " << ret << std::endl;
498 }
499
500 return ret;
501}
502
503/*inline IPv4::Addr cvt_pnr_ip_v4(const std::string& hexaddr)
504{
505 BufferAllocated v(4, BufAllocFlags::CONSTRUCT_ZERO);
506 parse_hex(v, hexaddr);
507 if (v.size() != 4)
508throw tun_linux_error("bad hex address");
509 IPv4::Addr ret = IPv4::Addr::from_bytes(v.data());
510 return IP::Addr::from_ipv4(ret);
511}*/
512
513inline void add_del_route(const std::string &addr_str,
514 const int prefix_len,
515 const std::string &gateway_str,
516 const std::string &dev,
517 const int metric,
518 const unsigned int flags,
519 std::vector<IP::Route> *rtvec,
520 Action::Ptr &create,
521 Action::Ptr &destroy)
522{
523 if (flags & R_IPv6)
524 {
525 const IPv6::Addr addr = IPv6::Addr::from_string(addr_str);
527 const IPv6::Addr net = addr & netmask;
528
529 if (flags & R_ADD_SYS)
530 {
531 // ip route add 2001:db8:1::/48 via 2001:db8:1::1
533 add->route.addr = net;
534 add->route.prefix_len = prefix_len;
535 add->gw = IPv6::Addr::from_string(gateway_str);
536 add->dev = dev;
537 add->metric = metric;
538 add->add = true;
539
540 create = add;
541 // for the destroy command, copy the add command but replace "add" with "delete"
542 NetlinkRoute6::Ptr del(add->copy());
543 del->add = false;
544 destroy = del;
545 }
546
547 if (rtvec && (flags & R_ADD_DCO))
548 rtvec->emplace_back(IP::Addr::from_ipv6(net), prefix_len);
549 }
550 else
551 {
552 const IPv4::Addr addr = IPv4::Addr::from_string(addr_str);
554 const IPv4::Addr net = addr & netmask;
555
556 if (flags & R_ADD_SYS)
557 {
558 // ip route add 192.0.2.128/25 via 192.0.2.1
560 add->route.addr = net;
561 add->route.prefix_len = prefix_len;
562 add->gw = IPv4::Addr::from_string(gateway_str);
563 add->dev = dev;
564 add->metric = metric;
565 add->add = true;
566
567 create = add;
568 // for the destroy command, copy the add command but replace "add" with "delete"
569 NetlinkRoute4::Ptr del(add->copy());
570 del->add = false;
571 destroy = del;
572 }
573
574 if (rtvec && (flags & R_ADD_DCO))
575 rtvec->emplace_back(IP::Addr::from_ipv4(net), prefix_len);
576 }
577}
578
579inline void add_del_route(const std::string &addr_str,
580 const int prefix_len,
581 const std::string &gateway_str,
582 const std::string &dev,
583 const int metric,
584 const unsigned int flags, // add interface route to rtvec if defined
585 std::vector<IP::Route> *rtvec,
586 ActionList &create,
587 ActionList &destroy)
588{
589 Action::Ptr c, d;
590 add_del_route(addr_str, prefix_len, gateway_str, dev, metric, flags, rtvec, c, d);
591 create.add(c);
592 destroy.add(d);
593}
594
595inline void iface_up(const std::string &iface_name,
596 const int mtu,
597 ActionList &create,
598 ActionList &destroy)
599{
600 {
602 add->dev = iface_name;
603 add->up = true;
604 add->mtu = mtu;
605
606 create.add(add);
607 // for the destroy command, copy the add command but replace "up" with "down"
608 NetlinkLinkSet::Ptr del(add->copy());
609 del->up = false;
610 destroy.add(del);
611 }
612}
613
614inline void iface_config(const std::string &iface_name,
615 int unit,
616 const TunBuilderCapture &pull,
617 std::vector<IP::Route> *rtvec,
618 ActionList &create,
619 ActionList &destroy)
620{
621 // set local4 and local6 to point to IPv4/6 route configurations
622 const TunBuilderCapture::RouteAddress *local4 = pull.vpn_ipv4();
623 const TunBuilderCapture::RouteAddress *local6 = pull.vpn_ipv6();
624
625 // Set IPv4 Interface
626 if (local4)
627 {
629 add->addr = IPv4::Addr::from_string(local4->address);
630 add->prefixlen = local4->prefix_length;
631 add->broadcast = IPv4::Addr::from_string(local4->address)
632 | ~IPv4::Addr::netmask_from_prefix_len(local4->prefix_length);
633 add->dev = iface_name;
634 add->add = true;
635 // if (unit >= 0)
636 // {
637 // add->argv.push_back("label");
638 // add->argv.push_back(iface_name + ':' + openvpn::to_string(unit));
639 // }
640 create.add(add);
641
642 // for the destroy command, copy the add command but replace "add" with "delete"
643 NetlinkAddr4::Ptr del(add->copy());
644 del->add = false;
645 destroy.add(del);
646
647 // add interface route to rtvec if defined
648 add_del_route(local4->address,
649 local4->prefix_length,
650 local4->address,
651 iface_name,
652 0,
653 R_ADD_DCO,
654 rtvec,
655 create,
656 destroy);
657 }
658
659 // Set IPv6 Interface
660 if (local6 && !pull.block_ipv6)
661 {
663 add->addr = IPv6::Addr::from_string(local6->address);
664 add->prefixlen = local6->prefix_length;
665 add->dev = iface_name;
666 add->add = true;
667
668 create.add(add);
669
670 // for the destroy command, copy the add command but replace "add" with "delete"
671 NetlinkAddr6::Ptr del(add->copy());
672 del->add = false;
673 destroy.add(del);
674
675 // add interface route to rtvec if defined
676 add_del_route(local6->address,
677 local6->prefix_length,
678 local6->address,
679 iface_name,
680 0,
682 rtvec,
683 create,
684 destroy);
685 }
686}
687
689{
690 static inline void tun_config(const std::string &iface_name,
691 const TunBuilderCapture &pull,
692 std::vector<IP::Route> *rtvec,
693 ActionList &create,
694 ActionList &destroy,
695 const unsigned int flags) // TunConfigFlags
696 {
697 // set local4 and local6 to point to IPv4/6 route configurations
698 const TunBuilderCapture::RouteAddress *local4 = pull.vpn_ipv4();
699 const TunBuilderCapture::RouteAddress *local6 = pull.vpn_ipv6();
700
701 // configure interface
703 iface_up(iface_name, pull.mtu, create, destroy);
704 iface_config(iface_name, -1, pull, rtvec, create, destroy);
705
706 // Process Routes
707 {
708 for (const auto &route : pull.add_routes)
709 {
710 if (route.ipv6)
711 {
712 if (local6 && !pull.block_ipv6)
713 add_del_route(route.address,
714 route.prefix_length,
715 local6->gateway,
716 iface_name,
717 route.metric,
719 rtvec,
720 create,
721 destroy);
722 }
723 else
724 {
725 if (local4 && !local4->gateway.empty())
726 add_del_route(route.address,
727 route.prefix_length,
728 local4->gateway,
729 iface_name,
730 route.metric,
731 R_ADD_ALL,
732 rtvec,
733 create,
734 destroy);
735 else
736 OPENVPN_LOG("ERROR: IPv4 route pushed without IPv4 ifconfig and/or route-gateway");
737 }
738 }
739 }
740
741 // Process exclude routes
742 if (!pull.exclude_routes.empty())
743 {
744 LinuxGW46Netlink gw(iface_name);
745
746 for (const auto &route : pull.exclude_routes)
747 {
748 if (route.ipv6)
749 {
750 OPENVPN_LOG("NOTE: exclude IPv6 routes not supported yet"); // fixme
751 }
752 else
753 {
754 if (gw.v4.defined())
755 add_del_route(route.address,
756 route.prefix_length,
757 gw.v4.addr().to_string(),
758 gw.v4.dev(),
759 route.metric,
760 R_ADD_SYS,
761 rtvec,
762 create,
763 destroy);
764 else
765 OPENVPN_LOG("NOTE: cannot determine gateway for exclude IPv4 routes");
766 }
767 }
768 }
769
770 // Process IPv4 redirect-gateway
772 {
773 if (pull.reroute_gw.ipv4 && local4)
774 {
775 // add bypass route
777 && !pull.remote_address.ipv6
779 {
780 add_bypass_route(iface_name,
782 false,
783 rtvec,
784 create,
785 destroy);
786 }
787
788 add_del_route("0.0.0.0", 1, local4->gateway, iface_name, 0, R_ADD_ALL, rtvec, create, destroy);
789 add_del_route("128.0.0.0", 1, local4->gateway, iface_name, 0, R_ADD_ALL, rtvec, create, destroy);
790 }
791
792 // Process IPv6 redirect-gateway
793 if (pull.reroute_gw.ipv6 && !pull.block_ipv6 && local6)
794 {
795 // add bypass route
797 && pull.remote_address.ipv6
799 {
800 add_bypass_route(iface_name,
802 true,
803 rtvec,
804 create,
805 destroy);
806 }
807
808 add_del_route("0000::", 1, local6->gateway, iface_name, 0, R_ADD_ALL | R_IPv6, rtvec, create, destroy);
809 add_del_route("8000::", 1, local6->gateway, iface_name, 0, R_ADD_ALL | R_IPv6, rtvec, create, destroy);
810 }
811 }
812
813 // fixme -- Process block-ipv6
814
815 // fixme -- Handle pushed DNS servers
816 }
817
818 static inline void add_bypass_route(const std::string &tun_iface_name,
819 const std::string &address,
820 bool ipv6,
821 std::vector<IP::Route> *rtvec,
822 ActionList &create,
823 ActionList &destroy)
824 {
825 LinuxGW46Netlink gw(tun_iface_name, address);
826
827 if (!ipv6 && gw.v4.defined())
829 32,
830 gw.v4.addr().to_string(),
831 gw.dev(),
832 0,
833 R_ADD_SYS,
834 rtvec,
835 create,
836 destroy);
837
838 if (ipv6 && gw.v6.defined())
840 128,
841 gw.v6.addr().to_string(),
842 gw.dev(),
843 0,
845 rtvec,
846 create,
847 destroy);
848 }
849};
850} // namespace openvpn::TunNetlink
void add(Action *action)
Definition action.hpp:57
std::string to_string() const
Definition ip.hpp:528
static Addr from_ipv6(IPv6::Addr addr)
Definition ip.hpp:268
static Addr from_ipv4(IPv4::Addr addr)
Definition ip.hpp:260
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv4.hpp:189
unsigned int prefix_len() const
Definition ipv4.hpp:456
std::string to_string() const
Definition ipv4.hpp:232
static Addr from_string(const std::string &ipstr, const TITLE &title)
Definition ipv4.hpp:205
unsigned int prefix_len() const
Definition ipv6.hpp:526
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv6.hpp:328
static void add(ipv6addr &dest, const ipv6addr &src)
Definition ipv6.hpp:864
std::string to_string() const
Definition ipv6.hpp:131
static Addr from_string(const std::string &ipstr, const TITLE &title)
Definition ipv6.hpp:104
The smart pointer class.
Definition rc.hpp:119
Route address class that may use non-canonical form.
Definition capture.hpp:295
RemoteAddress remote_address
Definition capture.hpp:1082
std::vector< Route > add_routes
Definition capture.hpp:1091
const RouteAddress * vpn_ipv6() const
Gets the IPv6 tunnel address.
Definition capture.hpp:914
const RouteAddress * vpn_ipv4() const
Gets the IPv4 tunnel address.
Definition capture.hpp:902
std::vector< Route > exclude_routes
Definition capture.hpp:1092
#define OPENVPN_LOG(args)
@ TUN_MTU_DEFAULT
Definition tunmtu.hpp:20
const auto metric
reroute_gw flags
remote_address ipv6
remote_address address
std::string ret
std::ostringstream os
int prefix_len(const IPv4::Addr::base_type mask)
static void add(const Time &t1, const Time::Duration &d1)