gnunet-service-nat_externalip.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009, 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. * Code to figure out what our external IPv4 address(es) might
  18. * be (external IPv4s are what is seen on the rest of the Internet).
  19. *
  20. * This can be implemented using different methods, and we allow
  21. * the main service to be notified about changes to what we believe
  22. * is our external IPv4 address.
  23. *
  24. * Note that this is explicitly only about NATed systems; if one
  25. * of our network interfaces has a global IP address this does
  26. * not count as "external".
  27. *
  28. * @file nat/gnunet-service-nat_externalip.c
  29. * @brief Functions for monitoring external IPv4 addresses
  30. * @author Christian Grothoff
  31. */
  32. #include "platform.h"
  33. #include <math.h>
  34. #include "gnunet_util_lib.h"
  35. #include "gnunet_protocols.h"
  36. #include "gnunet_signatures.h"
  37. #include "gnunet_statistics_service.h"
  38. #include "gnunet_resolver_service.h"
  39. #include "gnunet_nat_service.h"
  40. #include "gnunet-service-nat.h"
  41. #include "gnunet-service-nat_externalip.h"
  42. #include "gnunet-service-nat_stun.h"
  43. #include "gnunet-service-nat_mini.h"
  44. #include "gnunet-service-nat_helper.h"
  45. #include "nat.h"
  46. #include <gcrypt.h>
  47. /**
  48. * How long do we wait until we re-try running `external-ip` if the
  49. * command failed to terminate nicely?
  50. */
  51. #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
  52. /**
  53. * How long do we wait until we re-try running `external-ip` if the
  54. * command failed (but terminated)?
  55. */
  56. #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
  57. /**
  58. * How long do we wait until we re-try running `external-ip` if the
  59. * command succeeded?
  60. */
  61. #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
  62. /**
  63. * Handle to monitor for external IP changes.
  64. */
  65. struct GN_ExternalIPMonitor
  66. {
  67. /**
  68. * Kept in DLL.
  69. */
  70. struct GN_ExternalIPMonitor *next;
  71. /**
  72. * Kept in DLL.
  73. */
  74. struct GN_ExternalIPMonitor *prev;
  75. /**
  76. * Function to call when we believe our external IPv4 address changed.
  77. */
  78. GN_NotifyExternalIPv4Change cb;
  79. /**
  80. * Closure for @e cb.
  81. */
  82. void *cb_cls;
  83. };
  84. /**
  85. * List of monitors, kept in DLL.
  86. */
  87. static struct GN_ExternalIPMonitor *mon_head;
  88. /**
  89. * List of monitors, kept in DLL.
  90. */
  91. static struct GN_ExternalIPMonitor *mon_tail;
  92. /**
  93. * Task run to obtain our external IP (if #enable_upnp is set
  94. * and if we find we have a NATed IP address).
  95. */
  96. static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
  97. /**
  98. * Handle to our operation to run `external-ip`.
  99. */
  100. static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
  101. /**
  102. * What is our external IP address as claimed by `external-ip`?
  103. * 0 for unknown.
  104. */
  105. static struct in_addr mini_external_ipv4;
  106. /**
  107. * Tell relevant clients about a change in our external
  108. * IPv4 address.
  109. *
  110. * @param add #GNUNET_YES to add, #GNUNET_NO to remove
  111. * @param v4 the external address that changed
  112. */
  113. static void
  114. notify_monitors_external_ipv4_change (int add,
  115. const struct in_addr *v4)
  116. {
  117. for (struct GN_ExternalIPMonitor *mon = mon_head;
  118. NULL != mon;
  119. mon = mon->next)
  120. mon->cb (mon->cb_cls,
  121. v4,
  122. add);
  123. }
  124. /**
  125. * Task used to run `external-ip` to get our external IPv4
  126. * address and pass it to NATed clients if possible.
  127. *
  128. * @param cls NULL
  129. */
  130. static void
  131. run_external_ip (void *cls);
  132. /**
  133. * We learn our current external IP address. If it changed,
  134. * notify all of our applicable clients. Also re-schedule
  135. * #run_external_ip with an appropriate timeout.
  136. *
  137. * @param cls NULL
  138. * @param addr the address, NULL on errors
  139. * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
  140. */
  141. static void
  142. handle_external_ip (void *cls,
  143. const struct in_addr *addr,
  144. enum GNUNET_NAT_StatusCode result)
  145. {
  146. char buf[INET_ADDRSTRLEN];
  147. probe_external_ip_op = NULL;
  148. GNUNET_SCHEDULER_cancel (probe_external_ip_task);
  149. probe_external_ip_task
  150. = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
  151. ? EXTERN_IP_RETRY_FAILURE
  152. : EXTERN_IP_RETRY_SUCCESS,
  153. &run_external_ip,
  154. NULL);
  155. switch (result)
  156. {
  157. case GNUNET_NAT_ERROR_SUCCESS:
  158. GNUNET_assert (NULL != addr);
  159. if (addr->s_addr == mini_external_ipv4.s_addr)
  160. return; /* not change */
  161. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  162. "Our external IP is now %s\n",
  163. inet_ntop (AF_INET,
  164. addr,
  165. buf,
  166. sizeof (buf)));
  167. if (0 != mini_external_ipv4.s_addr)
  168. notify_monitors_external_ipv4_change (GNUNET_NO,
  169. &mini_external_ipv4);
  170. mini_external_ipv4 = *addr;
  171. notify_monitors_external_ipv4_change (GNUNET_YES,
  172. &mini_external_ipv4);
  173. break;
  174. default:
  175. if (0 != mini_external_ipv4.s_addr)
  176. notify_monitors_external_ipv4_change (GNUNET_NO,
  177. &mini_external_ipv4);
  178. mini_external_ipv4.s_addr = 0;
  179. break;
  180. }
  181. }
  182. /**
  183. * Task used to run `external-ip` to get our external IPv4
  184. * address and pass it to NATed clients if possible.
  185. *
  186. * @param cls NULL
  187. */
  188. static void
  189. run_external_ip (void *cls)
  190. {
  191. probe_external_ip_task
  192. = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
  193. &run_external_ip,
  194. NULL);
  195. if (NULL != probe_external_ip_op)
  196. {
  197. GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
  198. probe_external_ip_op = NULL;
  199. }
  200. probe_external_ip_op
  201. = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
  202. NULL);
  203. }
  204. /**
  205. * We have changed our opinion about being NATed in the first
  206. * place. Adapt our probing.
  207. *
  208. * @param have_nat #GNUNET_YES if we believe we are behind NAT
  209. */
  210. void
  211. GN_nat_status_changed (int have_nat)
  212. {
  213. if (GNUNET_YES != enable_upnp)
  214. return;
  215. if ( (GNUNET_YES == have_nat) &&
  216. (NULL == probe_external_ip_task) &&
  217. (NULL == probe_external_ip_op) )
  218. {
  219. probe_external_ip_task
  220. = GNUNET_SCHEDULER_add_now (&run_external_ip,
  221. NULL);
  222. return;
  223. }
  224. if (GNUNET_NO == have_nat)
  225. {
  226. if (NULL != probe_external_ip_task)
  227. {
  228. GNUNET_SCHEDULER_cancel (probe_external_ip_task);
  229. probe_external_ip_task = NULL;
  230. }
  231. if (NULL != probe_external_ip_op)
  232. {
  233. GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
  234. probe_external_ip_op = NULL;
  235. }
  236. }
  237. }
  238. /**
  239. * Start monitoring external IPv4 addresses.
  240. *
  241. * @param cb function to call on changes
  242. * @param cb_cls closure for @a cb
  243. * @return handle to cancel
  244. */
  245. struct GN_ExternalIPMonitor *
  246. GN_external_ipv4_monitor_start (GN_NotifyExternalIPv4Change cb,
  247. void *cb_cls)
  248. {
  249. struct GN_ExternalIPMonitor *mon;
  250. mon = GNUNET_new (struct GN_ExternalIPMonitor);
  251. mon->cb = cb;
  252. mon->cb_cls = cb_cls;
  253. GNUNET_CONTAINER_DLL_insert (mon_head,
  254. mon_tail,
  255. mon);
  256. if (0 != mini_external_ipv4.s_addr)
  257. cb (cb_cls,
  258. &mini_external_ipv4,
  259. GNUNET_YES);
  260. return mon;
  261. }
  262. /**
  263. * Stop calling monitor.
  264. *
  265. * @param mon monitor to call
  266. */
  267. void
  268. GN_external_ipv4_monitor_stop (struct GN_ExternalIPMonitor *mon)
  269. {
  270. GNUNET_CONTAINER_DLL_remove (mon_head,
  271. mon_tail,
  272. mon);
  273. GNUNET_free (mon);
  274. }
  275. /* end of gnunet-service-nat_externalip.c */