mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Use an std::map instead of a custom hash table for MAC address prefix
lookup. The hash table used linear probing which got very slow as the hash table got full. Using std::map is about 10 times faster. The hash table was slow enough that it took the majority of the time for me in an ARP scan of a single address. # nmap -sP 192.168.0.190 mac_prefix_init took 0.49261 s. Nmap done: 1 IP address (1 host up) scanned in 0.59 seconds # nmap -sP 192.168.0.190 mac_prefix_init took 0.04392 s. Nmap done: 1 IP address (1 host up) scanned in 0.13 seconds The memory usage of std::map is probably greater. The hash table used 19037 pointers and about 13000 structures of size 8 (on a 32-bit architecture), or about 176 KB. Assuming the map has left, right, and parent pointers, and a red-black indicator per node, the usage is 16 bytes per prefix plus 8 bytes for the structure data, or 304 KB total. But this makes fingerdiff so much faster, I want to leave it in place at least until this round of OS integration is done.
This commit is contained in:
87
MACLookup.cc
87
MACLookup.cc
@@ -91,6 +91,7 @@
|
|||||||
|
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
/* Character pool memory allocation */
|
/* Character pool memory allocation */
|
||||||
#include "MACLookup.h"
|
#include "MACLookup.h"
|
||||||
@@ -101,28 +102,12 @@
|
|||||||
|
|
||||||
extern NmapOps o;
|
extern NmapOps o;
|
||||||
|
|
||||||
struct MAC_entry {
|
std::map<int, char *> MacTable;
|
||||||
int prefix; /* -1 means none set */
|
|
||||||
char *vendor;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MAC_hash_table {
|
|
||||||
int table_capacity; /* How many members the table can hold */
|
|
||||||
int table_members; /* How many members it has now */
|
|
||||||
struct MAC_entry **table;
|
|
||||||
} MacTable;
|
|
||||||
|
|
||||||
static inline int MacCharPrefix2Key(const u8 *prefix) {
|
static inline int MacCharPrefix2Key(const u8 *prefix) {
|
||||||
return (prefix[0] << 16) + (prefix[1] << 8) + prefix[2];
|
return (prefix[0] << 16) + (prefix[1] << 8) + prefix[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hashes the prefix into a position from 0 to table_capacity - 1. Does not
|
|
||||||
check if the position is free or anything */
|
|
||||||
static inline int MACTableHash(int prefix, int table_capacity) {
|
|
||||||
// Maybe I should think about changing this sometime.
|
|
||||||
return prefix % table_capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mac_prefix_init() {
|
static void mac_prefix_init() {
|
||||||
static int initialized = 0;
|
static int initialized = 0;
|
||||||
if (initialized) return;
|
if (initialized) return;
|
||||||
@@ -130,14 +115,9 @@ static void mac_prefix_init() {
|
|||||||
char filename[256];
|
char filename[256];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char line[128];
|
char line[128];
|
||||||
int pfx, pos;
|
int pfx;
|
||||||
char *endptr, *p;
|
char *endptr, *vendor;
|
||||||
int lineno = 0;
|
int lineno = 0;
|
||||||
struct MAC_entry *ME;
|
|
||||||
|
|
||||||
MacTable.table_capacity = 19037;
|
|
||||||
MacTable.table_members = 0;
|
|
||||||
MacTable.table = (struct MAC_entry **) safe_zalloc(MacTable.table_capacity * sizeof(struct MAC_entry *));
|
|
||||||
|
|
||||||
/* Now it is time to read in all of the entries ... */
|
/* Now it is time to read in all of the entries ... */
|
||||||
if (nmap_fetchfile(filename, sizeof(filename), "nmap-mac-prefixes") != 1){
|
if (nmap_fetchfile(filename, sizeof(filename), "nmap-mac-prefixes") != 1){
|
||||||
@@ -169,26 +149,17 @@ static void mac_prefix_init() {
|
|||||||
/* Now grab the vendor */
|
/* Now grab the vendor */
|
||||||
while(*endptr && isspace((int) (unsigned char) *endptr)) endptr++;
|
while(*endptr && isspace((int) (unsigned char) *endptr)) endptr++;
|
||||||
assert(*endptr);
|
assert(*endptr);
|
||||||
p = endptr;
|
vendor = endptr;
|
||||||
while(*endptr && *endptr != '\n' && *endptr != '\r') endptr++;
|
while(*endptr && *endptr != '\n' && *endptr != '\r') endptr++;
|
||||||
*endptr = '\0';
|
*endptr = '\0';
|
||||||
|
|
||||||
// Create the new MAC_entry
|
if (MacTable.find(pfx) == MacTable.end()) {
|
||||||
ME = (struct MAC_entry *) cp_alloc(sizeof(struct MAC_entry));
|
MacTable[pfx] = cp_strdup(vendor);
|
||||||
ME->prefix = pfx;
|
} else {
|
||||||
ME->vendor = cp_strdup(p);
|
if (o.debugging > 1)
|
||||||
|
error("MAC prefix %06X is duplicated in %s; ignoring duplicates.", pfx, filename);
|
||||||
|
}
|
||||||
|
|
||||||
if (MacTable.table_members > MacTable.table_capacity * 0.8)
|
|
||||||
error("WARNING: nmap-mac-prefixes has grown to more than 80%% of our hash table size. MacTable.table_capacity should be increased");
|
|
||||||
|
|
||||||
// Now insert it into the table
|
|
||||||
if (MacTable.table_members >= MacTable.table_capacity)
|
|
||||||
fatal("No space for further MAC prefixes from nmap-mac-prefixes. Increase MacTable.table_capacity");
|
|
||||||
|
|
||||||
pos = MACTableHash(pfx, MacTable.table_capacity);
|
|
||||||
while (MacTable.table[pos]) pos = (pos + 1) % MacTable.table_capacity;
|
|
||||||
MacTable.table[pos] = ME;
|
|
||||||
MacTable.table_members++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -196,16 +167,14 @@ static void mac_prefix_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct MAC_entry *findMACEntry(int prefix) {
|
static const char *findMACEntry(int prefix) {
|
||||||
int pos = MACTableHash(prefix, MacTable.table_capacity);
|
std::map<int, char *>::iterator i;
|
||||||
|
|
||||||
while (MacTable.table[pos]) {
|
i = MacTable.find(prefix);
|
||||||
if (MacTable.table[pos]->prefix == prefix)
|
if (i == MacTable.end())
|
||||||
return MacTable.table[pos];
|
return NULL;
|
||||||
pos = (pos + 1) % MacTable.table_capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Takes a three byte MAC address prefix (passing the whole MAC is OK
|
/* Takes a three byte MAC address prefix (passing the whole MAC is OK
|
||||||
@@ -213,13 +182,10 @@ static struct MAC_entry *findMACEntry(int prefix) {
|
|||||||
NULL is returned if no vendor is found for the given prefix or if there
|
NULL is returned if no vendor is found for the given prefix or if there
|
||||||
is some other error. */
|
is some other error. */
|
||||||
const char *MACPrefix2Corp(const u8 *prefix) {
|
const char *MACPrefix2Corp(const u8 *prefix) {
|
||||||
struct MAC_entry *ent;
|
|
||||||
|
|
||||||
if (!prefix) fatal("%s called with a NULL prefix", __func__);
|
if (!prefix) fatal("%s called with a NULL prefix", __func__);
|
||||||
mac_prefix_init();
|
mac_prefix_init();
|
||||||
|
|
||||||
ent = findMACEntry(MacCharPrefix2Key(prefix));
|
return findMACEntry(MacCharPrefix2Key(prefix));
|
||||||
return (ent)? ent->vendor : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Takes a string and looks through the table for a vendor name which
|
/* Takes a string and looks through the table for a vendor name which
|
||||||
@@ -229,18 +195,19 @@ const char *MACPrefix2Corp(const u8 *prefix) {
|
|||||||
is not particularly efficient and so should be rewriteen if it is
|
is not particularly efficient and so should be rewriteen if it is
|
||||||
called often */
|
called often */
|
||||||
bool MACCorp2Prefix(const char *vendorstr, u8 *mac_data) {
|
bool MACCorp2Prefix(const char *vendorstr, u8 *mac_data) {
|
||||||
|
std::map<int, char *>::iterator i;
|
||||||
|
|
||||||
if (!vendorstr) fatal("%s: vendorstr is NULL", __func__);
|
if (!vendorstr) fatal("%s: vendorstr is NULL", __func__);
|
||||||
if (!mac_data) fatal("%s: mac_data is NULL", __func__);
|
if (!mac_data) fatal("%s: mac_data is NULL", __func__);
|
||||||
mac_prefix_init();
|
mac_prefix_init();
|
||||||
|
|
||||||
for(int i = 0; i < MacTable.table_capacity; i++ ) {
|
for (i = MacTable.begin(); i != MacTable.end(); i++) {
|
||||||
if (MacTable.table[i])
|
if (strcasestr(i->second, vendorstr)) {
|
||||||
if (strcasestr(MacTable.table[i]->vendor, vendorstr)) {
|
mac_data[0] = i->first >> 16;
|
||||||
mac_data[0] = MacTable.table[i]->prefix >> 16;
|
mac_data[1] = (i->first >> 8) & 0xFF;
|
||||||
mac_data[1] = (MacTable.table[i]->prefix >> 8) & 0xFF;
|
mac_data[2] = i->first & 0xFF;
|
||||||
mac_data[2] = MacTable.table[i]->prefix & 0xFF;
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user