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