diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-10-18 15:55:30 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-10-18 15:55:30 +0200 |
commit | e76f4a66930043ede71300fffe38ab48746ca5b5 (patch) | |
tree | 46c819e569b08775072aaa79274c3de382e3401a /src | |
parent | c7c6446e3ea37531b67252a452937f3578570a57 (diff) | |
download | gnunet-e76f4a66930043ede71300fffe38ab48746ca5b5.tar.gz gnunet-e76f4a66930043ede71300fffe38ab48746ca5b5.zip |
add support for /etc/hosts
Diffstat (limited to 'src')
-rw-r--r-- | src/include/gnunet_disk_lib.h | 1 | ||||
-rw-r--r-- | src/util/gnunet-service-resolver.c | 264 |
2 files changed, 254 insertions, 11 deletions
diff --git a/src/include/gnunet_disk_lib.h b/src/include/gnunet_disk_lib.h index b7376b99b..950df5a4e 100644 --- a/src/include/gnunet_disk_lib.h +++ b/src/include/gnunet_disk_lib.h | |||
@@ -781,6 +781,7 @@ GNUNET_DISK_file_change_owner (const char *filename, | |||
781 | */ | 781 | */ |
782 | struct GNUNET_DISK_MapHandle; | 782 | struct GNUNET_DISK_MapHandle; |
783 | 783 | ||
784 | |||
784 | /** | 785 | /** |
785 | * Map a file into memory | 786 | * Map a file into memory |
786 | * @param h open file handle | 787 | * @param h open file handle |
diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c index 252408466..d907bd8d9 100644 --- a/src/util/gnunet-service-resolver.c +++ b/src/util/gnunet-service-resolver.c | |||
@@ -57,6 +57,7 @@ struct RecordListEntry | |||
57 | * Cached data. | 57 | * Cached data. |
58 | */ | 58 | */ |
59 | struct GNUNET_DNSPARSER_Record *record; | 59 | struct GNUNET_DNSPARSER_Record *record; |
60 | |||
60 | }; | 61 | }; |
61 | 62 | ||
62 | 63 | ||
@@ -165,6 +166,16 @@ static struct ResolveCache *cache_head; | |||
165 | static struct ResolveCache *cache_tail; | 166 | static struct ResolveCache *cache_tail; |
166 | 167 | ||
167 | /** | 168 | /** |
169 | * Head of the linked list of DNS lookup results from /etc/hosts. | ||
170 | */ | ||
171 | static struct ResolveCache *hosts_head; | ||
172 | |||
173 | /** | ||
174 | * Tail of the linked list of DNS lookup results from /etc/hosts. | ||
175 | */ | ||
176 | static struct ResolveCache *hosts_tail; | ||
177 | |||
178 | /** | ||
168 | * Start of the linked list of active DNS lookups. | 179 | * Start of the linked list of active DNS lookups. |
169 | */ | 180 | */ |
170 | static struct ActiveLookup *lookup_head; | 181 | static struct ActiveLookup *lookup_head; |
@@ -219,6 +230,34 @@ free_cache_entry (struct ResolveCache *rc) | |||
219 | 230 | ||
220 | 231 | ||
221 | /** | 232 | /** |
233 | * Remove @a entry from cache. | ||
234 | * | ||
235 | * @param rc entry to free | ||
236 | */ | ||
237 | static void | ||
238 | free_hosts_entry (struct ResolveCache *rc) | ||
239 | { | ||
240 | struct RecordListEntry *pos; | ||
241 | |||
242 | while (NULL != (pos = rc->records_head)) | ||
243 | { | ||
244 | GNUNET_CONTAINER_DLL_remove (rc->records_head, | ||
245 | rc->records_tail, | ||
246 | pos); | ||
247 | GNUNET_DNSPARSER_free_record (pos->record); | ||
248 | GNUNET_free (pos->record); | ||
249 | GNUNET_free (pos); | ||
250 | } | ||
251 | GNUNET_free_non_null (rc->hostname); | ||
252 | GNUNET_CONTAINER_DLL_remove (hosts_head, | ||
253 | hosts_tail, | ||
254 | rc); | ||
255 | cache_size--; | ||
256 | GNUNET_free (rc); | ||
257 | } | ||
258 | |||
259 | |||
260 | /** | ||
222 | * Release resources associated with @a al | 261 | * Release resources associated with @a al |
223 | * | 262 | * |
224 | * @param al an active lookup | 263 | * @param al an active lookup |
@@ -299,8 +338,9 @@ static int | |||
299 | lookup_dns_servers (char ***server_addrs) | 338 | lookup_dns_servers (char ***server_addrs) |
300 | { | 339 | { |
301 | struct GNUNET_DISK_FileHandle *fh; | 340 | struct GNUNET_DISK_FileHandle *fh; |
302 | char buf[2048]; | 341 | struct GNUNET_DISK_MapHandle *mh; |
303 | ssize_t bytes_read; | 342 | off_t bytes_read; |
343 | const char *buf; | ||
304 | size_t read_offset; | 344 | size_t read_offset; |
305 | unsigned int num_dns_servers; | 345 | unsigned int num_dns_servers; |
306 | 346 | ||
@@ -314,9 +354,28 @@ lookup_dns_servers (char ***server_addrs) | |||
314 | "DNS resolution will not be possible.\n"); | 354 | "DNS resolution will not be possible.\n"); |
315 | return -1; | 355 | return -1; |
316 | } | 356 | } |
317 | bytes_read = GNUNET_DISK_file_read (fh, | 357 | if (GNUNET_OK != |
318 | buf, | 358 | GNUNET_DISK_file_handle_size (fh, |
319 | sizeof (buf)); | 359 | &bytes_read)) |
360 | { | ||
361 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
362 | "Could not determine size of /etc/resolv.conf. " | ||
363 | "DNS resolution will not be possible.\n"); | ||
364 | GNUNET_DISK_file_close (fh); | ||
365 | return -1; | ||
366 | } | ||
367 | if (bytes_read > SIZE_MAX) | ||
368 | { | ||
369 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
370 | "/etc/resolv.conf file too large to mmap. " | ||
371 | "DNS resolution will not be possible.\n"); | ||
372 | GNUNET_DISK_file_close (fh); | ||
373 | return -1; | ||
374 | } | ||
375 | buf = GNUNET_DISK_file_map (fh, | ||
376 | &mh, | ||
377 | GNUNET_DISK_MAP_TYPE_READ, | ||
378 | (size_t) bytes_read); | ||
320 | *server_addrs = NULL; | 379 | *server_addrs = NULL; |
321 | read_offset = 0; | 380 | read_offset = 0; |
322 | num_dns_servers = 0; | 381 | num_dns_servers = 0; |
@@ -346,6 +405,7 @@ lookup_dns_servers (char ***server_addrs) | |||
346 | } | 405 | } |
347 | read_offset += line_len + 1; | 406 | read_offset += line_len + 1; |
348 | } | 407 | } |
408 | GNUNET_DISK_file_unmap (mh); | ||
349 | GNUNET_DISK_file_close (fh); | 409 | GNUNET_DISK_file_close (fh); |
350 | return (int) num_dns_servers; | 410 | return (int) num_dns_servers; |
351 | } | 411 | } |
@@ -534,9 +594,14 @@ remove_expired (struct ResolveCache *rc) | |||
534 | { | 594 | { |
535 | n = pos->next; | 595 | n = pos->next; |
536 | if (now.abs_value_us > pos->record->expiration_time.abs_value_us) | 596 | if (now.abs_value_us > pos->record->expiration_time.abs_value_us) |
597 | { | ||
537 | GNUNET_CONTAINER_DLL_remove (rc->records_head, | 598 | GNUNET_CONTAINER_DLL_remove (rc->records_head, |
538 | rc->records_tail, | 599 | rc->records_tail, |
539 | pos); | 600 | pos); |
601 | GNUNET_DNSPARSER_free_record (pos->record); | ||
602 | GNUNET_free (pos->record); | ||
603 | GNUNET_free (pos); | ||
604 | } | ||
540 | } | 605 | } |
541 | if (NULL == rc->records_head) | 606 | if (NULL == rc->records_head) |
542 | { | 607 | { |
@@ -584,15 +649,22 @@ try_cache (const char *hostname, | |||
584 | struct ResolveCache *next; | 649 | struct ResolveCache *next; |
585 | int found; | 650 | int found; |
586 | 651 | ||
587 | next = cache_head; | 652 | for (pos = hosts_head; NULL != pos; pos = pos->next) |
588 | for (pos = next; NULL != pos; pos = next) | ||
589 | { | ||
590 | next = pos->next; | ||
591 | if (GNUNET_YES == remove_expired (pos)) | ||
592 | continue; | ||
593 | if (0 == strcmp (pos->hostname, | 653 | if (0 == strcmp (pos->hostname, |
594 | hostname)) | 654 | hostname)) |
595 | break; | 655 | break; |
656 | if (NULL == pos) | ||
657 | { | ||
658 | next = cache_head; | ||
659 | for (pos = next; NULL != pos; pos = next) | ||
660 | { | ||
661 | next = pos->next; | ||
662 | if (GNUNET_YES == remove_expired (pos)) | ||
663 | continue; | ||
664 | if (0 == strcmp (pos->hostname, | ||
665 | hostname)) | ||
666 | break; | ||
667 | } | ||
596 | } | 668 | } |
597 | if (NULL == pos) | 669 | if (NULL == pos) |
598 | { | 670 | { |
@@ -853,6 +925,8 @@ handle_resolve_result (void *cls, | |||
853 | packet_size, | 925 | packet_size, |
854 | &handle_resolve_result, | 926 | &handle_resolve_result, |
855 | al); | 927 | al); |
928 | GNUNET_free (packet_buf); | ||
929 | GNUNET_DNSPARSER_free_packet (parsed); | ||
856 | return; | 930 | return; |
857 | } | 931 | } |
858 | } | 932 | } |
@@ -1169,7 +1243,174 @@ shutdown_task (void *cls) | |||
1169 | free_active_lookup (lookup_head); | 1243 | free_active_lookup (lookup_head); |
1170 | while (NULL != cache_head) | 1244 | while (NULL != cache_head) |
1171 | free_cache_entry (cache_head); | 1245 | free_cache_entry (cache_head); |
1246 | while (NULL != hosts_head) | ||
1247 | free_hosts_entry (hosts_head); | ||
1172 | GNUNET_DNSSTUB_stop (dnsstub_ctx); | 1248 | GNUNET_DNSSTUB_stop (dnsstub_ctx); |
1249 | GNUNET_free (my_domain); | ||
1250 | } | ||
1251 | |||
1252 | |||
1253 | /** | ||
1254 | * Add information about a host from /etc/hosts | ||
1255 | * to our cache. | ||
1256 | * | ||
1257 | * @param hostname the name of the host | ||
1258 | * @param rec_type DNS record type to use | ||
1259 | * @param data payload | ||
1260 | * @param data_size number of bytes in @a data | ||
1261 | */ | ||
1262 | static void | ||
1263 | add_host (const char *hostname, | ||
1264 | uint16_t rec_type, | ||
1265 | const void *data, | ||
1266 | size_t data_size) | ||
1267 | { | ||
1268 | struct ResolveCache *rc; | ||
1269 | struct RecordListEntry *rle; | ||
1270 | struct GNUNET_DNSPARSER_Record *rec; | ||
1271 | |||
1272 | rec = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_Record)); | ||
1273 | rec->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
1274 | rec->type = rec_type; | ||
1275 | rec->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET; | ||
1276 | rec->name = GNUNET_strdup (hostname); | ||
1277 | rec->data.raw.data = GNUNET_memdup (data, | ||
1278 | data_size); | ||
1279 | rec->data.raw.data_len = data_size; | ||
1280 | rle = GNUNET_new (struct RecordListEntry); | ||
1281 | rle->record = rec; | ||
1282 | rc = GNUNET_new (struct ResolveCache); | ||
1283 | rc->hostname = GNUNET_strdup (hostname); | ||
1284 | GNUNET_CONTAINER_DLL_insert (rc->records_head, | ||
1285 | rc->records_tail, | ||
1286 | rle); | ||
1287 | GNUNET_CONTAINER_DLL_insert (hosts_head, | ||
1288 | hosts_tail, | ||
1289 | rc); | ||
1290 | } | ||
1291 | |||
1292 | |||
1293 | /** | ||
1294 | * Extract host information from a line in /etc/hosts | ||
1295 | * | ||
1296 | * @param line the line to parse | ||
1297 | * @param line_len number of bytes in @a line | ||
1298 | */ | ||
1299 | static void | ||
1300 | extract_hosts (const char *line, | ||
1301 | size_t line_len) | ||
1302 | { | ||
1303 | const char *c; | ||
1304 | struct in_addr v4; | ||
1305 | struct in6_addr v6; | ||
1306 | char *tbuf; | ||
1307 | char *tok; | ||
1308 | |||
1309 | /* ignore everything after '#' */ | ||
1310 | c = memrchr (line, | ||
1311 | (unsigned char) '#', | ||
1312 | line_len); | ||
1313 | if (NULL != c) | ||
1314 | line_len = c - line; | ||
1315 | /* ignore leading whitespace */ | ||
1316 | while ( (0 > line_len) && | ||
1317 | isspace ((unsigned char) *line) ) | ||
1318 | { | ||
1319 | line++; | ||
1320 | line_len--; | ||
1321 | } | ||
1322 | tbuf = GNUNET_strndup (line, | ||
1323 | line_len); | ||
1324 | tok = strtok (tbuf, " \t"); | ||
1325 | if (NULL == tok) | ||
1326 | { | ||
1327 | GNUNET_free (tbuf); | ||
1328 | return; | ||
1329 | } | ||
1330 | if (1 == inet_pton (AF_INET, | ||
1331 | tok, | ||
1332 | &v4)) | ||
1333 | { | ||
1334 | while (NULL != (tok = strtok (NULL, " \t"))) | ||
1335 | add_host (tok, | ||
1336 | GNUNET_DNSPARSER_TYPE_A, | ||
1337 | &v4, | ||
1338 | sizeof (struct in_addr)); | ||
1339 | } | ||
1340 | else if (1 == inet_pton (AF_INET6, | ||
1341 | tok, | ||
1342 | &v6)) | ||
1343 | { | ||
1344 | while (NULL != (tok = strtok (NULL, " \t"))) | ||
1345 | add_host (tok, | ||
1346 | GNUNET_DNSPARSER_TYPE_AAAA, | ||
1347 | &v6, | ||
1348 | sizeof (struct in6_addr)); | ||
1349 | } | ||
1350 | GNUNET_free (tbuf); | ||
1351 | } | ||
1352 | |||
1353 | |||
1354 | /** | ||
1355 | * Reads the list of hosts from /etc/hosts. | ||
1356 | */ | ||
1357 | static void | ||
1358 | load_etc_hosts (void) | ||
1359 | { | ||
1360 | struct GNUNET_DISK_FileHandle *fh; | ||
1361 | struct GNUNET_DISK_MapHandle *mh; | ||
1362 | off_t bytes_read; | ||
1363 | const char *buf; | ||
1364 | size_t read_offset; | ||
1365 | |||
1366 | fh = GNUNET_DISK_file_open ("/etc/hosts", | ||
1367 | GNUNET_DISK_OPEN_READ, | ||
1368 | GNUNET_DISK_PERM_NONE); | ||
1369 | if (NULL == fh) | ||
1370 | { | ||
1371 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1372 | "Failed to open /etc/hosts"); | ||
1373 | return; | ||
1374 | } | ||
1375 | if (GNUNET_OK != | ||
1376 | GNUNET_DISK_file_handle_size (fh, | ||
1377 | &bytes_read)) | ||
1378 | { | ||
1379 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1380 | "Could not determin size of /etc/hosts. " | ||
1381 | "DNS resolution will not be possible.\n"); | ||
1382 | GNUNET_DISK_file_close (fh); | ||
1383 | return; | ||
1384 | } | ||
1385 | if (bytes_read > SIZE_MAX) | ||
1386 | { | ||
1387 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1388 | "/etc/hosts file too large to mmap. " | ||
1389 | "DNS resolution will not be possible.\n"); | ||
1390 | GNUNET_DISK_file_close (fh); | ||
1391 | return; | ||
1392 | } | ||
1393 | buf = GNUNET_DISK_file_map (fh, | ||
1394 | &mh, | ||
1395 | GNUNET_DISK_MAP_TYPE_READ, | ||
1396 | (size_t) bytes_read); | ||
1397 | read_offset = 0; | ||
1398 | while (read_offset < bytes_read) | ||
1399 | { | ||
1400 | const char *newline; | ||
1401 | size_t line_len; | ||
1402 | |||
1403 | newline = strchr (buf + read_offset, | ||
1404 | '\n'); | ||
1405 | if (NULL == newline) | ||
1406 | break; | ||
1407 | line_len = newline - buf - read_offset; | ||
1408 | extract_hosts (buf + read_offset, | ||
1409 | line_len); | ||
1410 | read_offset += line_len + 1; | ||
1411 | } | ||
1412 | GNUNET_DISK_file_unmap (mh); | ||
1413 | GNUNET_DISK_file_close (fh); | ||
1173 | } | 1414 | } |
1174 | 1415 | ||
1175 | 1416 | ||
@@ -1190,6 +1431,7 @@ init_cb (void *cls, | |||
1190 | 1431 | ||
1191 | (void) cfg; | 1432 | (void) cfg; |
1192 | (void) sh; | 1433 | (void) sh; |
1434 | load_etc_hosts (); | ||
1193 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | 1435 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, |
1194 | cls); | 1436 | cls); |
1195 | dnsstub_ctx = GNUNET_DNSSTUB_start (128); | 1437 | dnsstub_ctx = GNUNET_DNSSTUB_start (128); |