gnunet-service-gns_interceptor.c 11 KB

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