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