1
0
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:
david
2009-11-11 21:25:07 +00:00
parent 53deb965ce
commit 86d766a34e

View File

@@ -91,6 +91,7 @@
/* $Id$ */
#include <map>
/* Character pool memory allocation */
#include "MACLookup.h"
@@ -101,28 +102,12 @@
extern NmapOps o;
struct MAC_entry {
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;
std::map<int, char *> MacTable;
static inline int MacCharPrefix2Key(const u8 *prefix) {
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 int initialized = 0;
if (initialized) return;
@@ -130,14 +115,9 @@ static void mac_prefix_init() {
char filename[256];
FILE *fp;
char line[128];
int pfx, pos;
char *endptr, *p;
int pfx;
char *endptr, *vendor;
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 ... */
if (nmap_fetchfile(filename, sizeof(filename), "nmap-mac-prefixes") != 1){
@@ -169,26 +149,17 @@ static void mac_prefix_init() {
/* Now grab the vendor */
while(*endptr && isspace((int) (unsigned char) *endptr)) endptr++;
assert(*endptr);
p = endptr;
vendor = endptr;
while(*endptr && *endptr != '\n' && *endptr != '\r') endptr++;
*endptr = '\0';
// Create the new MAC_entry
ME = (struct MAC_entry *) cp_alloc(sizeof(struct MAC_entry));
ME->prefix = pfx;
ME->vendor = cp_strdup(p);
if (MacTable.find(pfx) == MacTable.end()) {
MacTable[pfx] = cp_strdup(vendor);
} else {
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);
@@ -196,16 +167,14 @@ static void mac_prefix_init() {
}
static struct MAC_entry *findMACEntry(int prefix) {
int pos = MACTableHash(prefix, MacTable.table_capacity);
static const char *findMACEntry(int prefix) {
std::map<int, char *>::iterator i;
while (MacTable.table[pos]) {
if (MacTable.table[pos]->prefix == prefix)
return MacTable.table[pos];
pos = (pos + 1) % MacTable.table_capacity;
}
i = MacTable.find(prefix);
if (i == MacTable.end())
return NULL;
return NULL;
return i->second;
}
/* 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
is some other error. */
const char *MACPrefix2Corp(const u8 *prefix) {
struct MAC_entry *ent;
if (!prefix) fatal("%s called with a NULL prefix", __func__);
mac_prefix_init();
ent = findMACEntry(MacCharPrefix2Key(prefix));
return (ent)? ent->vendor : NULL;
return findMACEntry(MacCharPrefix2Key(prefix));
}
/* 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
called often */
bool MACCorp2Prefix(const char *vendorstr, u8 *mac_data) {
std::map<int, char *>::iterator i;
if (!vendorstr) fatal("%s: vendorstr is NULL", __func__);
if (!mac_data) fatal("%s: mac_data is NULL", __func__);
mac_prefix_init();
for(int i = 0; i < MacTable.table_capacity; i++ ) {
if (MacTable.table[i])
if (strcasestr(MacTable.table[i]->vendor, vendorstr)) {
mac_data[0] = MacTable.table[i]->prefix >> 16;
mac_data[1] = (MacTable.table[i]->prefix >> 8) & 0xFF;
mac_data[2] = MacTable.table[i]->prefix & 0xFF;
return true;
}
for (i = MacTable.begin(); i != MacTable.end(); i++) {
if (strcasestr(i->second, vendorstr)) {
mac_data[0] = i->first >> 16;
mac_data[1] = (i->first >> 8) & 0xFF;
mac_data[2] = i->first & 0xFF;
return true;
}
}
return false;
}