1 /*
2 * Copyright (c)2019 ZeroTier, Inc.
3 *
4 * Use of this software is governed by the Business Source License included
5 * in the LICENSE.TXT file in the project's root directory.
6 *
7 * Change Date: 2025-01-01
8 *
9 * On the date above, in accordance with the Business Source License, use
10 * of this software will be governed by version 2.0 of the Apache License.
11 */
12 /****/
13
14 #include "../node/Constants.hpp"
15
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #ifdef __WINDOWS__
22 #include <WinSock2.h>
23 #include <Windows.h>
24 #include <netioapi.h>
25 #include <IPHlpApi.h>
26 #endif
27
28 #ifdef __UNIX_LIKE__
29 #include <unistd.h>
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #ifndef ZT_SDK
37 #include <net/route.h>
38 #endif
39 #include <net/if.h>
40 #ifdef __BSD__
41 #include <net/if_dl.h>
42 #include <sys/sysctl.h>
43 #endif
44 #include <ifaddrs.h>
45 #endif
46
47 #include <vector>
48 #include <algorithm>
49 #include <utility>
50
51 #include "ManagedRoute.hpp"
52 #ifdef __LINUX__
53 #include "LinuxNetLink.hpp"
54 #endif
55
56 #define ZT_BSD_ROUTE_CMD "/sbin/route"
57
58 namespace ZeroTier {
59
60 namespace {
61
62 // Fork a target into two more specific targets e.g. 0.0.0.0/0 -> 0.0.0.0/1, 128.0.0.0/1
63 // If the target is already maximally-specific, 'right' will be unchanged and 'left' will be 't'
_forkTarget(const InetAddress & t,InetAddress & left,InetAddress & right)64 static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &right)
65 {
66 const unsigned int bits = t.netmaskBits() + 1;
67 left = t;
68 if (t.ss_family == AF_INET) {
69 if (bits <= 32) {
70 left.setPort(bits);
71 right = t;
72 reinterpret_cast<struct sockaddr_in *>(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits)));
73 right.setPort(bits);
74 } else {
75 right.zero();
76 }
77 } else if (t.ss_family == AF_INET6) {
78 if (bits <= 128) {
79 left.setPort(bits);
80 right = t;
81 uint8_t *b = reinterpret_cast<uint8_t *>(reinterpret_cast<struct sockaddr_in6 *>(&right)->sin6_addr.s6_addr);
82 b[bits / 8] ^= 1 << (8 - (bits % 8));
83 right.setPort(bits);
84 } else {
85 right.zero();
86 }
87 }
88 }
89
90 struct _RTE
91 {
92 InetAddress target;
93 InetAddress via;
94 char device[128];
95 int metric;
96 bool ifscope;
97 };
98
99 #ifdef __BSD__ // ------------------------------------------------------------
100 #define ZT_ROUTING_SUPPORT_FOUND 1
101
102 #ifndef ZT_SDK
_getRTEs(const InetAddress & target,bool contains)103 static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
104 {
105 std::vector<_RTE> rtes;
106 int mib[6];
107 size_t needed;
108
109 mib[0] = CTL_NET;
110 mib[1] = PF_ROUTE;
111 mib[2] = 0;
112 mib[3] = 0;
113 mib[4] = NET_RT_DUMP;
114 mib[5] = 0;
115 if (!sysctl(mib,6,NULL,&needed,NULL,0)) {
116 if (needed <= 0)
117 return rtes;
118
119 char *buf = (char *)::malloc(needed);
120 if (buf) {
121 if (!sysctl(mib,6,buf,&needed,NULL,0)) {
122 struct rt_msghdr *rtm;
123 for(char *next=buf,*end=buf+needed;next<end;) {
124 rtm = (struct rt_msghdr *)next;
125 char *saptr = (char *)(rtm + 1);
126 char *saend = next + rtm->rtm_msglen;
127
128 InetAddress sa_t,sa_v;
129 int deviceIndex = -9999;
130
131 if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) {
132 int which = 0;
133 while (saptr < saend) {
134 struct sockaddr *sa = (struct sockaddr *)saptr;
135 unsigned int salen = sa->sa_len;
136 if (!salen)
137 break;
138
139 // Skip missing fields in rtm_addrs bit field
140 while ((rtm->rtm_addrs & 1) == 0) {
141 rtm->rtm_addrs >>= 1;
142 ++which;
143 if (which > 6)
144 break;
145 }
146 if (which > 6)
147 break;
148
149 rtm->rtm_addrs >>= 1;
150 switch(which++) {
151 case 0:
152 //printf("RTA_DST\n");
153 if (sa->sa_family == AF_INET6) {
154 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
155 if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) {
156 // BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec.
157 unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff);
158 sin6->sin6_addr.s6_addr[2] = 0;
159 sin6->sin6_addr.s6_addr[3] = 0;
160 if (!sin6->sin6_scope_id)
161 sin6->sin6_scope_id = interfaceIndex;
162 }
163 }
164 sa_t = *sa;
165 break;
166 case 1:
167 //printf("RTA_GATEWAY\n");
168 switch(sa->sa_family) {
169 case AF_LINK:
170 deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index;
171 break;
172 case AF_INET:
173 case AF_INET6:
174 sa_v = *sa;
175 break;
176 }
177 break;
178 case 2: {
179 //printf("RTA_NETMASK\n");
180 if (sa_t.ss_family == AF_INET6) {
181 salen = sizeof(struct sockaddr_in6);
182 unsigned int bits = 0;
183 for(int i=0;i<16;++i) {
184 unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i];
185 if (c == 0xff)
186 bits += 8;
187 else break;
188 }
189 sa_t.setPort(bits);
190 } else if (sa_t.ss_family == AF_INET) {
191 salen = sizeof(struct sockaddr_in);
192 sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr));
193 }
194 } break;
195 /*
196 case 3:
197 //printf("RTA_GENMASK\n");
198 break;
199 case 4:
200 //printf("RTA_IFP\n");
201 break;
202 case 5:
203 //printf("RTA_IFA\n");
204 break;
205 case 6:
206 //printf("RTA_AUTHOR\n");
207 break;
208 */
209 }
210
211 saptr += salen;
212 }
213
214 if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) {
215 rtes.push_back(_RTE());
216 rtes.back().target = sa_t;
217 rtes.back().via = sa_v;
218 if (deviceIndex >= 0) {
219 if_indextoname(deviceIndex,rtes.back().device);
220 } else {
221 rtes.back().device[0] = (char)0;
222 }
223 rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount;
224 }
225 }
226
227 next = saend;
228 }
229 }
230
231 ::free(buf);
232 }
233 }
234
235 return rtes;
236 }
237 #endif
238
_routeCmd(const char * op,const InetAddress & target,const InetAddress & via,const char * ifscope,const char * localInterface)239 static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *ifscope,const char *localInterface)
240 {
241 //char f1[1024],f2[1024]; printf("%s %s %s %s %s\n",op,target.toString(f1),via.toString(f2),ifscope,localInterface);
242 long p = (long)fork();
243 if (p > 0) {
244 int exitcode = -1;
245 ::waitpid(p,&exitcode,0);
246 } else if (p == 0) {
247 ::close(STDOUT_FILENO);
248 ::close(STDERR_FILENO);
249 char ttmp[64];
250 char iptmp[64];
251 if (via) {
252 if ((ifscope)&&(ifscope[0])) {
253 #ifdef ZT_TRACE
254 fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s" ZT_EOL_S, ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp));
255 #endif
256 ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0);
257 } else {
258 #ifdef ZT_TRACE
259 fprintf(stderr, "DEBUG: route %s %s %s %s" ZT_EOL_S, op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp));
260 #endif
261 ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0);
262 }
263 } else if ((localInterface)&&(localInterface[0])) {
264 if ((ifscope)&&(ifscope[0])) {
265 #ifdef ZT_TRACE
266 fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s -interface %s" ZT_EOL_S, op, ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),localInterface);
267 #endif
268 ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0);
269 } else {
270 #ifdef ZT_TRACE
271 fprintf(stderr, "DEBUG: route %s %s %s -interface %s" ZT_EOL_S, op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),localInterface);
272 #endif
273 ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0);
274 }
275 }
276 ::_exit(-1);
277 }
278 }
279
280 #endif // __BSD__ ------------------------------------------------------------
281
282 #ifdef __LINUX__ // ----------------------------------------------------------
283 #define ZT_ROUTING_SUPPORT_FOUND 1
284
285 // This has been replaced by LinuxNetLink
286
287 #endif // __LINUX__ ----------------------------------------------------------
288
289 #ifdef __WINDOWS__ // --------------------------------------------------------
290 #define ZT_ROUTING_SUPPORT_FOUND 1
291
_winRoute(bool del,const NET_LUID & interfaceLuid,const NET_IFINDEX & interfaceIndex,const InetAddress & target,const InetAddress & via)292 static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &interfaceIndex,const InetAddress &target,const InetAddress &via)
293 {
294 MIB_IPFORWARD_ROW2 rtrow;
295 InitializeIpForwardEntry(&rtrow);
296 rtrow.InterfaceLuid.Value = interfaceLuid.Value;
297 rtrow.InterfaceIndex = interfaceIndex;
298 if (target.ss_family == AF_INET) {
299 rtrow.DestinationPrefix.Prefix.si_family = AF_INET;
300 rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET;
301 rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&target)->sin_addr.S_un.S_addr;
302 if (via.ss_family == AF_INET) {
303 rtrow.NextHop.si_family = AF_INET;
304 rtrow.NextHop.Ipv4.sin_family = AF_INET;
305 rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&via)->sin_addr.S_un.S_addr;
306 }
307 } else if (target.ss_family == AF_INET6) {
308 rtrow.DestinationPrefix.Prefix.si_family = AF_INET6;
309 rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6;
310 memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,reinterpret_cast<const struct sockaddr_in6 *>(&target)->sin6_addr.u.Byte,16);
311 if (via.ss_family == AF_INET6) {
312 rtrow.NextHop.si_family = AF_INET6;
313 rtrow.NextHop.Ipv6.sin6_family = AF_INET6;
314 memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte,reinterpret_cast<const struct sockaddr_in6 *>(&via)->sin6_addr.u.Byte,16);
315 }
316 } else {
317 return false;
318 }
319 rtrow.DestinationPrefix.PrefixLength = target.netmaskBits();
320 rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength;
321 rtrow.ValidLifetime = 0xffffffff;
322 rtrow.PreferredLifetime = 0xffffffff;
323 rtrow.Metric = -1;
324 rtrow.Protocol = MIB_IPPROTO_NETMGMT;
325 rtrow.Loopback = FALSE;
326 rtrow.AutoconfigureAddress = FALSE;
327 rtrow.Publish = FALSE;
328 rtrow.Immortal = FALSE;
329 rtrow.Age = 0;
330 rtrow.Origin = NlroManual;
331 if (del) {
332 return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR);
333 } else {
334 NTSTATUS r = CreateIpForwardEntry2(&rtrow);
335 if (r == NO_ERROR) {
336 return true;
337 } else if (r == ERROR_OBJECT_ALREADY_EXISTS) {
338 return (SetIpForwardEntry2(&rtrow) == NO_ERROR);
339 } else {
340 return false;
341 }
342 }
343 }
344
_winHasRoute(const NET_LUID & interfaceLuid,const NET_IFINDEX & interfaceIndex,const InetAddress & target,const InetAddress & via)345 static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &interfaceIndex, const InetAddress &target, const InetAddress &via)
346 {
347 MIB_IPFORWARD_ROW2 rtrow;
348 InitializeIpForwardEntry(&rtrow);
349 rtrow.InterfaceLuid.Value = interfaceLuid.Value;
350 rtrow.InterfaceIndex = interfaceIndex;
351 if (target.ss_family == AF_INET) {
352 rtrow.DestinationPrefix.Prefix.si_family = AF_INET;
353 rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET;
354 rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&target)->sin_addr.S_un.S_addr;
355 if (via.ss_family == AF_INET) {
356 rtrow.NextHop.si_family = AF_INET;
357 rtrow.NextHop.Ipv4.sin_family = AF_INET;
358 rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&via)->sin_addr.S_un.S_addr;
359 }
360 } else if (target.ss_family == AF_INET6) {
361 rtrow.DestinationPrefix.Prefix.si_family = AF_INET6;
362 rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6;
363 memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6 *>(&target)->sin6_addr.u.Byte, 16);
364 if (via.ss_family == AF_INET6) {
365 rtrow.NextHop.si_family = AF_INET6;
366 rtrow.NextHop.Ipv6.sin6_family = AF_INET6;
367 memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6 *>(&via)->sin6_addr.u.Byte, 16);
368 }
369 } else {
370 return false;
371 }
372 rtrow.DestinationPrefix.PrefixLength = target.netmaskBits();
373 rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength;
374 return (GetIpForwardEntry2(&rtrow) == NO_ERROR);
375 }
376
377 #endif // __WINDOWS__ --------------------------------------------------------
378
379 #ifndef ZT_ROUTING_SUPPORT_FOUND
380 #error "ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS."
381 #endif
382
383 } // anonymous namespace
384
ManagedRoute(const InetAddress & target,const InetAddress & via,const InetAddress & src,const char * device)385 ManagedRoute::ManagedRoute(const InetAddress &target,const InetAddress &via,const InetAddress &src,const char *device)
386 {
387 _target = target;
388 _via = via;
389 _src = src;
390
391 if (_via.ss_family == AF_INET) {
392 _via.setPort(32);
393 } else if (_via.ss_family == AF_INET6) {
394 _via.setPort(128);
395 }
396
397 if (_src.ss_family == AF_INET) {
398 _src.setPort(32);
399 } else if (_src.ss_family == AF_INET6) {
400 _src.setPort(128);
401 }
402
403 Utils::scopy(_device,sizeof(_device),device);
404 _systemDevice[0] = (char)0;
405 }
406
~ManagedRoute()407 ManagedRoute::~ManagedRoute()
408 {
409 this->remove();
410 }
411
412 /* Linux NOTE: for default route override, some Linux distributions will
413 * require a change to the rp_filter parameter. A value of '1' will prevent
414 * default route override from working properly.
415 *
416 * sudo sysctl -w net.ipv4.conf.all.rp_filter=2
417 *
418 * Add to /etc/sysctl.conf or /etc/sysctl.d/... to make permanent.
419 *
420 * This is true of CentOS/RHEL 6+ and possibly others. This is because
421 * Linux default route override implies asymmetric routes, which then
422 * trigger Linux's "martian packet" filter. */
423
424 #ifndef ZT_SDK
sync()425 bool ManagedRoute::sync()
426 {
427 #ifdef __WINDOWS__
428 NET_LUID interfaceLuid;
429 interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
430 NET_IFINDEX interfaceIndex = -1;
431 if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR)
432 return false;
433 #endif
434
435 InetAddress leftt,rightt;
436 if (_target.netmaskBits() == 0) // bifurcate only the default route
437 _forkTarget(_target,leftt,rightt);
438 else leftt = _target;
439
440 #ifdef __BSD__ // ------------------------------------------------------------
441
442 if (_device[0]) {
443 bool haveDevice = false;
444 struct ifaddrs *ifa = (struct ifaddrs *)0;
445 if (!getifaddrs(&ifa)) {
446 struct ifaddrs *p = ifa;
447 while (p) {
448 if ((p->ifa_name)&&(!strcmp(_device, p->ifa_name))) {
449 haveDevice = true;
450 break;
451 }
452 p = p->ifa_next;
453 }
454 freeifaddrs(ifa);
455 }
456 if (!haveDevice)
457 return false;
458 }
459
460 // Find lowest metric system route that this route should override (if any)
461 InetAddress newSystemVia;
462 char newSystemDevice[128];
463 newSystemDevice[0] = (char)0;
464 int systemMetric = 9999999;
465 std::vector<_RTE> rtes(_getRTEs(_target,false));
466 for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
467 if (r->via) {
468 if ( ((!newSystemVia)||(r->metric < systemMetric)) && (strcmp(r->device,_device) != 0) ) {
469 newSystemVia = r->via;
470 Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device);
471 systemMetric = r->metric;
472 }
473 }
474 }
475
476 // Get device corresponding to route if we don't have that already
477 if ((newSystemVia)&&(!newSystemDevice[0])) {
478 rtes = _getRTEs(newSystemVia,true);
479 for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
480 if ( (r->device[0]) && (strcmp(r->device,_device) != 0) ) {
481 Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device);
482 break;
483 }
484 }
485 }
486 if (!newSystemDevice[0])
487 newSystemVia.zero();
488
489 // Shadow system route if it exists, also delete any obsolete shadows
490 // and replace them with the new state. sync() is called periodically to
491 // allow us to do that if underlying connectivity changes.
492 if ((_systemVia != newSystemVia)||(strcmp(_systemDevice,newSystemDevice) != 0)) {
493 if (_systemVia) {
494 _routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0);
495 if (rightt)
496 _routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0);
497 }
498
499 _systemVia = newSystemVia;
500 Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice);
501
502 if (_systemVia) {
503 _routeCmd("add",leftt,_systemVia,_systemDevice,(const char *)0);
504 //_routeCmd("change",leftt,_systemVia,_systemDevice,(const char *)0);
505 if (rightt) {
506 _routeCmd("add",rightt,_systemVia,_systemDevice,(const char *)0);
507 //_routeCmd("change",rightt,_systemVia,_systemDevice,(const char *)0);
508 }
509 }
510 }
511
512 //if (!_applied.count(leftt)) {
513 _applied[leftt] = !_via;
514 //_routeCmd("delete",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
515 _routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
516 //_routeCmd("change",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
517 //}
518 if (rightt) {
519 _applied[rightt] = !_via;
520 //_routeCmd("delete",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
521 _routeCmd("add",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
522 //_routeCmd("change",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
523 }
524
525 #endif // __BSD__ ------------------------------------------------------------
526
527 #ifdef __LINUX__ // ----------------------------------------------------------
528
529 const char *const devptr = (_via) ? (const char *)0 : _device;
530 if ((leftt)&&(!LinuxNetLink::getInstance().routeIsSet(leftt,_via,_src,devptr))) {
531 _applied[leftt] = false; // boolean unused
532 LinuxNetLink::getInstance().addRoute(leftt, _via, _src, devptr);
533 }
534 if ((rightt)&&(!LinuxNetLink::getInstance().routeIsSet(rightt,_via,_src,devptr))) {
535 _applied[rightt] = false; // boolean unused
536 LinuxNetLink::getInstance().addRoute(rightt, _via, _src, devptr);
537 }
538
539 #endif // __LINUX__ ----------------------------------------------------------
540
541 #ifdef __WINDOWS__ // --------------------------------------------------------
542
543 if ( (!_applied.count(leftt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,leftt,_via)) ) {
544 _applied[leftt] = false; // boolean unused
545 _winRoute(false,interfaceLuid,interfaceIndex,leftt,_via);
546 }
547 if ( (rightt) && ( (!_applied.count(rightt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,rightt,_via)) ) ) {
548 _applied[rightt] = false; // boolean unused
549 _winRoute(false,interfaceLuid,interfaceIndex,rightt,_via);
550 }
551
552 #endif // __WINDOWS__ --------------------------------------------------------
553
554 return true;
555 }
556 #endif
557
remove()558 void ManagedRoute::remove()
559 {
560 #ifdef __WINDOWS__
561 NET_LUID interfaceLuid;
562 interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
563 NET_IFINDEX interfaceIndex = -1;
564 if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR)
565 return;
566 #endif
567
568 #ifdef __BSD__
569 if (_systemVia) {
570 InetAddress leftt,rightt;
571 _forkTarget(_target,leftt,rightt);
572 _routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0);
573 if (rightt)
574 _routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0);
575 }
576 #endif // __BSD__ ------------------------------------------------------------
577
578 for(std::map<InetAddress,bool>::iterator r(_applied.begin());r!=_applied.end();++r) {
579 #ifdef __BSD__ // ------------------------------------------------------------
580 _routeCmd("delete",r->first,_via,r->second ? _device : (const char *)0,(_via) ? (const char *)0 : _device);
581 #endif // __BSD__ ------------------------------------------------------------
582
583 #ifdef __LINUX__ // ----------------------------------------------------------
584 //_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device);
585 LinuxNetLink::getInstance().delRoute(r->first,_via,_src,(_via) ? (const char *)0 : _device);
586 #endif // __LINUX__ ----------------------------------------------------------
587
588 #ifdef __WINDOWS__ // --------------------------------------------------------
589 _winRoute(true,interfaceLuid,interfaceIndex,r->first,_via);
590 #endif // __WINDOWS__ --------------------------------------------------------
591 }
592
593 _target.zero();
594 _via.zero();
595 _systemVia.zero();
596 _device[0] = (char)0;
597 _systemDevice[0] = (char)0;
598 _applied.clear();
599 }
600
601 } // namespace ZeroTier
602