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