gnunet-nat-auto.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2015, 2016, 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-auto.c
  18. * @brief Command-line tool for testing and autoconfiguration of NAT traversal
  19. * @author Christian Grothoff
  20. * @author Bruno Cabral
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_nat_service.h"
  25. #include "gnunet_nat_auto_service.h"
  26. /**
  27. * Value to return from #main().
  28. */
  29. static int global_ret;
  30. /**
  31. * Handle to ongoing autoconfiguration.
  32. */
  33. static struct GNUNET_NAT_AUTO_AutoHandle *ah;
  34. /**
  35. * If we do auto-configuration, should we write the result
  36. * to a file?
  37. */
  38. static int write_cfg;
  39. /**
  40. * Configuration filename.
  41. */
  42. static const char *cfg_file;
  43. /**
  44. * Original configuration.
  45. */
  46. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  47. /**
  48. * Adapter we are supposed to test.
  49. */
  50. static char *section_name;
  51. /**
  52. * Should we run autoconfiguration?
  53. */
  54. static int do_auto;
  55. /**
  56. * Handle to a NAT test operation.
  57. */
  58. static struct GNUNET_NAT_AUTO_Test *nt;
  59. /**
  60. * Flag set to 1 if we use IPPROTO_UDP.
  61. */
  62. static int use_udp;
  63. /**
  64. * Flag set to 1 if we use IPPROTO_TCP.
  65. */
  66. static int use_tcp;
  67. /**
  68. * Protocol to use.
  69. */
  70. static uint8_t proto;
  71. /**
  72. * Test if all activities have finished, and if so,
  73. * terminate.
  74. */
  75. static void
  76. test_finished ()
  77. {
  78. if (NULL != ah)
  79. return;
  80. if (NULL != nt)
  81. return;
  82. GNUNET_SCHEDULER_shutdown ();
  83. }
  84. /**
  85. * Function to iterate over sugested changes options
  86. *
  87. * @param cls closure
  88. * @param section name of the section
  89. * @param option name of the option
  90. * @param value value of the option
  91. */
  92. static void
  93. auto_conf_iter (void *cls,
  94. const char *section,
  95. const char *option,
  96. const char *value)
  97. {
  98. struct GNUNET_CONFIGURATION_Handle *new_cfg = cls;
  99. PRINTF ("%s: %s\n",
  100. option,
  101. value);
  102. if (NULL != new_cfg)
  103. GNUNET_CONFIGURATION_set_value_string (new_cfg,
  104. section,
  105. option,
  106. value);
  107. }
  108. /**
  109. * Function called with the result from the autoconfiguration.
  110. *
  111. * @param cls closure
  112. * @param diff minimal suggested changes to the original configuration
  113. * to make it work (as best as we can)
  114. * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
  115. * @param type what the situation of the NAT
  116. */
  117. static void
  118. auto_config_cb (void *cls,
  119. const struct GNUNET_CONFIGURATION_Handle *diff,
  120. enum GNUNET_NAT_StatusCode result,
  121. enum GNUNET_NAT_Type type)
  122. {
  123. const char *nat_type;
  124. char unknown_type[64];
  125. struct GNUNET_CONFIGURATION_Handle *new_cfg;
  126. ah = NULL;
  127. switch (type)
  128. {
  129. case GNUNET_NAT_TYPE_NO_NAT:
  130. nat_type = "NO NAT";
  131. break;
  132. case GNUNET_NAT_TYPE_UNREACHABLE_NAT:
  133. nat_type = "NAT but we can traverse";
  134. break;
  135. case GNUNET_NAT_TYPE_STUN_PUNCHED_NAT:
  136. nat_type = "NAT but STUN is able to identify the correct information";
  137. break;
  138. case GNUNET_NAT_TYPE_UPNP_NAT:
  139. nat_type = "NAT but UPNP opened the ports";
  140. break;
  141. default:
  142. SPRINTF (unknown_type,
  143. "NAT unknown, type %u",
  144. type);
  145. nat_type = unknown_type;
  146. break;
  147. }
  148. GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
  149. "NAT status: %s/%s\n",
  150. GNUNET_NAT_AUTO_status2string (result),
  151. nat_type);
  152. if (NULL == diff)
  153. return;
  154. /* Shortcut: if there are no changes suggested, bail out early. */
  155. if (GNUNET_NO ==
  156. GNUNET_CONFIGURATION_is_dirty (diff))
  157. {
  158. test_finished ();
  159. return;
  160. }
  161. /* Apply diff to original configuration and show changes
  162. to the user */
  163. new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL;
  164. GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
  165. _("Suggested configuration changes:\n"));
  166. GNUNET_CONFIGURATION_iterate_section_values (diff,
  167. "nat",
  168. &auto_conf_iter,
  169. new_cfg);
  170. /* If desired, write configuration to file; we write only the
  171. changes to the defaults to keep things compact. */
  172. if (write_cfg)
  173. {
  174. struct GNUNET_CONFIGURATION_Handle *def_cfg;
  175. GNUNET_CONFIGURATION_set_value_string (new_cfg,
  176. "ARM",
  177. "CONFIG",
  178. NULL);
  179. def_cfg = GNUNET_CONFIGURATION_create ();
  180. GNUNET_break (GNUNET_OK ==
  181. GNUNET_CONFIGURATION_load (def_cfg,
  182. NULL));
  183. if (GNUNET_OK !=
  184. GNUNET_CONFIGURATION_write_diffs (def_cfg,
  185. new_cfg,
  186. cfg_file))
  187. {
  188. GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
  189. _("Failed to write configuration to `%s'\n"),
  190. cfg_file);
  191. global_ret = 1;
  192. }
  193. else
  194. {
  195. GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
  196. _("Wrote updated configuration to `%s'\n"),
  197. cfg_file);
  198. }
  199. GNUNET_CONFIGURATION_destroy (def_cfg);
  200. }
  201. if (NULL != new_cfg)
  202. GNUNET_CONFIGURATION_destroy (new_cfg);
  203. test_finished ();
  204. }
  205. /**
  206. * Function called to report success or failure for
  207. * NAT configuration test.
  208. *
  209. * @param cls closure
  210. * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
  211. */
  212. static void
  213. test_report_cb (void *cls,
  214. enum GNUNET_NAT_StatusCode result)
  215. {
  216. nt = NULL;
  217. PRINTF ("NAT test result: %s\n",
  218. GNUNET_NAT_AUTO_status2string (result));
  219. test_finished ();
  220. }
  221. /**
  222. * Task run on shutdown.
  223. *
  224. * @param cls NULL
  225. */
  226. static void
  227. do_shutdown (void *cls)
  228. {
  229. if (NULL != ah)
  230. {
  231. GNUNET_NAT_AUTO_autoconfig_cancel (ah);
  232. ah = NULL;
  233. }
  234. if (NULL != nt)
  235. {
  236. GNUNET_NAT_AUTO_test_stop (nt);
  237. nt = NULL;
  238. }
  239. }
  240. /**
  241. * Main function that will be run.
  242. *
  243. * @param cls closure
  244. * @param args remaining command-line arguments
  245. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  246. * @param c configuration
  247. */
  248. static void
  249. run (void *cls,
  250. char *const *args,
  251. const char *cfgfile,
  252. const struct GNUNET_CONFIGURATION_Handle *c)
  253. {
  254. cfg_file = cfgfile;
  255. cfg = c;
  256. GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
  257. NULL);
  258. if (do_auto)
  259. {
  260. ah = GNUNET_NAT_AUTO_autoconfig_start (c,
  261. &auto_config_cb,
  262. NULL);
  263. }
  264. if (use_tcp && use_udp)
  265. {
  266. if (do_auto)
  267. return;
  268. GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
  269. "Cannot use TCP and UDP\n");
  270. global_ret = 1;
  271. return;
  272. }
  273. proto = 0;
  274. if (use_tcp)
  275. proto = IPPROTO_TCP;
  276. if (use_udp)
  277. proto = IPPROTO_UDP;
  278. if (NULL != section_name)
  279. {
  280. nt = GNUNET_NAT_AUTO_test_start (c,
  281. proto,
  282. section_name,
  283. &test_report_cb,
  284. NULL);
  285. }
  286. test_finished ();
  287. }
  288. /**
  289. * Main function of gnunet-nat-auto
  290. *
  291. * @param argc number of command-line arguments
  292. * @param argv command line
  293. * @return 0 on success, -1 on error
  294. */
  295. int
  296. main (int argc,
  297. char *const argv[])
  298. {
  299. struct GNUNET_GETOPT_CommandLineOption options[] = {
  300. GNUNET_GETOPT_option_flag ('a',
  301. "auto",
  302. gettext_noop ("run autoconfiguration"),
  303. &do_auto),
  304. GNUNET_GETOPT_option_string ('S',
  305. "section",
  306. "NAME",
  307. gettext_noop ("section name providing the configuration for the adapter"),
  308. &section_name),
  309. GNUNET_GETOPT_option_flag ('t',
  310. "tcp",
  311. gettext_noop ("use TCP"),
  312. &use_tcp),
  313. GNUNET_GETOPT_option_flag ('u',
  314. "udp",
  315. gettext_noop ("use UDP"),
  316. &use_udp),
  317. GNUNET_GETOPT_option_flag ('w',
  318. "write",
  319. gettext_noop ("write configuration file (for autoconfiguration)"),
  320. &write_cfg),
  321. GNUNET_GETOPT_OPTION_END
  322. };
  323. if (GNUNET_OK !=
  324. GNUNET_STRINGS_get_utf8_args (argc, argv,
  325. &argc, &argv))
  326. return 2;
  327. if (GNUNET_OK !=
  328. GNUNET_PROGRAM_run (argc, argv,
  329. "gnunet-nat-auto [options]",
  330. _("GNUnet NAT traversal autoconfiguration"),
  331. options,
  332. &run,
  333. NULL))
  334. {
  335. global_ret = 1;
  336. }
  337. GNUNET_free ((void*) argv);
  338. return global_ret;
  339. }
  340. /* end of gnunet-nat-auto.c */