gnunet-service-nat-auto_legacy.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2015 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.c
  18. * @brief functions for auto-configuration of the network
  19. * @author Christian Grothoff
  20. * @author Bruno Cabral
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_resolver_service.h"
  25. #include "gnunet_nat_lib.h"
  26. #include "nat.h"
  27. #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__)
  28. /**
  29. * How long do we wait for the NAT test to report success?
  30. */
  31. #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
  32. #define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
  33. /**
  34. * Phases of the auto configuration.
  35. */
  36. enum AutoPhase
  37. {
  38. /**
  39. * Initial start value.
  40. */
  41. AUTO_INIT = 0,
  42. /**
  43. * Test our external IP.
  44. */
  45. AUTO_EXTERNAL_IP,
  46. /**
  47. * Test our external IP.
  48. */
  49. AUTO_STUN,
  50. /**
  51. * Test our internal IP.
  52. */
  53. AUTO_LOCAL_IP,
  54. /**
  55. * Test if NAT was punched.
  56. */
  57. AUTO_NAT_PUNCHED,
  58. /**
  59. * Test if UPnP is working.
  60. */
  61. AUTO_UPNPC,
  62. /**
  63. * Test if ICMP server works.
  64. */
  65. AUTO_ICMP_SERVER,
  66. /**
  67. * Test if ICMP client works.
  68. */
  69. AUTO_ICMP_CLIENT,
  70. /**
  71. * Last phase, we're done.
  72. */
  73. AUTO_DONE
  74. };
  75. /**
  76. * Handle to auto-configuration in progress.
  77. */
  78. struct GNUNET_NAT_AutoHandle
  79. {
  80. /**
  81. * Handle to the active NAT test.
  82. */
  83. struct GNUNET_NAT_Test *tst;
  84. /**
  85. * Function to call when done.
  86. */
  87. GNUNET_NAT_AutoResultCallback fin_cb;
  88. /**
  89. * Closure for @e fin_cb.
  90. */
  91. void *fin_cb_cls;
  92. /**
  93. * Handle for active 'GNUNET_NAT_mini_get_external_ipv4'-operation.
  94. */
  95. struct GNUNET_NAT_ExternalHandle *eh;
  96. /**
  97. * Current configuration (with updates from previous phases)
  98. */
  99. struct GNUNET_CONFIGURATION_Handle *cfg;
  100. /**
  101. * Original configuration (used to calculate differences)
  102. */
  103. struct GNUNET_CONFIGURATION_Handle *initial_cfg;
  104. /**
  105. * Task identifier for the timeout.
  106. */
  107. struct GNUNET_SCHEDULER_Task *task;
  108. /**
  109. * Message queue to the gnunet-nat-server.
  110. */
  111. struct GNUNET_MQ_Handle *mq;
  112. /**
  113. * Where are we in the test?
  114. */
  115. enum AutoPhase phase;
  116. /**
  117. * Situation of the NAT
  118. */
  119. enum GNUNET_NAT_Type type;
  120. /**
  121. * Do we have IPv6?
  122. */
  123. int have_v6;
  124. /**
  125. * UPnP already set the external ip address ?
  126. */
  127. int upnp_set_external_address;
  128. /**
  129. * Did the external server connected back ?
  130. */
  131. int connected_back;
  132. /**
  133. * Address detected by STUN
  134. */
  135. char *stun_ip;
  136. unsigned int stun_port;
  137. /**
  138. * Internal IP is the same as the public one ?
  139. */
  140. int internal_ip_is_public;
  141. /**
  142. * Error code for better debugging and user feedback
  143. */
  144. enum GNUNET_NAT_StatusCode ret;
  145. };
  146. /**
  147. * The listen socket of the service for IPv4
  148. */
  149. static struct GNUNET_NETWORK_Handle *lsock4;
  150. /**
  151. * The listen task ID for IPv4
  152. */
  153. static struct GNUNET_SCHEDULER_Task *ltask4;
  154. /**
  155. * The port the test service is running on (default 7895)
  156. */
  157. static unsigned long long port = 7895;
  158. static char *stun_server = "stun.ekiga.net";
  159. static unsigned int stun_port = 3478;
  160. /**
  161. * Run the next phase of the auto test.
  162. *
  163. * @param ah auto test handle
  164. */
  165. static void
  166. next_phase (struct GNUNET_NAT_AutoHandle *ah);
  167. static void
  168. process_stun_reply(struct sockaddr_in *answer,
  169. struct GNUNET_NAT_AutoHandle *ah)
  170. {
  171. ah->stun_ip = inet_ntoa(answer->sin_addr);
  172. ah->stun_port = ntohs (answer->sin_port);
  173. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  174. "External IP is: %s , with port %u\n",
  175. ah->stun_ip,
  176. ah->stun_port);
  177. next_phase (ah);
  178. }
  179. /**
  180. * Function that terminates the test.
  181. */
  182. static void
  183. stop_stun ()
  184. {
  185. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  186. "Stopping STUN and quitting...\n");
  187. /* Clean task */
  188. if (NULL != ltask4)
  189. {
  190. GNUNET_SCHEDULER_cancel (ltask4);
  191. ltask4 = NULL;
  192. }
  193. /* Clean socket */
  194. if (NULL != lsock4)
  195. {
  196. GNUNET_NETWORK_socket_close (lsock4);
  197. lsock4 = NULL;
  198. }
  199. }
  200. /**
  201. * Activity on our incoming socket. Read data from the
  202. * incoming connection.
  203. *
  204. * @param cls
  205. */
  206. static void
  207. do_udp_read (void *cls)
  208. {
  209. struct GNUNET_NAT_AutoHandle *ah = cls;
  210. unsigned char reply_buf[1024];
  211. ssize_t rlen;
  212. struct sockaddr_in answer;
  213. const struct GNUNET_SCHEDULER_TaskContext *tc;
  214. tc = GNUNET_SCHEDULER_get_task_context ();
  215. if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
  216. (GNUNET_NETWORK_fdset_isset (tc->read_ready,
  217. lsock4)))
  218. {
  219. rlen = GNUNET_NETWORK_socket_recv (lsock4,
  220. reply_buf,
  221. sizeof (reply_buf));
  222. //Lets handle the packet
  223. memset (&answer, 0, sizeof(struct sockaddr_in));
  224. if (ah->phase == AUTO_NAT_PUNCHED)
  225. {
  226. //Destroy the connection
  227. GNUNET_NETWORK_socket_close (lsock4);
  228. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  229. "The external server was able to connect back");
  230. ah->connected_back = GNUNET_YES;
  231. next_phase (ah);
  232. }
  233. else
  234. {
  235. if (GNUNET_OK ==
  236. GNUNET_NAT_stun_handle_packet (reply_buf, rlen, &answer))
  237. {
  238. //Process the answer
  239. process_stun_reply (&answer, ah);
  240. }
  241. else
  242. {
  243. next_phase (ah);
  244. }
  245. }
  246. }
  247. else
  248. {
  249. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  250. "TIMEOUT while waiting for an answer\n");
  251. if (ah->phase == AUTO_NAT_PUNCHED)
  252. {
  253. stop_stun();
  254. }
  255. next_phase (ah);
  256. }
  257. }
  258. /**
  259. * Create an IPv4 listen socket bound to our port.
  260. *
  261. * @return NULL on error
  262. */
  263. static struct GNUNET_NETWORK_Handle *
  264. bind_v4 ()
  265. {
  266. struct GNUNET_NETWORK_Handle *ls;
  267. struct sockaddr_in sa4;
  268. int eno;
  269. memset (&sa4, 0, sizeof (sa4));
  270. sa4.sin_family = AF_INET;
  271. sa4.sin_port = htons (port);
  272. #if HAVE_SOCKADDR_IN_SIN_LEN
  273. sa4.sin_len = sizeof (sa4);
  274. #endif
  275. ls = GNUNET_NETWORK_socket_create (AF_INET,
  276. SOCK_DGRAM,
  277. 0);
  278. if (NULL == ls)
  279. return NULL;
  280. if (GNUNET_OK !=
  281. GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4,
  282. sizeof (sa4)))
  283. {
  284. eno = errno;
  285. GNUNET_NETWORK_socket_close (ls);
  286. errno = eno;
  287. return NULL;
  288. }
  289. return ls;
  290. }
  291. static void
  292. request_callback (void *cls,
  293. enum GNUNET_NAT_StatusCode result)
  294. {
  295. // struct GNUNET_NAT_AutoHandle *ah = cls;
  296. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  297. "Request callback: stop and quit\n");
  298. stop_stun ();
  299. // next_phase (ah); FIXME this always will be NULL, as called in test_stun()
  300. }
  301. /**
  302. * Function called by NAT to report the outcome of the nat-test.
  303. * Clean up and update GUI.
  304. *
  305. * @param cls the auto handle
  306. * @param success currently always #GNUNET_OK
  307. * @param emsg NULL on success, otherwise an error message
  308. */
  309. static void
  310. result_callback (void *cls,
  311. enum GNUNET_NAT_StatusCode ret)
  312. {
  313. struct GNUNET_NAT_AutoHandle *ah = cls;
  314. if (GNUNET_NAT_ERROR_SUCCESS == ret)
  315. GNUNET_NAT_test_stop (ah->tst);
  316. ah->tst = NULL;
  317. ah->ret = ret;
  318. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  319. GNUNET_NAT_ERROR_SUCCESS == ret
  320. ? _("NAT traversal with ICMP Server succeeded.\n")
  321. : _("NAT traversal with ICMP Server failed.\n"));
  322. GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "ENABLE_ICMP_SERVER",
  323. GNUNET_NAT_ERROR_SUCCESS == ret ? "NO" : "YES");
  324. next_phase (ah);
  325. }
  326. /**
  327. * Main function for the connection reversal test.
  328. *
  329. * @param cls the `struct GNUNET_NAT_AutoHandle`
  330. */
  331. static void
  332. reversal_test (void *cls)
  333. {
  334. struct GNUNET_NAT_AutoHandle *ah = cls;
  335. ah->task = NULL;
  336. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  337. _("Testing connection reversal with ICMP server.\n"));
  338. GNUNET_RESOLVER_connect (ah->cfg);
  339. ah->tst = GNUNET_NAT_test_start (ah->cfg, GNUNET_YES, 0, 0, TIMEOUT,
  340. &result_callback, ah);
  341. }
  342. /**
  343. * Set our external IPv4 address based on the UPnP.
  344. *
  345. *
  346. * @param cls closure with our setup context
  347. * @param addr the address, NULL on errors
  348. * @param emsg NULL on success, otherwise an error message
  349. */
  350. static void
  351. set_external_ipv4 (void *cls,
  352. const struct in_addr *addr,
  353. enum GNUNET_NAT_StatusCode ret)
  354. {
  355. struct GNUNET_NAT_AutoHandle *ah = cls;
  356. char buf[INET_ADDRSTRLEN];
  357. ah->eh = NULL;
  358. ah->ret = ret;
  359. if (GNUNET_NAT_ERROR_SUCCESS != ret)
  360. {
  361. next_phase (ah);
  362. return;
  363. }
  364. /* enable 'behind nat' */
  365. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  366. _("Detected external IP `%s'\n"),
  367. inet_ntop (AF_INET,
  368. addr,
  369. buf,
  370. sizeof (buf)));
  371. GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "BEHIND_NAT", "YES");
  372. /* set external IP address */
  373. if (NULL == inet_ntop (AF_INET, addr, buf, sizeof (buf)))
  374. {
  375. GNUNET_break (0);
  376. /* actually, this should never happen, as the caller already executed just
  377. * this check, but for consistency (eg: future changes in the caller)
  378. * we still need to report this error...
  379. */
  380. ah->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID;
  381. next_phase (ah);
  382. return;
  383. }
  384. GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "EXTERNAL_ADDRESS",
  385. buf);
  386. ah->upnp_set_external_address = GNUNET_YES;
  387. next_phase (ah);
  388. }
  389. /**
  390. * Determine our external IPv4 address.
  391. *
  392. * @param ah auto setup context
  393. */
  394. static void
  395. test_external_ip (struct GNUNET_NAT_AutoHandle *ah)
  396. {
  397. if (GNUNET_NAT_ERROR_SUCCESS != ah->ret)
  398. next_phase (ah);
  399. // FIXME: CPS?
  400. /* try to detect external IP */
  401. ah->eh = GNUNET_NAT_mini_get_external_ipv4 (TIMEOUT,
  402. &set_external_ipv4, ah);
  403. }
  404. /**
  405. * Determine our external IPv4 address and port using an external STUN server
  406. *
  407. * @param ah auto setup context
  408. */
  409. static void
  410. test_stun (struct GNUNET_NAT_AutoHandle *ah)
  411. {
  412. GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running STUN test\n");
  413. /* Get port from the configuration */
  414. if (GNUNET_OK !=
  415. GNUNET_CONFIGURATION_get_value_number (ah->cfg,
  416. "transport-udp",
  417. "PORT",
  418. &port))
  419. {
  420. port = 2086;
  421. }
  422. //Lets create the socket
  423. lsock4 = bind_v4 ();
  424. if (NULL == lsock4)
  425. {
  426. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
  427. next_phase(ah);
  428. return;
  429. }
  430. else
  431. {
  432. //Lets call our function now when it accepts
  433. ltask4 = GNUNET_SCHEDULER_add_read_net (NAT_SERVER_TIMEOUT,
  434. lsock4,
  435. &do_udp_read,
  436. ah);
  437. }
  438. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  439. "STUN service listens on port %u\n",
  440. (unsigned int) port);
  441. if (GNUNET_NO ==
  442. GNUNET_NAT_stun_make_request (stun_server,
  443. stun_port,
  444. lsock4,
  445. &request_callback,
  446. NULL))
  447. {
  448. /*An error happened*/
  449. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "STUN error, stopping\n");
  450. stop_stun ();
  451. next_phase (ah);
  452. }
  453. }
  454. /**
  455. * Process list of local IP addresses. Find and set the
  456. * one of the default interface.
  457. *
  458. * @param cls our `struct GNUNET_NAT_AutoHandle`
  459. * @param name name of the interface (can be NULL for unknown)
  460. * @param isDefault is this presumably the default interface
  461. * @param addr address of this interface (can be NULL for unknown or unassigned)
  462. * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
  463. * @param netmask the network mask (can be NULL for unknown or unassigned))
  464. * @param addrlen length of the @a addr and @a broadcast_addr
  465. * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
  466. */
  467. static int
  468. process_if (void *cls,
  469. const char *name,
  470. int isDefault,
  471. const struct sockaddr *addr,
  472. const struct sockaddr *broadcast_addr,
  473. const struct sockaddr *netmask,
  474. socklen_t addrlen)
  475. {
  476. struct GNUNET_NAT_AutoHandle *ah = cls;
  477. const struct sockaddr_in *in;
  478. char buf[INET_ADDRSTRLEN];
  479. if ( (sizeof (struct sockaddr_in6) == addrlen) &&
  480. (0 != memcmp (&in6addr_loopback, &((const struct sockaddr_in6 *) addr)->sin6_addr,
  481. sizeof (struct in6_addr))) &&
  482. (! IN6_IS_ADDR_LINKLOCAL(&((const struct sockaddr_in6 *) addr)->sin6_addr)) )
  483. {
  484. ah->have_v6 = GNUNET_YES;
  485. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  486. _("This system has a global IPv6 address, setting IPv6 to supported.\n"));
  487. return GNUNET_OK;
  488. }
  489. if (addrlen != sizeof (struct sockaddr_in))
  490. return GNUNET_OK;
  491. in = (const struct sockaddr_in *) addr;
  492. /* set internal IP address */
  493. if (NULL == inet_ntop (AF_INET, &in->sin_addr, buf, sizeof (buf)))
  494. {
  495. GNUNET_break (0);
  496. return GNUNET_OK;
  497. }
  498. GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "INTERNAL_ADDRESS",
  499. buf);
  500. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  501. _("Detected internal network address `%s'.\n"),
  502. buf);
  503. ah->ret = GNUNET_NAT_ERROR_SUCCESS;
  504. /* Check if our internal IP is the same as the External detect by STUN*/
  505. if(ah->stun_ip && (strcmp(buf, ah->stun_ip) == 0) )
  506. {
  507. ah->internal_ip_is_public = GNUNET_YES;
  508. GNUNET_log (GNUNET_ERROR_TYPE_INFO,"A internal IP is the sameas the external");
  509. /* No need to continue*/
  510. return GNUNET_SYSERR;
  511. }
  512. /* no need to continue iteration if we found the default */
  513. if (!isDefault)
  514. return GNUNET_OK;
  515. else
  516. return GNUNET_SYSERR;
  517. }
  518. /**
  519. * Determine our local IP addresses; detect internal IP & IPv6-support
  520. *
  521. * @param ah auto setup context
  522. */
  523. static void
  524. test_local_ip (struct GNUNET_NAT_AutoHandle *ah)
  525. {
  526. ah->have_v6 = GNUNET_NO;
  527. ah->ret = GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO; // reset to success if any of the IFs in below iterator has a valid IP
  528. GNUNET_OS_network_interfaces_list (&process_if, ah);
  529. GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "DISABLEV6",
  530. (GNUNET_YES == ah->have_v6) ? "NO" : "YES");
  531. next_phase (ah);
  532. }
  533. /**
  534. * We got disconnected from the NAT server. Stop
  535. * waiting for a reply.
  536. *
  537. * @param cls the `struct GNUNET_NAT_AutoHandle`
  538. * @param error error code
  539. */
  540. static void
  541. mq_error_handler (void *cls,
  542. enum GNUNET_MQ_Error error)
  543. {
  544. struct GNUNET_NAT_AutoHandle *ah = cls;
  545. GNUNET_MQ_destroy (ah->mq);
  546. ah->mq = NULL;
  547. /* wait a bit first? */
  548. next_phase (ah);
  549. }
  550. /**
  551. * Test if NAT has been punched
  552. *
  553. * @param ah auto setup context
  554. */
  555. static void
  556. test_nat_punched (struct GNUNET_NAT_AutoHandle *ah)
  557. {
  558. struct GNUNET_NAT_TestMessage *msg;
  559. struct GNUNET_MQ_Envelope *env;
  560. if (! ah->stun_ip)
  561. {
  562. LOG (GNUNET_ERROR_TYPE_INFO,
  563. "We don't have a STUN IP");
  564. next_phase (ah);
  565. return;
  566. }
  567. LOG (GNUNET_ERROR_TYPE_INFO,
  568. "Asking gnunet-nat-server to connect to `%s'\n",
  569. ah->stun_ip);
  570. ah->mq = GNUNET_CLIENT_connect (ah->cfg,
  571. "gnunet-nat-server",
  572. NULL,
  573. &mq_error_handler,
  574. ah);
  575. if (NULL == ah->mq)
  576. {
  577. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  578. _("Failed to connect to `gnunet-nat-server'\n"));
  579. next_phase (ah);
  580. return;
  581. }
  582. env = GNUNET_MQ_msg (msg,
  583. GNUNET_MESSAGE_TYPE_NAT_TEST);
  584. msg->dst_ipv4 = inet_addr (ah->stun_ip);
  585. msg->dport = htons (ah->stun_port);
  586. msg->data = port;
  587. msg->is_tcp = htonl ((uint32_t) GNUNET_NO);
  588. GNUNET_MQ_send (ah->mq,
  589. env);
  590. if (NULL != ltask4)
  591. {
  592. GNUNET_SCHEDULER_cancel (ltask4);
  593. ltask4 = GNUNET_SCHEDULER_add_read_net (NAT_SERVER_TIMEOUT,
  594. lsock4,
  595. &do_udp_read,
  596. ah);
  597. }
  598. }
  599. /**
  600. * Test if UPnPC works.
  601. *
  602. * @param ah auto setup context
  603. */
  604. static void
  605. test_upnpc (struct GNUNET_NAT_AutoHandle *ah)
  606. {
  607. int have_upnpc;
  608. if (GNUNET_NAT_ERROR_SUCCESS != ah->ret)
  609. next_phase (ah);
  610. // test if upnpc is available
  611. have_upnpc = (GNUNET_SYSERR !=
  612. GNUNET_OS_check_helper_binary ("upnpc", GNUNET_NO, NULL));
  613. //FIXME: test if upnpc is actually working, that is, if transports start to work once we use UPnP
  614. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  615. (have_upnpc)
  616. ? _("upnpc found, enabling its use\n")
  617. : _("upnpc not found\n"));
  618. GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "ENABLE_UPNP",
  619. (GNUNET_YES == have_upnpc) ? "YES" : "NO");
  620. next_phase (ah);
  621. }
  622. /**
  623. * Test if ICMP server is working
  624. *
  625. * @param ah auto setup context
  626. */
  627. static void
  628. test_icmp_server (struct GNUNET_NAT_AutoHandle *ah)
  629. {
  630. int ext_ip;
  631. int nated;
  632. int binary;
  633. char *tmp;
  634. char *helper;
  635. ext_ip = GNUNET_NO;
  636. nated = GNUNET_NO;
  637. binary = GNUNET_NO;
  638. tmp = NULL;
  639. helper = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
  640. if ( (GNUNET_OK ==
  641. GNUNET_CONFIGURATION_get_value_string (ah->cfg,
  642. "nat",
  643. "EXTERNAL_ADDRESS",
  644. &tmp)) &&
  645. (0 < strlen (tmp)) )
  646. {
  647. ext_ip = GNUNET_OK;
  648. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  649. _("test_icmp_server not possible, as we have no public IPv4 address\n"));
  650. }
  651. else
  652. goto err;
  653. if (GNUNET_YES ==
  654. GNUNET_CONFIGURATION_get_value_yesno (ah->cfg,
  655. "nat",
  656. "BEHIND_NAT"))
  657. {
  658. nated = GNUNET_YES;
  659. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  660. _("test_icmp_server not possible, as we are not behind NAT\n"));
  661. }
  662. else
  663. goto err;
  664. if (GNUNET_YES ==
  665. GNUNET_OS_check_helper_binary (helper,
  666. GNUNET_YES,
  667. "-d 127.0.0.1" ))
  668. {
  669. binary = GNUNET_OK; // use localhost as source for that one udp-port, ok for testing
  670. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  671. _("No working gnunet-helper-nat-server found\n"));
  672. }
  673. err:
  674. GNUNET_free_non_null (tmp);
  675. GNUNET_free (helper);
  676. if ( (GNUNET_OK == ext_ip) &&
  677. (GNUNET_YES == nated) &&
  678. (GNUNET_OK == binary) )
  679. ah->task = GNUNET_SCHEDULER_add_now (&reversal_test,
  680. ah);
  681. else
  682. next_phase (ah);
  683. }
  684. /**
  685. * Test if ICMP client is working
  686. *
  687. * @param ah auto setup context
  688. */
  689. static void
  690. test_icmp_client (struct GNUNET_NAT_AutoHandle *ah)
  691. {
  692. char *tmp;
  693. char *helper;
  694. tmp = NULL;
  695. helper = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client");
  696. if ( (GNUNET_OK ==
  697. GNUNET_CONFIGURATION_get_value_string (ah->cfg,
  698. "nat",
  699. "INTERNAL_ADDRESS",
  700. &tmp)) &&
  701. (0 < strlen (tmp)) )
  702. {
  703. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  704. _("test_icmp_client not possible, as we have no internal IPv4 address\n"));
  705. }
  706. else
  707. goto err;
  708. if (GNUNET_YES !=
  709. GNUNET_CONFIGURATION_get_value_yesno (ah->cfg,
  710. "nat",
  711. "BEHIND_NAT"))
  712. {
  713. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  714. _("test_icmp_server not possible, as we are not behind NAT\n"));
  715. }
  716. else
  717. goto err;
  718. if (GNUNET_YES ==
  719. GNUNET_OS_check_helper_binary (helper,
  720. GNUNET_YES,
  721. "-d 127.0.0.1 127.0.0.2 42"))
  722. {
  723. // none of these parameters are actually used in privilege testing mode
  724. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  725. _("No working gnunet-helper-nat-server found\n"));
  726. }
  727. err:
  728. GNUNET_free_non_null (tmp);
  729. GNUNET_free (helper);
  730. next_phase (ah);
  731. }
  732. /**
  733. * Run the next phase of the auto test.
  734. */
  735. static void
  736. next_phase (struct GNUNET_NAT_AutoHandle *ah)
  737. {
  738. struct GNUNET_CONFIGURATION_Handle *diff;
  739. ah->phase++;
  740. switch (ah->phase)
  741. {
  742. case AUTO_INIT:
  743. GNUNET_assert (0);
  744. break;
  745. case AUTO_EXTERNAL_IP:
  746. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  747. "Will run AUTO_EXTERNAL_IP\n");
  748. test_external_ip (ah);
  749. break;
  750. case AUTO_STUN:
  751. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  752. "Will run AUTO_STUN\n");
  753. test_stun (ah);
  754. break;
  755. case AUTO_LOCAL_IP:
  756. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  757. "Will run AUTO_LOCAL_IP\n");
  758. test_local_ip (ah);
  759. break;
  760. case AUTO_NAT_PUNCHED:
  761. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  762. "Will run AUTO_NAT_PUNCHED\n");
  763. test_nat_punched (ah);
  764. break;
  765. case AUTO_UPNPC:
  766. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  767. "Will run AUTO_UPNPC\n");
  768. test_upnpc (ah);
  769. break;
  770. case AUTO_ICMP_SERVER:
  771. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  772. "Will run AUTO_ICMP_SERVER\n");
  773. test_icmp_server (ah);
  774. break;
  775. case AUTO_ICMP_CLIENT:
  776. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  777. "Will run AUTO_ICMP_CLIENT\n");
  778. test_icmp_client (ah);
  779. break;
  780. case AUTO_DONE:
  781. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  782. "Done with tests\n");
  783. if (!ah->internal_ip_is_public)
  784. {
  785. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  786. "nat",
  787. "BEHIND_NAT",
  788. "YES");
  789. if (ah->connected_back)
  790. {
  791. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  792. "nat",
  793. "PUNCHED_NAT",
  794. "YES");
  795. }
  796. else
  797. {
  798. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  799. "nat",
  800. "PUNCHED_NAT",
  801. "NO");
  802. }
  803. if (ah->stun_ip)
  804. {
  805. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  806. "nat",
  807. "EXTERNAL_ADDRESS",
  808. ah->stun_ip);
  809. if (ah->connected_back)
  810. {
  811. ah->type = GNUNET_NAT_TYPE_STUN_PUNCHED_NAT;
  812. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  813. "nat",
  814. "USE_STUN",
  815. "YES");
  816. }
  817. else
  818. {
  819. ah->type = GNUNET_NAT_TYPE_UNREACHABLE_NAT;
  820. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  821. "nat",
  822. "USE_STUN",
  823. "NO");
  824. }
  825. }
  826. if (0 != ah->stun_port)
  827. {
  828. GNUNET_CONFIGURATION_set_value_number (ah->cfg,
  829. "transport-udp",
  830. "ADVERTISED_PORT",
  831. ah->stun_port);
  832. }
  833. }
  834. else
  835. {
  836. //The internal IP is the same as public, but we didn't got a incoming connection
  837. if (ah->connected_back)
  838. {
  839. ah->type = GNUNET_NAT_TYPE_NO_NAT;
  840. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  841. "nat",
  842. "BEHIND_NAT",
  843. "NO");
  844. }
  845. else
  846. {
  847. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  848. "nat",
  849. "BEHIND_NAT",
  850. "YES");
  851. ah->type = GNUNET_NAT_TYPE_UNREACHABLE_NAT;
  852. if (ah->stun_ip)
  853. {
  854. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  855. "nat",
  856. "EXTERNAL_ADDRESS",
  857. ah->stun_ip);
  858. }
  859. if (0 != ah->stun_port)
  860. {
  861. GNUNET_CONFIGURATION_set_value_number (ah->cfg,
  862. "transport-udp",
  863. "ADVERTISED_PORT",
  864. ah->stun_port);
  865. }
  866. }
  867. }
  868. diff = GNUNET_CONFIGURATION_get_diff (ah->initial_cfg,
  869. ah->cfg);
  870. ah->fin_cb (ah->fin_cb_cls,
  871. diff,
  872. ah->ret,
  873. ah->type);
  874. GNUNET_CONFIGURATION_destroy (diff);
  875. GNUNET_NAT_autoconfig_cancel (ah);
  876. }
  877. }
  878. /**
  879. * Start auto-configuration routine. The resolver service should
  880. * be available when this function is called.
  881. *
  882. * @param cfg initial configuration
  883. * @param cb function to call with autoconfiguration result
  884. * @param cb_cls closure for @a cb
  885. * @return handle to cancel operation
  886. */
  887. struct GNUNET_NAT_AutoHandle *
  888. GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
  889. GNUNET_NAT_AutoResultCallback cb,
  890. void *cb_cls)
  891. {
  892. struct GNUNET_NAT_AutoHandle *ah;
  893. ah = GNUNET_new (struct GNUNET_NAT_AutoHandle);
  894. ah->fin_cb = cb;
  895. ah->fin_cb_cls = cb_cls;
  896. ah->ret = GNUNET_NAT_ERROR_SUCCESS;
  897. ah->cfg = GNUNET_CONFIGURATION_dup (cfg);
  898. ah->initial_cfg = GNUNET_CONFIGURATION_dup (cfg);
  899. /* never use loopback addresses if user wanted autoconfiguration */
  900. GNUNET_CONFIGURATION_set_value_string (ah->cfg,
  901. "nat",
  902. "USE_LOCALADDR",
  903. "NO");
  904. next_phase (ah);
  905. return ah;
  906. }
  907. /**
  908. * Abort autoconfiguration.
  909. *
  910. * @param ah handle for operation to abort
  911. */
  912. void
  913. GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah)
  914. {
  915. if (NULL != ah->tst)
  916. {
  917. GNUNET_NAT_test_stop (ah->tst);
  918. ah->tst = NULL;
  919. }
  920. if (NULL != ah->eh)
  921. {
  922. GNUNET_NAT_mini_get_external_ipv4_cancel (ah->eh);
  923. ah->eh = NULL;
  924. }
  925. if (NULL != ah->mq)
  926. {
  927. GNUNET_MQ_destroy (ah->mq);
  928. ah->mq = NULL;
  929. }
  930. if (NULL != ah->task)
  931. {
  932. GNUNET_SCHEDULER_cancel (ah->task);
  933. ah->task = NULL;
  934. }
  935. GNUNET_CONFIGURATION_destroy (ah->cfg);
  936. GNUNET_CONFIGURATION_destroy (ah->initial_cfg);
  937. GNUNET_free (ah);
  938. }
  939. /* end of nat_auto.c */