aboutsummaryrefslogtreecommitdiff
path: root/src/dns
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-04-06 19:37:53 +0200
committerChristian Grothoff <christian@grothoff.org>2018-04-06 19:37:53 +0200
commit5bed6253dcde97fd7d6ea45d91d3ff95141d0fb7 (patch)
tree585a4f2550efe83fae029e3cdb5421b0f1f93779 /src/dns
parent1f754809a913093ba215b6b6689d28b7dfb66e4c (diff)
downloadgnunet-5bed6253dcde97fd7d6ea45d91d3ff95141d0fb7.tar.gz
gnunet-5bed6253dcde97fd7d6ea45d91d3ff95141d0fb7.zip
complete importer
Diffstat (limited to 'src/dns')
-rw-r--r--src/dns/dnsstub.c9
-rw-r--r--src/dns/gnunet-zoneimport.c304
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 */
31struct Request 34struct 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 */
56static struct GNUNET_DNSSTUB_Context *ctx; 86static 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 */
59static unsigned int pending; 91static unsigned int pending;
60 92
93/**
94 * Number of lookups we performed overall.
95 */
61static unsigned int lookups; 96static unsigned int lookups;
62 97
98/**
99 * Number of lookups that failed.
100 */
101static unsigned int failures;
102
103/**
104 * Number of records we found.
105 */
106static unsigned int records;
107
108/**
109 * Head of DLL of all requests to perform.
110 */
63static struct Request *req_head; 111static struct Request *req_head;
64 112
113/**
114 * Tail of DLL of all requests to perform.
115 */
65static struct Request *req_tail; 116static struct Request *req_tail;
66 117
67// the number of queries that are outstanding 118/**
68static unsigned int pending; 119 * Main task.
69 120 */
70static unsigned int lookups; 121static 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 */
146static void
147process_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
168static 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 */
302static int
169submit_req (struct Request *req) 303submit_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 */
196static void 337static void
197process_queue() 338process_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 */
363static void
364do_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 */
212static void 383static void
213run (void *cls) 384run (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 */
223static void 400static void
224queue (const char *hostname) 401queue (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 */
273int 459int
274main (int argc, 460main (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}