diff --git a/CHANGELOG b/CHANGELOG index 94ce2aa61..f239b5153 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,15 @@ # Nmap Changelog ($Id$); -*-text-*- +o The ARP host discovery scan now filters ARP packets based on their + target address address field, not the destination address in the + enclosing ethernet frame. Some operating systems, including Windows + 7 and Solaris 10, are known to at least sometimes send their ARP + replies to the broadcast address and Nmap wouldn't notice them. The + symptom of this was that root scans wouldn't work ("Host seems + down") but non-root scans would work. Thanks to Mike Calmus and + Vijay Sankar for reporting the problem, and Marcus Haebler for + suggesting the fix. + o The -fno-strict-aliasing option is now used unconditionally when using GCC. It was already this way, in effect, because a test against the GCC version number was reversed: <= 4 rather than >= 4. diff --git a/scan_engine.cc b/scan_engine.cc index 50e2dcf93..d5508199b 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -5011,7 +5011,6 @@ static void begin_sniffer(UltraScanInfo *USI, vector &Targets) { string pcap_filter=""; /* 20 IPv6 addresses is max (45 byte addy + 14 (" or src host ")) * 20 == 1180 */ string dst_hosts=""; - char macstring[100]; unsigned int len = 0; unsigned int targetno; bool doIndividual = Targets.size() <= 20; // Don't bother IP limits if scanning huge # of hosts @@ -5028,15 +5027,26 @@ static void begin_sniffer(UltraScanInfo *USI, vector &Targets) { } USI->pd = my_pcap_open_live(Targets[0]->deviceName(), 100, (o.spoofsource)? 1 : 0, pcap_selectable_fd_valid()? 200 : 2); - if(USI->ping_scan_arp){ + if (USI->ping_scan_arp){ + /* Some OSs including Windows 7 and Solaris 10 have been seen to send their + ARP replies to the broadcast address, not to the (unicast) address that + the request came from, therefore listening for ARP packets directed to + us is not enough. Look inside the ARP reply at the target address field + instead. The filter string will look like + arp and arp[18:4] = 0xAABBCCDD and arp[22:2] = 0xCCDD */ + char macstring[2 * ETH_ADDR_LEN + 1]; const u8 *mac = Targets[0]->SrcMACAddress(); assert(mac); - pcap_filter="arp and ether dst host "; - len = Snprintf(macstring, sizeof(macstring), - "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - if(len>=sizeof(macstring)) - fatal("macstring too long"); - pcap_filter+=macstring; + len = Snprintf(macstring, sizeof(macstring), "%02X%02X%02X%02X%02X%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + if (len != sizeof(macstring) - 1) + fatal("macstring length is %d, should be %u", len, sizeof(macstring) - 1); + /* First four bytes of MAC. */ + pcap_filter = "arp and arp[18:4] = 0x"; + pcap_filter.append(macstring, 0, 4 * 2); + /* Last two bytes. */ + pcap_filter += " and arp[22:2] = 0x"; + pcap_filter.append(macstring, 4 * 2, 2 * 2); //its not arp, so lets check if for a protocol scan. } else if(USI->prot_scan || (USI->ping_scan && USI->ptech.rawprotoscan)){ if (doIndividual){