dns_api.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2012, 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. * @file dns/dns_api.c
  18. * @brief API to access the DNS service.
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_dns_service.h"
  23. #include "dns.h"
  24. /**
  25. * Handle to identify an individual DNS request.
  26. */
  27. struct GNUNET_DNS_RequestHandle
  28. {
  29. /**
  30. * Handle to DNS API.
  31. */
  32. struct GNUNET_DNS_Handle *dh;
  33. /**
  34. * Stored in network byte order (as for us, it is just a random number).
  35. */
  36. uint64_t request_id;
  37. /**
  38. * Re-connect counter, to make sure we did not reconnect in the meantime.
  39. */
  40. uint32_t generation;
  41. };
  42. /**
  43. * DNS handle
  44. */
  45. struct GNUNET_DNS_Handle
  46. {
  47. /**
  48. * Connection to DNS service, or NULL.
  49. */
  50. struct GNUNET_MQ_Handle *mq;
  51. /**
  52. * Configuration to use.
  53. */
  54. const struct GNUNET_CONFIGURATION_Handle *cfg;
  55. /**
  56. * Function to call to get replies.
  57. */
  58. GNUNET_DNS_RequestHandler rh;
  59. /**
  60. * Closure for @e rh.
  61. */
  62. void *rh_cls;
  63. /**
  64. * Task to reconnect to the service.
  65. */
  66. struct GNUNET_SCHEDULER_Task *reconnect_task;
  67. /**
  68. * Re-connect counter, to make sure we did not reconnect in the meantime.
  69. */
  70. uint32_t generation;
  71. /**
  72. * Flags for events we care about.
  73. */
  74. enum GNUNET_DNS_Flags flags;
  75. /**
  76. * Number of GNUNET_DNS_RequestHandles we have outstanding. Must be 0 before
  77. * we can be disconnected.
  78. */
  79. unsigned int pending_requests;
  80. };
  81. /**
  82. * Reconnect to the DNS service.
  83. *
  84. * @param cls handle with the connection to connect
  85. * @param tc scheduler context (unused)
  86. */
  87. static void
  88. reconnect (void *cls);
  89. /**
  90. * Drop the existing connection and reconnect to the DNS service.
  91. *
  92. * @param dh handle with the connection
  93. */
  94. static void
  95. force_reconnect (struct GNUNET_DNS_Handle *dh)
  96. {
  97. if (NULL != dh->mq)
  98. {
  99. GNUNET_MQ_destroy (dh->mq);
  100. dh->mq = NULL;
  101. }
  102. dh->reconnect_task =
  103. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  104. &reconnect,
  105. dh);
  106. }
  107. /**
  108. * Generic error handler, called with the appropriate error code and
  109. * the same closure specified at the creation of the message queue.
  110. * Not every message queue implementation supports an error handler.
  111. *
  112. * @param cls closure with the `struct GNUNET_DNS_Handle *`
  113. * @param error error code
  114. */
  115. static void
  116. mq_error_handler (void *cls,
  117. enum GNUNET_MQ_Error error)
  118. {
  119. struct GNUNET_DNS_Handle *dh = cls;
  120. force_reconnect (dh);
  121. }
  122. /**
  123. * This receives packets from the DNS service and calls the application to
  124. * check that the request is well-formed
  125. *
  126. * @param cls the struct GNUNET_DNS_Handle
  127. * @param req message from the service (request)
  128. */
  129. static int
  130. check_request (void *cls,
  131. const struct GNUNET_DNS_Request *req)
  132. {
  133. if (0 != ntohl (req->reserved))
  134. {
  135. GNUNET_break (0);
  136. return GNUNET_SYSERR;
  137. }
  138. return GNUNET_OK;
  139. }
  140. /**
  141. * This receives packets from the DNS service and calls the application to
  142. * handle it.
  143. *
  144. * @param cls the `struct GNUNET_DNS_Handle *`
  145. * @param msg message from the service (request)
  146. */
  147. static void
  148. handle_request (void *cls,
  149. const struct GNUNET_DNS_Request *req)
  150. {
  151. struct GNUNET_DNS_Handle *dh = cls;
  152. size_t payload_length = ntohs (req->header.size) - sizeof(*req);
  153. struct GNUNET_DNS_RequestHandle *rh;
  154. rh = GNUNET_new (struct GNUNET_DNS_RequestHandle);
  155. rh->dh = dh;
  156. rh->request_id = req->request_id;
  157. rh->generation = dh->generation;
  158. dh->pending_requests++;
  159. dh->rh (dh->rh_cls,
  160. rh,
  161. payload_length,
  162. (const char *) &req[1]);
  163. }
  164. /**
  165. * Reconnect to the DNS service.
  166. *
  167. * @param cls handle with the connection to connect
  168. */
  169. static void
  170. reconnect (void *cls)
  171. {
  172. struct GNUNET_DNS_Handle *dh = cls;
  173. struct GNUNET_MQ_MessageHandler handlers[] = {
  174. GNUNET_MQ_hd_var_size (request,
  175. GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST,
  176. struct GNUNET_DNS_Request,
  177. dh),
  178. GNUNET_MQ_handler_end ()
  179. };
  180. struct GNUNET_MQ_Envelope *env;
  181. struct GNUNET_DNS_Register *msg;
  182. dh->reconnect_task = NULL;
  183. dh->mq = GNUNET_CLIENT_connect (dh->cfg,
  184. "dns",
  185. handlers,
  186. &mq_error_handler,
  187. dh);
  188. if (NULL == dh->mq)
  189. return;
  190. dh->generation++;
  191. env = GNUNET_MQ_msg (msg,
  192. GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT);
  193. msg->flags = htonl (dh->flags);
  194. GNUNET_MQ_send (dh->mq,
  195. env);
  196. }
  197. /**
  198. * If a GNUNET_DNS_RequestHandler calls this function, the request is
  199. * given to other clients or the global DNS for resolution. Once a
  200. * global response has been obtained, the request handler is AGAIN
  201. * called to give it a chance to observe and modify the response after
  202. * the "normal" resolution. It is not legal for the request handler
  203. * to call this function if a response is already present.
  204. *
  205. * @param rh request that should now be forwarded
  206. */
  207. void
  208. GNUNET_DNS_request_forward (struct GNUNET_DNS_RequestHandle *rh)
  209. {
  210. struct GNUNET_MQ_Envelope *env;
  211. struct GNUNET_DNS_Response *resp;
  212. GNUNET_assert (0 < rh->dh->pending_requests--);
  213. if (rh->generation != rh->dh->generation)
  214. {
  215. GNUNET_free (rh);
  216. return;
  217. }
  218. env = GNUNET_MQ_msg (resp,
  219. GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
  220. resp->drop_flag = htonl (1);
  221. resp->request_id = rh->request_id;
  222. GNUNET_MQ_send (rh->dh->mq,
  223. env);
  224. GNUNET_free (rh);
  225. }
  226. /**
  227. * If a GNUNET_DNS_RequestHandler calls this function, the request is
  228. * to be dropped and no response should be generated.
  229. *
  230. * @param rh request that should now be dropped
  231. */
  232. void
  233. GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh)
  234. {
  235. struct GNUNET_MQ_Envelope *env;
  236. struct GNUNET_DNS_Response *resp;
  237. GNUNET_assert (0 < rh->dh->pending_requests--);
  238. if (rh->generation != rh->dh->generation)
  239. {
  240. GNUNET_free (rh);
  241. return;
  242. }
  243. env = GNUNET_MQ_msg (resp,
  244. GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
  245. resp->request_id = rh->request_id;
  246. resp->drop_flag = htonl (0);
  247. GNUNET_MQ_send (rh->dh->mq,
  248. env);
  249. GNUNET_free (rh);
  250. }
  251. /**
  252. * If a GNUNET_DNS_RequestHandler calls this function, the request is
  253. * supposed to be answered with the data provided to this call (with
  254. * the modifications the function might have made).
  255. *
  256. * @param rh request that should now be answered
  257. * @param reply_length size of @a reply (uint16_t to force sane size)
  258. * @param reply reply data
  259. */
  260. void
  261. GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh,
  262. uint16_t reply_length,
  263. const char *reply)
  264. {
  265. struct GNUNET_MQ_Envelope *env;
  266. struct GNUNET_DNS_Response *resp;
  267. GNUNET_assert (0 < rh->dh->pending_requests--);
  268. if (rh->generation != rh->dh->generation)
  269. {
  270. GNUNET_free (rh);
  271. return;
  272. }
  273. if (reply_length + sizeof(struct GNUNET_DNS_Response)
  274. >= GNUNET_MAX_MESSAGE_SIZE)
  275. {
  276. GNUNET_break (0);
  277. GNUNET_free (rh);
  278. return;
  279. }
  280. env = GNUNET_MQ_msg_extra (resp,
  281. reply_length,
  282. GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE);
  283. resp->drop_flag = htonl (2);
  284. resp->request_id = rh->request_id;
  285. GNUNET_memcpy (&resp[1],
  286. reply,
  287. reply_length);
  288. GNUNET_MQ_send (rh->dh->mq,
  289. env);
  290. GNUNET_free (rh);
  291. }
  292. /**
  293. * Connect to the service-dns
  294. *
  295. * @param cfg configuration to use
  296. * @param flags when to call @a rh
  297. * @param rh function to call with DNS requests
  298. * @param rh_cls closure to pass to @a rh
  299. * @return DNS handle
  300. */
  301. struct GNUNET_DNS_Handle *
  302. GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
  303. enum GNUNET_DNS_Flags flags,
  304. GNUNET_DNS_RequestHandler rh,
  305. void *rh_cls)
  306. {
  307. struct GNUNET_DNS_Handle *dh;
  308. dh = GNUNET_new (struct GNUNET_DNS_Handle);
  309. dh->cfg = cfg;
  310. dh->flags = flags;
  311. dh->rh = rh;
  312. dh->rh_cls = rh_cls;
  313. dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh);
  314. return dh;
  315. }
  316. /**
  317. * Disconnect from the DNS service.
  318. *
  319. * @param dh DNS handle
  320. */
  321. void
  322. GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *dh)
  323. {
  324. if (NULL != dh->mq)
  325. {
  326. GNUNET_MQ_destroy (dh->mq);
  327. dh->mq = NULL;
  328. }
  329. if (NULL != dh->reconnect_task)
  330. {
  331. GNUNET_SCHEDULER_cancel (dh->reconnect_task);
  332. dh->reconnect_task = NULL;
  333. }
  334. /* make sure client has no pending requests left over! */
  335. GNUNET_break (0 == dh->pending_requests);
  336. GNUNET_free (dh);
  337. }
  338. /* end of dns_api.c */