gnunet-helper-vpn.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2010, 2012 Christian Grothoff
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file vpn/gnunet-helper-vpn.c
  18. * @brief the helper for the VPN service. Opens a virtual network-interface,
  19. * sends data received on the if to stdout, sends data received on stdin to the
  20. * interface
  21. * @author Philipp Tölke
  22. * @author Christian Grothoff
  23. *
  24. * The following list of people have reviewed this code and considered
  25. * it safe since the last modification (if you reviewed it, please
  26. * have your name added to the list):
  27. *
  28. * - Philipp Tölke
  29. */
  30. #include "platform.h"
  31. #include <linux/if_tun.h>
  32. /**
  33. * Need 'struct GNUNET_MessageHeader'.
  34. */
  35. #include "gnunet_crypto_lib.h"
  36. #include "gnunet_common.h"
  37. /**
  38. * Need VPN message types.
  39. */
  40. #include "gnunet_protocols.h"
  41. /**
  42. * Should we print (interesting|debug) messages that can happen during
  43. * normal operation?
  44. */
  45. #define DEBUG GNUNET_NO
  46. /**
  47. * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
  48. */
  49. #define MAX_SIZE 65536
  50. #ifndef _LINUX_IN6_H
  51. /**
  52. * This is in linux/include/net/ipv6.h, but not always exported...
  53. */
  54. struct in6_ifreq
  55. {
  56. struct in6_addr ifr6_addr;
  57. uint32_t ifr6_prefixlen;
  58. unsigned int ifr6_ifindex;
  59. };
  60. #endif
  61. /**
  62. * Creates a tun-interface called dev;
  63. *
  64. * @param dev is asumed to point to a char[IFNAMSIZ]
  65. * if *dev == '\\0', uses the name supplied by the kernel;
  66. * @return the fd to the tun or -1 on error
  67. */
  68. static int
  69. init_tun (char *dev)
  70. {
  71. struct ifreq ifr;
  72. int fd;
  73. if (NULL == dev)
  74. {
  75. errno = EINVAL;
  76. return -1;
  77. }
  78. if (-1 == (fd = open ("/dev/net/tun", O_RDWR)))
  79. {
  80. fprintf (stderr,
  81. "Error opening `%s': %s\n",
  82. "/dev/net/tun",
  83. strerror (errno));
  84. return -1;
  85. }
  86. if (fd >= FD_SETSIZE)
  87. {
  88. fprintf (stderr,
  89. "File descriptor to large: %d",
  90. fd);
  91. (void) close (fd);
  92. return -1;
  93. }
  94. memset (&ifr, 0, sizeof (ifr));
  95. ifr.ifr_flags = IFF_TUN;
  96. if ('\0' != *dev)
  97. strncpy (ifr.ifr_name,
  98. dev,
  99. IFNAMSIZ);
  100. if (-1 == ioctl (fd,
  101. TUNSETIFF,
  102. (void *) &ifr))
  103. {
  104. fprintf (stderr,
  105. "Error with ioctl on `%s': %s\n",
  106. "/dev/net/tun",
  107. strerror (errno));
  108. (void) close (fd);
  109. return -1;
  110. }
  111. strcpy (dev, ifr.ifr_name);
  112. return fd;
  113. }
  114. /**
  115. * @brief Sets the IPv6-Address given in address on the interface dev
  116. *
  117. * @param dev the interface to configure
  118. * @param address the IPv6-Address
  119. * @param prefix_len the length of the network-prefix
  120. */
  121. static void
  122. set_address6 (const char *dev,
  123. const char *address,
  124. unsigned long prefix_len)
  125. {
  126. struct ifreq ifr;
  127. struct in6_ifreq ifr6;
  128. struct sockaddr_in6 sa6;
  129. int fd;
  130. /*
  131. * parse the new address
  132. */
  133. memset (&sa6, 0, sizeof (struct sockaddr_in6));
  134. sa6.sin6_family = AF_INET6;
  135. if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr))
  136. {
  137. fprintf (stderr,
  138. "Failed to parse IPv6 address `%s'\n",
  139. address);
  140. exit (1);
  141. }
  142. if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
  143. {
  144. fprintf (stderr,
  145. "Error creating socket: %s\n",
  146. strerror (errno));
  147. exit (1);
  148. }
  149. memset (&ifr, 0, sizeof (struct ifreq));
  150. /*
  151. * Get the index of the if
  152. */
  153. strncpy (ifr.ifr_name,
  154. dev,
  155. IFNAMSIZ);
  156. if (-1 == ioctl (fd,
  157. SIOGIFINDEX,
  158. &ifr))
  159. {
  160. fprintf (stderr,
  161. "ioctl failed at %d: %s\n",
  162. __LINE__,
  163. strerror (errno));
  164. (void) close (fd);
  165. exit (1);
  166. }
  167. memset (&ifr6, 0, sizeof (struct in6_ifreq));
  168. ifr6.ifr6_addr = sa6.sin6_addr;
  169. ifr6.ifr6_ifindex = ifr.ifr_ifindex;
  170. ifr6.ifr6_prefixlen = prefix_len;
  171. /*
  172. * Set the address
  173. */
  174. if (-1 == ioctl (fd,
  175. SIOCSIFADDR,
  176. &ifr6))
  177. {
  178. fprintf (stderr,
  179. "ioctl failed at line %d: %s\n",
  180. __LINE__,
  181. strerror (errno));
  182. (void) close (fd);
  183. exit (1);
  184. }
  185. /*
  186. * Get the flags
  187. */
  188. if (-1 == ioctl (fd,
  189. SIOCGIFFLAGS,
  190. &ifr))
  191. {
  192. fprintf (stderr,
  193. "ioctl failed at line %d: %s\n",
  194. __LINE__,
  195. strerror (errno));
  196. (void) close (fd);
  197. exit (1);
  198. }
  199. /*
  200. * Add the UP and RUNNING flags
  201. */
  202. ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
  203. if (-1 == ioctl (fd,
  204. SIOCSIFFLAGS,
  205. &ifr))
  206. {
  207. fprintf (stderr,
  208. "ioctl failed at line %d: %s\n",
  209. __LINE__,
  210. strerror (errno));
  211. (void) close (fd);
  212. exit (1);
  213. }
  214. if (0 != close (fd))
  215. {
  216. fprintf (stderr,
  217. "close failed: %s\n",
  218. strerror (errno));
  219. exit (1);
  220. }
  221. }
  222. /**
  223. * @brief Sets the IPv4-Address given in address on the interface dev
  224. *
  225. * @param dev the interface to configure
  226. * @param address the IPv4-Address
  227. * @param mask the netmask
  228. */
  229. static void
  230. set_address4 (const char *dev,
  231. const char *address,
  232. const char *mask)
  233. {
  234. int fd;
  235. struct sockaddr_in *addr;
  236. struct ifreq ifr;
  237. memset (&ifr, 0, sizeof (struct ifreq));
  238. addr = (struct sockaddr_in *) &(ifr.ifr_addr);
  239. addr->sin_family = AF_INET;
  240. /*
  241. * Parse the address
  242. */
  243. if (1 != inet_pton (AF_INET,
  244. address,
  245. &addr->sin_addr.s_addr))
  246. {
  247. fprintf (stderr,
  248. "Failed to parse IPv4 address `%s'\n",
  249. address);
  250. exit (1);
  251. }
  252. if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
  253. {
  254. fprintf (stderr,
  255. "Error creating socket: %s\n",
  256. strerror (errno));
  257. exit (1);
  258. }
  259. strncpy (ifr.ifr_name, dev, IFNAMSIZ);
  260. /*
  261. * Set the address
  262. */
  263. if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
  264. {
  265. fprintf (stderr,
  266. "ioctl failed at %d: %s\n",
  267. __LINE__,
  268. strerror (errno));
  269. (void) close (fd);
  270. exit (1);
  271. }
  272. /*
  273. * Parse the netmask
  274. */
  275. addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
  276. if (1 != inet_pton (AF_INET,
  277. mask,
  278. &addr->sin_addr.s_addr))
  279. {
  280. fprintf (stderr,
  281. "Failed to parse IPv4 address mask `%s'\n",
  282. mask);
  283. (void) close (fd);
  284. exit (1);
  285. }
  286. /*
  287. * Set the netmask
  288. */
  289. if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
  290. {
  291. fprintf (stderr,
  292. "ioctl failed at line %d: %s\n",
  293. __LINE__,
  294. strerror (errno));
  295. (void) close (fd);
  296. exit (1);
  297. }
  298. /*
  299. * Get the flags
  300. */
  301. if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
  302. {
  303. fprintf (stderr,
  304. "ioctl failed at line %d: %s\n",
  305. __LINE__,
  306. strerror (errno));
  307. (void) close (fd);
  308. exit (1);
  309. }
  310. /*
  311. * Add the UP and RUNNING flags
  312. */
  313. ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
  314. if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
  315. {
  316. fprintf (stderr,
  317. "ioctl failed at line %d: %s\n",
  318. __LINE__,
  319. strerror (errno));
  320. (void) close (fd);
  321. exit (1);
  322. }
  323. if (0 != close (fd))
  324. {
  325. fprintf (stderr,
  326. "close failed: %s\n",
  327. strerror (errno));
  328. (void) close (fd);
  329. exit (1);
  330. }
  331. }
  332. /**
  333. * Start forwarding to and from the tunnel.
  334. *
  335. * @param fd_tun tunnel FD
  336. */
  337. static void
  338. run (int fd_tun)
  339. {
  340. /*
  341. * The buffer filled by reading from fd_tun
  342. */
  343. unsigned char buftun[MAX_SIZE];
  344. ssize_t buftun_size = 0;
  345. unsigned char *buftun_read = NULL;
  346. /*
  347. * The buffer filled by reading from stdin
  348. */
  349. unsigned char bufin[MAX_SIZE];
  350. ssize_t bufin_size = 0;
  351. size_t bufin_rpos = 0;
  352. unsigned char *bufin_read = NULL;
  353. fd_set fds_w;
  354. fd_set fds_r;
  355. /* read refers to reading from fd_tun, writing to stdout */
  356. int read_open = 1;
  357. /* write refers to reading from stdin, writing to fd_tun */
  358. int write_open = 1;
  359. while ((1 == read_open) && (1 == write_open))
  360. {
  361. FD_ZERO (&fds_w);
  362. FD_ZERO (&fds_r);
  363. /*
  364. * We are supposed to read and the buffer is empty
  365. * -> select on read from tun
  366. */
  367. if (read_open && (0 == buftun_size))
  368. FD_SET (fd_tun, &fds_r);
  369. /*
  370. * We are supposed to read and the buffer is not empty
  371. * -> select on write to stdout
  372. */
  373. if (read_open && (0 != buftun_size))
  374. FD_SET (1, &fds_w);
  375. /*
  376. * We are supposed to write and the buffer is empty
  377. * -> select on read from stdin
  378. */
  379. if (write_open && (NULL == bufin_read))
  380. FD_SET (0, &fds_r);
  381. /*
  382. * We are supposed to write and the buffer is not empty
  383. * -> select on write to tun
  384. */
  385. if (write_open && (NULL != bufin_read))
  386. FD_SET (fd_tun, &fds_w);
  387. int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
  388. if (-1 == r)
  389. {
  390. if (EINTR == errno)
  391. continue;
  392. fprintf (stderr,
  393. "select failed: %s\n",
  394. strerror (errno));
  395. exit (1);
  396. }
  397. if (r > 0)
  398. {
  399. if (FD_ISSET (fd_tun, &fds_r))
  400. {
  401. buftun_size =
  402. read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader),
  403. MAX_SIZE - sizeof (struct GNUNET_MessageHeader));
  404. if (-1 == buftun_size)
  405. {
  406. fprintf (stderr,
  407. "read-error: %s\n",
  408. strerror (errno));
  409. shutdown (fd_tun, SHUT_RD);
  410. shutdown (1, SHUT_WR);
  411. read_open = 0;
  412. buftun_size = 0;
  413. }
  414. else if (0 == buftun_size)
  415. {
  416. fprintf (stderr, "EOF on tun\n");
  417. shutdown (fd_tun, SHUT_RD);
  418. shutdown (1, SHUT_WR);
  419. read_open = 0;
  420. buftun_size = 0;
  421. }
  422. else
  423. {
  424. buftun_read = buftun;
  425. struct GNUNET_MessageHeader *hdr =
  426. (struct GNUNET_MessageHeader *) buftun;
  427. buftun_size += sizeof (struct GNUNET_MessageHeader);
  428. hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
  429. hdr->size = htons (buftun_size);
  430. }
  431. }
  432. else if (FD_ISSET (1, &fds_w))
  433. {
  434. ssize_t written = write (1,
  435. buftun_read,
  436. buftun_size);
  437. if (-1 == written)
  438. {
  439. #if !DEBUG
  440. if (errno != EPIPE)
  441. #endif
  442. fprintf (stderr,
  443. "write-error to stdout: %s\n",
  444. strerror (errno));
  445. shutdown (fd_tun, SHUT_RD);
  446. shutdown (1, SHUT_WR);
  447. read_open = 0;
  448. buftun_size = 0;
  449. }
  450. else if (0 == written)
  451. {
  452. fprintf (stderr,
  453. "write returned 0!?\n");
  454. exit (1);
  455. }
  456. else
  457. {
  458. buftun_size -= written;
  459. buftun_read += written;
  460. }
  461. }
  462. if (FD_ISSET (0, &fds_r))
  463. {
  464. bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
  465. if (-1 == bufin_size)
  466. {
  467. fprintf (stderr,
  468. "read-error: %s\n",
  469. strerror (errno));
  470. shutdown (0, SHUT_RD);
  471. shutdown (fd_tun, SHUT_WR);
  472. write_open = 0;
  473. bufin_size = 0;
  474. }
  475. else if (0 == bufin_size)
  476. {
  477. #if DEBUG
  478. fprintf (stderr, "EOF on stdin\n");
  479. #endif
  480. shutdown (0, SHUT_RD);
  481. shutdown (fd_tun, SHUT_WR);
  482. write_open = 0;
  483. bufin_size = 0;
  484. }
  485. else
  486. {
  487. struct GNUNET_MessageHeader *hdr;
  488. PROCESS_BUFFER:
  489. bufin_rpos += bufin_size;
  490. if (bufin_rpos < sizeof (struct GNUNET_MessageHeader))
  491. continue;
  492. hdr = (struct GNUNET_MessageHeader *) bufin;
  493. if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
  494. {
  495. fprintf (stderr,
  496. "protocol violation!\n");
  497. exit (1);
  498. }
  499. if (ntohs (hdr->size) > bufin_rpos)
  500. continue;
  501. bufin_read = bufin + sizeof (struct GNUNET_MessageHeader);
  502. bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader);
  503. bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader);
  504. }
  505. }
  506. else if (FD_ISSET (fd_tun, &fds_w))
  507. {
  508. ssize_t written = write (fd_tun,
  509. bufin_read,
  510. bufin_size);
  511. if (-1 == written)
  512. {
  513. fprintf (stderr,
  514. "write-error to tun: %s\n",
  515. strerror (errno));
  516. shutdown (0, SHUT_RD);
  517. shutdown (fd_tun, SHUT_WR);
  518. write_open = 0;
  519. bufin_size = 0;
  520. }
  521. else if (0 == written)
  522. {
  523. fprintf (stderr, "write returned 0!?\n");
  524. exit (1);
  525. }
  526. else
  527. {
  528. bufin_size -= written;
  529. bufin_read += written;
  530. if (0 == bufin_size)
  531. {
  532. memmove (bufin, bufin_read, bufin_rpos);
  533. bufin_read = NULL; /* start reading again */
  534. bufin_size = 0;
  535. goto PROCESS_BUFFER;
  536. }
  537. }
  538. }
  539. }
  540. }
  541. }
  542. /**
  543. * Open VPN tunnel interface.
  544. *
  545. * @param argc must be 6
  546. * @param argv 0: binary name (gnunet-helper-vpn)
  547. * 1: tunnel interface name (gnunet-vpn)
  548. * 2: IPv6 address (::1), "-" to disable
  549. * 3: IPv6 netmask length in bits (64), ignored if #2 is "-"
  550. * 4: IPv4 address (1.2.3.4), "-" to disable
  551. * 5: IPv4 netmask (255.255.0.0), ignored if #4 is "-"
  552. */
  553. int
  554. main (int argc, char **argv)
  555. {
  556. char dev[IFNAMSIZ];
  557. int fd_tun;
  558. int global_ret;
  559. if (6 != argc)
  560. {
  561. fprintf (stderr, "Fatal: must supply 5 arguments!\n");
  562. return 1;
  563. }
  564. strncpy (dev,
  565. argv[1],
  566. IFNAMSIZ);
  567. dev[IFNAMSIZ - 1] = '\0';
  568. if (-1 == (fd_tun = init_tun (dev)))
  569. {
  570. fprintf (stderr,
  571. "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
  572. dev,
  573. argv[2],
  574. argv[3],
  575. argv[4],
  576. argv[5]);
  577. return 1;
  578. }
  579. if (0 != strcmp (argv[2], "-"))
  580. {
  581. const char *address = argv[2];
  582. long prefix_len = atol (argv[3]);
  583. if ((prefix_len < 1) || (prefix_len > 127))
  584. {
  585. fprintf (stderr,
  586. "Fatal: prefix_len out of range\n");
  587. close (fd_tun);
  588. return 1;
  589. }
  590. set_address6 (dev,
  591. address,
  592. prefix_len);
  593. }
  594. if (0 != strcmp (argv[4], "-"))
  595. {
  596. const char *address = argv[4];
  597. const char *mask = argv[5];
  598. set_address4 (dev, address, mask);
  599. }
  600. uid_t uid = getuid ();
  601. #ifdef HAVE_SETRESUID
  602. if (0 != setresuid (uid, uid, uid))
  603. {
  604. fprintf (stderr,
  605. "Failed to setresuid: %s\n",
  606. strerror (errno));
  607. global_ret = 2;
  608. goto cleanup;
  609. }
  610. #else
  611. if (0 != (setuid (uid) | seteuid (uid)))
  612. {
  613. fprintf (stderr,
  614. "Failed to setuid: %s\n",
  615. strerror (errno));
  616. global_ret = 2;
  617. goto cleanup;
  618. }
  619. #endif
  620. if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
  621. {
  622. fprintf (stderr,
  623. "Failed to protect against SIGPIPE: %s\n",
  624. strerror (errno));
  625. /* no exit, we might as well die with SIGPIPE should it ever happen */
  626. }
  627. run (fd_tun);
  628. global_ret = 0;
  629. cleanup:
  630. close (fd_tun);
  631. return global_ret;
  632. }