LinuxNetLink.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2018 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. #include "LinuxNetLink.hpp"
  27. #include <unistd.h>
  28. namespace ZeroTier {
  29. LinuxNetLink::LinuxNetLink()
  30. : _t()
  31. , _running(false)
  32. , _routes_ipv4()
  33. , _routes_ipv6()
  34. , _seq(0)
  35. , _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))
  36. , _la({0})
  37. {
  38. // set socket timeout to 1 sec so we're not permablocking recv() calls
  39. struct timeval tv;
  40. tv.tv_sec = 1;
  41. tv.tv_usec = 0;
  42. if(setsockopt(_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) != 0) {
  43. fprintf(stderr, "setsockopt failed: %s\n", strerror(errno));
  44. }
  45. _la.nl_family = AF_NETLINK;
  46. _la.nl_pid = getpid();
  47. _la.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR|RTMGRP_IPV4_ROUTE|RTMGRP_IPV6_ROUTE|RTMGRP_NOTIFY;
  48. if (bind(_fd, (struct sockaddr*)&_la, sizeof(_la))) {
  49. fprintf(stderr, "Error connecting to RTNETLINK: %s\n", strerror(errno));
  50. ::exit(1);
  51. }
  52. _running = true;
  53. _t = Thread::start(this);
  54. fprintf(stderr, "Requesting IPV4 Routes\n");
  55. _requestIPv4Routes();
  56. Thread::sleep(10);
  57. fprintf(stderr, "Requesting IPV6 Routes\n");
  58. _requestIPv6Routes();
  59. }
  60. LinuxNetLink::~LinuxNetLink()
  61. {
  62. _running = false;
  63. Thread::join(_t);
  64. ::close(_fd);
  65. }
  66. void LinuxNetLink::threadMain() throw()
  67. {
  68. char buf[8192];
  69. char *p = NULL;
  70. struct nlmsghdr *nlp;
  71. int nll = 0;
  72. int rtn = 0;
  73. p = buf;
  74. while(_running) {
  75. rtn = recv(_fd, p, sizeof(buf) - nll, 0);
  76. if (rtn > 0) {
  77. nlp = (struct nlmsghdr *)p;
  78. if(nlp->nlmsg_type == NLMSG_ERROR && (nlp->nlmsg_flags & NLM_F_ACK) != NLM_F_ACK) {
  79. fprintf(stderr, "NLMSG_ERROR\n");
  80. struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlp);
  81. if (err->error != 0) {
  82. fprintf(stderr, "rtnetlink error: %s\n", strerror(-(err->error)));
  83. }
  84. p = buf;
  85. nll = 0;
  86. continue;
  87. }
  88. if (nlp->nlmsg_type == NLMSG_NOOP) {
  89. fprintf(stderr, "noop\n");
  90. continue;
  91. }
  92. if( (nlp->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI || (nlp->nlmsg_type == NLMSG_DONE))
  93. {
  94. if (nlp->nlmsg_type == NLMSG_DONE) {
  95. _processMessage(nlp, nll);
  96. p = buf;
  97. nll = 0;
  98. continue;
  99. }
  100. p += rtn;
  101. nll += rtn;
  102. }
  103. if (nlp->nlmsg_type == NLMSG_OVERRUN) {
  104. fprintf(stderr, "NLMSG_OVERRUN: Data lost\n");
  105. p = buf;
  106. nll = 0;
  107. continue;
  108. }
  109. nll += rtn;
  110. _processMessage(nlp, nll);
  111. p = buf;
  112. nll = 0;
  113. }
  114. else {
  115. Thread::sleep(100);
  116. continue;
  117. }
  118. }
  119. }
  120. void LinuxNetLink::_processMessage(struct nlmsghdr *nlp, int nll)
  121. {
  122. for(; NLMSG_OK(nlp, nll); nlp=NLMSG_NEXT(nlp, nll))
  123. {
  124. switch(nlp->nlmsg_type)
  125. {
  126. case RTM_NEWLINK:
  127. _linkAdded(nlp);
  128. break;
  129. case RTM_DELLINK:
  130. _linkDeleted(nlp);
  131. break;
  132. case RTM_NEWADDR:
  133. _ipAddressAdded(nlp);
  134. break;
  135. case RTM_DELADDR:
  136. _ipAddressDeleted(nlp);
  137. break;
  138. case RTM_NEWROUTE:
  139. _routeAdded(nlp);
  140. break;
  141. case RTM_DELROUTE:
  142. _routeDeleted(nlp);
  143. break;
  144. default:
  145. fprintf(stderr, "ignore msgtype %d...\n", nlp->nlmsg_type);
  146. }
  147. }
  148. }
  149. void LinuxNetLink::_ipAddressAdded(struct nlmsghdr *nlp)
  150. {
  151. struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp);
  152. struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap);
  153. int ifal = IFA_PAYLOAD(nlp);
  154. char addr[40] = {0};
  155. char local[40] = {0};
  156. char label[40] = {0};
  157. char bcast[40] = {0};
  158. for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal))
  159. {
  160. switch(rtap->rta_type) {
  161. case IFA_ADDRESS:
  162. inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40);
  163. break;
  164. case IFA_LOCAL:
  165. inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40);
  166. break;
  167. case IFA_LABEL:
  168. memcpy(label, RTA_DATA(rtap), 40);
  169. break;
  170. case IFA_BROADCAST:
  171. inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40);
  172. break;
  173. }
  174. }
  175. fprintf(stderr, "Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast);
  176. }
  177. void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr *nlp)
  178. {
  179. struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp);
  180. struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap);
  181. int ifal = IFA_PAYLOAD(nlp);
  182. char addr[40] = {0};
  183. char local[40] = {0};
  184. char label[40] = {0};
  185. char bcast[40] = {0};
  186. for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal))
  187. {
  188. switch(rtap->rta_type) {
  189. case IFA_ADDRESS:
  190. inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40);
  191. break;
  192. case IFA_LOCAL:
  193. inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40);
  194. break;
  195. case IFA_LABEL:
  196. memcpy(label, RTA_DATA(rtap), 40);
  197. break;
  198. case IFA_BROADCAST:
  199. inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40);
  200. break;
  201. }
  202. }
  203. fprintf(stderr, "Removed IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast);
  204. }
  205. void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp)
  206. {
  207. char dsts[40] = {0};
  208. char gws[40] = {0};
  209. char ifs[16] = {0};
  210. char ms[24] = {0};
  211. struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp);
  212. struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp);
  213. int rtl = RTM_PAYLOAD(nlp);
  214. for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl))
  215. {
  216. switch(rtap->rta_type)
  217. {
  218. case RTA_DST:
  219. inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, rtp->rtm_family == AF_INET ? 24 : 40);
  220. break;
  221. case RTA_GATEWAY:
  222. inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, rtp->rtm_family == AF_INET ? 24 : 40);
  223. break;
  224. case RTA_OIF:
  225. sprintf(ifs, "%d", *((int*)RTA_DATA(rtap)));
  226. break;
  227. }
  228. }
  229. sprintf(ms, "%d", rtp->rtm_dst_len);
  230. fprintf(stderr, "Route Added: dst %s/%s gw %s if %s\n", dsts, ms, gws, ifs);
  231. }
  232. void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp)
  233. {
  234. char dsts[40] = {0};
  235. char gws[40] = {0};
  236. char ifs[16] = {0};
  237. char ms[24] = {0};
  238. struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp);
  239. struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp);
  240. int rtl = RTM_PAYLOAD(nlp);
  241. for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl))
  242. {
  243. switch(rtap->rta_type)
  244. {
  245. case RTA_DST:
  246. inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, rtp->rtm_family == AF_INET ? 24 : 40);
  247. break;
  248. case RTA_GATEWAY:
  249. inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, rtp->rtm_family == AF_INET ? 24 : 40);
  250. break;
  251. case RTA_OIF:
  252. sprintf(ifs, "%d", *((int*)RTA_DATA(rtap)));
  253. break;
  254. }
  255. }
  256. sprintf(ms, "%d", rtp->rtm_dst_len);
  257. fprintf(stderr, "Route Deleted: dst %s/%s gw %s if %s\n", dsts, ms, gws, ifs);
  258. }
  259. void LinuxNetLink::_linkAdded(struct nlmsghdr *nlp)
  260. {
  261. char mac[20] = {0};
  262. unsigned int mtu = 0;
  263. char ifname[40] = {0};
  264. struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp);
  265. struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);
  266. int ifil = RTM_PAYLOAD(nlp);
  267. const char *ptr;
  268. unsigned char *ptr2;
  269. for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil))
  270. {
  271. switch(rtap->rta_type) {
  272. case IFLA_ADDRESS:
  273. ptr2 = (unsigned char*)RTA_DATA(rtap);
  274. snprintf(mac, 20, "%02x:%02x:%02x:%02x:%02x:%02x",
  275. ptr2[0], ptr2[1], ptr2[2], ptr2[3], ptr2[4], ptr2[5]);
  276. break;
  277. case IFLA_IFNAME:
  278. ptr = (const char*)RTA_DATA(rtap);
  279. memcpy(ifname, ptr, strlen(ptr));
  280. break;
  281. case IFLA_MTU:
  282. memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int));
  283. break;
  284. }
  285. }
  286. fprintf(stderr, "Link Added: %s mac: %s, mtu: %d\n", ifname, mac, mtu);
  287. }
  288. void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp)
  289. {
  290. char mac[20] = {0};
  291. unsigned int mtu = 0;
  292. char ifname[40] = {0};
  293. struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp);
  294. struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);
  295. int ifil = RTM_PAYLOAD(nlp);
  296. const char *ptr;
  297. unsigned char *ptr2;
  298. for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil))
  299. {
  300. switch(rtap->rta_type) {
  301. case IFLA_ADDRESS:
  302. ptr2 = (unsigned char*)RTA_DATA(rtap);
  303. snprintf(mac, 20, "%02x:%02x:%02x:%02x:%02x:%02x",
  304. ptr2[0], ptr2[1], ptr2[2], ptr2[3], ptr2[4], ptr2[5]);
  305. break;
  306. case IFLA_IFNAME:
  307. ptr = (const char*)RTA_DATA(rtap);
  308. memcpy(ifname, ptr, strlen(ptr));
  309. break;
  310. case IFLA_MTU:
  311. memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int));
  312. break;
  313. }
  314. }
  315. fprintf(stderr, "Link Deleted: %s mac: %s, mtu: %d\n", ifname, mac, mtu);
  316. }
  317. void LinuxNetLink::_requestIPv4Routes()
  318. {
  319. struct nl_req req;
  320. bzero(&req, sizeof(req));
  321. req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  322. req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  323. req.nl.nlmsg_type = RTM_GETROUTE;
  324. req.nl.nlmsg_pid = 0;
  325. req.nl.nlmsg_seq = ++_seq;
  326. req.rt.rtm_family = AF_INET;
  327. req.rt.rtm_table = RT_TABLE_MAIN;
  328. struct sockaddr_nl pa;
  329. bzero(&pa, sizeof(pa));
  330. pa.nl_family = AF_NETLINK;
  331. struct msghdr msg;
  332. bzero(&msg, sizeof(msg));
  333. msg.msg_name = (void*)&pa;
  334. msg.msg_namelen = sizeof(pa);
  335. struct iovec iov;
  336. bzero(&iov, sizeof(iov));
  337. iov.iov_base = (void*)&req.nl;
  338. iov.iov_len = req.nl.nlmsg_len;
  339. msg.msg_iov = &iov;
  340. msg.msg_iovlen = 1;
  341. sendmsg(_fd, &msg, 0);
  342. }
  343. void LinuxNetLink::_requestIPv6Routes()
  344. {
  345. struct nl_req req;
  346. bzero(&req, sizeof(req));
  347. req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  348. req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  349. req.nl.nlmsg_type = RTM_GETROUTE;
  350. req.nl.nlmsg_pid = 0;
  351. req.nl.nlmsg_seq = ++_seq;
  352. req.rt.rtm_family = AF_INET6;
  353. req.rt.rtm_table = RT_TABLE_MAIN;
  354. struct sockaddr_nl pa;
  355. bzero(&pa, sizeof(pa));
  356. pa.nl_family = AF_NETLINK;
  357. struct msghdr msg;
  358. bzero(&msg, sizeof(msg));
  359. msg.msg_name = (void*)&pa;
  360. msg.msg_namelen = sizeof(pa);
  361. struct iovec iov;
  362. bzero(&iov, sizeof(iov));
  363. iov.iov_base = (void*)&req.nl;
  364. iov.iov_len = req.nl.nlmsg_len;
  365. msg.msg_iov = &iov;
  366. msg.msg_iovlen = 1;
  367. while((sendmsg(_fd, &msg, 0)) == -1) {
  368. fprintf(stderr, "ipv6 waiting...");
  369. Thread::sleep(100);
  370. }
  371. }
  372. void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, const char *ifaceName)
  373. {
  374. }
  375. void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, const char *ifaceName)
  376. {
  377. }
  378. void LinuxNetLink::addInterface(const char *iface, unsigned int mtu)
  379. {
  380. }
  381. void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface)
  382. {
  383. }
  384. RouteList LinuxNetLink::getIPV4Routes() const
  385. {
  386. return _routes_ipv4;
  387. }
  388. RouteList LinuxNetLink::getIPV6Routes() const
  389. {
  390. return _routes_ipv6;
  391. }
  392. } // namespace ZeroTier