nat_api_stun.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009, 2015, 2016 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. * This code provides some support for doing STUN transactions.
  18. * We send simplest possible packet ia REQUEST with BIND to a STUN server.
  19. *
  20. * All STUN packets start with a simple header made of a type,
  21. * length (excluding the header) and a 16-byte random transaction id.
  22. * Following the header we may have zero or more attributes, each
  23. * structured as a type, length and a value (whose format depends
  24. * on the type, but often contains addresses).
  25. * Of course all fields are in network format.
  26. *
  27. * This code was based on ministun.c.
  28. *
  29. * @file nat/nat_api_stun.c
  30. * @brief Functions for STUN functionality
  31. * @author Bruno Souza Cabral
  32. */
  33. #include "platform.h"
  34. #include "gnunet_util_lib.h"
  35. #include "gnunet_resolver_service.h"
  36. #include "gnunet_nat_service.h"
  37. #include "nat_stun.h"
  38. #define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
  39. #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
  40. /**
  41. * Handle to a request given to the resolver. Can be used to cancel
  42. * the request prior to the timeout or successful execution. Also
  43. * used to track our internal state for the request.
  44. */
  45. struct GNUNET_NAT_STUN_Handle
  46. {
  47. /**
  48. * Handle to a pending DNS lookup request.
  49. */
  50. struct GNUNET_RESOLVER_RequestHandle *dns_active;
  51. /**
  52. * Handle to the listen socket
  53. */
  54. struct GNUNET_NETWORK_Handle *sock;
  55. /**
  56. * Stun server address
  57. */
  58. char *stun_server;
  59. /**
  60. * Function to call when a error occours
  61. */
  62. GNUNET_NAT_TestCallback cb;
  63. /**
  64. * Closure for @e cb.
  65. */
  66. void *cb_cls;
  67. /**
  68. * Do we got a DNS resolution successfully?
  69. */
  70. int dns_success;
  71. /**
  72. * STUN port
  73. */
  74. uint16_t stun_port;
  75. };
  76. /**
  77. * Encode a class and method to a compatible STUN format
  78. *
  79. * @param msg_class class to be converted
  80. * @param method method to be converted
  81. * @return message in a STUN compatible format
  82. */
  83. static int
  84. encode_message (enum StunClasses msg_class,
  85. enum StunMethods method)
  86. {
  87. return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) |
  88. (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2);
  89. }
  90. /**
  91. * Fill the stun_header with a random request_id
  92. *
  93. * @param req, stun header to be filled
  94. */
  95. static void
  96. generate_request_id (struct stun_header *req)
  97. {
  98. req->magic = htonl(STUN_MAGIC_COOKIE);
  99. for (unsigned int x = 0; x < 3; x++)
  100. req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
  101. UINT32_MAX);
  102. }
  103. /**
  104. * Try to establish a connection given the specified address.
  105. *
  106. * @param cls our `struct GNUNET_NAT_STUN_Handle *`
  107. * @param addr address to try, NULL for "last call"
  108. * @param addrlen length of @a addr
  109. */
  110. static void
  111. stun_dns_callback (void *cls,
  112. const struct sockaddr *addr,
  113. socklen_t addrlen)
  114. {
  115. struct GNUNET_NAT_STUN_Handle *rh = cls;
  116. struct stun_header req;
  117. struct sockaddr_in server;
  118. if (NULL == addr)
  119. {
  120. rh->dns_active = NULL;
  121. if (GNUNET_NO == rh->dns_success)
  122. {
  123. LOG (GNUNET_ERROR_TYPE_INFO,
  124. "Error resolving host %s\n",
  125. rh->stun_server);
  126. rh->cb (rh->cb_cls,
  127. GNUNET_NAT_ERROR_NOT_ONLINE);
  128. }
  129. else if (GNUNET_SYSERR == rh->dns_success)
  130. {
  131. rh->cb (rh->cb_cls,
  132. GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
  133. }
  134. else
  135. {
  136. rh->cb (rh->cb_cls,
  137. GNUNET_NAT_ERROR_SUCCESS);
  138. }
  139. GNUNET_NAT_stun_make_request_cancel (rh);
  140. return;
  141. }
  142. rh->dns_success = GNUNET_YES;
  143. memset (&server, 0, sizeof(server));
  144. server.sin_family = AF_INET;
  145. server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
  146. server.sin_port = htons (rh->stun_port);
  147. #if HAVE_SOCKADDR_IN_SIN_LEN
  148. server.sin_len = (u_char) sizeof (struct sockaddr_in);
  149. #endif
  150. /* Craft the simplest possible STUN packet. A request binding */
  151. generate_request_id (&req);
  152. req.msglen = htons (0);
  153. req.msgtype = htons (encode_message (STUN_REQUEST,
  154. STUN_BINDING));
  155. /* Send the packet */
  156. if (-1 ==
  157. GNUNET_NETWORK_socket_sendto (rh->sock,
  158. &req,
  159. sizeof (req),
  160. (const struct sockaddr *) &server,
  161. sizeof (server)))
  162. {
  163. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
  164. "sendto");
  165. rh->dns_success = GNUNET_SYSERR;
  166. return;
  167. }
  168. }
  169. /**
  170. * Make Generic STUN request. Sends a generic stun request to the
  171. * server specified using the specified socket.
  172. *
  173. * @param server the address of the stun server
  174. * @param port port of the stun server, in host byte order
  175. * @param sock the socket used to send the request
  176. * @param cb callback in case of error
  177. * @param cb_cls closure for @a cb
  178. * @return NULL on error
  179. */
  180. struct GNUNET_NAT_STUN_Handle *
  181. GNUNET_NAT_stun_make_request (const char *server,
  182. uint16_t port,
  183. struct GNUNET_NETWORK_Handle *sock,
  184. GNUNET_NAT_TestCallback cb,
  185. void *cb_cls)
  186. {
  187. struct GNUNET_NAT_STUN_Handle *rh;
  188. rh = GNUNET_new (struct GNUNET_NAT_STUN_Handle);
  189. rh->sock = sock;
  190. rh->cb = cb;
  191. rh->cb_cls = cb_cls;
  192. rh->stun_server = GNUNET_strdup (server);
  193. rh->stun_port = port;
  194. rh->dns_success = GNUNET_NO;
  195. rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server,
  196. AF_INET,
  197. TIMEOUT,
  198. &stun_dns_callback,
  199. rh);
  200. if (NULL == rh->dns_active)
  201. {
  202. GNUNET_NAT_stun_make_request_cancel (rh);
  203. return NULL;
  204. }
  205. return rh;
  206. }
  207. /**
  208. * Cancel active STUN request. Frees associated resources
  209. * and ensures that the callback is no longer invoked.
  210. *
  211. * @param rh request to cancel
  212. */
  213. void
  214. GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh)
  215. {
  216. if (NULL != rh->dns_active)
  217. {
  218. GNUNET_RESOLVER_request_cancel (rh->dns_active);
  219. rh->dns_active = NULL;
  220. }
  221. GNUNET_free (rh->stun_server);
  222. GNUNET_free (rh);
  223. }
  224. /* end of nat_stun.c */