diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-04-06 19:37:53 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-04-06 19:37:53 +0200 |
commit | 5bed6253dcde97fd7d6ea45d91d3ff95141d0fb7 (patch) | |
tree | 585a4f2550efe83fae029e3cdb5421b0f1f93779 /src/dns | |
parent | 1f754809a913093ba215b6b6689d28b7dfb66e4c (diff) | |
download | gnunet-5bed6253dcde97fd7d6ea45d91d3ff95141d0fb7.tar.gz gnunet-5bed6253dcde97fd7d6ea45d91d3ff95141d0fb7.zip |
complete importer
Diffstat (limited to 'src/dns')
-rw-r--r-- | src/dns/dnsstub.c | 9 | ||||
-rw-r--r-- | src/dns/gnunet-zoneimport.c | 304 |
2 files changed, 255 insertions, 58 deletions
diff --git a/src/dns/dnsstub.c b/src/dns/dnsstub.c index c79502ce9..f9dc7a696 100644 --- a/src/dns/dnsstub.c +++ b/src/dns/dnsstub.c | |||
@@ -567,6 +567,15 @@ read_response (void *cls) | |||
567 | tc = GNUNET_SCHEDULER_get_task_context (); | 567 | tc = GNUNET_SCHEDULER_get_task_context (); |
568 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) | 568 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) |
569 | { | 569 | { |
570 | /* signal "failure" (from timeout) */ | ||
571 | if (NULL != rs->rc) | ||
572 | { | ||
573 | rs->rc (rs->rc_cls, | ||
574 | rs, | ||
575 | NULL, | ||
576 | 0); | ||
577 | rs->rc = NULL; | ||
578 | } | ||
570 | /* timeout */ | 579 | /* timeout */ |
571 | cleanup_rs (rs); | 580 | cleanup_rs (rs); |
572 | return; | 581 | return; |
diff --git a/src/dns/gnunet-zoneimport.c b/src/dns/gnunet-zoneimport.c index bcc742314..4284859ed 100644 --- a/src/dns/gnunet-zoneimport.c +++ b/src/dns/gnunet-zoneimport.c | |||
@@ -28,23 +28,50 @@ | |||
28 | #include <gnunet_dnsstub_lib.h> | 28 | #include <gnunet_dnsstub_lib.h> |
29 | #include <gnunet_dnsparser_lib.h> | 29 | #include <gnunet_dnsparser_lib.h> |
30 | 30 | ||
31 | /** | ||
32 | * Request we should make. | ||
33 | */ | ||
31 | struct Request | 34 | struct Request |
32 | { | 35 | { |
36 | /** | ||
37 | * Requests are kept in a DLL. | ||
38 | */ | ||
33 | struct Request *next; | 39 | struct Request *next; |
40 | |||
41 | /** | ||
42 | * Requests are kept in a DLL. | ||
43 | */ | ||
34 | struct Request *prev; | 44 | struct Request *prev; |
45 | |||
46 | /** | ||
47 | * Socket used to make the request, NULL if not active. | ||
48 | */ | ||
35 | struct GNUNET_DNSSTUB_RequestSocket *rs; | 49 | struct GNUNET_DNSSTUB_RequestSocket *rs; |
50 | |||
36 | /** | 51 | /** |
37 | * Raw DNS query. | 52 | * Raw DNS query. |
38 | */ | 53 | */ |
39 | void *raw; | 54 | void *raw; |
55 | |||
40 | /** | 56 | /** |
41 | * Number of bytes in @e raw. | 57 | * Number of bytes in @e raw. |
42 | */ | 58 | */ |
43 | size_t raw_len; | 59 | size_t raw_len; |
44 | 60 | ||
61 | /** | ||
62 | * Hostname we are resolving. | ||
63 | */ | ||
45 | char *hostname; | 64 | char *hostname; |
65 | |||
66 | /** | ||
67 | * When did we last issue this request? | ||
68 | */ | ||
46 | time_t time; | 69 | time_t time; |
47 | int issueNum; | 70 | |
71 | /** | ||
72 | * How often did we issue this query? | ||
73 | */ | ||
74 | int issue_num; | ||
48 | 75 | ||
49 | /** | 76 | /** |
50 | * random 16-bit DNS query identifier. | 77 | * random 16-bit DNS query identifier. |
@@ -53,35 +80,117 @@ struct Request | |||
53 | }; | 80 | }; |
54 | 81 | ||
55 | 82 | ||
83 | /** | ||
84 | * Context for DNS resolution. | ||
85 | */ | ||
56 | static struct GNUNET_DNSSTUB_Context *ctx; | 86 | static struct GNUNET_DNSSTUB_Context *ctx; |
57 | 87 | ||
58 | // the number of queries that are outstanding | 88 | /** |
89 | * The number of queries that are outstanding | ||
90 | */ | ||
59 | static unsigned int pending; | 91 | static unsigned int pending; |
60 | 92 | ||
93 | /** | ||
94 | * Number of lookups we performed overall. | ||
95 | */ | ||
61 | static unsigned int lookups; | 96 | static unsigned int lookups; |
62 | 97 | ||
98 | /** | ||
99 | * Number of lookups that failed. | ||
100 | */ | ||
101 | static unsigned int failures; | ||
102 | |||
103 | /** | ||
104 | * Number of records we found. | ||
105 | */ | ||
106 | static unsigned int records; | ||
107 | |||
108 | /** | ||
109 | * Head of DLL of all requests to perform. | ||
110 | */ | ||
63 | static struct Request *req_head; | 111 | static struct Request *req_head; |
64 | 112 | ||
113 | /** | ||
114 | * Tail of DLL of all requests to perform. | ||
115 | */ | ||
65 | static struct Request *req_tail; | 116 | static struct Request *req_tail; |
66 | 117 | ||
67 | // the number of queries that are outstanding | 118 | /** |
68 | static unsigned int pending; | 119 | * Main task. |
69 | 120 | */ | |
70 | static unsigned int lookups; | 121 | static struct GNUNET_SCHEDULER_Task *t; |
71 | 122 | ||
123 | /** | ||
124 | * Maximum number of queries pending at the same time. | ||
125 | */ | ||
72 | #define THRESH 20 | 126 | #define THRESH 20 |
73 | 127 | ||
128 | /** | ||
129 | * TIME_THRESH is in usecs. How quickly do we submit fresh queries. | ||
130 | * Used as an additional throttle. | ||
131 | */ | ||
132 | #define TIME_THRESH 10 | ||
133 | |||
134 | /** | ||
135 | * How often do we retry a query before giving up for good? | ||
136 | */ | ||
74 | #define MAX_RETRIES 5 | 137 | #define MAX_RETRIES 5 |
75 | 138 | ||
76 | 139 | ||
77 | // time_thresh is in usecs, but note that adns isn't consistent | 140 | /** |
78 | // in how long it takes to submit queries, so 40usecs is | 141 | * We received @a rec for @a req. Remember the answer. |
79 | // really equivalent to 25,000 queries per second, but clearly it doesn't | 142 | * |
80 | // operate in that range. Thus, 10 is just a 'magic' number that we can | 143 | * @param req request |
81 | // tweak depending on how fast we want to submit queries. | 144 | * @param rec response |
82 | #define TIME_THRESH 10 | 145 | */ |
146 | static void | ||
147 | process_record (struct Request *req, | ||
148 | struct GNUNET_DNSPARSER_Record *rec) | ||
149 | { | ||
150 | char buf[INET6_ADDRSTRLEN]; | ||
83 | 151 | ||
84 | #define MAX_RETRIES 5 | 152 | records++; |
153 | switch (rec->type) | ||
154 | { | ||
155 | case GNUNET_DNSPARSER_TYPE_A: | ||
156 | fprintf (stdout, | ||
157 | "%s A %s\n", | ||
158 | req->hostname, | ||
159 | inet_ntop (AF_INET, | ||
160 | rec->data.raw.data, | ||
161 | buf, | ||
162 | sizeof (buf))); | ||
163 | break; | ||
164 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
165 | fprintf (stdout, | ||
166 | "%s AAAA %s\n", | ||
167 | req->hostname, | ||
168 | inet_ntop (AF_INET6, | ||
169 | rec->data.raw.data, | ||
170 | buf, | ||
171 | sizeof (buf))); | ||
172 | break; | ||
173 | case GNUNET_DNSPARSER_TYPE_NS: | ||
174 | fprintf (stdout, | ||
175 | "%s NS %s\n", | ||
176 | req->hostname, | ||
177 | rec->data.hostname); | ||
178 | break; | ||
179 | case GNUNET_DNSPARSER_TYPE_CNAME: | ||
180 | fprintf (stdout, | ||
181 | "%s CNAME %s\n", | ||
182 | req->hostname, | ||
183 | rec->data.hostname); | ||
184 | break; | ||
185 | case GNUNET_DNSPARSER_TYPE_MX: | ||
186 | fprintf (stdout, | ||
187 | "%s MX %u %s\n", | ||
188 | req->hostname, | ||
189 | (unsigned int) rec->data.mx->preference, | ||
190 | rec->data.mx->mxhost); | ||
191 | break; | ||
192 | } | ||
193 | } | ||
85 | 194 | ||
86 | 195 | ||
87 | /** | 196 | /** |
@@ -104,12 +213,21 @@ process_result (void *cls, | |||
104 | if (NULL == dns) | 213 | if (NULL == dns) |
105 | { | 214 | { |
106 | /* stub gave up */ | 215 | /* stub gave up */ |
216 | pending--; | ||
107 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 217 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
108 | "Stub gave up on DNS reply for `%s'\n", | 218 | "Stub gave up on DNS reply for `%s'\n", |
109 | req->hostname); | 219 | req->hostname); |
110 | GNUNET_CONTAINER_DLL_remove (req_head, | 220 | GNUNET_CONTAINER_DLL_remove (req_head, |
111 | req_tail, | 221 | req_tail, |
112 | req); | 222 | req); |
223 | if (req->issue_num > MAX_RETRIES) | ||
224 | { | ||
225 | failures++; | ||
226 | GNUNET_free (req->hostname); | ||
227 | GNUNET_free (req->raw); | ||
228 | GNUNET_free (req); | ||
229 | return; | ||
230 | } | ||
113 | GNUNET_CONTAINER_DLL_insert_tail (req_head, | 231 | GNUNET_CONTAINER_DLL_insert_tail (req_head, |
114 | req_tail, | 232 | req_tail, |
115 | req); | 233 | req); |
@@ -118,6 +236,12 @@ process_result (void *cls, | |||
118 | } | 236 | } |
119 | if (req->id != dns->id) | 237 | if (req->id != dns->id) |
120 | return; | 238 | return; |
239 | pending--; | ||
240 | GNUNET_DNSSTUB_resolve_cancel (req->rs); | ||
241 | req->rs = NULL; | ||
242 | GNUNET_CONTAINER_DLL_remove (req_head, | ||
243 | req_tail, | ||
244 | req); | ||
121 | p = GNUNET_DNSPARSER_parse ((const char *) dns, | 245 | p = GNUNET_DNSPARSER_parse ((const char *) dns, |
122 | dns_len); | 246 | dns_len); |
123 | if (NULL == p) | 247 | if (NULL == p) |
@@ -125,60 +249,70 @@ process_result (void *cls, | |||
125 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 249 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
126 | "Failed to parse DNS reply for `%s'\n", | 250 | "Failed to parse DNS reply for `%s'\n", |
127 | req->hostname); | 251 | req->hostname); |
128 | GNUNET_CONTAINER_DLL_remove (req_head, | 252 | if (req->issue_num > MAX_RETRIES) |
129 | req_tail, | 253 | { |
130 | req); | 254 | failures++; |
255 | GNUNET_free (req->hostname); | ||
256 | GNUNET_free (req->raw); | ||
257 | GNUNET_free (req); | ||
258 | return; | ||
259 | } | ||
131 | GNUNET_CONTAINER_DLL_insert_tail (req_head, | 260 | GNUNET_CONTAINER_DLL_insert_tail (req_head, |
132 | req_tail, | 261 | req_tail, |
133 | req); | 262 | req); |
134 | GNUNET_DNSSTUB_resolve_cancel (req->rs); | ||
135 | req->rs = NULL; | ||
136 | return; | 263 | return; |
137 | } | 264 | } |
138 | for (unsigned int i=0;i<p->num_answers;i++) | 265 | for (unsigned int i=0;i<p->num_answers;i++) |
139 | { | 266 | { |
140 | struct GNUNET_DNSPARSER_Record *rs = &p->answers[i]; | 267 | struct GNUNET_DNSPARSER_Record *rs = &p->answers[i]; |
141 | char buf[INET_ADDRSTRLEN]; | ||
142 | 268 | ||
143 | switch (rs->type) | 269 | process_record (req, |
144 | { | 270 | rs); |
145 | case GNUNET_DNSPARSER_TYPE_A: | 271 | } |
146 | fprintf (stdout, | 272 | for (unsigned int i=0;i<p->num_authority_records;i++) |
147 | "%s %s\n", | 273 | { |
148 | req->hostname, | 274 | struct GNUNET_DNSPARSER_Record *rs = &p->authority_records[i]; |
149 | inet_ntop (AF_INET, | 275 | |
150 | rs->data.raw.data, | 276 | process_record (req, |
151 | buf, | 277 | rs); |
152 | sizeof (buf))); | 278 | } |
153 | break; | 279 | for (unsigned int i=0;i<p->num_additional_records;i++) |
154 | } | 280 | { |
281 | struct GNUNET_DNSPARSER_Record *rs = &p->additional_records[i]; | ||
282 | |||
283 | process_record (req, | ||
284 | rs); | ||
155 | } | 285 | } |
156 | GNUNET_DNSPARSER_free_packet (p); | 286 | 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); | 287 | GNUNET_free (req->hostname); |
163 | GNUNET_free (req->raw); | 288 | GNUNET_free (req->raw); |
164 | GNUNET_free (req); | 289 | GNUNET_free (req); |
165 | } | 290 | } |
166 | 291 | ||
167 | 292 | ||
168 | static void | 293 | /** |
294 | * Submit a request to DNS unless we need to slow down because | ||
295 | * we are at the rate limit. | ||
296 | * | ||
297 | * @param req request to submit | ||
298 | * @return #GNUNET_OK if request was submitted | ||
299 | * #GNUNET_NO if request was already submitted | ||
300 | * #GNUNET_SYSERR if we are at the rate limit | ||
301 | */ | ||
302 | static int | ||
169 | submit_req (struct Request *req) | 303 | submit_req (struct Request *req) |
170 | { | 304 | { |
171 | static struct timeval last_request; | 305 | static struct timeval last_request; |
172 | struct timeval now; | 306 | struct timeval now; |
173 | 307 | ||
174 | if (NULL != req->rs) | 308 | if (NULL != req->rs) |
175 | return; /* already submitted */ | 309 | return GNUNET_NO; /* already submitted */ |
176 | gettimeofday (&now, | 310 | gettimeofday (&now, |
177 | NULL); | 311 | NULL); |
178 | if ( ( ( (now.tv_sec - last_request.tv_sec) == 0) && | 312 | if ( ( ( (now.tv_sec - last_request.tv_sec) == 0) && |
179 | ( (now.tv_usec - last_request.tv_usec) < TIME_THRESH) ) || | 313 | ( (now.tv_usec - last_request.tv_usec) < TIME_THRESH) ) || |
180 | (pending >= THRESH) ) | 314 | (pending >= THRESH) ) |
181 | return; | 315 | return GNUNET_SYSERR; |
182 | GNUNET_assert (NULL == req->rs); | 316 | GNUNET_assert (NULL == req->rs); |
183 | req->rs = GNUNET_DNSSTUB_resolve2 (ctx, | 317 | req->rs = GNUNET_DNSSTUB_resolve2 (ctx, |
184 | req->raw, | 318 | req->raw, |
@@ -186,40 +320,83 @@ submit_req (struct Request *req) | |||
186 | &process_result, | 320 | &process_result, |
187 | req); | 321 | req); |
188 | GNUNET_assert (NULL != req->rs); | 322 | GNUNET_assert (NULL != req->rs); |
323 | req->issue_num++; | ||
189 | last_request = now; | 324 | last_request = now; |
190 | lookups++; | 325 | lookups++; |
191 | pending++; | 326 | pending++; |
192 | req->time = time (NULL); | 327 | req->time = time (NULL); |
328 | return GNUNET_OK; | ||
193 | } | 329 | } |
194 | 330 | ||
195 | 331 | ||
332 | /** | ||
333 | * Process as many requests as possible from the queue. | ||
334 | * | ||
335 | * @param cls NULL | ||
336 | */ | ||
196 | static void | 337 | static void |
197 | process_queue() | 338 | process_queue(void *cls) |
198 | { | 339 | { |
199 | struct Request *wl = wl = req_head; | 340 | (void) cls; |
200 | 341 | t = NULL; | |
201 | if ( (pending < THRESH) && | 342 | for (struct Request *req = req_head; |
202 | (NULL != wl) ) | 343 | NULL != req; |
344 | req = req->next) | ||
203 | { | 345 | { |
204 | struct Request *req = wl; | 346 | if (GNUNET_SYSERR == submit_req (req)) |
347 | break; | ||
348 | } | ||
349 | if (NULL != req_head) | ||
350 | t = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | ||
351 | &process_queue, | ||
352 | NULL); | ||
353 | else | ||
354 | GNUNET_SCHEDULER_shutdown (); | ||
355 | } | ||
356 | |||
205 | 357 | ||
206 | wl = req->next; | 358 | /** |
207 | submit_req (req); | 359 | * Clean up and terminate the process. |
360 | * | ||
361 | * @param cls NULL | ||
362 | */ | ||
363 | static void | ||
364 | do_shutdown (void *cls) | ||
365 | { | ||
366 | (void) cls; | ||
367 | if (NULL != t) | ||
368 | { | ||
369 | GNUNET_SCHEDULER_cancel (t); | ||
370 | t = NULL; | ||
208 | } | 371 | } |
372 | GNUNET_DNSSTUB_stop (ctx); | ||
373 | ctx = NULL; | ||
209 | } | 374 | } |
210 | 375 | ||
211 | 376 | ||
377 | /** | ||
378 | * Process requests from the queue, then if the queue is | ||
379 | * not empty, try again. | ||
380 | * | ||
381 | * @param cls NULL | ||
382 | */ | ||
212 | static void | 383 | static void |
213 | run (void *cls) | 384 | run (void *cls) |
214 | { | 385 | { |
215 | process_queue (); | 386 | (void) cls; |
216 | if (NULL != req_head) | 387 | |
217 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | 388 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, |
218 | &run, | 389 | NULL); |
219 | NULL); | 390 | t = GNUNET_SCHEDULER_add_now (&process_queue, |
391 | NULL); | ||
220 | } | 392 | } |
221 | 393 | ||
222 | 394 | ||
395 | /** | ||
396 | * Add @a hostname to the list of requests to be made. | ||
397 | * | ||
398 | * @param hostname name to resolve | ||
399 | */ | ||
223 | static void | 400 | static void |
224 | queue (const char *hostname) | 401 | queue (const char *hostname) |
225 | { | 402 | { |
@@ -238,10 +415,12 @@ queue (const char *hostname) | |||
238 | return; | 415 | return; |
239 | } | 416 | } |
240 | q.name = (char *) hostname; | 417 | q.name = (char *) hostname; |
241 | q.type = GNUNET_DNSPARSER_TYPE_ANY; | 418 | q.type = GNUNET_DNSPARSER_TYPE_NS; |
242 | q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET; | 419 | q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET; |
243 | 420 | ||
244 | memset (&p, 0, sizeof (p)); | 421 | memset (&p, |
422 | 0, | ||
423 | sizeof (p)); | ||
245 | p.num_queries = 1; | 424 | p.num_queries = 1; |
246 | p.queries = &q; | 425 | p.queries = &q; |
247 | p.id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, | 426 | p.id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, |
@@ -270,6 +449,13 @@ queue (const char *hostname) | |||
270 | } | 449 | } |
271 | 450 | ||
272 | 451 | ||
452 | /** | ||
453 | * Call with IP address of resolver to query. | ||
454 | * | ||
455 | * @param argc should be 2 | ||
456 | * @param argv[1] should contain IP address | ||
457 | * @return 0 on success | ||
458 | */ | ||
273 | int | 459 | int |
274 | main (int argc, | 460 | main (int argc, |
275 | char **argv) | 461 | char **argv) |
@@ -300,9 +486,11 @@ main (int argc, | |||
300 | } | 486 | } |
301 | GNUNET_SCHEDULER_run (&run, | 487 | GNUNET_SCHEDULER_run (&run, |
302 | NULL); | 488 | NULL); |
303 | GNUNET_DNSSTUB_stop (ctx); | 489 | fprintf (stderr, |
304 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 490 | "Did %u lookups, found %u records, %u lookups failed, %u pending on shutdown\n", |
305 | "Did %u lookups\n", | 491 | lookups, |
306 | lookups); | 492 | records, |
493 | failures, | ||
494 | pending); | ||
307 | return 0; | 495 | return 0; |
308 | } | 496 | } |