MacEthernetTapAgent.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * You can be released from the requirements of the license by purchasing
  21. * a commercial license. Buying such a license is mandatory as soon as you
  22. * develop commercial closed-source software that incorporates or links
  23. * directly against ZeroTier software without disclosing the source code
  24. * of your own application.
  25. */
  26. /*
  27. * This creates a pair of feth devices with the lower numbered device
  28. * being the ZeroTier virtual interface and the other being the device
  29. * used to actually read and write packets. The latter gets no IP config
  30. * and is only used for I/O. The behavior of feth is similar to the
  31. * veth pairs that exist on Linux.
  32. *
  33. * The feth device has only existed since MacOS Sierra, but that's fairly
  34. * long ago in Mac terms.
  35. *
  36. * I/O with feth must be done using two different sockets. The BPF socket
  37. * is used to receive packets, while an AF_NDRV (low-level network driver
  38. * access) socket must be used to inject. AF_NDRV can't read IP frames
  39. * since BSD doesn't forward packets out the NDRV tap if they've already
  40. * been handled, and while BPF can inject its MTU for injected packets
  41. * is limited to 2048. AF_NDRV packet injection is required to inject
  42. * ZeroTier's large MTU frames.
  43. *
  44. * Benchmarks show that this performs similarly to the old tap.kext driver,
  45. * and a kext is no longer required. Splitting it off into an agent will
  46. * also make it easier to have zerotier-one itself drop permissions.
  47. *
  48. * All this stuff is basically undocumented. A lot of tracing through
  49. * the Darwin/XNU kernel source was required to figure out how to make
  50. * this actually work.
  51. *
  52. * See also:
  53. *
  54. * https://apple.stackexchange.com/questions/337715/fake-ethernet-interfaces-feth-if-fake-anyone-ever-seen-this
  55. * https://opensource.apple.com/source/xnu/xnu-4570.41.2/bsd/net/if_fake.c.auto.html
  56. *
  57. */
  58. #include <stdio.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <stdarg.h>
  62. #include <unistd.h>
  63. #include <signal.h>
  64. #include <fcntl.h>
  65. #include <errno.h>
  66. #include <sys/signal.h>
  67. #include <sys/types.h>
  68. #include <sys/stat.h>
  69. #include <sys/ioctl.h>
  70. #include <sys/wait.h>
  71. #include <sys/select.h>
  72. #include <sys/cdefs.h>
  73. #include <sys/uio.h>
  74. #include <sys/param.h>
  75. #include <sys/ioctl.h>
  76. #include <sys/socket.h>
  77. #include <sys/sysctl.h>
  78. #include <netinet/in.h>
  79. #include <arpa/inet.h>
  80. #include <net/bpf.h>
  81. #include <net/route.h>
  82. #include <net/if.h>
  83. #include <net/if_arp.h>
  84. #include <net/if_dl.h>
  85. #include <net/if_media.h>
  86. #include <net/ndrv.h>
  87. #include <netinet/in_var.h>
  88. #include <netinet/icmp6.h>
  89. #include <netinet6/in6_var.h>
  90. #include <netinet6/nd6.h>
  91. #include <ifaddrs.h>
  92. #include "../version.h"
  93. #include "MacEthernetTapAgent.h"
  94. #ifndef SIOCAUTOCONF_START
  95. #define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */
  96. #endif
  97. #ifndef SIOCAUTOCONF_STOP
  98. #define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */
  99. #endif
  100. #define P_IFCONFIG "/sbin/ifconfig"
  101. static unsigned char s_pktReadBuf[131072] __attribute__ ((__aligned__(16)));
  102. static unsigned char s_stdinReadBuf[131072] __attribute__ ((__aligned__(16)));
  103. static char s_deviceName[IFNAMSIZ];
  104. static char s_peerDeviceName[IFNAMSIZ];
  105. static int s_bpffd = -1;
  106. static int s_ndrvfd = -1;
  107. static pid_t s_parentPid;
  108. static void configureIpv6Parameters(const char *ifname,int performNUD,int acceptRouterAdverts)
  109. {
  110. struct in6_ndireq nd;
  111. struct in6_ifreq ifr;
  112. int s = socket(AF_INET6,SOCK_DGRAM,0);
  113. if (s <= 0)
  114. return;
  115. memset(&nd,0,sizeof(nd));
  116. strncpy(nd.ifname,ifname,sizeof(nd.ifname));
  117. if (ioctl(s,SIOCGIFINFO_IN6,&nd)) {
  118. close(s);
  119. return;
  120. }
  121. unsigned long oldFlags = (unsigned long)nd.ndi.flags;
  122. if (performNUD)
  123. nd.ndi.flags |= ND6_IFF_PERFORMNUD;
  124. else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD;
  125. if (oldFlags != (unsigned long)nd.ndi.flags) {
  126. if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) {
  127. close(s);
  128. return;
  129. }
  130. }
  131. memset(&ifr,0,sizeof(ifr));
  132. strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name));
  133. if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) {
  134. close(s);
  135. return;
  136. }
  137. close(s);
  138. }
  139. static int run(const char *path,...)
  140. {
  141. va_list ap;
  142. char *args[16];
  143. int argNo = 1;
  144. va_start(ap,path);
  145. args[0] = (char *)path;
  146. for(;argNo<15;++argNo) {
  147. args[argNo] = va_arg(ap,char *);
  148. if (!args[argNo]) {
  149. break;
  150. }
  151. }
  152. args[argNo++] = (char *)0;
  153. va_end(ap);
  154. pid_t pid = vfork();
  155. if (pid < 0) {
  156. return -1;
  157. } else if (pid == 0) {
  158. dup2(STDERR_FILENO,STDOUT_FILENO);
  159. execv(args[0],args);
  160. _exit(-1);
  161. }
  162. int rv = 0;
  163. waitpid(pid,&rv,0);
  164. return rv;
  165. }
  166. static void die()
  167. {
  168. if (s_ndrvfd >= 0)
  169. close(s_ndrvfd);
  170. if (s_bpffd >= 0)
  171. close(s_bpffd);
  172. if (s_deviceName[0])
  173. run("/sbin/ifconfig",s_deviceName,"destroy",(char *)0);
  174. if (s_peerDeviceName[0])
  175. run("/sbin/ifconfig",s_peerDeviceName,"destroy",(char *)0);
  176. }
  177. int main(int argc,char **argv)
  178. {
  179. char buf[128];
  180. struct ifreq ifr;
  181. u_int fl;
  182. fd_set rfds,wfds,efds;
  183. struct iovec iov[2];
  184. s_deviceName[0] = 0;
  185. s_peerDeviceName[0] = 0;
  186. s_parentPid = getppid();
  187. atexit(&die);
  188. signal(SIGIO,SIG_IGN);
  189. signal(SIGCHLD,SIG_IGN);
  190. signal(SIGPIPE,SIG_IGN);
  191. signal(SIGUSR1,SIG_IGN);
  192. signal(SIGUSR2,SIG_IGN);
  193. signal(SIGALRM,SIG_IGN);
  194. signal(SIGQUIT,&exit);
  195. signal(SIGTERM,&exit);
  196. signal(SIGKILL,&exit);
  197. signal(SIGINT,&exit);
  198. signal(SIGPIPE,&exit);
  199. if (getuid() != 0) {
  200. if (setuid(0) != 0) {
  201. fprintf(stderr,"E must be run as root or with root setuid bit on executable\n");
  202. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST;
  203. }
  204. }
  205. if (argc < 5) {
  206. fprintf(stderr,"E invalid or missing argument(s) (usage: MacEthernetTapAgent <0-4999> <mac> <mtu> <metric>)\n");
  207. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST;
  208. }
  209. const int deviceNo = atoi(argv[1]);
  210. if ((deviceNo < 0)||(deviceNo > 4999)) {
  211. fprintf(stderr,"E invalid or missing argument(s) (usage: MacEthernetTapAgent <0-4999> <mac> <mtu> <metric>)\n");
  212. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST;
  213. }
  214. const char *mac = argv[2];
  215. const char *mtu = argv[3];
  216. const char *metric = argv[4];
  217. s_ndrvfd = socket(AF_NDRV,SOCK_RAW,0);
  218. if (s_ndrvfd < 0) {
  219. fprintf(stderr,"E unable to open AF_NDRV socket\n");
  220. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  221. }
  222. snprintf(s_deviceName,sizeof(s_deviceName),"feth%d",deviceNo);
  223. snprintf(s_peerDeviceName,sizeof(s_peerDeviceName),"feth%d",deviceNo+5000);
  224. if (run(P_IFCONFIG,s_peerDeviceName,"create",(char *)0) != 0) {
  225. fprintf(stderr,"E unable to create %s\n",s_deviceName);
  226. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  227. }
  228. usleep(10);
  229. if (run(P_IFCONFIG,s_deviceName,"create",(char *)0) != 0) {
  230. fprintf(stderr,"E unable to create %s\n",s_deviceName);
  231. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  232. }
  233. run(P_IFCONFIG,s_deviceName,"lladdr",mac,(char *)0);
  234. usleep(10);
  235. run(P_IFCONFIG,s_peerDeviceName,"peer",s_deviceName,(char *)0);
  236. usleep(10);
  237. run(P_IFCONFIG,s_peerDeviceName,"mtu","16370","up",(char *)0); /* 16370 is the largest MTU MacOS/Darwin seems to allow */
  238. usleep(10);
  239. run(P_IFCONFIG,s_deviceName,"mtu",mtu,"metric",metric,"up",(char *)0);
  240. usleep(10);
  241. configureIpv6Parameters(s_deviceName,1,0);
  242. usleep(10);
  243. struct sockaddr_ndrv nd;
  244. nd.snd_len = sizeof(struct sockaddr_ndrv);
  245. nd.snd_family = AF_NDRV;
  246. memcpy(nd.snd_name,s_peerDeviceName,sizeof(nd.snd_name));
  247. if (bind(s_ndrvfd,(struct sockaddr *)&nd,sizeof(nd)) != 0) {
  248. fprintf(stderr,"E unable to bind AF_NDRV socket\n");
  249. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  250. }
  251. if (connect(s_ndrvfd,(struct sockaddr *)&nd,sizeof(nd)) != 0) {
  252. fprintf(stderr,"E unable to connect AF_NDRV socket\n");
  253. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  254. }
  255. /* Start at /dev/bpf1 since some simple bpf-using net utilities hard-code /dev/bpf0.
  256. * Things like libpcap are smart enough to search. */
  257. for(int bpfno=1;bpfno<5000;++bpfno) {
  258. char tmp[32];
  259. snprintf(tmp,sizeof(tmp),"/dev/bpf%d",bpfno);
  260. s_bpffd = open(tmp,O_RDWR);
  261. if (s_bpffd >= 0) {
  262. break;
  263. }
  264. }
  265. if (s_bpffd < 0) {
  266. fprintf(stderr,"E unable to open bpf device\n");
  267. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  268. }
  269. fl = sizeof(s_pktReadBuf);
  270. if (ioctl(s_bpffd,BIOCSBLEN,&fl) != 0) {
  271. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  272. }
  273. const size_t readPktSize = (size_t)fl;
  274. fl = 1;
  275. if (ioctl(s_bpffd,BIOCIMMEDIATE,&fl) != 0) {
  276. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  277. }
  278. fl = 0;
  279. if (ioctl(s_bpffd,BIOCSSEESENT,&fl) != 0) {
  280. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  281. }
  282. memset(&ifr,0,sizeof(ifr));
  283. memcpy(ifr.ifr_name,s_peerDeviceName,IFNAMSIZ);
  284. if (ioctl(s_bpffd,BIOCSETIF,&ifr) != 0) {
  285. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  286. }
  287. fl = 1;
  288. if (ioctl(s_bpffd,BIOCSHDRCMPLT,&fl) != 0) {
  289. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  290. }
  291. fl = 1;
  292. if (ioctl(s_bpffd,BIOCPROMISC,&fl) != 0) {
  293. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE;
  294. }
  295. fprintf(stderr,"I %s %s %d.%d.%d.%d\n",s_deviceName,s_peerDeviceName,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION,ZEROTIER_ONE_VERSION_BUILD);
  296. FD_ZERO(&rfds);
  297. FD_ZERO(&wfds);
  298. FD_ZERO(&efds);
  299. long stdinReadPtr = 0;
  300. for(;;) {
  301. FD_SET(STDIN_FILENO,&rfds);
  302. FD_SET(s_bpffd,&rfds);
  303. if (select(s_bpffd+1,&rfds,&wfds,&efds,(struct timeval *)0) < 0) {
  304. if ((errno == EAGAIN)||(errno == EINTR)) {
  305. usleep(10);
  306. continue;
  307. }
  308. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_READ_ERROR;
  309. }
  310. if (FD_ISSET(s_bpffd,&rfds)) {
  311. long n = (long)read(s_bpffd,s_pktReadBuf,readPktSize);
  312. if (n > 0) {
  313. for(unsigned char *p=s_pktReadBuf,*eof=p+n;p<eof;) {
  314. struct bpf_hdr *h = (struct bpf_hdr *)p;
  315. if ((h->bh_caplen > 0)&&((p + h->bh_hdrlen + h->bh_caplen) <= eof)) {
  316. uint16_t len = (uint16_t)h->bh_caplen;
  317. iov[0].iov_base = &len;
  318. iov[0].iov_len = 2;
  319. iov[1].iov_base = p + h->bh_hdrlen;
  320. iov[1].iov_len = h->bh_caplen;
  321. writev(STDOUT_FILENO,iov,2);
  322. }
  323. p += BPF_WORDALIGN(h->bh_hdrlen + h->bh_caplen);
  324. }
  325. }
  326. }
  327. if (FD_ISSET(STDIN_FILENO,&rfds)) {
  328. long n = (long)read(STDIN_FILENO,s_stdinReadBuf + stdinReadPtr,sizeof(s_stdinReadBuf) - stdinReadPtr);
  329. if (n > 0) {
  330. stdinReadPtr += n;
  331. while (stdinReadPtr >= 2) {
  332. long len = *((uint16_t *)s_stdinReadBuf);
  333. if (stdinReadPtr >= (len + 2)) {
  334. if (len > 0) {
  335. unsigned char *msg = s_stdinReadBuf + 2;
  336. switch(msg[0]) {
  337. case ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET:
  338. if (len > 1) {
  339. if (write(s_ndrvfd,msg+1,len-1) < 0) {
  340. fprintf(stderr,"E inject failed size==%ld errno==%d\n",len-1,errno);
  341. }
  342. }
  343. break;
  344. case ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG: {
  345. char *args[16];
  346. args[0] = P_IFCONFIG;
  347. args[1] = s_deviceName;
  348. int argNo = 2;
  349. for(int argPtr=0,k=1,l=(int)len;k<l;++k) {
  350. if (!msg[k]) {
  351. if (argPtr > 0) {
  352. argPtr = 0;
  353. ++argNo;
  354. if (argNo >= 15) {
  355. break;
  356. }
  357. }
  358. } else {
  359. if (argPtr == 0) {
  360. args[argNo] = (char *)(msg + k);
  361. }
  362. argPtr++;
  363. }
  364. }
  365. args[argNo] = (char *)0;
  366. if (argNo > 2) {
  367. pid_t pid = fork();
  368. if (pid < 0) {
  369. return -1;
  370. } else if (pid == 0) {
  371. dup2(STDERR_FILENO,STDOUT_FILENO);
  372. execv(args[0],args);
  373. _exit(-1);
  374. }
  375. int rv = 0;
  376. waitpid(pid,&rv,0);
  377. }
  378. } break;
  379. case ZT_MACETHERNETTAPAGENT_STDIN_CMD_EXIT:
  380. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS;
  381. default:
  382. fprintf(stderr,"E unrecognized message type over pipe from host process: %d (length: %d)\n",(int)msg[0],(int)len);
  383. break;
  384. }
  385. }
  386. if (stdinReadPtr > (len + 2)) {
  387. memmove(s_stdinReadBuf,s_stdinReadBuf + len + 2,stdinReadPtr -= (len + 2));
  388. } else {
  389. stdinReadPtr = 0;
  390. }
  391. } else {
  392. break;
  393. }
  394. }
  395. }
  396. }
  397. }
  398. return ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS;
  399. }