OpenVPN 3 Core Library
Loading...
Searching...
No Matches
test_route_emulation.cpp
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
13/* Without doing this log dance core will not compile ... */
14
15#include "test_common.hpp"
16
18
19
20namespace unittests {
21#define DEBUG_PRINT_ROUTES \
22 for (auto &rt : tb->routes) \
23 std::cout << rt << std::endl;
24
25/* Helper function for quick result comparision */
26std::string join_string_vector_sorted(std::vector<std::string> vec, const char *const delim = ", ")
27{
28 std::sort(vec.begin(), vec.end());
29 std::ostringstream res;
30 std::copy(vec.begin(), vec.end(), std::ostream_iterator<std::string>(res, delim));
31 return res.str();
32}
33
34/* Simple class that just records */
36{
37 public:
38 bool is_ipv6;
40 : is_ipv6(ipv6)
41 {
42 }
43
44 bool tun_builder_add_route(const std::string &address,
45 int prefix_length,
46 int metric,
47 bool ipv6) override
48 {
49 auto rt = address + "/" + std::to_string(prefix_length);
50 routes.push_back(rt);
51 routesAddr.push_back(openvpn::IP::Route(rt));
52 return is_ipv6 == ipv6;
53 }
54
55 bool tun_builder_set_remote_address(const std::string &address, bool ipv6) override
56 {
57 addresses.push_back(address);
58 return is_ipv6 == ipv6;
59 }
60
61 std::vector<std::string> addresses;
62 std::vector<std::string> routes;
63 std::vector<openvpn::IP::Route> routesAddr;
64
65 bool containsIP(std::string ipaddr)
66 {
67 return containsIP(openvpn::IP::Addr(ipaddr));
68 }
69
71 {
72 for (auto &rt : routesAddr)
73 {
74 if (rt.contains(ipaddr))
75 return true;
76 }
77 return false;
78 }
79};
80
81class RouteEmulationTest : public testing::Test
82{
83 protected:
88
90 : ipflags(nullptr), tb(nullptr)
91 {
92 }
93
94 void teardown()
95 {
96 delete tb;
97 delete ipflags;
98 }
99
100 void setup(bool ipv6, bool excludeServer, bool keepEmu = false)
101 {
102 teardown();
103
104 tb = new TunBuilderMock(ipv6);
105
108
109 if (!keepEmu)
110 {
112 new openvpn::EmulateExcludeRouteFactoryImpl(excludeServer));
113
114 emu = factory->new_obj();
115 }
116 }
117
118 // Helper functions to make writing test suite a bit easier
119 void inclRoute(const std::string &incRoute)
120 {
121 addRoute(true, incRoute);
122 }
123 void exclRoute(const std::string &exclRoute)
124 {
125 addRoute(false, exclRoute);
126 }
127
128 void addRoute(bool include, const std::string &route)
129 {
130 std::string ipstr = route.substr(0, route.find('/'));
131 std::string mask = route.substr(route.find('/') + 1);
132 emu->add_route(include, openvpn::IP::Addr(ipstr), std::stoi(mask));
133 }
134
135 void doEmulate(std::string serverip = "1.2.3.4")
136 {
137 emu->emulate(this->tb, *this->ipflags, openvpn::IP::Addr(serverip));
138 }
139
141 {
142 teardown();
143 }
144};
145
146TEST_F(RouteEmulationTest, ExcludeOneSubnet)
147{
148 setup(false, false);
149
150 emu->add_default_routes(true, true);
151
152 emu->add_route(false, openvpn::IP::Addr("192.168.100.0"), 24);
153
154 doEmulate();
155
156 ASSERT_EQ(tb->routes.size(), 24u);
157}
158
159TEST_F(RouteEmulationTest, ExcludeSubnetsNoDefault)
160{
161 setup(false, false);
162 // include this net
163 emu->add_route(true, openvpn::IP::Addr("10.20.0.0"), 16);
164
165 // but not the first half
166 emu->add_route(false, openvpn::IP::Addr("10.20.0.0"), 17);
167
168 doEmulate();
169
170 ASSERT_EQ(tb->routes.size(), 1u);
171 ASSERT_EQ(tb->routes.at(0), "10.20.128.0/17");
172
173 setup(true, false);
174
175 emu->add_route(true, openvpn::IP::Addr("2500:1000::"), 32);
176 // but not the first half
177 emu->add_route(false, openvpn::IP::Addr("2500:1000:8000::"), 33);
178
179 doEmulate();
180
181 ASSERT_EQ(tb->routes.size(), 1u);
182 ASSERT_EQ(tb->routes.at(0), "2500:1000::/33");
183}
184
186{
187 setup(false, true);
188 emu->add_default_routes(true, true);
189 doEmulate("1.2.3.4");
190
191 ASSERT_EQ(tb->routes.size(), 32u);
192 ASSERT_FALSE(tb->containsIP("1.2.3.4"));
193 ASSERT_TRUE(tb->containsIP("1.2.3.5"));
194 ASSERT_TRUE(tb->containsIP("1.2.3.3"));
195 ASSERT_TRUE(tb->containsIP("4.3.2.1"));
196
197 setup(true, true);
198 emu->add_default_routes(true, true);
199 doEmulate("::1.2.3.4");
200
201 ASSERT_EQ(tb->routes.size(), 128u);
202 ASSERT_FALSE(tb->containsIP("::1.2.3.4"));
203 ASSERT_TRUE(tb->containsIP("::1.2.3.5"));
204 ASSERT_TRUE(tb->containsIP("::1.2.3.3"));
205 ASSERT_TRUE(tb->containsIP("::4.3.2.1"));
206}
207
209{
210 // This sets up a number of routes that are all included in each
211
212 setup(false, false);
213 inclRoute("192.64.0.0/16");
214 // second quarter.
215 exclRoute("192.64.64.0/18");
216 // last quarter
217 inclRoute("192.64.112.0/20");
218 // first quarter
219 exclRoute("192.64.112.0/22");
220 // first quarter again
221 inclRoute("192.64.112.0/24");
222 // second quarter
223 exclRoute("192.64.112.64/26");
224
225 doEmulate();
226
227 // Excluded by 192.64.112.64/26
228 ASSERT_FALSE(tb->containsIP("192.64.112.64"));
229 ASSERT_FALSE(tb->containsIP("192.64.112.87"));
230
231 // Included by 192.64.112.0/24
232 ASSERT_TRUE(tb->containsIP("192.64.112.5"));
233 ASSERT_TRUE(tb->containsIP("192.64.112.129"));
234 ASSERT_TRUE(tb->containsIP("192.64.112.255"));
235
236 // Excluded by 192.64.112.0/22
237 ASSERT_FALSE(tb->containsIP("192.64.113.91"));
238 ASSERT_FALSE(tb->containsIP("192.64.114.92"));
239 ASSERT_FALSE(tb->containsIP("192.64.115.93"));
240
241
242 // Included by 192.64.112.0/20
243 ASSERT_TRUE(tb->containsIP("192.64.116.94"));
244 ASSERT_TRUE(tb->containsIP("192.64.123.95"));
245
246
247 // Excluded by 192.64.64.0/18"
248 ASSERT_FALSE(tb->containsIP("192.64.64.96"));
249 ASSERT_FALSE(tb->containsIP("192.64.97.98"));
250 ASSERT_FALSE(tb->containsIP("192.64.111.99"));
251
252 // included in 192.64.0.0/16
253 ASSERT_TRUE(tb->containsIP("192.64.0.0"));
254 ASSERT_TRUE(tb->containsIP("192.64.1.2"));
255
256 // Not in the at all
257 ASSERT_FALSE(tb->containsIP("1.2.3.4"));
258 ASSERT_FALSE(tb->containsIP("192.63.255.255"));
259 ASSERT_FALSE(tb->containsIP("192.65.0.0"));
260 ASSERT_FALSE(tb->containsIP("128.0.0.0"));
261 ASSERT_FALSE(tb->containsIP("192.0.0.0"));
262 ASSERT_FALSE(tb->containsIP("255.255.255.255"));
263}
264
266{
267 setup(false, false);
268
269 emu->add_default_routes(true, true);
270
271 doEmulate();
272
273 ASSERT_EQ(tb->routes.size(), 1u);
274 ASSERT_EQ(tb->routes.at(0), "0.0.0.0/0");
275
276 // Now something more tricky add unnecessary extra route
277 // to confuse our emulation layer
278 setup(false, false, true);
279
280 inclRoute("192.168.0.0/24");
281
282 doEmulate();
283
284 ASSERT_EQ(tb->routes.size(), 2u);
285 ASSERT_EQ(tb->routes.at(0), "0.0.0.0/0");
286}
287
288} // namespace unittests
The smart pointer class.
Definition rc.hpp:119
TunBuilder methods, loosely based on the Android VpnService.Builder abstraction.
Definition base.hpp:42
void addRoute(bool include, const std::string &route)
openvpn::EmulateExcludeRoute::Ptr emu
void doEmulate(std::string serverip="1.2.3.4")
void setup(bool ipv6, bool excludeServer, bool keepEmu=false)
void inclRoute(const std::string &incRoute)
void exclRoute(const std::string &exclRoute)
bool containsIP(openvpn::IP::Addr ipaddr)
bool containsIP(std::string ipaddr)
bool tun_builder_set_remote_address(const std::string &address, bool ipv6) override
Callback to set the address of the remote server.
std::vector< openvpn::IP::Route > routesAddr
std::vector< std::string > addresses
bool tun_builder_add_route(const std::string &address, int prefix_length, int metric, bool ipv6) override
Callback to add a route to the VPN interface.
std::vector< std::string > routes
std::string join_string_vector_sorted(std::vector< std::string > vec, const char *const delim=", ")
TEST_F(IpHelperTest, TestAddRoute4)
virtual EmulateExcludeRoute::Ptr new_obj() const =0
const auto metric
remote_address ipv6
remote_address address