gnunet-service-gns_interceptor.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009-2013 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 gns/gnunet-service-gns_interceptor.c
  18. * @brief GNUnet GNS interceptor logic
  19. * @author Martin Schanzenbach
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_dns_service.h"
  25. #include "gnunet_dnsparser_lib.h"
  26. #include "gnunet-service-gns.h"
  27. #include "gnunet-service-gns_resolver.h"
  28. #include "gnunet-service-gns_interceptor.h"
  29. #include "gns.h"
  30. /**
  31. * How deep do we allow recursions to go before we abort?
  32. */
  33. #define MAX_RECURSION 256
  34. /**
  35. * Handle to a DNS intercepted
  36. * reslution request
  37. */
  38. struct InterceptLookupHandle
  39. {
  40. /**
  41. * We keep these in a DLL.
  42. */
  43. struct InterceptLookupHandle *next;
  44. /**
  45. * We keep these in a DLL.
  46. */
  47. struct InterceptLookupHandle *prev;
  48. /**
  49. * the request handle to reply to
  50. */
  51. struct GNUNET_DNS_RequestHandle *request_handle;
  52. /**
  53. * the dns parser packet received
  54. */
  55. struct GNUNET_DNSPARSER_Packet *packet;
  56. /**
  57. * Handle for the lookup operation.
  58. */
  59. struct GNS_ResolverHandle *lookup;
  60. };
  61. /**
  62. * Our handle to the DNS handler library
  63. */
  64. static struct GNUNET_DNS_Handle *dns_handle;
  65. /**
  66. * Head of the DLL.
  67. */
  68. static struct InterceptLookupHandle *ilh_head;
  69. /**
  70. * Tail of the DLL.
  71. */
  72. static struct InterceptLookupHandle *ilh_tail;
  73. /**
  74. * Reply to dns request with the result from our lookup.
  75. *
  76. * @param cls the closure to the request (an InterceptLookupHandle)
  77. * @param rd_count the number of records to return
  78. * @param rd the record data
  79. */
  80. static void
  81. reply_to_dns (void *cls, uint32_t rd_count,
  82. const struct GNUNET_GNSRECORD_Data *rd)
  83. {
  84. struct InterceptLookupHandle *ilh = cls;
  85. struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
  86. struct GNUNET_DNSPARSER_Query *query = &packet->queries[0];
  87. uint32_t i;
  88. size_t len;
  89. int ret;
  90. char *buf;
  91. unsigned int num_answers;
  92. unsigned int skip_answers;
  93. unsigned int skip_additional;
  94. size_t off = 0;
  95. /* Put records in the DNS packet */
  96. num_answers = 0;
  97. for (i = 0; i < rd_count; i++)
  98. if (rd[i].record_type == query->type)
  99. num_answers++;
  100. skip_answers = 0;
  101. skip_additional = 0;
  102. {
  103. struct GNUNET_DNSPARSER_Record answer_records[num_answers];
  104. struct GNUNET_DNSPARSER_Record additional_records[rd_count - num_answers];
  105. packet->answers = answer_records;
  106. packet->additional_records = additional_records;
  107. /* FIXME: need to handle #GNUNET_GNSRECORD_RF_SHADOW_RECORD option
  108. (by ignoring records where this flag is set if there is any
  109. other record of that type in the result set) */
  110. for (i = 0; i < rd_count; i++)
  111. {
  112. if (rd[i].record_type == query->type)
  113. {
  114. answer_records[i - skip_answers].name = query->name;
  115. answer_records[i - skip_answers].type = rd[i].record_type;
  116. switch (rd[i].record_type)
  117. {
  118. case GNUNET_DNSPARSER_TYPE_NS:
  119. case GNUNET_DNSPARSER_TYPE_CNAME:
  120. case GNUNET_DNSPARSER_TYPE_PTR:
  121. answer_records[i - skip_answers].data.hostname
  122. = GNUNET_DNSPARSER_parse_name (rd[i].data,
  123. rd[i].data_size,
  124. &off);
  125. if ((off != rd[i].data_size) ||
  126. (NULL == answer_records[i].data.hostname))
  127. {
  128. GNUNET_break_op (0);
  129. skip_answers++;
  130. }
  131. break;
  132. case GNUNET_DNSPARSER_TYPE_SOA:
  133. answer_records[i - skip_answers].data.soa
  134. = GNUNET_DNSPARSER_parse_soa (rd[i].data,
  135. rd[i].data_size,
  136. &off);
  137. if ((off != rd[i].data_size) ||
  138. (NULL == answer_records[i].data.soa))
  139. {
  140. GNUNET_break_op (0);
  141. skip_answers++;
  142. }
  143. break;
  144. case GNUNET_DNSPARSER_TYPE_SRV:
  145. /* FIXME: SRV is not yet supported */
  146. skip_answers++;
  147. break;
  148. case GNUNET_DNSPARSER_TYPE_MX:
  149. answer_records[i - skip_answers].data.mx
  150. = GNUNET_DNSPARSER_parse_mx (rd[i].data,
  151. rd[i].data_size,
  152. &off);
  153. if ((off != rd[i].data_size) ||
  154. (NULL == answer_records[i].data.hostname))
  155. {
  156. GNUNET_break_op (0);
  157. skip_answers++;
  158. }
  159. break;
  160. default:
  161. answer_records[i - skip_answers].data.raw.data_len = rd[i].data_size;
  162. answer_records[i - skip_answers].data.raw.data = (char *) rd[i].data;
  163. break;
  164. }
  165. GNUNET_break (0 == (rd[i - skip_answers].flags
  166. & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
  167. answer_records[i - skip_answers].expiration_time.abs_value_us =
  168. rd[i].expiration_time;
  169. answer_records[i - skip_answers].dns_traffic_class =
  170. GNUNET_TUN_DNS_CLASS_INTERNET;
  171. }
  172. else
  173. {
  174. additional_records[i - skip_additional].name = query->name;
  175. additional_records[i - skip_additional].type = rd[i].record_type;
  176. switch (rd[i].record_type)
  177. {
  178. case GNUNET_DNSPARSER_TYPE_NS:
  179. case GNUNET_DNSPARSER_TYPE_CNAME:
  180. case GNUNET_DNSPARSER_TYPE_PTR:
  181. additional_records[i - skip_additional].data.hostname
  182. = GNUNET_DNSPARSER_parse_name (rd[i].data,
  183. rd[i].data_size,
  184. &off);
  185. if ((off != rd[i].data_size) ||
  186. (NULL == additional_records[i].data.hostname))
  187. {
  188. GNUNET_break_op (0);
  189. skip_additional++;
  190. }
  191. break;
  192. case GNUNET_DNSPARSER_TYPE_SOA:
  193. additional_records[i - skip_additional].data.soa
  194. = GNUNET_DNSPARSER_parse_soa (rd[i].data,
  195. rd[i].data_size,
  196. &off);
  197. if ((off != rd[i].data_size) ||
  198. (NULL == additional_records[i].data.hostname))
  199. {
  200. GNUNET_break_op (0);
  201. skip_additional++;
  202. }
  203. break;
  204. case GNUNET_DNSPARSER_TYPE_MX:
  205. additional_records[i - skip_additional].data.mx
  206. = GNUNET_DNSPARSER_parse_mx (rd[i].data,
  207. rd[i].data_size,
  208. &off);
  209. if ((off != rd[i].data_size) ||
  210. (NULL == additional_records[i].data.hostname))
  211. {
  212. GNUNET_break_op (0);
  213. skip_additional++;
  214. }
  215. break;
  216. case GNUNET_DNSPARSER_TYPE_SRV:
  217. /* FIXME: SRV is not yet supported */
  218. skip_answers++;
  219. break;
  220. default:
  221. additional_records[i - skip_additional].data.raw.data_len =
  222. rd[i].data_size;
  223. additional_records[i - skip_additional].data.raw.data =
  224. (char *) rd[i].data;
  225. break;
  226. }
  227. GNUNET_break (0 == (rd[i - skip_additional].flags
  228. & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
  229. additional_records[i - skip_additional].expiration_time.abs_value_us =
  230. rd[i].expiration_time;
  231. additional_records[i - skip_additional].dns_traffic_class =
  232. GNUNET_TUN_DNS_CLASS_INTERNET;
  233. }
  234. }
  235. packet->num_answers = num_answers - skip_answers;
  236. packet->num_additional_records = rd_count - num_answers - skip_additional;
  237. packet->flags.authoritative_answer = 1;
  238. if (NULL == rd)
  239. packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NAME_ERROR;
  240. else
  241. packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
  242. packet->flags.query_or_response = 1;
  243. ret = GNUNET_DNSPARSER_pack (packet,
  244. 1024, /* maximum allowed size for DNS reply */
  245. &buf,
  246. &len);
  247. if (GNUNET_OK != ret)
  248. {
  249. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  250. _ ("Error converting GNS response to DNS response!\n"));
  251. if (GNUNET_NO == ret)
  252. GNUNET_free (buf);
  253. }
  254. else
  255. {
  256. GNUNET_DNS_request_answer (ilh->request_handle,
  257. len,
  258. buf);
  259. GNUNET_free (buf);
  260. }
  261. packet->num_answers = 0;
  262. packet->answers = NULL;
  263. packet->num_additional_records = 0;
  264. packet->additional_records = NULL;
  265. GNUNET_DNSPARSER_free_packet (packet);
  266. }
  267. GNUNET_CONTAINER_DLL_remove (ilh_head, ilh_tail, ilh);
  268. GNUNET_free (ilh);
  269. }
  270. /**
  271. * The DNS request handler. Called for every incoming DNS request.
  272. *
  273. * @param cls closure, unused
  274. * @param rh request handle to user for reply
  275. * @param request_length number of bytes in @a request
  276. * @param request UDP payload of the DNS request
  277. */
  278. static void
  279. handle_dns_request (void *cls,
  280. struct GNUNET_DNS_RequestHandle *rh,
  281. size_t request_length,
  282. const char *request)
  283. {
  284. struct GNUNET_DNSPARSER_Packet *p;
  285. struct InterceptLookupHandle *ilh;
  286. struct GNUNET_CRYPTO_EcdsaPublicKey zone;
  287. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  288. "Hijacked a DNS request. Processing.\n");
  289. if (NULL == (p = GNUNET_DNSPARSER_parse (request, request_length)))
  290. {
  291. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  292. "Received malformed DNS packet, leaving it untouched.\n");
  293. GNUNET_DNS_request_forward (rh);
  294. GNUNET_DNSPARSER_free_packet (p);
  295. return;
  296. }
  297. /* Check TLD and decide if we or legacy dns is responsible */
  298. if (1 != p->num_queries)
  299. {
  300. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  301. "Not exactly one query in DNS packet. Forwarding untouched.\n");
  302. GNUNET_DNS_request_forward (rh);
  303. GNUNET_DNSPARSER_free_packet (p);
  304. return;
  305. }
  306. /* Check for GNS TLDs. */
  307. if (GNUNET_YES ==
  308. GNS_find_tld (GNS_get_tld (p->queries[0].name),
  309. &zone))
  310. {
  311. /* Start resolution in GNS */
  312. ilh = GNUNET_new (struct InterceptLookupHandle);
  313. GNUNET_CONTAINER_DLL_insert (ilh_head,
  314. ilh_tail,
  315. ilh);
  316. ilh->packet = p;
  317. ilh->request_handle = rh;
  318. ilh->lookup = GNS_resolver_lookup (&zone,
  319. p->queries[0].type,
  320. p->queries[0].name,
  321. GNUNET_GNS_LO_DEFAULT,
  322. MAX_RECURSION,
  323. &reply_to_dns, ilh);
  324. return;
  325. }
  326. /* This request does not concern us. Forward to real DNS. */
  327. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  328. "Request for `%s' is forwarded to DNS untouched.\n",
  329. p->queries[0].name);
  330. GNUNET_DNS_request_forward (rh);
  331. GNUNET_DNSPARSER_free_packet (p);
  332. }
  333. /**
  334. * Initialized the interceptor
  335. *
  336. * @param c the configuration
  337. * @return #GNUNET_OK on success
  338. */
  339. int
  340. GNS_interceptor_init (const struct GNUNET_CONFIGURATION_Handle *c)
  341. {
  342. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  343. "DNS hijacking enabled. Connecting to DNS service.\n");
  344. dns_handle = GNUNET_DNS_connect (c,
  345. GNUNET_DNS_FLAG_PRE_RESOLUTION,
  346. &handle_dns_request,
  347. NULL);
  348. if (NULL == dns_handle)
  349. {
  350. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  351. _ ("Failed to connect to the DNS service!\n"));
  352. return GNUNET_SYSERR;
  353. }
  354. return GNUNET_YES;
  355. }
  356. /**
  357. * Disconnect from interceptor
  358. */
  359. void
  360. GNS_interceptor_done ()
  361. {
  362. struct InterceptLookupHandle *ilh;
  363. while (NULL != (ilh = ilh_head))
  364. {
  365. GNUNET_CONTAINER_DLL_remove (ilh_head,
  366. ilh_tail,
  367. ilh);
  368. GNS_resolver_lookup_cancel (ilh->lookup);
  369. GNUNET_DNS_request_drop (ilh->request_handle);
  370. GNUNET_DNSPARSER_free_packet (ilh->packet);
  371. GNUNET_free (ilh);
  372. }
  373. if (NULL != dns_handle)
  374. {
  375. GNUNET_DNS_disconnect (dns_handle);
  376. dns_handle = NULL;
  377. }
  378. }
  379. /* end of gnunet-service-gns_interceptor.c */