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 #ifdef __GNUC__
15 #pragma GCC diagnostic ignored "-Wrestrict"
16 #endif
17 
18 #include "../node/Constants.hpp"
19 
20 #ifdef __LINUX__
21 
22 #include "../node/Utils.hpp"
23 #include "../node/Mutex.hpp"
24 #include "../node/Dictionary.hpp"
25 #include "OSUtils.hpp"
26 #include "LinuxEthernetTap.hpp"
27 #include "LinuxNetLink.hpp"
28 
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/ioctl.h>
40 #include <sys/wait.h>
41 #include <sys/select.h>
42 #include <netinet/in.h>
43 #include <net/if_arp.h>
44 #include <arpa/inet.h>
45 #include <linux/if.h>
46 #include <linux/if_tun.h>
47 #include <linux/if_addr.h>
48 #include <linux/if_ether.h>
49 #include <ifaddrs.h>
50 
51 #include <algorithm>
52 #include <utility>
53 #include <string>
54 
55 #ifndef IFNAMSIZ
56 #define IFNAMSIZ 16
57 #endif
58 
59 #define ZT_TAP_BUF_SIZE 16384
60 
61 // ff:ff:ff:ff:ff:ff with no ADI
62 static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0);
63 
64 namespace ZeroTier {
65 
66 static const char _base32_chars[32] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7' };
_base32_5_to_8(const uint8_t * in,char * out)67 static void _base32_5_to_8(const uint8_t *in,char *out)
68 {
69 	out[0] = _base32_chars[(in[0]) >> 3];
70 	out[1] = _base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6];
71 	out[2] = _base32_chars[(in[1] & 0x3e) >> 1];
72 	out[3] = _base32_chars[(in[1] & 0x01) << 4 | (in[2] & 0xf0) >> 4];
73 	out[4] = _base32_chars[(in[2] & 0x0f) << 1 | (in[3] & 0x80) >> 7];
74 	out[5] = _base32_chars[(in[3] & 0x7c) >> 2];
75 	out[6] = _base32_chars[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5];
76 	out[7] = _base32_chars[(in[4] & 0x1f)];
77 }
78 
LinuxEthernetTap(const char * homePath,const MAC & mac,unsigned int mtu,unsigned int metric,uint64_t nwid,const char * friendlyName,void (* handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),void * arg)79 LinuxEthernetTap::LinuxEthernetTap(
80 	const char *homePath,
81 	const MAC &mac,
82 	unsigned int mtu,
83 	unsigned int metric,
84 	uint64_t nwid,
85 	const char *friendlyName,
86 	void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
87 	void *arg) :
88 	_handler(handler),
89 	_arg(arg),
90 	_nwid(nwid),
91 	_mac(mac),
92 	_homePath(homePath),
93 	_mtu(mtu),
94 	_fd(0),
95 	_enabled(true),
96 	_run(true)
97 {
98 	static std::mutex s_tapCreateLock;
99 	char procpath[128],nwids[32];
100 	struct stat sbuf;
101 
102 	// Create only one tap at a time globally.
103 	std::lock_guard<std::mutex> tapCreateLock(s_tapCreateLock);
104 
105 	// Make sure Linux netlink is initialized.
106 	(void)LinuxNetLink::getInstance();
107 
108 	OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid);
109 
110 	_fd = ::open("/dev/net/tun",O_RDWR);
111 	if (_fd <= 0) {
112 		_fd = ::open("/dev/tun",O_RDWR);
113 		if (_fd <= 0)
114 			throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno));
115 	}
116 
117 	struct ifreq ifr;
118 	memset(&ifr,0,sizeof(ifr));
119 
120 	// Restore device names from legacy devicemap, but for new devices we use a base32-based
121 	// canonical device name.
122 	std::map<std::string,std::string> globalDeviceMap;
123 	FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r");
124 	if (devmapf) {
125 		char buf[256];
126 		while (fgets(buf,sizeof(buf),devmapf)) {
127 			char *x = (char *)0;
128 			char *y = (char *)0;
129 			char *saveptr = (char *)0;
130 			for(char *f=Utils::stok(buf,"\r\n=",&saveptr);(f);f=Utils::stok((char *)0,"\r\n=",&saveptr)) {
131 				if (!x) x = f;
132 				else if (!y) y = f;
133 				else break;
134 			}
135 			if ((x)&&(y)&&(x[0])&&(y[0]))
136 				globalDeviceMap[x] = y;
137 		}
138 		fclose(devmapf);
139 	}
140 	bool recalledDevice = false;
141 	std::map<std::string,std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids);
142 	if (gdmEntry != globalDeviceMap.end()) {
143 		Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),gdmEntry->second.c_str());
144 		OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
145 		recalledDevice = (stat(procpath,&sbuf) != 0);
146 	}
147 
148 	if (!recalledDevice) {
149 #ifdef __SYNOLOGY__
150 		int devno = 50;
151 		do {
152 			OSUtils::ztsnprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth%d",devno++);
153 			OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
154 		} while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist
155 #else
156 		uint64_t trial = 0; // incremented in the very unlikely event of a name collision with another network
157 		do {
158 			const uint64_t nwid40 = (nwid ^ (nwid >> 24)) + trial++;
159 			uint8_t tmp2[5];
160 			char tmp3[11];
161 			tmp2[0] = (uint8_t)((nwid40 >> 32) & 0xff);
162 			tmp2[1] = (uint8_t)((nwid40 >> 24) & 0xff);
163 			tmp2[2] = (uint8_t)((nwid40 >> 16) & 0xff);
164 			tmp2[3] = (uint8_t)((nwid40 >> 8) & 0xff);
165 			tmp2[4] = (uint8_t)(nwid40 & 0xff);
166 			tmp3[0] = 'z';
167 			tmp3[1] = 't';
168 			_base32_5_to_8(tmp2,tmp3 + 2);
169 			tmp3[10] = (char)0;
170 			memcpy(ifr.ifr_name,tmp3,11);
171 			OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
172 		} while (stat(procpath,&sbuf) == 0);
173 #endif
174 	}
175 
176 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
177 	if (ioctl(_fd,TUNSETIFF,(void *)&ifr) < 0) {
178 		::close(_fd);
179 		throw std::runtime_error("unable to configure TUN/TAP device for TAP operation");
180 	}
181 
182 	::ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here
183 	_dev = ifr.ifr_name;
184 	::fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC);
185 
186 	(void)::pipe(_shutdownSignalPipe);
187 
188 	_tapReaderThread = std::thread([this]{
189 		uint8_t b[ZT_TAP_BUF_SIZE];
190 		fd_set readfds,nullfds;
191 		int n,nfds,r;
192 		std::vector<void *> buffers;
193 		struct ifreq ifr;
194 
195 		memset(&ifr,0,sizeof(ifr));
196 		strcpy(ifr.ifr_name,_dev.c_str());
197 
198 		const int sock = socket(AF_INET,SOCK_DGRAM,0);
199 		if (sock <= 0)
200 			return;
201 
202 		if (ioctl(sock,SIOCGIFFLAGS,(void *)&ifr) < 0) {
203 			::close(sock);
204 			printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n");
205 			return;
206 		}
207 
208 		ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER;
209 		_mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data,6);
210 		if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) {
211 			::close(sock);
212 			printf("WARNING: ioctl() failed setting up Linux tap device (set MAC)\n");
213 			return;
214 		}
215 
216 		usleep(100000);
217 
218 		ifr.ifr_flags |= IFF_MULTICAST;
219 		ifr.ifr_flags |= IFF_UP;
220 		if (ioctl(sock,SIOCSIFFLAGS,(void *)&ifr) < 0) {
221 			::close(sock);
222 			printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n");
223 			return;
224 		}
225 
226 		usleep(100000);
227 
228 		ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER;
229 		_mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data,6);
230 		if (ioctl(sock,SIOCSIFHWADDR,(void *)&ifr) < 0) {
231 			::close(sock);
232 			printf("WARNING: ioctl() failed setting up Linux tap device (set MAC)\n");
233 			return;
234 		}
235 
236 		ifr.ifr_ifru.ifru_mtu = (int)_mtu;
237 		if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) {
238 			::close(sock);
239 			printf("WARNING: ioctl() failed setting up Linux tap device (set MTU)\n");
240 			return;
241 		}
242 
243 		fcntl(_fd,F_SETFL,O_NONBLOCK);
244 
245 		::close(sock);
246 
247 		if (!_run)
248 			return;
249 
250 		FD_ZERO(&readfds);
251 		FD_ZERO(&nullfds);
252 		nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
253 
254 		r = 0;
255 		for(;;) {
256 			FD_SET(_shutdownSignalPipe[0],&readfds);
257 			FD_SET(_fd,&readfds);
258 			select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
259 
260 			if (FD_ISSET(_shutdownSignalPipe[0],&readfds))
261 				break;
262 
263 			if (FD_ISSET(_fd,&readfds)) {
264 				for(;;) { // read until there are no more packets, then return to outer select() loop
265 					n = (int)::read(_fd,b + r,ZT_TAP_BUF_SIZE - r);
266 					if (n > 0) {
267 						// Some tap drivers like to send the ethernet frame and the
268 						// payload in two chunks, so handle that by accumulating
269 						// data until we have at least a frame.
270 						r += n;
271 						if (r > 14) {
272 							if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
273 								r = _mtu + 14;
274 
275 							if (_enabled) {
276 								//_tapq.post(std::pair<void *,int>(buf,r));
277 								//buf = nullptr;
278 								MAC to(b, 6),from(b + 6, 6);
279 								unsigned int etherType = Utils::ntoh(((const uint16_t *)b)[6]);
280 								_handler(_arg, nullptr, _nwid, from, to, etherType, 0, (const void *)(b + 14),(unsigned int)(r - 14));
281 							}
282 
283 							r = 0;
284 						}
285 					} else {
286 						r = 0;
287 						break;
288 					}
289 				}
290 			}
291 		}
292 	});
293 }
294 
~LinuxEthernetTap()295 LinuxEthernetTap::~LinuxEthernetTap()
296 {
297 	_run = false;
298 	(void)::write(_shutdownSignalPipe[1],"\0",1);
299 	_tapReaderThread.join();
300 	::close(_fd);
301 	::close(_shutdownSignalPipe[0]);
302 	::close(_shutdownSignalPipe[1]);
303 }
304 
setEnabled(bool en)305 void LinuxEthernetTap::setEnabled(bool en)
306 {
307 	_enabled = en;
308 }
309 
enabled() const310 bool LinuxEthernetTap::enabled() const
311 {
312 	return _enabled;
313 }
314 
___removeIp(const std::string & _dev,const InetAddress & ip)315 static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
316 {
317 	LinuxNetLink::getInstance().removeAddress(ip, _dev.c_str());
318 	return true;
319 }
320 
addIps(std::vector<InetAddress> ips)321 bool LinuxEthernetTap::addIps(std::vector<InetAddress> ips)
322 {
323 #ifdef __SYNOLOGY__
324 	std::string filepath = "/etc/sysconfig/network-scripts/ifcfg-"+_dev;
325 	std::string cfg_contents = "DEVICE="+_dev+"\nBOOTPROTO=static";
326 	int ip4=0,ip6=0,ip4_tot=0,ip6_tot=0;
327 
328 	for(int i=0; i<(int)ips.size(); i++) {
329 		if (ips[i].isV4())
330 			ip4_tot++;
331 		else
332 			ip6_tot++;
333 	}
334 	// Assemble and write contents of ifcfg-dev file
335 	for(int i=0; i<(int)ips.size(); i++) {
336 		if (ips[i].isV4()) {
337 			char iptmp[64],iptmp2[64];
338 			std::string numstr4 = ip4_tot > 1 ? std::to_string(ip4) : "";
339 			cfg_contents += "\nIPADDR"+numstr4+"="+ips[i].toIpString(iptmp)
340 				+ "\nNETMASK"+numstr4+"="+ips[i].netmask().toIpString(iptmp2)+"\n";
341 			ip4++;
342 		} else {
343 			char iptmp[64],iptmp2[64];
344 			std::string numstr6 = ip6_tot > 1 ? std::to_string(ip6) : "";
345 			cfg_contents += "\nIPV6ADDR"+numstr6+"="+ips[i].toIpString(iptmp)
346 				+ "\nNETMASK"+numstr6+"="+ips[i].netmask().toIpString(iptmp2)+"\n";
347 			ip6++;
348 		}
349 	}
350 	OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length());
351 	// Finally, add IPs
352 	for(int i=0; i<(int)ips.size(); i++){
353 		LinuxNetLink::getInstance().addAddress(ips[i], _dev.c_str());
354 	}
355 	return true;
356 #endif // __SYNOLOGY__
357 	return false;
358 }
359 
addIp(const InetAddress & ip)360 bool LinuxEthernetTap::addIp(const InetAddress &ip)
361 {
362 	if (!ip)
363 		return false;
364 
365 	std::vector<InetAddress> allIps(ips());
366 	if (std::binary_search(allIps.begin(),allIps.end(),ip))
367 		return true;
368 
369 	// Remove and reconfigure if address is the same but netmask is different
370 	for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
371 		if (i->ipsEqual(ip))
372 			___removeIp(_dev,*i);
373 	}
374 
375 	LinuxNetLink::getInstance().addAddress(ip, _dev.c_str());
376 
377 	return true;
378 }
379 
removeIp(const InetAddress & ip)380 bool LinuxEthernetTap::removeIp(const InetAddress &ip)
381 {
382 	if (!ip)
383 		return true;
384 	std::vector<InetAddress> allIps(ips());
385 	if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) {
386 		if (___removeIp(_dev,ip))
387 			return true;
388 	}
389 	return false;
390 }
391 
ips() const392 std::vector<InetAddress> LinuxEthernetTap::ips() const
393 {
394 	struct ifaddrs *ifa = (struct ifaddrs *)0;
395 	if (getifaddrs(&ifa))
396 		return std::vector<InetAddress>();
397 
398 	std::vector<InetAddress> r;
399 
400 	struct ifaddrs *p = ifa;
401 	while (p) {
402 		if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
403 			switch(p->ifa_addr->sa_family) {
404 				case AF_INET: {
405 					struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
406 					struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
407 					r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
408 				}	break;
409 				case AF_INET6: {
410 					struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
411 					struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
412 					uint32_t b[4];
413 					memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
414 					r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
415 				}	break;
416 			}
417 		}
418 		p = p->ifa_next;
419 	}
420 
421 	if (ifa)
422 		freeifaddrs(ifa);
423 
424 	std::sort(r.begin(),r.end());
425 	r.erase(std::unique(r.begin(),r.end()),r.end());
426 
427 	return r;
428 }
429 
put(const MAC & from,const MAC & to,unsigned int etherType,const void * data,unsigned int len)430 void LinuxEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
431 {
432 	char putBuf[ZT_MAX_MTU + 64];
433 	if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
434 		to.copyTo(putBuf,6);
435 		from.copyTo(putBuf + 6,6);
436 		*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
437 		memcpy(putBuf + 14,data,len);
438 		len += 14;
439 		(void)::write(_fd,putBuf,len);
440 	}
441 }
442 
deviceName() const443 std::string LinuxEthernetTap::deviceName() const
444 {
445 	return _dev;
446 }
447 
setFriendlyName(const char * friendlyName)448 void LinuxEthernetTap::setFriendlyName(const char *friendlyName)
449 {
450 }
451 
scanMulticastGroups(std::vector<MulticastGroup> & added,std::vector<MulticastGroup> & removed)452 void LinuxEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
453 {
454 	char *ptr,*ptr2;
455 	unsigned char mac[6];
456 	std::vector<MulticastGroup> newGroups;
457 
458 	int fd = ::open("/proc/net/dev_mcast",O_RDONLY);
459 	if (fd > 0) {
460 		char buf[131072];
461 		int n = (int)::read(fd,buf,sizeof(buf));
462 		if ((n > 0)&&(n < (int)sizeof(buf))) {
463 			buf[n] = (char)0;
464 			for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) {
465 				int fno = 0;
466 				char *devname = (char *)0;
467 				char *mcastmac = (char *)0;
468 				for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) {
469 					if (fno == 1)
470 						devname = f;
471 					else if (fno == 4)
472 						mcastmac = f;
473 					++fno;
474 				}
475 				if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6))
476 					newGroups.push_back(MulticastGroup(MAC(mac,6),0));
477 			}
478 		}
479 		::close(fd);
480 	}
481 
482 	std::vector<InetAddress> allIps(ips());
483 	for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
484 		newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
485 
486 	std::sort(newGroups.begin(),newGroups.end());
487 	newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end());
488 
489 	for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
490 		if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
491 			added.push_back(*m);
492 	}
493 	for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
494 		if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
495 			removed.push_back(*m);
496 	}
497 
498 	_multicastGroups.swap(newGroups);
499 }
500 
setMtu(unsigned int mtu)501 void LinuxEthernetTap::setMtu(unsigned int mtu)
502 {
503 	if (_mtu != mtu) {
504 		_mtu = mtu;
505 		int sock = socket(AF_INET,SOCK_DGRAM,0);
506 		if (sock > 0) {
507 			struct ifreq ifr;
508 			memset(&ifr,0,sizeof(ifr));
509 			ifr.ifr_ifru.ifru_mtu = (int)mtu;
510 			ioctl(sock,SIOCSIFMTU,(void *)&ifr);
511 			close(sock);
512 		}
513 	}
514 }
515 
516 } // namespace ZeroTier
517 
518 #endif // __LINUX__
519