gnunet-nat-server.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2011, 2017 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-nat-server.c
  18. * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_nat_service.h"
  24. #include "gnunet_protocols.h"
  25. #include "nat-auto.h"
  26. /**
  27. * Information we track per client.
  28. */
  29. struct ClientData
  30. {
  31. /**
  32. * Timeout task.
  33. */
  34. struct GNUNET_SCHEDULER_Task *tt;
  35. /**
  36. * Client handle.
  37. */
  38. struct GNUNET_SERVICE_Client *client;
  39. };
  40. /**
  41. * Our configuration.
  42. */
  43. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  44. /**
  45. * Try contacting the peer using autonomous NAT traveral method.
  46. *
  47. * @param dst_ipv4 IPv4 address to send the fake ICMP message
  48. * @param dport destination port to include in ICMP message
  49. * @param is_tcp mark for TCP (#GNUNET_YES) or UDP (#GNUNET_NO)
  50. */
  51. static void
  52. try_anat (uint32_t dst_ipv4,
  53. uint16_t dport,
  54. int is_tcp)
  55. {
  56. struct GNUNET_NAT_Handle *h;
  57. struct sockaddr_in lsa;
  58. struct sockaddr_in rsa;
  59. const struct sockaddr *sa;
  60. socklen_t sa_len;
  61. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  62. "Asking for connection reversal with %x and code %u\n",
  63. (unsigned int) dst_ipv4,
  64. (unsigned int) dport);
  65. memset (&lsa, 0, sizeof (lsa));
  66. lsa.sin_family = AF_INET;
  67. #if HAVE_SOCKADDR_IN_SIN_LEN
  68. lsa.sin_len = sizeof (sa);
  69. #endif
  70. lsa.sin_addr.s_addr = 0;
  71. lsa.sin_port = htons (dport);
  72. memset (&rsa, 0, sizeof (rsa));
  73. rsa.sin_family = AF_INET;
  74. #if HAVE_SOCKADDR_IN_SIN_LEN
  75. rsa.sin_len = sizeof (sa);
  76. #endif
  77. rsa.sin_addr.s_addr = dst_ipv4;
  78. rsa.sin_port = htons (dport);
  79. sa_len = sizeof (lsa);
  80. sa = (const struct sockaddr *) &lsa;
  81. h = GNUNET_NAT_register (cfg,
  82. "none",
  83. is_tcp ? IPPROTO_TCP : IPPROTO_UDP,
  84. 1,
  85. &sa,
  86. &sa_len,
  87. NULL, NULL, NULL);
  88. GNUNET_NAT_request_reversal (h,
  89. &lsa,
  90. &rsa);
  91. GNUNET_NAT_unregister (h);
  92. }
  93. /**
  94. * Closure for #tcp_send.
  95. */
  96. struct TcpContext
  97. {
  98. /**
  99. * TCP socket.
  100. */
  101. struct GNUNET_NETWORK_Handle *s;
  102. /**
  103. * Data to transmit.
  104. */
  105. uint16_t data;
  106. };
  107. /**
  108. * Task called by the scheduler once we can do the TCP send
  109. * (or once we failed to connect...).
  110. *
  111. * @param cls the `struct TcpContext`
  112. */
  113. static void
  114. tcp_send (void *cls)
  115. {
  116. struct TcpContext *ctx = cls;
  117. const struct GNUNET_SCHEDULER_TaskContext *tc;
  118. tc = GNUNET_SCHEDULER_get_task_context ();
  119. if ((NULL != tc->write_ready) &&
  120. (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s)))
  121. {
  122. if (-1 ==
  123. GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data)))
  124. {
  125. GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
  126. }
  127. GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
  128. }
  129. GNUNET_NETWORK_socket_close (ctx->s);
  130. GNUNET_free (ctx);
  131. }
  132. /**
  133. * Try to send @a data to the
  134. * IP @a dst_ipv4' at port @a dport via TCP.
  135. *
  136. * @param dst_ipv4 target IP
  137. * @param dport target port
  138. * @param data data to send
  139. */
  140. static void
  141. try_send_tcp (uint32_t dst_ipv4,
  142. uint16_t dport,
  143. uint16_t data)
  144. {
  145. struct GNUNET_NETWORK_Handle *s;
  146. struct sockaddr_in sa;
  147. struct TcpContext *ctx;
  148. s = GNUNET_NETWORK_socket_create (AF_INET,
  149. SOCK_STREAM,
  150. 0);
  151. if (NULL == s)
  152. {
  153. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
  154. "socket");
  155. return;
  156. }
  157. memset (&sa, 0, sizeof (sa));
  158. sa.sin_family = AF_INET;
  159. #if HAVE_SOCKADDR_IN_SIN_LEN
  160. sa.sin_len = sizeof (sa);
  161. #endif
  162. sa.sin_addr.s_addr = dst_ipv4;
  163. sa.sin_port = htons (dport);
  164. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  165. "Sending TCP message to `%s'\n",
  166. GNUNET_a2s ((struct sockaddr *) &sa,
  167. sizeof (sa)));
  168. if ( (GNUNET_OK !=
  169. GNUNET_NETWORK_socket_connect (s,
  170. (const struct sockaddr *) &sa,
  171. sizeof (sa))) &&
  172. (errno != EINPROGRESS) )
  173. {
  174. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
  175. "connect");
  176. GNUNET_NETWORK_socket_close (s);
  177. return;
  178. }
  179. ctx = GNUNET_new (struct TcpContext);
  180. ctx->s = s;
  181. ctx->data = data;
  182. GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
  183. s,
  184. &tcp_send,
  185. ctx);
  186. }
  187. /**
  188. * Try to send @a data to the
  189. * IP @a dst_ipv4 at port @a dport via UDP.
  190. *
  191. * @param dst_ipv4 target IP
  192. * @param dport target port
  193. * @param data data to send
  194. */
  195. static void
  196. try_send_udp (uint32_t dst_ipv4,
  197. uint16_t dport,
  198. uint16_t data)
  199. {
  200. struct GNUNET_NETWORK_Handle *s;
  201. struct sockaddr_in sa;
  202. s = GNUNET_NETWORK_socket_create (AF_INET,
  203. SOCK_DGRAM,
  204. 0);
  205. if (NULL == s)
  206. {
  207. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
  208. "socket");
  209. return;
  210. }
  211. memset (&sa, 0, sizeof (sa));
  212. sa.sin_family = AF_INET;
  213. #if HAVE_SOCKADDR_IN_SIN_LEN
  214. sa.sin_len = sizeof (sa);
  215. #endif
  216. sa.sin_addr.s_addr = dst_ipv4;
  217. sa.sin_port = htons (dport);
  218. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  219. "Sending UDP packet to `%s'\n",
  220. GNUNET_a2s ((struct sockaddr *) &sa,
  221. sizeof (sa)));
  222. if (-1 ==
  223. GNUNET_NETWORK_socket_sendto (s,
  224. &data,
  225. sizeof (data),
  226. (const struct sockaddr *) &sa,
  227. sizeof (sa)))
  228. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
  229. "sendto");
  230. GNUNET_NETWORK_socket_close (s);
  231. }
  232. /**
  233. * We've received a request to probe a NAT
  234. * traversal. Do it.
  235. *
  236. * @param cls handle to client (we always close)
  237. * @param msg message with details about what to test
  238. */
  239. static void
  240. handle_test (void *cls,
  241. const struct GNUNET_NAT_AUTO_TestMessage *tm)
  242. {
  243. struct ClientData *cd = cls;
  244. uint16_t dport;
  245. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  246. "Received test request\n");
  247. dport = ntohs (tm->dport);
  248. if (0 == dport)
  249. try_anat (tm->dst_ipv4,
  250. ntohs (tm->data),
  251. (int) ntohl (tm->is_tcp));
  252. else if (GNUNET_YES == ntohl (tm->is_tcp))
  253. try_send_tcp (tm->dst_ipv4,
  254. dport,
  255. tm->data);
  256. else
  257. try_send_udp (tm->dst_ipv4,
  258. dport,
  259. tm->data);
  260. GNUNET_SERVICE_client_drop (cd->client);
  261. }
  262. /**
  263. * Main function that will be run.
  264. *
  265. * @param cls closure
  266. * @param c configuration
  267. * @param srv service handle
  268. */
  269. static void
  270. run (void *cls,
  271. const struct GNUNET_CONFIGURATION_Handle *c,
  272. struct GNUNET_SERVICE_Handle *srv)
  273. {
  274. cfg = c;
  275. }
  276. /**
  277. * Forcefully drops client after 1s.
  278. *
  279. * @param cls our `struct ClientData` of a client to drop
  280. */
  281. static void
  282. force_timeout (void *cls)
  283. {
  284. struct ClientData *cd = cls;
  285. cd->tt = NULL;
  286. GNUNET_SERVICE_client_drop (cd->client);
  287. }
  288. /**
  289. * Callback called when a client connects to the service.
  290. *
  291. * @param cls closure for the service
  292. * @param c the new client that connected to the service
  293. * @param mq the message queue used to send messages to the client
  294. * @return our `struct ClientData`
  295. */
  296. static void *
  297. client_connect_cb (void *cls,
  298. struct GNUNET_SERVICE_Client *c,
  299. struct GNUNET_MQ_Handle *mq)
  300. {
  301. struct ClientData *cd;
  302. cd = GNUNET_new (struct ClientData);
  303. cd->client = c;
  304. cd->tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  305. &force_timeout,
  306. cd);
  307. return cd;
  308. }
  309. /**
  310. * Callback called when a client disconnected from the service
  311. *
  312. * @param cls closure for the service
  313. * @param c the client that disconnected
  314. * @param internal_cls our `struct ClientData`
  315. */
  316. static void
  317. client_disconnect_cb (void *cls,
  318. struct GNUNET_SERVICE_Client *c,
  319. void *internal_cls)
  320. {
  321. struct ClientData *cd = internal_cls;
  322. if (NULL != cd->tt)
  323. GNUNET_SCHEDULER_cancel (cd->tt);
  324. GNUNET_free (cd);
  325. }
  326. /**
  327. * Define "main" method using service macro.
  328. */
  329. GNUNET_SERVICE_MAIN
  330. ("nat-server",
  331. GNUNET_SERVICE_OPTION_NONE,
  332. &run,
  333. &client_connect_cb,
  334. &client_disconnect_cb,
  335. NULL,
  336. GNUNET_MQ_hd_fixed_size (test,
  337. GNUNET_MESSAGE_TYPE_NAT_TEST,
  338. struct GNUNET_NAT_AUTO_TestMessage,
  339. NULL),
  340. GNUNET_MQ_handler_end ());
  341. #if defined(LINUX) && defined(__GLIBC__)
  342. #include <malloc.h>
  343. /**
  344. * MINIMIZE heap size (way below 128k) since this process doesn't need much.
  345. */
  346. void __attribute__ ((constructor))
  347. GNUNET_ARM_memory_init ()
  348. {
  349. mallopt (M_TRIM_THRESHOLD, 4 * 1024);
  350. mallopt (M_TOP_PAD, 1 * 1024);
  351. malloc_trim (0);
  352. }
  353. #endif
  354. /* end of gnunet-nat-server.c */