diff options
-rw-r--r-- | doc/man/gnunet-zoneimport.1 | 2 | ||||
-rw-r--r-- | src/namestore/gnunet-zoneimport.c | 243 |
2 files changed, 158 insertions, 87 deletions
diff --git a/doc/man/gnunet-zoneimport.1 b/doc/man/gnunet-zoneimport.1 index afe3354e6..687e6f900 100644 --- a/doc/man/gnunet-zoneimport.1 +++ b/doc/man/gnunet-zoneimport.1 | |||
@@ -18,7 +18,7 @@ gnunet\-zoneimport will issue many DNS queries in parallel, but is rate-limited | |||
18 | 18 | ||
19 | gnunet\-zoneimport operates incrementally. It will check if the namestore already has (non-expired) records stored for a given name in the respective zone and not issue those requests again. Thus, it is fine to restart gnunet\-zoneimport whenever the list of domain names changes. | 19 | gnunet\-zoneimport operates incrementally. It will check if the namestore already has (non-expired) records stored for a given name in the respective zone and not issue those requests again. Thus, it is fine to restart gnunet\-zoneimport whenever the list of domain names changes. |
20 | 20 | ||
21 | Finally, gnunet\-zoneimport keeps information for each domain name in memory. This consumes about 200 bytes per label, or 2 GB for 10 million labels. | 21 | Finally, gnunet\-zoneimport keeps information for each domain name in memory. This consumes about 200 bytes per domain name, or 1 GB for 5 million labels. |
22 | 22 | ||
23 | .SH OPTIONS | 23 | .SH OPTIONS |
24 | .B | 24 | .B |
diff --git a/src/namestore/gnunet-zoneimport.c b/src/namestore/gnunet-zoneimport.c index bcc82607e..d57bb938d 100644 --- a/src/namestore/gnunet-zoneimport.c +++ b/src/namestore/gnunet-zoneimport.c | |||
@@ -104,7 +104,9 @@ struct Record | |||
104 | 104 | ||
105 | 105 | ||
106 | /** | 106 | /** |
107 | * Request we should make. | 107 | * Request we should make. We keep this struct in memory per request, |
108 | * thus optimizing it is crucial for the overall memory consumption of | ||
109 | * the zone importer. | ||
108 | */ | 110 | */ |
109 | struct Request | 111 | struct Request |
110 | { | 112 | { |
@@ -141,21 +143,13 @@ struct Request | |||
141 | struct GNUNET_DNSSTUB_RequestSocket *rs; | 143 | struct GNUNET_DNSSTUB_RequestSocket *rs; |
142 | 144 | ||
143 | /** | 145 | /** |
144 | * Raw DNS query. | 146 | * Hostname we are resolving, allocated at the end of |
145 | */ | 147 | * this struct (optimizing memory consumption by reducing |
146 | void *raw; | 148 | * total number of allocations). |
147 | |||
148 | /** | ||
149 | * Hostname we are resolving. | ||
150 | */ | 149 | */ |
151 | char *hostname; | 150 | char *hostname; |
152 | 151 | ||
153 | /** | 152 | /** |
154 | * Label (without TLD) which we are resolving. | ||
155 | */ | ||
156 | char *label; | ||
157 | |||
158 | /** | ||
159 | * Namestore operation pending for this record. | 153 | * Namestore operation pending for this record. |
160 | */ | 154 | */ |
161 | struct GNUNET_NAMESTORE_QueueEntry *qe; | 155 | struct GNUNET_NAMESTORE_QueueEntry *qe; |
@@ -166,12 +160,6 @@ struct Request | |||
166 | const struct Zone *zone; | 160 | const struct Zone *zone; |
167 | 161 | ||
168 | /** | 162 | /** |
169 | * Answer we got back and are currently parsing, or NULL | ||
170 | * if not active. | ||
171 | */ | ||
172 | struct GNUNET_DNSPARSER_Packet *p; | ||
173 | |||
174 | /** | ||
175 | * At what time does the (earliest) of the returned records | 163 | * At what time does the (earliest) of the returned records |
176 | * for this name expire? At this point, we need to re-fetch | 164 | * for this name expire? At this point, we need to re-fetch |
177 | * the record. | 165 | * the record. |
@@ -179,20 +167,10 @@ struct Request | |||
179 | struct GNUNET_TIME_Absolute expires; | 167 | struct GNUNET_TIME_Absolute expires; |
180 | 168 | ||
181 | /** | 169 | /** |
182 | * Number of bytes in @e raw. | ||
183 | */ | ||
184 | size_t raw_len; | ||
185 | |||
186 | /** | ||
187 | * When did we last issue this request? | ||
188 | */ | ||
189 | time_t time; | ||
190 | |||
191 | /** | ||
192 | * How often did we issue this query? (And failed, reset | 170 | * How often did we issue this query? (And failed, reset |
193 | * to zero once we were successful.) | 171 | * to zero once we were successful.) |
194 | */ | 172 | */ |
195 | int issue_num; | 173 | unsigned int issue_num; |
196 | 174 | ||
197 | /** | 175 | /** |
198 | * random 16-bit DNS query identifier. | 176 | * random 16-bit DNS query identifier. |
@@ -327,6 +305,96 @@ for_all_records (const struct GNUNET_DNSPARSER_Packet *p, | |||
327 | 305 | ||
328 | 306 | ||
329 | /** | 307 | /** |
308 | * Return just the label of the hostname in @a req. | ||
309 | * | ||
310 | * @param req request to process hostname of | ||
311 | * @return statically allocated pointer to the label, | ||
312 | * overwritten upon the next request! | ||
313 | */ | ||
314 | static const char * | ||
315 | get_label (struct Request *req) | ||
316 | { | ||
317 | static char label[64]; | ||
318 | const char *dot; | ||
319 | |||
320 | dot = strchr (req->hostname, | ||
321 | (unsigned char) '.'); | ||
322 | if (NULL == dot) | ||
323 | { | ||
324 | GNUNET_break (0); | ||
325 | return NULL; | ||
326 | } | ||
327 | if (((size_t) (dot - req->hostname)) >= sizeof (label)) | ||
328 | { | ||
329 | GNUNET_break (0); | ||
330 | return NULL; | ||
331 | } | ||
332 | memcpy (label, | ||
333 | req->hostname, | ||
334 | dot - req->hostname); | ||
335 | label[dot - req->hostname] = '\0'; | ||
336 | return label; | ||
337 | } | ||
338 | |||
339 | |||
340 | /** | ||
341 | * Build DNS query for @a hostname. | ||
342 | * | ||
343 | * @param hostname host to build query for | ||
344 | * @param raw_size[out] number of bytes in the query | ||
345 | * @return NULL on error, otherwise pointer to statically (!) | ||
346 | * allocated query buffer | ||
347 | */ | ||
348 | static void * | ||
349 | build_dns_query (struct Request *req, | ||
350 | size_t *raw_size) | ||
351 | { | ||
352 | static char raw[512]; | ||
353 | char *rawp; | ||
354 | struct GNUNET_DNSPARSER_Packet p; | ||
355 | struct GNUNET_DNSPARSER_Query q; | ||
356 | |||
357 | q.name = (char *) req->hostname; | ||
358 | q.type = GNUNET_DNSPARSER_TYPE_NS; | ||
359 | q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET; | ||
360 | |||
361 | memset (&p, | ||
362 | 0, | ||
363 | sizeof (p)); | ||
364 | p.num_queries = 1; | ||
365 | p.queries = &q; | ||
366 | p.id = req->id; | ||
367 | if (GNUNET_OK != | ||
368 | GNUNET_DNSPARSER_pack (&p, | ||
369 | UINT16_MAX, | ||
370 | &rawp, | ||
371 | raw_size)) | ||
372 | { | ||
373 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
374 | "Failed to pack query for hostname `%s'\n", | ||
375 | req->hostname); | ||
376 | rejects++; | ||
377 | return NULL; | ||
378 | } | ||
379 | if (*raw_size > sizeof (raw)) | ||
380 | { | ||
381 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
382 | "Failed to pack query for hostname `%s'\n", | ||
383 | req->hostname); | ||
384 | rejects++; | ||
385 | GNUNET_break (0); | ||
386 | GNUNET_free (rawp); | ||
387 | return NULL; | ||
388 | } | ||
389 | memcpy (raw, | ||
390 | rawp, | ||
391 | *raw_size); | ||
392 | GNUNET_free (rawp); | ||
393 | return raw; | ||
394 | } | ||
395 | |||
396 | |||
397 | /** | ||
330 | * Free @a req and data structures reachable from it. | 398 | * Free @a req and data structures reachable from it. |
331 | * | 399 | * |
332 | * @param req request to free | 400 | * @param req request to free |
@@ -343,9 +411,6 @@ free_request (struct Request *req) | |||
343 | rec); | 411 | rec); |
344 | GNUNET_free (rec); | 412 | GNUNET_free (rec); |
345 | } | 413 | } |
346 | GNUNET_free (req->hostname); | ||
347 | GNUNET_free (req->label); | ||
348 | GNUNET_free (req->raw); | ||
349 | GNUNET_free (req); | 414 | GNUNET_free (req); |
350 | } | 415 | } |
351 | 416 | ||
@@ -556,16 +621,35 @@ check_for_glue (void *cls, | |||
556 | 621 | ||
557 | 622 | ||
558 | /** | 623 | /** |
624 | * Closure for #process_record(). | ||
625 | */ | ||
626 | struct ProcessRecordContext | ||
627 | { | ||
628 | /** | ||
629 | * Answer we got back and are currently parsing, or NULL | ||
630 | * if not active. | ||
631 | */ | ||
632 | struct GNUNET_DNSPARSER_Packet *p; | ||
633 | |||
634 | /** | ||
635 | * Request we are processing. | ||
636 | */ | ||
637 | struct Request *req; | ||
638 | }; | ||
639 | |||
640 | |||
641 | /** | ||
559 | * We received @a rec for @a req. Remember the answer. | 642 | * We received @a rec for @a req. Remember the answer. |
560 | * | 643 | * |
561 | * @param cls a `struct Request` | 644 | * @param cls a `struct ProcessRecordContext` |
562 | * @param rec response | 645 | * @param rec response |
563 | */ | 646 | */ |
564 | static void | 647 | static void |
565 | process_record (void *cls, | 648 | process_record (void *cls, |
566 | const struct GNUNET_DNSPARSER_Record *rec) | 649 | const struct GNUNET_DNSPARSER_Record *rec) |
567 | { | 650 | { |
568 | struct Request *req = cls; | 651 | struct ProcessRecordContext *prc = cls; |
652 | struct Request *req = prc->req; | ||
569 | char dst[65536]; | 653 | char dst[65536]; |
570 | size_t dst_len; | 654 | size_t dst_len; |
571 | size_t off; | 655 | size_t off; |
@@ -602,7 +686,7 @@ process_record (void *cls, | |||
602 | gc.req = req; | 686 | gc.req = req; |
603 | gc.ns = rec->data.hostname; | 687 | gc.ns = rec->data.hostname; |
604 | gc.found = GNUNET_NO; | 688 | gc.found = GNUNET_NO; |
605 | for_all_records (req->p, | 689 | for_all_records (prc->p, |
606 | &check_for_glue, | 690 | &check_for_glue, |
607 | &gc); | 691 | &gc); |
608 | if ( (GNUNET_NO == gc.found) && | 692 | if ( (GNUNET_NO == gc.found) && |
@@ -803,7 +887,7 @@ store_completed_cb (void *cls, | |||
803 | { | 887 | { |
804 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 888 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
805 | "Stored records under `%s'\n", | 889 | "Stored records under `%s'\n", |
806 | req->label); | 890 | req->hostname); |
807 | pdot++; | 891 | pdot++; |
808 | if (0 == pdot % 1000) | 892 | if (0 == pdot % 1000) |
809 | fprintf (stderr, "."); | 893 | fprintf (stderr, "."); |
@@ -884,11 +968,16 @@ process_result (void *cls, | |||
884 | } | 968 | } |
885 | /* import new records */ | 969 | /* import new records */ |
886 | req->issue_num = 0; /* success, reset counter! */ | 970 | req->issue_num = 0; /* success, reset counter! */ |
887 | req->p = p; | 971 | { |
888 | for_all_records (p, | 972 | struct ProcessRecordContext prc = { |
889 | &process_record, | 973 | .req = req, |
890 | req); | 974 | .p = p |
891 | req->p = NULL; | 975 | }; |
976 | |||
977 | for_all_records (p, | ||
978 | &process_record, | ||
979 | &prc); | ||
980 | } | ||
892 | GNUNET_DNSPARSER_free_packet (p); | 981 | GNUNET_DNSPARSER_free_packet (p); |
893 | /* count records found, determine minimum expiration time */ | 982 | /* count records found, determine minimum expiration time */ |
894 | req->expires = GNUNET_TIME_UNIT_FOREVER_ABS; | 983 | req->expires = GNUNET_TIME_UNIT_FOREVER_ABS; |
@@ -921,7 +1010,7 @@ process_result (void *cls, | |||
921 | rd[off++] = rec->grd; | 1010 | rd[off++] = rec->grd; |
922 | req->qe = GNUNET_NAMESTORE_records_store (ns, | 1011 | req->qe = GNUNET_NAMESTORE_records_store (ns, |
923 | &req->zone->key, | 1012 | &req->zone->key, |
924 | req->label, | 1013 | get_label (req), |
925 | rd_count, | 1014 | rd_count, |
926 | rd, | 1015 | rd, |
927 | &store_completed_cb, | 1016 | &store_completed_cb, |
@@ -945,6 +1034,8 @@ submit_req (struct Request *req) | |||
945 | { | 1034 | { |
946 | static struct GNUNET_TIME_Absolute last_request; | 1035 | static struct GNUNET_TIME_Absolute last_request; |
947 | struct GNUNET_TIME_Absolute now; | 1036 | struct GNUNET_TIME_Absolute now; |
1037 | void *raw; | ||
1038 | size_t raw_size; | ||
948 | 1039 | ||
949 | if (NULL != req->qe) | 1040 | if (NULL != req->qe) |
950 | return GNUNET_NO; /* namestore op still pending */ | 1041 | return GNUNET_NO; /* namestore op still pending */ |
@@ -964,9 +1055,17 @@ submit_req (struct Request *req) | |||
964 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1055 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
965 | "Requesting resolution for `%s'\n", | 1056 | "Requesting resolution for `%s'\n", |
966 | req->hostname); | 1057 | req->hostname); |
1058 | raw = build_dns_query (req, | ||
1059 | &raw_size); | ||
1060 | if (NULL == raw) | ||
1061 | { | ||
1062 | GNUNET_break (0); | ||
1063 | free_request (req); | ||
1064 | return GNUNET_SYSERR; | ||
1065 | } | ||
967 | req->rs = GNUNET_DNSSTUB_resolve (ctx, | 1066 | req->rs = GNUNET_DNSSTUB_resolve (ctx, |
968 | req->raw, | 1067 | raw, |
969 | req->raw_len, | 1068 | raw_size, |
970 | &process_result, | 1069 | &process_result, |
971 | req); | 1070 | req); |
972 | GNUNET_assert (NULL != req->rs); | 1071 | GNUNET_assert (NULL != req->rs); |
@@ -974,7 +1073,6 @@ submit_req (struct Request *req) | |||
974 | last_request = now; | 1073 | last_request = now; |
975 | lookups++; | 1074 | lookups++; |
976 | pending++; | 1075 | pending++; |
977 | req->time = time (NULL); | ||
978 | return GNUNET_OK; | 1076 | return GNUNET_OK; |
979 | } | 1077 | } |
980 | 1078 | ||
@@ -1137,7 +1235,7 @@ ns_lookup_error_cb (void *cls) | |||
1137 | req->qe = NULL; | 1235 | req->qe = NULL; |
1138 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1236 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1139 | "Failed to load data from namestore for `%s'\n", | 1237 | "Failed to load data from namestore for `%s'\n", |
1140 | req->label); | 1238 | req->hostname); |
1141 | insert_sorted (req); | 1239 | insert_sorted (req); |
1142 | pending--; | 1240 | pending--; |
1143 | continue_stdin (); | 1241 | continue_stdin (); |
@@ -1168,7 +1266,7 @@ ns_lookup_result_cb (void *cls, | |||
1168 | &req->zone->key, | 1266 | &req->zone->key, |
1169 | sizeof (*zone))); | 1267 | sizeof (*zone))); |
1170 | GNUNET_break (0 == strcasecmp (label, | 1268 | GNUNET_break (0 == strcasecmp (label, |
1171 | req->label)); | 1269 | get_label (req))); |
1172 | for (unsigned int i=0;i<rd_count;i++) | 1270 | for (unsigned int i=0;i<rd_count;i++) |
1173 | { | 1271 | { |
1174 | struct GNUNET_TIME_Absolute at; | 1272 | struct GNUNET_TIME_Absolute at; |
@@ -1184,7 +1282,7 @@ ns_lookup_result_cb (void *cls, | |||
1184 | { | 1282 | { |
1185 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1283 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1186 | "Empty record set in namestore for `%s'\n", | 1284 | "Empty record set in namestore for `%s'\n", |
1187 | req->label); | 1285 | req->hostname); |
1188 | } | 1286 | } |
1189 | else | 1287 | else |
1190 | { | 1288 | { |
@@ -1207,7 +1305,7 @@ ns_lookup_result_cb (void *cls, | |||
1207 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1305 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1208 | "Hot-start with %u existing records for `%s'\n", | 1306 | "Hot-start with %u existing records for `%s'\n", |
1209 | pos, | 1307 | pos, |
1210 | req->label); | 1308 | req->hostname); |
1211 | } | 1309 | } |
1212 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1310 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1213 | "Adding `%s' to worklist to start at %s\n", | 1311 | "Adding `%s' to worklist to start at %s\n", |
@@ -1226,13 +1324,10 @@ ns_lookup_result_cb (void *cls, | |||
1226 | static void | 1324 | static void |
1227 | queue (const char *hostname) | 1325 | queue (const char *hostname) |
1228 | { | 1326 | { |
1229 | struct GNUNET_DNSPARSER_Packet p; | ||
1230 | struct GNUNET_DNSPARSER_Query q; | ||
1231 | struct Request *req; | 1327 | struct Request *req; |
1232 | char *raw; | ||
1233 | size_t raw_size; | ||
1234 | const char *dot; | 1328 | const char *dot; |
1235 | struct Zone *zone; | 1329 | struct Zone *zone; |
1330 | size_t hlen; | ||
1236 | 1331 | ||
1237 | if (GNUNET_OK != | 1332 | if (GNUNET_OK != |
1238 | GNUNET_DNSPARSER_check_name (hostname)) | 1333 | GNUNET_DNSPARSER_check_name (hostname)) |
@@ -1268,44 +1363,20 @@ queue (const char *hostname) | |||
1268 | continue_stdin (); | 1363 | continue_stdin (); |
1269 | return; | 1364 | return; |
1270 | } | 1365 | } |
1271 | q.name = (char *) hostname; | ||
1272 | q.type = GNUNET_DNSPARSER_TYPE_NS; | ||
1273 | q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET; | ||
1274 | |||
1275 | memset (&p, | ||
1276 | 0, | ||
1277 | sizeof (p)); | ||
1278 | p.num_queries = 1; | ||
1279 | p.queries = &q; | ||
1280 | p.id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, | ||
1281 | UINT16_MAX); | ||
1282 | |||
1283 | if (GNUNET_OK != | ||
1284 | GNUNET_DNSPARSER_pack (&p, | ||
1285 | UINT16_MAX, | ||
1286 | &raw, | ||
1287 | &raw_size)) | ||
1288 | { | ||
1289 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1290 | "Failed to pack query for hostname `%s'\n", | ||
1291 | hostname); | ||
1292 | rejects++; | ||
1293 | continue_stdin (); | ||
1294 | return; | ||
1295 | } | ||
1296 | 1366 | ||
1297 | pending++; | 1367 | pending++; |
1298 | req = GNUNET_new (struct Request); | 1368 | hlen = strlen (hostname) + 1; |
1369 | req = GNUNET_malloc (sizeof (struct Request) + hlen); | ||
1299 | req->zone = zone; | 1370 | req->zone = zone; |
1300 | req->hostname = GNUNET_strdup (hostname); | 1371 | req->hostname = (char *) &req[1]; |
1301 | req->raw = raw; | 1372 | memcpy (req->hostname, |
1302 | req->raw_len = raw_size; | 1373 | hostname, |
1303 | req->id = p.id; | 1374 | hlen); |
1304 | req->label = GNUNET_strndup (hostname, | 1375 | req->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, |
1305 | dot - hostname); | 1376 | UINT16_MAX); |
1306 | req->qe = GNUNET_NAMESTORE_records_lookup (ns, | 1377 | req->qe = GNUNET_NAMESTORE_records_lookup (ns, |
1307 | &req->zone->key, | 1378 | &req->zone->key, |
1308 | req->label, | 1379 | get_label (req), |
1309 | &ns_lookup_error_cb, | 1380 | &ns_lookup_error_cb, |
1310 | req, | 1381 | req, |
1311 | &ns_lookup_result_cb, | 1382 | &ns_lookup_result_cb, |