ExtOsdep.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. #include <sys/times.h>
  2. #include <fcntl.h>
  3. #include <unistd.h>
  4. #include <iostream>
  5. #include "ExtOsdep.hpp"
  6. #include <list>
  7. #include "../node/AtomicCounter.hpp"
  8. #define ZT_TAP_BUF_SIZE 16384
  9. namespace ZeroTier {
  10. static int eodFd = -1;
  11. static Mutex eodMutex;
  12. static int eodMgmtFd = -1;
  13. struct EodRoute {
  14. InetAddress target;
  15. InetAddress via;
  16. InetAddress src;
  17. std::string ifname;
  18. };
  19. static std::list<EodRoute> allRoutes;
  20. template<typename T> static void __eodSend(const T &t) {
  21. write(eodFd, &t, sizeof(t));
  22. }
  23. static void strncpyx(char *dest, const char *src, size_t n) {
  24. strncpy(dest, src, n);
  25. if (n > 1) dest[n - 1] = 0;
  26. }
  27. static int __eodWait(unsigned char msg, unsigned char *d, unsigned l,
  28. unsigned maxl = 0, int *recvfd = nullptr) {
  29. if (!maxl) maxl = l;
  30. auto start = times(NULL);
  31. while (1) {
  32. msghdr mh;
  33. iovec iov;
  34. struct {
  35. size_t cmsg_len;
  36. int cmsg_level;
  37. int cmsg_type;
  38. int fd;
  39. } __attribute__((packed)) cmsg;
  40. memset(&mh, 0, sizeof(mh));
  41. mh.msg_iov = &iov;
  42. mh.msg_iovlen = 1;
  43. if (recvfd) {
  44. mh.msg_control = &cmsg;
  45. mh.msg_controllen = sizeof(cmsg);
  46. }
  47. iov.iov_base = d;
  48. iov.iov_len = maxl;
  49. int r = recvmsg(eodFd, &mh, MSG_TRUNC | MSG_CMSG_CLOEXEC);
  50. if (r > 0) {
  51. if (recvfd && mh.msg_controllen >= sizeof(cmsg)
  52. && cmsg.cmsg_len == sizeof(cmsg)
  53. && cmsg.cmsg_level == SOL_SOCKET
  54. && cmsg.cmsg_type == SCM_RIGHTS) {
  55. *recvfd = cmsg.fd;
  56. fprintf(stderr, "eodWait: received fd %d\n", *recvfd);
  57. }
  58. if (d[0] != msg) {
  59. fprintf(stderr, "eodWait: wrong msg, expected %u got %u\n", msg, d[0]);
  60. return -1;
  61. }
  62. if ((unsigned)r < l || (unsigned)r > maxl) {
  63. fprintf(stderr, "eodWait: wrong len, expected %u got %d\n", l, r);
  64. return -1;
  65. }
  66. return r;
  67. }
  68. if (times(NULL) - start > 500) {
  69. fprintf(stderr, "eodWait: timeout\n");
  70. return -1;
  71. }
  72. usleep(100000);
  73. }
  74. }
  75. template<typename T> static bool __eodWait(unsigned msg, T &t) {
  76. return __eodWait(msg, (unsigned char *)&t, sizeof(T)) == (int)sizeof(T);
  77. }
  78. template<typename M, typename R> static bool __eodXchg(const M &m, unsigned rm, R &r) {
  79. __eodSend(m);
  80. return __eodWait(rm, r);
  81. }
  82. template<typename M, typename R> static bool eodXchg(const M &m, unsigned rm, R &r) {
  83. Mutex::Lock l(eodMutex);
  84. return __eodXchg(m, rm, r);
  85. }
  86. void ExtOsdep::init(int fd1, int fd2) {
  87. eodFd = fd1;
  88. eodMgmtFd = fd2;
  89. fcntl(eodMgmtFd,F_SETFL,O_NONBLOCK);
  90. }
  91. void ExtOsdep::started(int *f, void **cp) {
  92. *f = eodMgmtFd;
  93. *cp = (void *)eodMgmtFd;
  94. unsigned char msg = ZT_EOD_MSG_STARTED;
  95. Mutex::Lock l(eodMutex);
  96. __eodSend(msg);
  97. }
  98. static std::string mgmtrd;
  99. static std::string mgmtwr;
  100. bool ExtOsdep::mgmtWritable(void *cookie) {
  101. if (cookie != (void *)eodMgmtFd) return false;
  102. if (mgmtwr.size() == 0) return true;
  103. auto sz = write(eodMgmtFd, mgmtwr.data(), mgmtwr.size());
  104. if (sz <= 0) return false;
  105. mgmtwr.erase(mgmtwr.begin(), mgmtwr.begin() + sz);
  106. return mgmtwr.empty();
  107. }
  108. bool ExtOsdep::mgmtRecv(void *cookie, void *data, unsigned long len,
  109. std::function<unsigned (unsigned, const std::string &, const std::string &, std::string &)> cb) {
  110. if (cookie != (void *)eodMgmtFd) return false;
  111. mgmtrd.append((char *)data, len);
  112. while (1) {
  113. auto req = (zt_eod_mgmt_req *)mgmtrd.data();
  114. if (mgmtrd.size() < sizeof(*req)) break;
  115. unsigned reqsz = sizeof(*req) + req->pathlen + req->datalen;
  116. if (mgmtrd.size() < reqsz) break;
  117. std::string resp;
  118. char *p = (char *)req->data;
  119. zt_eod_mgmt_reply rep;
  120. rep.scode = cb(req->method, std::string(p, p + req->pathlen),
  121. std::string(p + req->pathlen, p + req->pathlen + req->datalen), resp);
  122. rep.datalen = resp.size();
  123. mgmtrd.erase(mgmtrd.begin(), mgmtrd.begin() + reqsz);
  124. mgmtwr.append((char *)&rep, sizeof(rep));
  125. mgmtwr.append(resp);
  126. auto sz = write(eodMgmtFd, mgmtwr.data(), mgmtwr.size());
  127. if (sz > 0) mgmtwr.erase(mgmtwr.begin(), mgmtwr.begin() + sz);
  128. }
  129. return !mgmtwr.empty();
  130. }
  131. void ExtOsdep::routeAddDel(bool add, const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname) {
  132. Mutex::Lock l(eodMutex);
  133. std::string ifn;
  134. if (ifname) ifn = ifname;
  135. if (add) {
  136. for (auto x = allRoutes.begin(); x != allRoutes.end(); ++x) {
  137. if (x->target == target && x->via == via
  138. && x->src == src && x->ifname == ifn) return;
  139. }
  140. allRoutes.push_back({target, via, src, ifn});
  141. }
  142. else {
  143. bool found = false;
  144. for (auto x = allRoutes.begin(); x != allRoutes.end(); ++x) {
  145. if (x->target == target && x->via == via
  146. && x->src == src && x->ifname == ifn) {
  147. allRoutes.erase(x);
  148. found = true;
  149. break;
  150. }
  151. }
  152. if (!found) return;
  153. }
  154. zt_eod_msg_route req;
  155. memset(&req, 0, sizeof(req));
  156. req.cmd = add ? ZT_EOD_MSG_ADDROUTE : ZT_EOD_MSG_DELROUTE;
  157. req.afi = target.isV4() ? 1 : 2;
  158. req.dstlen = target.netmaskBits();
  159. memcpy(req.dst, target.rawIpData(), target.isV4() ? 4 : 16);
  160. if (ifname) strncpyx(req.dev, ifname, sizeof(req.dev));
  161. if (via) memcpy(req.gw, via.rawIpData(), target.isV4() ? 4 : 16);
  162. if (src) memcpy(req.src, src.rawIpData(), target.isV4() ? 4 : 16);
  163. unsigned char resp;
  164. __eodXchg(req, add ? ZT_EOD_MSG_ADDROUTERESP : ZT_EOD_MSG_DELROUTERESP, resp);
  165. }
  166. bool ExtOsdep::getBindAddrs(std::map<InetAddress,std::string> &ret) {
  167. Mutex::Lock l(eodMutex);
  168. unsigned char req = ZT_EOD_MSG_GETBINDADDRS;
  169. __eodSend(req);
  170. zt_eod_msg_getbindaddrsresp *resp;
  171. unsigned char buf[ZT_EOD_MAXMSGSIZE];
  172. int r = __eodWait(ZT_EOD_MSG_GETBINDADDRSRESP, (unsigned char *)buf, sizeof(*resp), sizeof(buf));
  173. if (r < (int)sizeof(*resp)) return false;
  174. int c = (r - (int)sizeof(*resp)) / sizeof(resp->addrs[0]);
  175. resp = (zt_eod_msg_getbindaddrsresp *)buf;
  176. for (int i = 0; i < c; ++i) {
  177. ret[InetAddress(resp->addrs[i].data, resp->addrs[i].afi == 1 ? 4 : 16, resp->addrs[i].len)]
  178. = resp->addrs[i].ifname;
  179. }
  180. return resp->result;
  181. }
  182. ExtOsdepTap::ExtOsdepTap(
  183. const char *homePath,
  184. const MAC &mac,
  185. unsigned int mtu,
  186. unsigned int metric,
  187. uint64_t nwid,
  188. const char *friendlyName,
  189. void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
  190. void *arg) :
  191. _handler(handler),
  192. _arg(arg),
  193. _nwid(nwid),
  194. _mac(mac),
  195. _homePath(homePath),
  196. _mtu(mtu),
  197. _fd(0),
  198. _enabled(true),
  199. _run(true)
  200. {
  201. zt_eod_msg_addtap req;
  202. req.cmd = ZT_EOD_MSG_ADDTAP;
  203. req.nwid = nwid;
  204. req.mtu = mtu;
  205. req.metric = metric;
  206. strncpyx(req.fname, friendlyName, sizeof(req.fname));
  207. mac.copyTo(req.mac, 6);
  208. zt_eod_msg_addtapresp resp;
  209. Mutex::Lock l(eodMutex);
  210. __eodSend(req);
  211. _fd = -1;
  212. if (__eodWait(ZT_EOD_MSG_ADDTAPRESP, (unsigned char *)&resp, sizeof(resp), sizeof(resp), &_fd) != sizeof(resp))
  213. throw std::runtime_error(std::string("could not create TAP"));
  214. _dev = resp.name;
  215. if (_dev.empty() || _fd < 0)
  216. throw std::runtime_error(std::string("could not create TAP"));
  217. fcntl(_fd,F_SETFL,O_NONBLOCK);
  218. // processing shamelessly copied from LinuxEthernetTap
  219. (void)::pipe(_shutdownSignalPipe);
  220. for(unsigned int t=0;t<2;++t) {
  221. _tapReaderThread[t] = std::thread([this, t]{
  222. fd_set readfds,nullfds;
  223. int n,nfds,r;
  224. void *buf = nullptr;
  225. std::vector<void *> buffers;
  226. if (!_run)
  227. return;
  228. FD_ZERO(&readfds);
  229. FD_ZERO(&nullfds);
  230. nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1;
  231. r = 0;
  232. for(;;) {
  233. FD_SET(_shutdownSignalPipe[0],&readfds);
  234. FD_SET(_fd,&readfds);
  235. select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0);
  236. if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread
  237. break;
  238. if (FD_ISSET(_fd,&readfds)) {
  239. for(;;) { // read until there are no more packets, then return to outer select() loop
  240. if (!buf) {
  241. // To reduce use of the mutex, we keep a local buffer vector and
  242. // swap (which is a pointer swap) with the global one when it's
  243. // empty. This retrieves a batch of buffers to use.
  244. if (buffers.empty()) {
  245. std::lock_guard<std::mutex> l(_buffers_l);
  246. buffers.swap(_buffers);
  247. }
  248. if (buffers.empty()) {
  249. buf = malloc(ZT_TAP_BUF_SIZE);
  250. if (!buf)
  251. break;
  252. } else {
  253. buf = buffers.back();
  254. buffers.pop_back();
  255. }
  256. }
  257. n = (int)::read(_fd,reinterpret_cast<uint8_t *>(buf) + r,ZT_TAP_BUF_SIZE - r);
  258. if (n > 0) {
  259. // Some tap drivers like to send the ethernet frame and the
  260. // payload in two chunks, so handle that by accumulating
  261. // data until we have at least a frame.
  262. r += n;
  263. if (r > 14) {
  264. if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
  265. r = _mtu + 14;
  266. if (_enabled && _tapqsize.load() < 1000) {
  267. ++_tapqsize;
  268. _tapq.post(std::pair<void *,int>(buf,r));
  269. buf = nullptr;
  270. }
  271. r = 0;
  272. }
  273. } else {
  274. r = 0;
  275. break;
  276. }
  277. }
  278. }
  279. }
  280. });
  281. }
  282. _tapProcessorThread = std::thread([this] {
  283. MAC to,from;
  284. std::pair<void *,int> qi;
  285. while (_tapq.get(qi)) {
  286. --_tapqsize;
  287. uint8_t *const b = reinterpret_cast<uint8_t *>(qi.first);
  288. if (b) {
  289. to.setTo(b, 6);
  290. from.setTo(b + 6, 6);
  291. unsigned int etherType = Utils::ntoh(((const uint16_t *)b)[6]);
  292. _handler(_arg, nullptr, _nwid, from, to, etherType, 0, (const void *)(b + 14),(unsigned int)(qi.second - 14));
  293. {
  294. std::lock_guard<std::mutex> l(_buffers_l);
  295. if (_buffers.size() < 128)
  296. _buffers.push_back(qi.first);
  297. else free(qi.first);
  298. }
  299. } else break;
  300. }
  301. });
  302. }
  303. ExtOsdepTap::~ExtOsdepTap() {
  304. _run = false;
  305. (void)::write(_shutdownSignalPipe[1],"\0",1); // causes reader thread(s) to exit
  306. _tapq.post(std::pair<void *,int>(nullptr,0)); // causes processor thread to exit
  307. _tapReaderThread[0].join();
  308. _tapReaderThread[1].join();
  309. _tapProcessorThread.join();
  310. ::close(_fd);
  311. ::close(_shutdownSignalPipe[0]);
  312. ::close(_shutdownSignalPipe[1]);
  313. for(std::vector<void *>::iterator i(_buffers.begin());i!=_buffers.end();++i)
  314. free(*i);
  315. std::vector< std::pair<void *,int> > dv(_tapq.drain());
  316. for(std::vector< std::pair<void *,int> >::iterator i(dv.begin());i!=dv.end();++i) {
  317. if (i->first)
  318. free(i->first);
  319. }
  320. zt_eod_msg_deltap req;
  321. req.cmd = ZT_EOD_MSG_DELTAP;
  322. strcpy(req.name, _dev.c_str());
  323. unsigned char resp;
  324. eodXchg(req, ZT_EOD_MSG_DELTAPRESP, resp);
  325. }
  326. void ExtOsdepTap::setEnabled(bool en) {
  327. _enabled = en;
  328. }
  329. bool ExtOsdepTap::enabled() const {
  330. return _enabled;
  331. }
  332. void ExtOsdepTap::doRemoveIp(const InetAddress &ip) {
  333. zt_eod_msg_ip req;
  334. req.cmd = ZT_EOD_MSG_DELIP;
  335. strcpy(req.name, _dev.c_str());
  336. req.afi = ip.isV4() ? 1 : 2;
  337. req.len = ip.netmaskBits();
  338. memcpy(req.data, ip.rawIpData(), ip.isV4() ? 4 : 16);
  339. unsigned char resp;
  340. __eodXchg(req, ZT_EOD_MSG_DELIPRESP, resp);
  341. }
  342. bool ExtOsdepTap::addIp(const InetAddress &ip) {
  343. Mutex::Lock l(eodMutex);
  344. for(auto i = allIps.begin();i!=allIps.end();++i) {
  345. if (*i == ip) return true;
  346. if (i->ipsEqual(ip)) doRemoveIp(*i);
  347. }
  348. zt_eod_msg_ip req;
  349. req.cmd = ZT_EOD_MSG_ADDIP;
  350. strcpy(req.name, _dev.c_str());
  351. req.afi = ip.isV4() ? 1 : 2;
  352. req.len = ip.netmaskBits();
  353. memcpy(req.data, ip.rawIpData(), ip.isV4() ? 4 : 16);
  354. unsigned char resp;
  355. __eodXchg(req, ZT_EOD_MSG_ADDIPRESP, resp);
  356. allIps.push_back(ip);
  357. return true;
  358. }
  359. bool ExtOsdepTap::addIps(std::vector<InetAddress> ips) {
  360. return false;
  361. }
  362. bool ExtOsdepTap::removeIp(const InetAddress &ip) {
  363. Mutex::Lock l(eodMutex);
  364. for(auto i = allIps.begin();i!=allIps.end();++i) {
  365. if (*i == ip) {
  366. doRemoveIp(*i);
  367. return true;
  368. }
  369. }
  370. return false;
  371. }
  372. std::vector<InetAddress> ExtOsdepTap::ips() const {
  373. std::vector<InetAddress> ret;
  374. Mutex::Lock l(eodMutex);
  375. zt_eod_msg_getips req;
  376. req.cmd = ZT_EOD_MSG_GETIPS;
  377. strcpy(req.name, _dev.c_str());
  378. __eodSend(req);
  379. zt_eod_msg_getipsresp *resp;
  380. unsigned char buf[ZT_EOD_MAXMSGSIZE];
  381. int r = __eodWait(ZT_EOD_MSG_GETIPSRESP, (unsigned char *)buf, sizeof(*resp), sizeof(buf));
  382. if (r < (int)sizeof(*resp)) return ret;
  383. int c = (r - (int)sizeof(*resp)) / sizeof(resp->addrs[0]);
  384. resp = (zt_eod_msg_getipsresp *)buf;
  385. for (int i = 0; i < c; ++i) {
  386. ret.push_back(InetAddress(resp->addrs[i].data, resp->addrs[i].afi == 1 ? 4 : 16, resp->addrs[i].len));
  387. }
  388. return ret;
  389. }
  390. void ExtOsdepTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) {
  391. char putBuf[ZT_MAX_MTU + 64];
  392. if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
  393. to.copyTo(putBuf,6);
  394. from.copyTo(putBuf + 6,6);
  395. *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType);
  396. memcpy(putBuf + 14,data,len);
  397. len += 14;
  398. (void)::write(_fd,putBuf,len);
  399. }
  400. }
  401. std::string ExtOsdepTap::deviceName() const {
  402. return _dev;
  403. }
  404. void ExtOsdepTap::setFriendlyName(const char *friendlyName) {}
  405. void ExtOsdepTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed) {
  406. char *ptr,*ptr2;
  407. unsigned char mac[6];
  408. std::vector<MulticastGroup> newGroups;
  409. int fd = ::open("/proc/net/dev_mcast",O_RDONLY);
  410. if (fd > 0) {
  411. char buf[131072];
  412. int n = (int)::read(fd,buf,sizeof(buf));
  413. if ((n > 0)&&(n < (int)sizeof(buf))) {
  414. buf[n] = (char)0;
  415. for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) {
  416. int fno = 0;
  417. char *devname = (char *)0;
  418. char *mcastmac = (char *)0;
  419. for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) {
  420. if (fno == 1)
  421. devname = f;
  422. else if (fno == 4)
  423. mcastmac = f;
  424. ++fno;
  425. }
  426. if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6))
  427. newGroups.push_back(MulticastGroup(MAC(mac,6),0));
  428. }
  429. }
  430. ::close(fd);
  431. }
  432. std::vector<InetAddress> allIps(ips());
  433. for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
  434. newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
  435. std::sort(newGroups.begin(),newGroups.end());
  436. newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end());
  437. for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
  438. if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
  439. added.push_back(*m);
  440. }
  441. for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
  442. if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
  443. removed.push_back(*m);
  444. }
  445. _multicastGroups.swap(newGroups);
  446. }
  447. void ExtOsdepTap::setMtu(unsigned int mtu) {
  448. if (mtu == _mtu) return;
  449. _mtu = mtu;
  450. zt_eod_msg_setmtu req;
  451. req.cmd = ZT_EOD_MSG_SETMTU;
  452. strcpy(req.name, _dev.c_str());
  453. req.mtu = mtu;
  454. unsigned char resp;
  455. eodXchg(req, ZT_EOD_MSG_SETMTURESP, resp);
  456. }
  457. } // namespace ZeroTier