OpenVPN 3 Core Library
Loading...
Searching...
No Matches
gw.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// Find default gateways on Linux using ip route command
13
14#ifndef OPENVPN_NETCONF_LINUX_GW_H
15#define OPENVPN_NETCONF_LINUX_GW_H
16
17#include <string>
18#include <limits>
19
26
27namespace openvpn {
29{
30 public:
31 OPENVPN_EXCEPTION(linux_gw_error);
32
33 LinuxGW(const std::string &ip_route_show_txt, const bool ignore_errors)
34 {
35 int best_metric = std::numeric_limits<int>::max();
36
37 SplitLines sl(ip_route_show_txt);
38 while (sl())
39 {
40 const std::string &line = sl.line_ref();
41
42 try
43 {
44 // parse an output line generated by "ip [-6] route show"
45 const std::vector<std::string> v = Split::by_space<std::vector<std::string>, NullLex, SpaceMatch, Split::NullLimit>(line);
46
47 // blank line?
48 if (v.empty())
49 continue;
50
51 // only interested in default routes
52 if (v[0] != "default")
53 continue;
54
55 // parse out route information
56 enum RouteInfo
57 {
58 INITIAL,
59 VIA,
60 DEV,
61 METRIC,
62 };
63
64 std::string d;
65 IP::Addr a;
66 int m = std::numeric_limits<int>::max();
67
68 RouteInfo ri = INITIAL;
69 for (const auto &term : v)
70 {
71 switch (ri)
72 {
73 case INITIAL:
74 if (term == "via")
75 ri = VIA;
76 else if (term == "dev")
77 ri = DEV;
78 else if (term == "metric")
79 ri = METRIC;
80 else
81 ri = INITIAL;
82 break;
83 case VIA:
84 a = IP::Addr(term, "via");
85 ri = INITIAL;
86 break;
87 case DEV:
88 d = validate_dev(term);
89 ri = INITIAL;
90 break;
91 case METRIC:
92 m = parse_number_throw<int>(term, "bad metric");
93 ri = INITIAL;
94 break;
95 }
96 }
97
98 // best metric?
99 if (m < best_metric || best_metric == std::numeric_limits<int>::max())
100 {
101 best_metric = m;
102 dev_ = std::move(d);
103 addr_ = a;
104 }
105 }
106 catch (const std::exception &e)
107 {
108 if (!ignore_errors)
109 OPENVPN_THROW(linux_gw_error, "error parsing line: " << line << " : " << e.what());
110 }
111 }
112 }
113
114 static std::string ip_route_show(const bool ipv6)
115 {
117 Argv argv;
118 argv.emplace_back("/sbin/ip");
119 if (ipv6)
120 argv.emplace_back("-6");
121 argv.emplace_back("route");
122 argv.emplace_back("show");
123 const int status = system_cmd(argv[0], argv, nullptr, pipe, 0, nullptr);
124 if (status != 0)
125 OPENVPN_THROW(linux_gw_error, "command returned error status " << status << " : " << argv.to_string());
126 return pipe.out;
127 }
128
129 const std::string &dev() const
130 {
131 return dev_;
132 }
133
134 const IP::Addr &addr() const
135 {
136 return addr_;
137 }
138
139 bool defined() const
140 {
141 return !dev_.empty() && addr_.defined();
142 }
143
144 std::string to_string() const
145 {
146 return dev_ + '/' + addr_.to_string();
147 }
148
149 private:
150 std::string validate_dev(const std::string &dev)
151 {
152 if (dev.empty())
153 OPENVPN_THROW_EXCEPTION("dev is empty");
154 return dev;
155 }
156
157 std::string dev_;
159};
160
162{
163 LinuxGW46(const bool ignore_errors)
164 : v4(LinuxGW::ip_route_show(false), ignore_errors),
165 v6(LinuxGW::ip_route_show(true), ignore_errors)
166 {
167 }
168
169 std::string to_string() const
170 {
171 std::string ret = "[";
172 if (v4.defined())
173 {
174 ret += "4:";
175 ret += v4.to_string();
176 }
177 if (v6.defined())
178 {
179 if (v4.defined())
180 ret += ' ';
181 ret += "6:";
182 ret += v6.to_string();
183 }
184 ret += "]";
185 return ret;
186 }
187
188 std::string dev() const
189 {
190 if (v4.defined())
191 return v4.dev();
192 else if (v6.defined())
193 return v6.dev();
194 else
195 throw LinuxGW::linux_gw_error("cannot determine gateway interface");
196 }
197
200};
201} // namespace openvpn
202
203#endif
std::string to_string() const
Definition argv.hpp:30
std::string to_string() const
Definition ip.hpp:528
bool defined() const
Definition ip.hpp:872
LinuxGW(const std::string &ip_route_show_txt, const bool ignore_errors)
Definition gw.hpp:33
std::string dev_
Definition gw.hpp:157
std::string to_string() const
Definition gw.hpp:144
OPENVPN_EXCEPTION(linux_gw_error)
const IP::Addr & addr() const
Definition gw.hpp:134
const std::string & dev() const
Definition gw.hpp:129
static std::string ip_route_show(const bool ipv6)
Definition gw.hpp:114
IP::Addr addr_
Definition gw.hpp:158
std::string validate_dev(const std::string &dev)
Definition gw.hpp:150
bool defined() const
Definition gw.hpp:139
std::string & line_ref()
#define OPENVPN_THROW_EXCEPTION(stuff)
#define OPENVPN_THROW(exc, stuff)
int system_cmd(const std::string &cmd, const Argv &argv, RedirectBase *redir, const Environ *env, const sigset_t *sigmask)
Definition process.hpp:90
std::string to_string() const
Definition gw.hpp:169
std::string dev() const
Definition gw.hpp:188
LinuxGW46(const bool ignore_errors)
Definition gw.hpp:163
remote_address ipv6
std::string ret