gnunet-nat-auto_legacy.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2011, 2016 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 nat/nat_test.c
  18. * @brief functions to test if the NAT configuration is successful at achieving NAT traversal (with the help of a gnunet-nat-server)
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_nat_lib.h"
  24. #include "nat.h"
  25. #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__)
  26. #define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
  27. /**
  28. * Entry we keep for each incoming connection.
  29. */
  30. struct NatActivity
  31. {
  32. /**
  33. * This is a doubly-linked list.
  34. */
  35. struct NatActivity *next;
  36. /**
  37. * This is a doubly-linked list.
  38. */
  39. struct NatActivity *prev;
  40. /**
  41. * Socket of the incoming connection.
  42. */
  43. struct GNUNET_NETWORK_Handle *sock;
  44. /**
  45. * Handle of the master context.
  46. */
  47. struct GNUNET_NAT_Test *h;
  48. /**
  49. * Task reading from the incoming connection.
  50. */
  51. struct GNUNET_SCHEDULER_Task *rtask;
  52. };
  53. /**
  54. * Entry we keep for each connection to the gnunet-nat-service.
  55. */
  56. struct ClientActivity
  57. {
  58. /**
  59. * This is a doubly-linked list.
  60. */
  61. struct ClientActivity *next;
  62. /**
  63. * This is a doubly-linked list.
  64. */
  65. struct ClientActivity *prev;
  66. /**
  67. * Socket of the incoming connection.
  68. */
  69. struct GNUNET_MQ_Handle *mq;
  70. /**
  71. * Handle to overall NAT test.
  72. */
  73. struct GNUNET_NAT_Test *h;
  74. };
  75. /**
  76. * Handle to a NAT test.
  77. */
  78. struct GNUNET_NAT_Test
  79. {
  80. /**
  81. * Configuration used
  82. */
  83. const struct GNUNET_CONFIGURATION_Handle *cfg;
  84. /**
  85. * Function to call with success report
  86. */
  87. GNUNET_NAT_TestCallback report;
  88. /**
  89. * Closure for @e report.
  90. */
  91. void *report_cls;
  92. /**
  93. * Handle to NAT traversal in use
  94. */
  95. struct GNUNET_NAT_Handle *nat;
  96. /**
  97. * Handle to listen socket, or NULL
  98. */
  99. struct GNUNET_NETWORK_Handle *lsock;
  100. /**
  101. * Head of list of nat activities.
  102. */
  103. struct NatActivity *na_head;
  104. /**
  105. * Tail of list of nat activities.
  106. */
  107. struct NatActivity *na_tail;
  108. /**
  109. * Head of list of client activities.
  110. */
  111. struct ClientActivity *ca_head;
  112. /**
  113. * Tail of list of client activities.
  114. */
  115. struct ClientActivity *ca_tail;
  116. /**
  117. * Identity of task for the listen socket (if any)
  118. */
  119. struct GNUNET_SCHEDULER_Task *ltask;
  120. /**
  121. * Task identifier for the timeout (if any)
  122. */
  123. struct GNUNET_SCHEDULER_Task *ttask;
  124. /**
  125. * #GNUNET_YES if we're testing TCP
  126. */
  127. int is_tcp;
  128. /**
  129. * Data that should be transmitted or source-port.
  130. */
  131. uint16_t data;
  132. /**
  133. * Advertised port to the other peer.
  134. */
  135. uint16_t adv_port;
  136. /**
  137. * Status code to be reported to the timeout/status call
  138. */
  139. enum GNUNET_NAT_StatusCode status;
  140. };
  141. /**
  142. * Function called from #GNUNET_NAT_register whenever someone asks us
  143. * to do connection reversal.
  144. *
  145. * @param cls closure, our `struct GNUNET_NAT_Handle`
  146. * @param addr public IP address of the other peer
  147. * @param addrlen actual lenght of the @a addr
  148. */
  149. static void
  150. reversal_cb (void *cls,
  151. const struct sockaddr *addr,
  152. socklen_t addrlen)
  153. {
  154. struct GNUNET_NAT_Test *h = cls;
  155. const struct sockaddr_in *sa;
  156. if (sizeof (struct sockaddr_in) != addrlen)
  157. return;
  158. sa = (const struct sockaddr_in *) addr;
  159. if (h->data != sa->sin_port)
  160. {
  161. LOG (GNUNET_ERROR_TYPE_DEBUG,
  162. "Received connection reversal request for wrong port\n");
  163. return; /* wrong port */
  164. }
  165. /* report success */
  166. h->report (h->report_cls,
  167. GNUNET_NAT_ERROR_SUCCESS);
  168. }
  169. /**
  170. * Activity on our incoming socket. Read data from the
  171. * incoming connection.
  172. *
  173. * @param cls the `struct GNUNET_NAT_Test`
  174. */
  175. static void
  176. do_udp_read (void *cls)
  177. {
  178. struct GNUNET_NAT_Test *tst = cls;
  179. uint16_t data;
  180. const struct GNUNET_SCHEDULER_TaskContext *tc;
  181. tc = GNUNET_SCHEDULER_get_task_context ();
  182. tst->ltask =
  183. GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  184. tst->lsock,
  185. &do_udp_read,
  186. tst);
  187. if ((NULL != tc->write_ready) &&
  188. (GNUNET_NETWORK_fdset_isset (tc->read_ready,
  189. tst->lsock)) &&
  190. (sizeof (data) ==
  191. GNUNET_NETWORK_socket_recv (tst->lsock,
  192. &data,
  193. sizeof (data))))
  194. {
  195. if (data == tst->data)
  196. tst->report (tst->report_cls,
  197. GNUNET_NAT_ERROR_SUCCESS);
  198. else
  199. LOG (GNUNET_ERROR_TYPE_DEBUG,
  200. "Received data mismatches expected value\n");
  201. }
  202. else
  203. LOG (GNUNET_ERROR_TYPE_DEBUG,
  204. "Failed to receive data from inbound connection\n");
  205. }
  206. /**
  207. * Activity on our incoming socket. Read data from the
  208. * incoming connection.
  209. *
  210. * @param cls the `struct NatActivity`
  211. */
  212. static void
  213. do_read (void *cls)
  214. {
  215. struct NatActivity *na = cls;
  216. struct GNUNET_NAT_Test *tst;
  217. uint16_t data;
  218. const struct GNUNET_SCHEDULER_TaskContext *tc;
  219. tc = GNUNET_SCHEDULER_get_task_context ();
  220. na->rtask = NULL;
  221. tst = na->h;
  222. GNUNET_CONTAINER_DLL_remove (tst->na_head,
  223. tst->na_tail,
  224. na);
  225. if ((NULL != tc->write_ready) &&
  226. (GNUNET_NETWORK_fdset_isset (tc->read_ready,
  227. na->sock)) &&
  228. (sizeof (data) ==
  229. GNUNET_NETWORK_socket_recv (na->sock,
  230. &data,
  231. sizeof (data))))
  232. {
  233. if (data == tst->data)
  234. tst->report (tst->report_cls,
  235. GNUNET_NAT_ERROR_SUCCESS);
  236. else
  237. LOG (GNUNET_ERROR_TYPE_DEBUG,
  238. "Received data does not match expected value\n");
  239. }
  240. else
  241. LOG (GNUNET_ERROR_TYPE_DEBUG,
  242. "Failed to receive data from inbound connection\n");
  243. GNUNET_NETWORK_socket_close (na->sock);
  244. GNUNET_free (na);
  245. }
  246. /**
  247. * Activity on our listen socket. Accept the
  248. * incoming connection.
  249. *
  250. * @param cls the `struct GNUNET_NAT_Test`
  251. */
  252. static void
  253. do_accept (void *cls)
  254. {
  255. struct GNUNET_NAT_Test *tst = cls;
  256. struct GNUNET_NETWORK_Handle *s;
  257. struct NatActivity *wl;
  258. tst->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  259. tst->lsock,
  260. &do_accept,
  261. tst);
  262. s = GNUNET_NETWORK_socket_accept (tst->lsock,
  263. NULL,
  264. NULL);
  265. if (NULL == s)
  266. {
  267. GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
  268. "accept");
  269. return; /* odd error */
  270. }
  271. LOG (GNUNET_ERROR_TYPE_DEBUG,
  272. "Got an inbound connection, waiting for data\n");
  273. wl = GNUNET_new (struct NatActivity);
  274. wl->sock = s;
  275. wl->h = tst;
  276. wl->rtask =
  277. GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  278. wl->sock,
  279. &do_read,
  280. wl);
  281. GNUNET_CONTAINER_DLL_insert (tst->na_head,
  282. tst->na_tail,
  283. wl);
  284. }
  285. /**
  286. * We got disconnected from the NAT server. Stop
  287. * waiting for a reply.
  288. *
  289. * @param cls the `struct ClientActivity`
  290. * @param error error code
  291. */
  292. static void
  293. mq_error_handler (void *cls,
  294. enum GNUNET_MQ_Error error)
  295. {
  296. struct ClientActivity *ca = cls;
  297. struct GNUNET_NAT_Test *tst = ca->h;
  298. GNUNET_CONTAINER_DLL_remove (tst->ca_head,
  299. tst->ca_tail,
  300. ca);
  301. GNUNET_MQ_destroy (ca->mq);
  302. GNUNET_free (ca);
  303. }
  304. /**
  305. * Address-callback, used to send message to gnunet-nat-server.
  306. *
  307. * @param cls closure
  308. * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
  309. * the previous (now invalid) one
  310. * @param addr either the previous or the new public IP address
  311. * @param addrlen actual length of the @a addr
  312. */
  313. static void
  314. addr_cb (void *cls,
  315. int add_remove,
  316. const struct sockaddr *addr,
  317. socklen_t addrlen)
  318. {
  319. struct GNUNET_NAT_Test *h = cls;
  320. struct ClientActivity *ca;
  321. struct GNUNET_MQ_Envelope *env;
  322. struct GNUNET_NAT_TestMessage *msg;
  323. const struct sockaddr_in *sa;
  324. if (GNUNET_YES != add_remove)
  325. return;
  326. if (addrlen != sizeof (struct sockaddr_in))
  327. {
  328. LOG (GNUNET_ERROR_TYPE_DEBUG,
  329. "NAT test ignores IPv6 address `%s' returned from NAT library\n",
  330. GNUNET_a2s (addr,
  331. addrlen));
  332. return; /* ignore IPv6 here */
  333. }
  334. LOG (GNUNET_ERROR_TYPE_INFO,
  335. "Asking gnunet-nat-server to connect to `%s'\n",
  336. GNUNET_a2s (addr,
  337. addrlen));
  338. ca = GNUNET_new (struct ClientActivity);
  339. ca->h = h;
  340. ca->mq = GNUNET_CLIENT_connect (h->cfg,
  341. "gnunet-nat-server",
  342. NULL,
  343. &mq_error_handler,
  344. ca);
  345. if (NULL == ca->mq)
  346. {
  347. GNUNET_free (ca);
  348. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  349. _("Failed to connect to `gnunet-nat-server'\n"));
  350. return;
  351. }
  352. GNUNET_CONTAINER_DLL_insert (h->ca_head,
  353. h->ca_tail,
  354. ca);
  355. sa = (const struct sockaddr_in *) addr;
  356. env = GNUNET_MQ_msg (msg,
  357. GNUNET_MESSAGE_TYPE_NAT_TEST);
  358. msg->dst_ipv4 = sa->sin_addr.s_addr;
  359. msg->dport = sa->sin_port;
  360. msg->data = h->data;
  361. msg->is_tcp = htonl ((uint32_t) h->is_tcp);
  362. GNUNET_MQ_send (ca->mq,
  363. env);
  364. }
  365. /**
  366. * Timeout task for a nat test.
  367. * Calls the report-callback with a timeout return value
  368. *
  369. * Destroys the nat handle after the callback has been processed.
  370. *
  371. * @param cls handle to the timed out NAT test
  372. */
  373. static void
  374. do_timeout (void *cls)
  375. {
  376. struct GNUNET_NAT_Test *nh = cls;
  377. nh->ttask = NULL;
  378. nh->report (nh->report_cls,
  379. (GNUNET_NAT_ERROR_SUCCESS == nh->status)
  380. ? GNUNET_NAT_ERROR_TIMEOUT
  381. : nh->status);
  382. }
  383. /**
  384. * Start testing if NAT traversal works using the
  385. * given configuration (IPv4-only).
  386. *
  387. * ALL failures are reported directly to the report callback
  388. *
  389. * @param cfg configuration for the NAT traversal
  390. * @param is_tcp #GNUNET_YES to test TCP, #GNUNET_NO to test UDP
  391. * @param bnd_port port to bind to, 0 for connection reversal
  392. * @param adv_port externally advertised port to use
  393. * @param timeout delay after which the test should be aborted
  394. * @param report function to call with the result of the test
  395. * @param report_cls closure for @a report
  396. * @return handle to cancel NAT test or NULL. The error is always indicated via the report callback
  397. */
  398. struct GNUNET_NAT_Test *
  399. GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
  400. int is_tcp,
  401. uint16_t bnd_port,
  402. uint16_t adv_port,
  403. struct GNUNET_TIME_Relative timeout,
  404. GNUNET_NAT_TestCallback report,
  405. void *report_cls)
  406. {
  407. struct GNUNET_NAT_Test *nh;
  408. struct sockaddr_in sa;
  409. const struct sockaddr *addrs[] = {
  410. (const struct sockaddr *) &sa
  411. };
  412. const socklen_t addrlens[] = {
  413. sizeof (sa)
  414. };
  415. memset (&sa, 0, sizeof (sa));
  416. sa.sin_family = AF_INET;
  417. sa.sin_port = htons (bnd_port);
  418. #if HAVE_SOCKADDR_IN_SIN_LEN
  419. sa.sin_len = sizeof (sa);
  420. #endif
  421. nh = GNUNET_new (struct GNUNET_NAT_Test);
  422. nh->cfg = cfg;
  423. nh->is_tcp = is_tcp;
  424. nh->data = bnd_port;
  425. nh->adv_port = adv_port;
  426. nh->report = report;
  427. nh->report_cls = report_cls;
  428. nh->status = GNUNET_NAT_ERROR_SUCCESS;
  429. if (0 == bnd_port)
  430. {
  431. nh->nat
  432. = GNUNET_NAT_register (cfg,
  433. is_tcp,
  434. 0,
  435. 0,
  436. NULL,
  437. NULL,
  438. &addr_cb,
  439. &reversal_cb,
  440. nh,
  441. NULL);
  442. }
  443. else
  444. {
  445. nh->lsock =
  446. GNUNET_NETWORK_socket_create (AF_INET,
  447. (is_tcp ==
  448. GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM,
  449. 0);
  450. if ((nh->lsock == NULL) ||
  451. (GNUNET_OK !=
  452. GNUNET_NETWORK_socket_bind (nh->lsock,
  453. (const struct sockaddr *) &sa,
  454. sizeof (sa))))
  455. {
  456. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  457. _("Failed to create listen socket bound to `%s' for NAT test: %s\n"),
  458. GNUNET_a2s ((const struct sockaddr *) &sa,
  459. sizeof (sa)),
  460. STRERROR (errno));
  461. if (NULL != nh->lsock)
  462. {
  463. GNUNET_NETWORK_socket_close (nh->lsock);
  464. nh->lsock = NULL;
  465. }
  466. nh->status = GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR;
  467. nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout,
  468. nh);
  469. return nh;
  470. }
  471. if (GNUNET_YES == is_tcp)
  472. {
  473. GNUNET_break (GNUNET_OK ==
  474. GNUNET_NETWORK_socket_listen (nh->lsock,
  475. 5));
  476. nh->ltask =
  477. GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  478. nh->lsock,
  479. &do_accept,
  480. nh);
  481. }
  482. else
  483. {
  484. nh->ltask =
  485. GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  486. nh->lsock,
  487. &do_udp_read,
  488. nh);
  489. }
  490. LOG (GNUNET_ERROR_TYPE_INFO,
  491. "NAT test listens on port %u (%s)\n",
  492. bnd_port,
  493. (GNUNET_YES == is_tcp) ? "tcp" : "udp");
  494. nh->nat = GNUNET_NAT_register (cfg,
  495. is_tcp,
  496. adv_port,
  497. 1,
  498. addrs,
  499. addrlens,
  500. &addr_cb,
  501. NULL,
  502. nh,
  503. NULL);
  504. if (NULL == nh->nat)
  505. {
  506. LOG (GNUNET_ERROR_TYPE_INFO,
  507. _("NAT test failed to start NAT library\n"));
  508. if (NULL != nh->ltask)
  509. {
  510. GNUNET_SCHEDULER_cancel (nh->ltask);
  511. nh->ltask = NULL;
  512. }
  513. if (NULL != nh->lsock)
  514. {
  515. GNUNET_NETWORK_socket_close (nh->lsock);
  516. nh->lsock = NULL;
  517. }
  518. nh->status = GNUNET_NAT_ERROR_NAT_REGISTER_FAILED;
  519. nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout,
  520. nh);
  521. return nh;
  522. }
  523. }
  524. nh->ttask = GNUNET_SCHEDULER_add_delayed (timeout,
  525. &do_timeout,
  526. nh);
  527. return nh;
  528. }
  529. /**
  530. * Stop an active NAT test.
  531. *
  532. * @param tst test to stop.
  533. */
  534. void
  535. GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst)
  536. {
  537. struct NatActivity *pos;
  538. struct ClientActivity *cpos;
  539. LOG (GNUNET_ERROR_TYPE_DEBUG,
  540. "Stopping NAT test\n");
  541. while (NULL != (cpos = tst->ca_head))
  542. {
  543. GNUNET_CONTAINER_DLL_remove (tst->ca_head,
  544. tst->ca_tail,
  545. cpos);
  546. GNUNET_MQ_destroy (cpos->mq);
  547. GNUNET_free (cpos);
  548. }
  549. while (NULL != (pos = tst->na_head))
  550. {
  551. GNUNET_CONTAINER_DLL_remove (tst->na_head,
  552. tst->na_tail,
  553. pos);
  554. GNUNET_SCHEDULER_cancel (pos->rtask);
  555. GNUNET_NETWORK_socket_close (pos->sock);
  556. GNUNET_free (pos);
  557. }
  558. if (NULL != tst->ttask)
  559. {
  560. GNUNET_SCHEDULER_cancel (tst->ttask);
  561. tst->ttask = NULL;
  562. }
  563. if (NULL != tst->ltask)
  564. {
  565. GNUNET_SCHEDULER_cancel (tst->ltask);
  566. tst->ltask = NULL;
  567. }
  568. if (NULL != tst->lsock)
  569. {
  570. GNUNET_NETWORK_socket_close (tst->lsock);
  571. tst->lsock = NULL;
  572. }
  573. if (NULL != tst->nat)
  574. {
  575. GNUNET_NAT_unregister (tst->nat);
  576. tst->nat = NULL;
  577. }
  578. GNUNET_free (tst);
  579. }
  580. /* end of nat_test.c */