aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/man/gnunet-zoneimport.12
-rw-r--r--src/namestore/gnunet-zoneimport.c243
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
19gnunet\-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. 19gnunet\-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
21Finally, gnunet\-zoneimport keeps information for each domain name in memory. This consumes about 200 bytes per label, or 2 GB for 10 million labels. 21Finally, 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 */
109struct Request 111struct 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 */
314static const char *
315get_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 */
348static void *
349build_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 */
626struct 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 */
564static void 647static void
565process_record (void *cls, 648process_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,
1226static void 1324static void
1227queue (const char *hostname) 1325queue (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,