nat_auto_api_test.c 17 KB

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