gnunet-dns-redirector.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2011 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 src/dns/gnunet-dns-redirector.c
  18. * @brief Tool to change DNS replies (for testing)
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_dns_service.h"
  24. #include "gnunet_dnsparser_lib.h"
  25. /**
  26. * Handle to DNS service.
  27. */
  28. static struct GNUNET_DNS_Handle *handle;
  29. /**
  30. * New target for A records.
  31. */
  32. static char *n4;
  33. /**
  34. * New target for AAAA records.
  35. */
  36. static char *n6;
  37. /**
  38. * Global return value (0 success).
  39. */
  40. static int ret;
  41. /**
  42. * Selected level of verbosity.
  43. */
  44. static unsigned int verbosity;
  45. /**
  46. * Modify the given DNS record.
  47. *
  48. * @param record record to modify
  49. */
  50. static void
  51. modify_record (const struct GNUNET_DNSPARSER_Record *record)
  52. {
  53. char buf[INET6_ADDRSTRLEN];
  54. switch (record->type)
  55. {
  56. case GNUNET_DNSPARSER_TYPE_A:
  57. if (record->data.raw.data_len != sizeof (struct in_addr))
  58. return;
  59. if (NULL != n4)
  60. {
  61. if (verbosity > 1)
  62. fprintf (stderr,
  63. "Changing A record from `%s' to `%s'\n",
  64. inet_ntop (AF_INET, record->data.raw.data, buf, sizeof (buf)),
  65. n4);
  66. GNUNET_assert (1 == inet_pton (AF_INET, n4, record->data.raw.data));
  67. }
  68. break;
  69. case GNUNET_DNSPARSER_TYPE_AAAA:
  70. if (record->data.raw.data_len != sizeof (struct in6_addr))
  71. return;
  72. if (NULL != n6)
  73. {
  74. if (verbosity > 1)
  75. fprintf (stderr,
  76. "Changing AAAA record from `%s' to `%s'\n",
  77. inet_ntop (AF_INET6, record->data.raw.data, buf, sizeof (buf)),
  78. n6);
  79. GNUNET_assert (1 == inet_pton (AF_INET6, n6, record->data.raw.data));
  80. }
  81. break;
  82. case GNUNET_DNSPARSER_TYPE_NS:
  83. case GNUNET_DNSPARSER_TYPE_CNAME:
  84. case GNUNET_DNSPARSER_TYPE_PTR:
  85. case GNUNET_DNSPARSER_TYPE_SOA:
  86. case GNUNET_DNSPARSER_TYPE_MX:
  87. case GNUNET_DNSPARSER_TYPE_TXT:
  88. break;
  89. default:
  90. break;
  91. }
  92. }
  93. /**
  94. * Signature of a function that is called whenever the DNS service
  95. * encounters a DNS request and needs to do something with it. The
  96. * function has then the chance to generate or modify the response by
  97. * calling one of the three "GNUNET_DNS_request_*" continuations.
  98. *
  99. * When a request is intercepted, this function is called first to
  100. * give the client a chance to do the complete address resolution;
  101. * "rdata" will be NULL for this first call for a DNS request, unless
  102. * some other client has already filled in a response.
  103. *
  104. * If multiple clients exist, all of them are called before the global
  105. * DNS. The global DNS is only called if all of the clients'
  106. * functions call GNUNET_DNS_request_forward. Functions that call
  107. * GNUNET_DNS_request_forward will be called again before a final
  108. * response is returned to the application. If any of the clients'
  109. * functions call GNUNET_DNS_request_drop, the response is dropped.
  110. *
  111. * @param cls closure
  112. * @param rh request handle to user for reply
  113. * @param request_length number of bytes in request
  114. * @param request udp payload of the DNS request
  115. */
  116. static void
  117. modify_request (void *cls,
  118. struct GNUNET_DNS_RequestHandle *rh,
  119. size_t request_length,
  120. const char *request)
  121. {
  122. struct GNUNET_DNSPARSER_Packet *p;
  123. unsigned int i;
  124. char *buf;
  125. size_t len;
  126. int ret;
  127. p = GNUNET_DNSPARSER_parse (request, request_length);
  128. if (NULL == p)
  129. {
  130. fprintf (stderr, "Received malformed DNS packet, leaving it untouched\n");
  131. GNUNET_DNS_request_forward (rh);
  132. return;
  133. }
  134. for (i=0;i<p->num_answers;i++)
  135. modify_record (&p->answers[i]);
  136. buf = NULL;
  137. ret = GNUNET_DNSPARSER_pack (p, 1024, &buf, &len);
  138. GNUNET_DNSPARSER_free_packet (p);
  139. if (GNUNET_OK != ret)
  140. {
  141. if (GNUNET_NO == ret)
  142. fprintf (stderr,
  143. "Modified DNS response did not fit, keeping old response\n");
  144. else
  145. GNUNET_break (0); /* our modifications should have been sane! */
  146. GNUNET_DNS_request_forward (rh);
  147. }
  148. else
  149. {
  150. if (verbosity > 0)
  151. fprintf (stdout,
  152. "Injecting modified DNS response\n");
  153. GNUNET_DNS_request_answer (rh, len, buf);
  154. }
  155. GNUNET_free_non_null (buf);
  156. }
  157. /**
  158. * Shutdown.
  159. */
  160. static void
  161. do_disconnect (void *cls)
  162. {
  163. if (NULL != handle)
  164. {
  165. GNUNET_DNS_disconnect (handle);
  166. handle = NULL;
  167. }
  168. }
  169. /**
  170. * Main function that will be run by the scheduler.
  171. *
  172. * @param cls closure
  173. * @param args remaining command-line arguments
  174. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  175. * @param cfg configuration
  176. */
  177. static void
  178. run (void *cls, char *const *args, const char *cfgfile,
  179. const struct GNUNET_CONFIGURATION_Handle *cfg)
  180. {
  181. struct in_addr i4;
  182. struct in6_addr i6;
  183. if ( (n4 != NULL) &&
  184. (1 != inet_pton (AF_INET, n4, &i4)) )
  185. {
  186. fprintf (stderr,
  187. "`%s' is nto a valid IPv4 address!\n",
  188. n4);
  189. return;
  190. }
  191. if ( (n6 != NULL) &&
  192. (1 != inet_pton (AF_INET6, n6, &i6)) )
  193. {
  194. fprintf (stderr,
  195. "`%s' is nto a valid IPv6 address!\n",
  196. n6);
  197. return;
  198. }
  199. handle =
  200. GNUNET_DNS_connect (cfg,
  201. GNUNET_DNS_FLAG_POST_RESOLUTION,
  202. &modify_request,
  203. NULL);
  204. GNUNET_SCHEDULER_add_shutdown (&do_disconnect, NULL);
  205. }
  206. int
  207. main (int argc, char *const *argv)
  208. {
  209. struct GNUNET_GETOPT_CommandLineOption options[] = {
  210. GNUNET_GETOPT_option_string ('4',
  211. "ipv4",
  212. "IPV4",
  213. gettext_noop ("set A records"),
  214. &n4),
  215. GNUNET_GETOPT_option_string ('6',
  216. "ipv4",
  217. "IPV6",
  218. gettext_noop ("set AAAA records"),
  219. &n6),
  220. GNUNET_GETOPT_option_verbose (&verbosity),
  221. GNUNET_GETOPT_OPTION_END
  222. };
  223. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  224. return 2;
  225. ret = (GNUNET_OK ==
  226. GNUNET_PROGRAM_run (argc, argv, "gnunet-dns-redirector",
  227. gettext_noop
  228. ("Change DNS replies to point elsewhere."), options,
  229. &run, NULL)) ? ret : 1;
  230. GNUNET_free ((void*) argv);
  231. return ret;
  232. }
  233. /* end of gnunet-dns-redirector.c */