Skip to content

Commit a363176

Browse files
committed
Fix /etc/hosts processing performance with all entries using same IP address
Some users use blacklist files like https://github.com/StevenBlack/hosts which can contain 200k+ host entries all pointing to 0.0.0.0. Due to the merge logic in the new hosts processor, all those entries will be associated as aliases for the same ip address. The first issue is that it attempts to check the status of all the hosts for the merged entry, when it should only be checking the new hosts added to the merged entry, so this caused exponential time as the entries got longer. The next issue is if searching for one of those hosts, it would append all the matches as cnames/aliases, but there is zero use for 200k aliases being appended to a lookup, so we are artificially capping this to 100. Bug report reference: https://bugs.gentoo.org/917400 Fix By: Brad House (@bradh352)
1 parent 0ef0f6b commit a363176

File tree

1 file changed

+33
-3
lines changed

1 file changed

+33
-3
lines changed

src/lib/ares__hosts_file.c

+33-3
Original file line numberDiff line numberDiff line change
@@ -422,9 +422,15 @@ static ares_status_t ares__hosts_file_add(ares_hosts_file_t *hosts,
422422
ares_hosts_entry_t *entry)
423423
{
424424
ares_hosts_entry_t *match = NULL;
425-
ares_status_t status = ARES_SUCCESS;
425+
ares_status_t status = ARES_SUCCESS;
426426
ares__llist_node_t *node;
427427
ares_hosts_file_match_t matchtype;
428+
size_t num_hostnames;
429+
430+
/* Record the number of hostnames in this entry file. If we merge into an
431+
* existing record, these will be *appended* to the entry, so we'll count
432+
* backwards when adding to the hosts hashtable */
433+
num_hostnames = ares__llist_len(entry->hosts);
428434

429435
matchtype = ares__hosts_file_match(hosts, entry, &match);
430436

@@ -450,10 +456,17 @@ static ares_status_t ares__hosts_file_add(ares_hosts_file_t *hosts,
450456
}
451457
}
452458

453-
for (node = ares__llist_node_first(entry->hosts); node != NULL;
454-
node = ares__llist_node_next(node)) {
459+
/* Go backwards, on a merge, hostnames are appended. Breakout once we've
460+
* consumed all the hosts that we appended */
461+
for (node = ares__llist_node_last(entry->hosts); node != NULL;
462+
node = ares__llist_node_prev(node)) {
455463
const char *val = ares__llist_node_val(node);
456464

465+
if (num_hostnames == 0)
466+
break;
467+
468+
num_hostnames--;
469+
457470
/* first hostname match wins. If we detect a duplicate hostname for another
458471
* ip it will automatically be added to the same entry */
459472
if (ares__htable_strvp_get(hosts->hosthash, val, NULL)) {
@@ -950,6 +963,12 @@ ares_status_t ares__hosts_entry_to_hostent(const ares_hosts_entry_t *entry,
950963

951964
/* Copy aliases */
952965
naliases = ares__llist_len(entry->hosts) - 1;
966+
967+
/* Cap at 100, some people use https://github.com/StevenBlack/hosts and we
968+
* don't need 200k+ aliases */
969+
if (naliases > 100)
970+
naliases = 100;
971+
953972
(*hostent)->h_aliases =
954973
ares_malloc_zero((naliases + 1) * sizeof(*(*hostent)->h_aliases));
955974
if ((*hostent)->h_aliases == NULL) {
@@ -968,6 +987,10 @@ ares_status_t ares__hosts_entry_to_hostent(const ares_hosts_entry_t *entry,
968987
goto fail;
969988
}
970989
idx++;
990+
991+
/* Break out if artificially capped */
992+
if (idx == naliases)
993+
break;
971994
node = ares__llist_node_next(node);
972995
}
973996

@@ -988,6 +1011,7 @@ static ares_status_t
9881011
const char *primaryhost;
9891012
ares__llist_node_t *node;
9901013
ares_status_t status;
1014+
size_t cnt = 0;
9911015

9921016
node = ares__llist_node_first(entry->hosts);
9931017
primaryhost = ares__llist_node_val(node);
@@ -997,6 +1021,12 @@ static ares_status_t
9971021
while (node != NULL) {
9981022
const char *host = ares__llist_node_val(node);
9991023

1024+
/* Cap at 100 entries. , some people use https://github.com/StevenBlack/hosts
1025+
* and we don't need 200k+ aliases */
1026+
cnt++;
1027+
if (cnt > 100)
1028+
break;
1029+
10001030
cname = ares__append_addrinfo_cname(&cnames);
10011031
if (cname == NULL) {
10021032
status = ARES_ENOMEM;

0 commit comments

Comments
 (0)