mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 12:41:29 +00:00
Fix an infinite loop in nmap_dns.cc.
This changes the DNS engine to use addto_etchosts to add entries from /etc/hosts into the DNS cache, rather than just inserting them using push_front. The reason for this is that there is a static unsigned variable in addto_etchosts that keeps track of how many entries there are in the cache. Using push_front bypassed this variable, allowing the entries in /etc/hosts to sneak in under the radar. Thus is was possible for the cache to contain, say, 266 entries when it thought it only had 256. When the cache size is greater than or equal to 256, addto_etchosts runs a deletion pass aiming to reduce the number of entries to 126. But the peculiar loop logic of that function means that more than 256 entries can be deleted. (How many more depends in part on how many entries there are in /etc/hosts. There must be at least one for the hang to occur.) When this happens, the signed counter underflows and becomes large positive, ~65000. The code empties the cache trying to get the counter under 127, but it can never happen. To reproduce the hang, make an /etc/hosts file like this: 1.0.0.1 host-1-1 1.0.0.2 host-1-2 1.0.0.3 host-1-3 1.0.0.4 host-1-4 1.0.0.5 host-1-5 1.0.0.6 host-1-6 1.0.0.7 host-1-7 1.0.0.8 host-1-8 1.0.0.9 host-1-9 1.0.0.10 host-1-10 2.0.0.1 host-2 3.0.0.1 host-3 ... 254.0.0.1 host-254 255.0.0.1 host-255 The hang can occur with even one entry in /etc/hosts, but saturating the cache like this makes the hang less dependent on network conditions. Then list-scan a netblock that is greater in size than 256 and is dense in DNS entries (at least 256 entries per 4096 IP addresses). For example, nmap -sL scanme.nmap.org/22 works for me currently.
This commit is contained in:
@@ -985,13 +985,8 @@ static void parse_etchosts(char *fname) {
|
||||
while (*tp == ' ' || *tp == '\t') tp++;
|
||||
|
||||
if (sscanf(tp, "%15s %255s", ipaddrstr, hname) == 2) {
|
||||
if (inet_pton(AF_INET, ipaddrstr, &ia)) {
|
||||
he = new host_elem;
|
||||
he->name = strdup(hname);
|
||||
he->addr = (u32) ia.s_addr;
|
||||
he->cache_hits = 0;
|
||||
etchosts[he->addr % HASH_TABLE_SIZE].push_front(he);
|
||||
}
|
||||
if (inet_pton(AF_INET, ipaddrstr, &ia))
|
||||
addto_etchosts(ia.s_addr, hname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user