diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-04-06 11:45:42 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-04-06 11:46:01 +0200 |
commit | 9c9773bbdc8ebe9c46fd297fdd96dad5b9f19697 (patch) | |
tree | 0ed44cb9b4d6347d81b7699d2758edf9c9e22878 /src/dns | |
parent | 08ded5f88e6369ac78db4bb26bcf215f8282f27c (diff) | |
download | gnunet-9c9773bbdc8ebe9c46fd297fdd96dad5b9f19697.tar.gz gnunet-9c9773bbdc8ebe9c46fd297fdd96dad5b9f19697.zip |
starting tool for zone import (very incomplete)
Diffstat (limited to 'src/dns')
-rw-r--r-- | src/dns/Makefile.am | 12 | ||||
-rw-r--r-- | src/dns/gnunet-zoneimport.c | 308 |
2 files changed, 319 insertions, 1 deletions
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am index 5af228121..8e5b06043 100644 --- a/src/dns/Makefile.am +++ b/src/dns/Makefile.am | |||
@@ -35,7 +35,9 @@ libexec_PROGRAMS = \ | |||
35 | gnunet-service-dns $(HIJACKBIN) | 35 | gnunet-service-dns $(HIJACKBIN) |
36 | 36 | ||
37 | noinst_PROGRAMS = \ | 37 | noinst_PROGRAMS = \ |
38 | gnunet-dns-monitor gnunet-dns-redirector | 38 | gnunet-dns-monitor \ |
39 | gnunet-dns-redirector \ | ||
40 | gnunet-zoneimport | ||
39 | 41 | ||
40 | plugin_LTLIBRARIES = \ | 42 | plugin_LTLIBRARIES = \ |
41 | libgnunet_plugin_block_dns.la | 43 | libgnunet_plugin_block_dns.la |
@@ -60,6 +62,14 @@ gnunet_dns_monitor_LDADD = \ | |||
60 | $(top_builddir)/src/util/libgnunetutil.la \ | 62 | $(top_builddir)/src/util/libgnunetutil.la \ |
61 | $(GN_LIBINTL) | 63 | $(GN_LIBINTL) |
62 | 64 | ||
65 | gnunet_zoneimport_SOURCES = \ | ||
66 | gnunet-zoneimport.c | ||
67 | gnunet_zoneimport_LDADD = \ | ||
68 | libgnunetdnsparser.la \ | ||
69 | libgnunetdnsstub.la \ | ||
70 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
71 | $(GN_LIBINTL) | ||
72 | |||
63 | gnunet_dns_redirector_SOURCES = \ | 73 | gnunet_dns_redirector_SOURCES = \ |
64 | gnunet-dns-redirector.c | 74 | gnunet-dns-redirector.c |
65 | gnunet_dns_redirector_LDADD = \ | 75 | gnunet_dns_redirector_LDADD = \ |
diff --git a/src/dns/gnunet-zoneimport.c b/src/dns/gnunet-zoneimport.c new file mode 100644 index 000000000..bcc742314 --- /dev/null +++ b/src/dns/gnunet-zoneimport.c | |||
@@ -0,0 +1,308 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2018 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
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 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file src/dns/gnunet-zoneimport.c | ||
23 | * @brief import a DNS zone for analysis, brute force | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include <gnunet_util_lib.h> | ||
28 | #include <gnunet_dnsstub_lib.h> | ||
29 | #include <gnunet_dnsparser_lib.h> | ||
30 | |||
31 | struct Request | ||
32 | { | ||
33 | struct Request *next; | ||
34 | struct Request *prev; | ||
35 | struct GNUNET_DNSSTUB_RequestSocket *rs; | ||
36 | /** | ||
37 | * Raw DNS query. | ||
38 | */ | ||
39 | void *raw; | ||
40 | /** | ||
41 | * Number of bytes in @e raw. | ||
42 | */ | ||
43 | size_t raw_len; | ||
44 | |||
45 | char *hostname; | ||
46 | time_t time; | ||
47 | int issueNum; | ||
48 | |||
49 | /** | ||
50 | * random 16-bit DNS query identifier. | ||
51 | */ | ||
52 | uint16_t id; | ||
53 | }; | ||
54 | |||
55 | |||
56 | static struct GNUNET_DNSSTUB_Context *ctx; | ||
57 | |||
58 | // the number of queries that are outstanding | ||
59 | static unsigned int pending; | ||
60 | |||
61 | static unsigned int lookups; | ||
62 | |||
63 | static struct Request *req_head; | ||
64 | |||
65 | static struct Request *req_tail; | ||
66 | |||
67 | // the number of queries that are outstanding | ||
68 | static unsigned int pending; | ||
69 | |||
70 | static unsigned int lookups; | ||
71 | |||
72 | #define THRESH 20 | ||
73 | |||
74 | #define MAX_RETRIES 5 | ||
75 | |||
76 | |||
77 | // time_thresh is in usecs, but note that adns isn't consistent | ||
78 | // in how long it takes to submit queries, so 40usecs is | ||
79 | // really equivalent to 25,000 queries per second, but clearly it doesn't | ||
80 | // operate in that range. Thus, 10 is just a 'magic' number that we can | ||
81 | // tweak depending on how fast we want to submit queries. | ||
82 | #define TIME_THRESH 10 | ||
83 | |||
84 | #define MAX_RETRIES 5 | ||
85 | |||
86 | |||
87 | /** | ||
88 | * Function called with the result of a DNS resolution. | ||
89 | * | ||
90 | * @param cls closure with the `struct Request` | ||
91 | * @param rs socket that received the response | ||
92 | * @param dns dns response, never NULL | ||
93 | * @param dns_len number of bytes in @a dns | ||
94 | */ | ||
95 | static void | ||
96 | process_result (void *cls, | ||
97 | struct GNUNET_DNSSTUB_RequestSocket *rs, | ||
98 | const struct GNUNET_TUN_DnsHeader *dns, | ||
99 | size_t dns_len) | ||
100 | { | ||
101 | struct Request *req = cls; | ||
102 | struct GNUNET_DNSPARSER_Packet *p; | ||
103 | |||
104 | if (NULL == dns) | ||
105 | { | ||
106 | /* stub gave up */ | ||
107 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
108 | "Stub gave up on DNS reply for `%s'\n", | ||
109 | req->hostname); | ||
110 | GNUNET_CONTAINER_DLL_remove (req_head, | ||
111 | req_tail, | ||
112 | req); | ||
113 | GNUNET_CONTAINER_DLL_insert_tail (req_head, | ||
114 | req_tail, | ||
115 | req); | ||
116 | req->rs = NULL; | ||
117 | return; | ||
118 | } | ||
119 | if (req->id != dns->id) | ||
120 | return; | ||
121 | p = GNUNET_DNSPARSER_parse ((const char *) dns, | ||
122 | dns_len); | ||
123 | if (NULL == p) | ||
124 | { | ||
125 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
126 | "Failed to parse DNS reply for `%s'\n", | ||
127 | req->hostname); | ||
128 | GNUNET_CONTAINER_DLL_remove (req_head, | ||
129 | req_tail, | ||
130 | req); | ||
131 | GNUNET_CONTAINER_DLL_insert_tail (req_head, | ||
132 | req_tail, | ||
133 | req); | ||
134 | GNUNET_DNSSTUB_resolve_cancel (req->rs); | ||
135 | req->rs = NULL; | ||
136 | return; | ||
137 | } | ||
138 | for (unsigned int i=0;i<p->num_answers;i++) | ||
139 | { | ||
140 | struct GNUNET_DNSPARSER_Record *rs = &p->answers[i]; | ||
141 | char buf[INET_ADDRSTRLEN]; | ||
142 | |||
143 | switch (rs->type) | ||
144 | { | ||
145 | case GNUNET_DNSPARSER_TYPE_A: | ||
146 | fprintf (stdout, | ||
147 | "%s %s\n", | ||
148 | req->hostname, | ||
149 | inet_ntop (AF_INET, | ||
150 | rs->data.raw.data, | ||
151 | buf, | ||
152 | sizeof (buf))); | ||
153 | break; | ||
154 | } | ||
155 | } | ||
156 | GNUNET_DNSPARSER_free_packet (p); | ||
157 | GNUNET_DNSSTUB_resolve_cancel (req->rs); | ||
158 | req->rs = NULL; | ||
159 | GNUNET_CONTAINER_DLL_remove (req_head, | ||
160 | req_tail, | ||
161 | req); | ||
162 | GNUNET_free (req->hostname); | ||
163 | GNUNET_free (req->raw); | ||
164 | GNUNET_free (req); | ||
165 | } | ||
166 | |||
167 | |||
168 | static void | ||
169 | submit_req (struct Request *req) | ||
170 | { | ||
171 | static struct timeval last_request; | ||
172 | struct timeval now; | ||
173 | |||
174 | if (NULL != req->rs) | ||
175 | return; /* already submitted */ | ||
176 | gettimeofday (&now, | ||
177 | NULL); | ||
178 | if ( ( ( (now.tv_sec - last_request.tv_sec) == 0) && | ||
179 | ( (now.tv_usec - last_request.tv_usec) < TIME_THRESH) ) || | ||
180 | (pending >= THRESH) ) | ||
181 | return; | ||
182 | GNUNET_assert (NULL == req->rs); | ||
183 | req->rs = GNUNET_DNSSTUB_resolve2 (ctx, | ||
184 | req->raw, | ||
185 | req->raw_len, | ||
186 | &process_result, | ||
187 | req); | ||
188 | GNUNET_assert (NULL != req->rs); | ||
189 | last_request = now; | ||
190 | lookups++; | ||
191 | pending++; | ||
192 | req->time = time (NULL); | ||
193 | } | ||
194 | |||
195 | |||
196 | static void | ||
197 | process_queue() | ||
198 | { | ||
199 | struct Request *wl = wl = req_head; | ||
200 | |||
201 | if ( (pending < THRESH) && | ||
202 | (NULL != wl) ) | ||
203 | { | ||
204 | struct Request *req = wl; | ||
205 | |||
206 | wl = req->next; | ||
207 | submit_req (req); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | |||
212 | static void | ||
213 | run (void *cls) | ||
214 | { | ||
215 | process_queue (); | ||
216 | if (NULL != req_head) | ||
217 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | ||
218 | &run, | ||
219 | NULL); | ||
220 | } | ||
221 | |||
222 | |||
223 | static void | ||
224 | queue (const char *hostname) | ||
225 | { | ||
226 | struct GNUNET_DNSPARSER_Packet p; | ||
227 | struct GNUNET_DNSPARSER_Query q; | ||
228 | struct Request *req; | ||
229 | char *raw; | ||
230 | size_t raw_size; | ||
231 | |||
232 | if (GNUNET_OK != | ||
233 | GNUNET_DNSPARSER_check_name (hostname)) | ||
234 | { | ||
235 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
236 | "Refusing invalid hostname `%s'\n", | ||
237 | hostname); | ||
238 | return; | ||
239 | } | ||
240 | q.name = (char *) hostname; | ||
241 | q.type = GNUNET_DNSPARSER_TYPE_ANY; | ||
242 | q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET; | ||
243 | |||
244 | memset (&p, 0, sizeof (p)); | ||
245 | p.num_queries = 1; | ||
246 | p.queries = &q; | ||
247 | p.id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, | ||
248 | UINT16_MAX); | ||
249 | |||
250 | if (GNUNET_OK != | ||
251 | GNUNET_DNSPARSER_pack (&p, | ||
252 | UINT16_MAX, | ||
253 | &raw, | ||
254 | &raw_size)) | ||
255 | { | ||
256 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
257 | "Failed to pack query for hostname `%s'\n", | ||
258 | hostname); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | req = GNUNET_new (struct Request); | ||
263 | req->hostname = strdup (hostname); | ||
264 | req->raw = raw; | ||
265 | req->raw_len = raw_size; | ||
266 | req->id = p.id; | ||
267 | GNUNET_CONTAINER_DLL_insert_tail (req_head, | ||
268 | req_tail, | ||
269 | req); | ||
270 | } | ||
271 | |||
272 | |||
273 | int | ||
274 | main (int argc, | ||
275 | char **argv) | ||
276 | { | ||
277 | char hn[256]; | ||
278 | |||
279 | if (2 != argc) | ||
280 | { | ||
281 | fprintf (stderr, | ||
282 | "Missing required configuration argument\n"); | ||
283 | return -1; | ||
284 | } | ||
285 | ctx = GNUNET_DNSSTUB_start (argv[1]); | ||
286 | if (NULL == ctx) | ||
287 | { | ||
288 | fprintf (stderr, | ||
289 | "Failed to initialize GNUnet DNS STUB\n"); | ||
290 | return 1; | ||
291 | } | ||
292 | while (NULL != | ||
293 | fgets (hn, | ||
294 | sizeof (hn), | ||
295 | stdin)) | ||
296 | { | ||
297 | if (strlen(hn) > 0) | ||
298 | hn[strlen(hn)-1] = '\0'; /* eat newline */ | ||
299 | queue (hn); | ||
300 | } | ||
301 | GNUNET_SCHEDULER_run (&run, | ||
302 | NULL); | ||
303 | GNUNET_DNSSTUB_stop (ctx); | ||
304 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
305 | "Did %u lookups\n", | ||
306 | lookups); | ||
307 | return 0; | ||
308 | } | ||