2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file src/dns/gnunet-dns-redirector.c
23 * @brief Tool to change DNS replies (for testing)
24 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dns_service.h"
30 #include "gnunet_dnsparser_lib.h"
33 * Handle to DNS service.
35 static struct GNUNET_DNS_Handle *handle;
38 * New target for A records.
43 * New target for AAAA records.
48 * Global return value (0 success).
53 * Selected level of verbosity.
55 static unsigned int verbosity;
59 * Modify the given DNS record.
61 * @param record record to modify
64 modify_record (const struct GNUNET_DNSPARSER_Record *record)
66 char buf[INET6_ADDRSTRLEN];
70 case GNUNET_DNSPARSER_TYPE_A:
71 if (record->data.raw.data_len != sizeof(struct in_addr))
77 "Changing A record from `%s' to `%s'\n",
78 inet_ntop (AF_INET, record->data.raw.data, buf, sizeof(buf)),
80 GNUNET_assert (1 == inet_pton (AF_INET, n4, record->data.raw.data));
84 case GNUNET_DNSPARSER_TYPE_AAAA:
85 if (record->data.raw.data_len != sizeof(struct in6_addr))
91 "Changing AAAA record from `%s' to `%s'\n",
92 inet_ntop (AF_INET6, record->data.raw.data, buf, sizeof(buf)),
94 GNUNET_assert (1 == inet_pton (AF_INET6, n6, record->data.raw.data));
98 case GNUNET_DNSPARSER_TYPE_NS:
99 case GNUNET_DNSPARSER_TYPE_CNAME:
100 case GNUNET_DNSPARSER_TYPE_PTR:
101 case GNUNET_DNSPARSER_TYPE_SOA:
102 case GNUNET_DNSPARSER_TYPE_MX:
103 case GNUNET_DNSPARSER_TYPE_TXT:
113 * Signature of a function that is called whenever the DNS service
114 * encounters a DNS request and needs to do something with it. The
115 * function has then the chance to generate or modify the response by
116 * calling one of the three "GNUNET_DNS_request_*" continuations.
118 * When a request is intercepted, this function is called first to
119 * give the client a chance to do the complete address resolution;
120 * "rdata" will be NULL for this first call for a DNS request, unless
121 * some other client has already filled in a response.
123 * If multiple clients exist, all of them are called before the global
124 * DNS. The global DNS is only called if all of the clients'
125 * functions call GNUNET_DNS_request_forward. Functions that call
126 * GNUNET_DNS_request_forward will be called again before a final
127 * response is returned to the application. If any of the clients'
128 * functions call GNUNET_DNS_request_drop, the response is dropped.
131 * @param rh request handle to user for reply
132 * @param request_length number of bytes in request
133 * @param request udp payload of the DNS request
136 modify_request (void *cls,
137 struct GNUNET_DNS_RequestHandle *rh,
138 size_t request_length,
141 struct GNUNET_DNSPARSER_Packet *p;
147 p = GNUNET_DNSPARSER_parse (request, request_length);
150 fprintf (stderr, "Received malformed DNS packet, leaving it untouched\n");
151 GNUNET_DNS_request_forward (rh);
154 for (i = 0; i < p->num_answers; i++)
155 modify_record (&p->answers[i]);
157 ret = GNUNET_DNSPARSER_pack (p, 1024, &buf, &len);
158 GNUNET_DNSPARSER_free_packet (p);
159 if (GNUNET_OK != ret)
161 if (GNUNET_NO == ret)
163 "Modified DNS response did not fit, keeping old response\n");
165 GNUNET_break (0); /* our modifications should have been sane! */
166 GNUNET_DNS_request_forward (rh);
172 "Injecting modified DNS response\n");
173 GNUNET_DNS_request_answer (rh, len, buf);
175 GNUNET_free_non_null (buf);
183 do_disconnect (void *cls)
187 GNUNET_DNS_disconnect (handle);
194 * Main function that will be run by the scheduler.
197 * @param args remaining command-line arguments
198 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
199 * @param cfg configuration
202 run (void *cls, char *const *args, const char *cfgfile,
203 const struct GNUNET_CONFIGURATION_Handle *cfg)
209 (1 != inet_pton (AF_INET, n4, &i4)))
212 "`%s' is nto a valid IPv4 address!\n",
217 (1 != inet_pton (AF_INET6, n6, &i6)))
220 "`%s' is nto a valid IPv6 address!\n",
226 GNUNET_DNS_connect (cfg,
227 GNUNET_DNS_FLAG_POST_RESOLUTION,
230 GNUNET_SCHEDULER_add_shutdown (&do_disconnect, NULL);
235 main (int argc, char *const *argv)
237 struct GNUNET_GETOPT_CommandLineOption options[] = {
238 GNUNET_GETOPT_option_string ('4',
241 gettext_noop ("set A records"),
244 GNUNET_GETOPT_option_string ('6',
247 gettext_noop ("set AAAA records"),
250 GNUNET_GETOPT_option_verbose (&verbosity),
251 GNUNET_GETOPT_OPTION_END
254 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
258 GNUNET_PROGRAM_run (argc, argv, "gnunet-dns-redirector",
260 ("Change DNS replies to point elsewhere."),
262 &run, NULL)) ? ret : 1;
263 GNUNET_free ((void *) argv);
268 /* end of gnunet-dns-redirector.c */