gnunet-service-nat_externalip.c 8.3 KB

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