aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-10-18 15:55:30 +0200
committerChristian Grothoff <christian@grothoff.org>2018-10-18 15:55:30 +0200
commite76f4a66930043ede71300fffe38ab48746ca5b5 (patch)
tree46c819e569b08775072aaa79274c3de382e3401a /src
parentc7c6446e3ea37531b67252a452937f3578570a57 (diff)
downloadgnunet-e76f4a66930043ede71300fffe38ab48746ca5b5.tar.gz
gnunet-e76f4a66930043ede71300fffe38ab48746ca5b5.zip
add support for /etc/hosts
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_disk_lib.h1
-rw-r--r--src/util/gnunet-service-resolver.c264
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 */
782struct GNUNET_DISK_MapHandle; 782struct 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;
165static struct ResolveCache *cache_tail; 166static struct ResolveCache *cache_tail;
166 167
167/** 168/**
169 * Head of the linked list of DNS lookup results from /etc/hosts.
170 */
171static struct ResolveCache *hosts_head;
172
173/**
174 * Tail of the linked list of DNS lookup results from /etc/hosts.
175 */
176static 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 */
170static struct ActiveLookup *lookup_head; 181static 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 */
237static void
238free_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
299lookup_dns_servers (char ***server_addrs) 338lookup_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 */
1262static void
1263add_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 */
1299static void
1300extract_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 */
1357static void
1358load_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);