gnunet-helper-nat-client-windows.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2010 GNUnet e.V.
  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 src/nat/gnunet-helper-nat-client-windows.c
  18. * @brief Tool to help bypass NATs using ICMP method; must run as
  19. * administrator on W32
  20. * This code is forx W32.
  21. * @author Nathan Evans
  22. *
  23. * This program will send ONE ICMP message using RAW sockets
  24. * to the IP address specified as the second argument. Since
  25. * it uses RAW sockets, it must be installed SUID or run as 'root'.
  26. * In order to keep the security risk of the resulting SUID binary
  27. * minimal, the program ONLY opens the RAW socket with root
  28. * privileges, then drops them and only then starts to process
  29. * command line arguments. The code also does not link against
  30. * any shared libraries (except libc) and is strictly minimal
  31. * (except for checking for errors). The following list of people
  32. * have reviewed this code and considered it safe since the last
  33. * modification (if you reviewed it, please have your name added
  34. * to the list):
  35. *
  36. * - Christian Grothoff
  37. * - Nathan Evans
  38. */
  39. #define _GNU_SOURCE
  40. /* Instead of including gnunet_common.h */
  41. #define GNUNET_memcpy(dst,src,n) do { if (0 != n) { (void) memcpy (dst,src,n); } } while (0)
  42. #define FD_SETSIZE 1024
  43. #include <winsock2.h>
  44. #include <ws2tcpip.h>
  45. #include <sys/time.h>
  46. #include <sys/types.h>
  47. #include <unistd.h>
  48. #include <stdio.h>
  49. #include <string.h>
  50. #include <errno.h>
  51. #include <stdlib.h>
  52. #include <stdint.h>
  53. #include <time.h>
  54. #define ICMP_ECHO 8
  55. #define IPDEFTTL 64
  56. #define ICMP_TIME_EXCEEDED 11
  57. /**
  58. * Must match IP given in the server.
  59. */
  60. #define DUMMY_IP "192.0.2.86"
  61. #define NAT_TRAV_PORT 22225
  62. /**
  63. * IPv4 header.
  64. */
  65. struct ip_header
  66. {
  67. /**
  68. * Version (4 bits) + Internet header length (4 bits)
  69. */
  70. uint8_t vers_ihl;
  71. /**
  72. * Type of service
  73. */
  74. uint8_t tos;
  75. /**
  76. * Total length
  77. */
  78. uint16_t pkt_len;
  79. /**
  80. * Identification
  81. */
  82. uint16_t id;
  83. /**
  84. * Flags (3 bits) + Fragment offset (13 bits)
  85. */
  86. uint16_t flags_frag_offset;
  87. /**
  88. * Time to live
  89. */
  90. uint8_t ttl;
  91. /**
  92. * Protocol
  93. */
  94. uint8_t proto;
  95. /**
  96. * Header checksum
  97. */
  98. uint16_t checksum;
  99. /**
  100. * Source address
  101. */
  102. uint32_t src_ip;
  103. /**
  104. * Destination address
  105. */
  106. uint32_t dst_ip;
  107. };
  108. /**
  109. * Format of ICMP packet.
  110. */
  111. struct icmp_ttl_exceeded_header
  112. {
  113. uint8_t type;
  114. uint8_t code;
  115. uint16_t checksum;
  116. uint32_t unused;
  117. /* followed by original payload */
  118. };
  119. struct icmp_echo_header
  120. {
  121. uint8_t type;
  122. uint8_t code;
  123. uint16_t checksum;
  124. uint32_t reserved;
  125. };
  126. /**
  127. * Beginning of UDP packet.
  128. */
  129. struct udp_header
  130. {
  131. uint16_t src_port;
  132. uint16_t dst_port;
  133. uint16_t length;
  134. uint16_t crc;
  135. };
  136. /**
  137. * Will this binary be run in permissions testing mode?
  138. */
  139. static boolean privilege_testing = FALSE;
  140. /**
  141. * Socket we use to send our ICMP packets.
  142. */
  143. static SOCKET rawsock;
  144. /**
  145. * Target "dummy" address.
  146. */
  147. static struct in_addr dummy;
  148. /**
  149. * Port we are listening on (communicated to the server).
  150. */
  151. static uint16_t port;
  152. /**
  153. * Convert IPv4 address from text to binary form.
  154. *
  155. * @param af address family
  156. * @param cp the address to print
  157. * @param buf where to write the address result
  158. * @return 1 on success
  159. */
  160. static int
  161. inet_pton (int af, const char *cp, struct in_addr *buf)
  162. {
  163. buf->s_addr = inet_addr (cp);
  164. if (buf->s_addr == INADDR_NONE)
  165. {
  166. fprintf (stderr, "Error %d handling address %s", WSAGetLastError (), cp);
  167. return 0;
  168. }
  169. return 1;
  170. }
  171. /**
  172. * CRC-16 for IP/ICMP headers.
  173. *
  174. * @param data what to calculate the CRC over
  175. * @param bytes number of bytes in data (must be multiple of 2)
  176. * @return the CRC 16.
  177. */
  178. static uint16_t
  179. calc_checksum (const uint16_t * data, unsigned int bytes)
  180. {
  181. uint32_t sum;
  182. unsigned int i;
  183. sum = 0;
  184. for (i = 0; i < bytes / 2; i++)
  185. sum += data[i];
  186. sum = (sum & 0xffff) + (sum >> 16);
  187. sum = htons (0xffff - sum);
  188. return sum;
  189. }
  190. /**
  191. * Send an ICMP message to the target.
  192. *
  193. * @param my_ip source address
  194. * @param other target address
  195. */
  196. static void
  197. send_icmp_udp (const struct in_addr *my_ip, const struct in_addr *other)
  198. {
  199. char packet[sizeof (struct ip_header) * 2 +
  200. sizeof (struct icmp_ttl_exceeded_header) +
  201. sizeof (struct udp_header)];
  202. struct ip_header ip_pkt;
  203. struct icmp_ttl_exceeded_header icmp_pkt;
  204. struct udp_header udp_pkt;
  205. struct sockaddr_in dst;
  206. size_t off;
  207. int err;
  208. /* ip header: send to (known) ip address */
  209. off = 0;
  210. ip_pkt.vers_ihl = 0x45;
  211. ip_pkt.tos = 0;
  212. ip_pkt.pkt_len = htons (sizeof (packet));
  213. ip_pkt.id = htons (256);
  214. ip_pkt.flags_frag_offset = 0;
  215. ip_pkt.ttl = 128;
  216. ip_pkt.proto = IPPROTO_ICMP;
  217. ip_pkt.checksum = 0;
  218. ip_pkt.src_ip = my_ip->s_addr;
  219. ip_pkt.dst_ip = other->s_addr;
  220. ip_pkt.checksum =
  221. htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
  222. GNUNET_memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
  223. off += sizeof (struct ip_header);
  224. icmp_pkt.type = ICMP_TIME_EXCEEDED;
  225. icmp_pkt.code = 0;
  226. icmp_pkt.checksum = 0;
  227. icmp_pkt.unused = 0;
  228. GNUNET_memcpy (&packet[off], &icmp_pkt, sizeof (struct icmp_ttl_exceeded_header));
  229. off += sizeof (struct icmp_ttl_exceeded_header);
  230. /* ip header of the presumably 'lost' udp packet */
  231. ip_pkt.vers_ihl = 0x45;
  232. ip_pkt.tos = 0;
  233. ip_pkt.pkt_len =
  234. htons (sizeof (struct ip_header) + sizeof (struct udp_header));
  235. ip_pkt.id = htons (0);
  236. ip_pkt.flags_frag_offset = 0;
  237. ip_pkt.ttl = 128;
  238. ip_pkt.proto = IPPROTO_UDP;
  239. ip_pkt.checksum = 0;
  240. ip_pkt.src_ip = other->s_addr;
  241. ip_pkt.dst_ip = dummy.s_addr;
  242. ip_pkt.checksum =
  243. htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
  244. GNUNET_memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
  245. off += sizeof (struct ip_header);
  246. /* build UDP header */
  247. udp_pkt.src_port = htons (NAT_TRAV_PORT);
  248. udp_pkt.dst_port = htons (NAT_TRAV_PORT);
  249. udp_pkt.length = htons (port);
  250. udp_pkt.crc = 0;
  251. GNUNET_memcpy (&packet[off], &udp_pkt, sizeof (struct udp_header));
  252. off += sizeof (struct udp_header);
  253. /* no go back to calculate ICMP packet checksum */
  254. icmp_pkt.checksum =
  255. htons (calc_checksum
  256. ((uint16_t *) & packet[off],
  257. sizeof (struct icmp_ttl_exceeded_header) +
  258. sizeof (struct ip_header) + sizeof (struct udp_header)));
  259. GNUNET_memcpy (&packet[sizeof (struct ip_header)], &icmp_pkt,
  260. sizeof (struct icmp_ttl_exceeded_header));
  261. memset (&dst, 0, sizeof (dst));
  262. dst.sin_family = AF_INET;
  263. dst.sin_addr = *other;
  264. err =
  265. sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst,
  266. sizeof (dst));
  267. if (err < 0)
  268. {
  269. fprintf (stderr, "sendto failed: %s\n", strerror (errno));
  270. }
  271. else if (sizeof (packet) != (size_t) err)
  272. {
  273. fprintf (stderr, "Error: partial send of ICMP message\n");
  274. }
  275. }
  276. /**
  277. * Send an ICMP message to the target.
  278. *
  279. * @param my_ip source address
  280. * @param other target address
  281. */
  282. static void
  283. send_icmp (const struct in_addr *my_ip, const struct in_addr *other)
  284. {
  285. struct ip_header ip_pkt;
  286. struct icmp_ttl_exceeded_header icmp_ttl;
  287. struct icmp_echo_header icmp_echo;
  288. struct sockaddr_in dst;
  289. char packet[sizeof (struct ip_header) * 2 +
  290. sizeof (struct icmp_ttl_exceeded_header) +
  291. sizeof (struct icmp_echo_header)];
  292. size_t off;
  293. int err;
  294. /* ip header: send to (known) ip address */
  295. off = 0;
  296. ip_pkt.vers_ihl = 0x45;
  297. ip_pkt.tos = 0;
  298. ip_pkt.pkt_len = htons (sizeof (packet));
  299. ip_pkt.id = htons (256);
  300. ip_pkt.flags_frag_offset = 0;
  301. ip_pkt.ttl = IPDEFTTL;
  302. ip_pkt.proto = IPPROTO_ICMP;
  303. ip_pkt.checksum = 0;
  304. ip_pkt.src_ip = my_ip->s_addr;
  305. ip_pkt.dst_ip = other->s_addr;
  306. ip_pkt.checksum =
  307. htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
  308. GNUNET_memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
  309. off += sizeof (ip_pkt);
  310. /* icmp reply: time exceeded */
  311. icmp_ttl.type = ICMP_TIME_EXCEEDED;
  312. icmp_ttl.code = 0;
  313. icmp_ttl.checksum = 0;
  314. icmp_ttl.unused = 0;
  315. GNUNET_memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header));
  316. off += sizeof (struct icmp_ttl_exceeded_header);
  317. /* ip header of the presumably 'lost' udp packet */
  318. ip_pkt.vers_ihl = 0x45;
  319. ip_pkt.tos = 0;
  320. ip_pkt.pkt_len =
  321. htons (sizeof (struct ip_header) + sizeof (struct icmp_echo_header));
  322. ip_pkt.id = htons (256);
  323. ip_pkt.flags_frag_offset = 0;
  324. ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */
  325. ip_pkt.proto = IPPROTO_ICMP;
  326. ip_pkt.src_ip = other->s_addr;
  327. ip_pkt.dst_ip = dummy.s_addr;
  328. ip_pkt.checksum = 0;
  329. ip_pkt.checksum =
  330. htons (calc_checksum ((uint16_t *) & ip_pkt, sizeof (struct ip_header)));
  331. GNUNET_memcpy (&packet[off], &ip_pkt, sizeof (struct ip_header));
  332. off += sizeof (struct ip_header);
  333. icmp_echo.type = ICMP_ECHO;
  334. icmp_echo.code = 0;
  335. icmp_echo.reserved = htonl (port);
  336. icmp_echo.checksum = 0;
  337. icmp_echo.checksum =
  338. htons (calc_checksum
  339. ((uint16_t *) & icmp_echo, sizeof (struct icmp_echo_header)));
  340. GNUNET_memcpy (&packet[off], &icmp_echo, sizeof (struct icmp_echo_header));
  341. /* no go back to calculate ICMP packet checksum */
  342. off = sizeof (struct ip_header);
  343. icmp_ttl.checksum =
  344. htons (calc_checksum
  345. ((uint16_t *) & packet[off],
  346. sizeof (struct icmp_ttl_exceeded_header) +
  347. sizeof (struct ip_header) + sizeof (struct icmp_echo_header)));
  348. GNUNET_memcpy (&packet[off], &icmp_ttl, sizeof (struct icmp_ttl_exceeded_header));
  349. memset (&dst, 0, sizeof (dst));
  350. dst.sin_family = AF_INET;
  351. dst.sin_addr = *other;
  352. err =
  353. sendto (rawsock, packet, sizeof (packet), 0, (struct sockaddr *) &dst,
  354. sizeof (dst));
  355. if (err < 0)
  356. {
  357. fprintf (stderr, "sendto failed: %s\n", strerror (errno));
  358. }
  359. else if (sizeof (packet) != (size_t) err)
  360. {
  361. fprintf (stderr, "Error: partial send of ICMP message\n");
  362. }
  363. }
  364. /**
  365. * Create an ICMP raw socket.
  366. *
  367. * @return INVALID_SOCKET on error
  368. */
  369. static SOCKET
  370. make_raw_socket ()
  371. {
  372. DWORD bOptVal = TRUE;
  373. int bOptLen = sizeof (bOptVal);
  374. SOCKET ret;
  375. ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
  376. if (INVALID_SOCKET == ret)
  377. {
  378. fprintf (stderr, "Error opening RAW socket: %s\n", strerror (errno));
  379. return INVALID_SOCKET;
  380. }
  381. if (0 !=
  382. setsockopt (ret, SOL_SOCKET, SO_BROADCAST, (char *) &bOptVal, bOptLen))
  383. {
  384. fprintf (stderr, "Error setting SO_BROADCAST to ON: %s\n",
  385. strerror (errno));
  386. closesocket (rawsock);
  387. return INVALID_SOCKET;
  388. }
  389. if (0 != setsockopt (ret, IPPROTO_IP, IP_HDRINCL, (char *) &bOptVal, bOptLen))
  390. {
  391. fprintf (stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror (errno));
  392. closesocket (rawsock);
  393. return INVALID_SOCKET;
  394. }
  395. return ret;
  396. }
  397. int
  398. main (int argc, char *const *argv)
  399. {
  400. struct in_addr external;
  401. struct in_addr target;
  402. WSADATA wsaData;
  403. unsigned int p;
  404. if (argc > 1 && 0 != strcmp (argv[1], "-d")){
  405. privilege_testing = TRUE;
  406. fprintf (stderr,
  407. "%s",
  408. "DEBUG: Running binary in privilege testing mode.");
  409. argv++;
  410. argc--;
  411. }
  412. if (argc != 4)
  413. {
  414. fprintf (stderr,
  415. "%s",
  416. "This program must be started with our IP, the targets external IP, and our port as arguments.\n");
  417. return 1;
  418. }
  419. if ((1 != inet_pton (AF_INET, argv[1], &external)) ||
  420. (1 != inet_pton (AF_INET, argv[2], &target)))
  421. {
  422. fprintf (stderr,
  423. "Error parsing IPv4 address: %s\n",
  424. strerror (errno));
  425. return 1;
  426. }
  427. if ((1 != sscanf (argv[3], "%u", &p)) || (0 == p) || (0xFFFF < p))
  428. {
  429. fprintf (stderr,
  430. "Error parsing port value `%s'\n",
  431. argv[3]);
  432. return 1;
  433. }
  434. port = (uint16_t) p;
  435. if (0 != WSAStartup (MAKEWORD (2, 1), &wsaData))
  436. {
  437. fprintf (stderr,
  438. "%s",
  439. "Failed to find Winsock 2.1 or better.\n");
  440. return 2;
  441. }
  442. if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy))
  443. {
  444. fprintf (stderr,
  445. "%s",
  446. "Internal error converting dummy IP to binary.\n");
  447. return 2;
  448. }
  449. if (-1 == (rawsock = make_raw_socket ()))
  450. return 3;
  451. if (!privilege_testing){
  452. send_icmp (&external, &target);
  453. send_icmp_udp (&external, &target);
  454. }
  455. closesocket (rawsock);
  456. WSACleanup ();
  457. return 0;
  458. }
  459. /* end of gnunet-helper-nat-client-windows.c */