diff --git a/MACLookup.cc b/MACLookup.cc index ea22ca190..c4e842604 100644 --- a/MACLookup.cc +++ b/MACLookup.cc @@ -75,10 +75,10 @@ extern NmapOps o; -std::map MacTable; +std::map MacTable; -static inline int MacCharPrefix2Key(const u8 *prefix) { - return (prefix[0] << 16) + (prefix[1] << 8) + prefix[2]; +static inline u64 nibble(char hex) { + return (hex & 0xf) + ((hex & 0x40) ? 9 : 0); } static void mac_prefix_init() { @@ -88,7 +88,7 @@ static void mac_prefix_init() { char filename[256]; FILE *fp; char line[128]; - int pfx; + u64 pfx; char *endptr, *vendor; int lineno = 0; @@ -114,7 +114,38 @@ static void mac_prefix_init() { break; } /* First grab the prefix */ - pfx = strtol(line, &endptr, 16); + endptr = line; + while(*endptr && isxdigit((int) (unsigned char) *endptr)) endptr++; + switch (endptr - line) { + case 6: + /* MA-L: 24 bits */ + pfx = (nibble(line[0]) << 20) + (nibble(line[1]) << 16) + + (nibble(line[2]) << 12) + (nibble(line[3]) << 8) + + (nibble(line[4]) << 4) + nibble(line[5]) + + ((u64)6 << 36); + break; + case 7: + /* MA-M: 28 bits */ + pfx = (nibble(line[0]) << 24) + (nibble(line[1]) << 20) + + (nibble(line[2]) << 16) + (nibble(line[3]) << 12) + + (nibble(line[4]) << 8) + (nibble(line[5]) << 4) + + nibble(line[6]) + + ((u64)7 << 36); + break; + case 9: + /* MA-S: 36 bits */ + pfx = (nibble(line[0]) << 32) + (nibble(line[1]) << 28) + + (nibble(line[2]) << 24) + (nibble(line[3]) << 20) + + (nibble(line[4]) << 16) + (nibble(line[5]) << 12) + + (nibble(line[6]) << 8) + (nibble(line[7]) << 4) + + nibble(line[8]) + + ((u64)9 << 36); + break; + default: + error("Parse error on line #%d of %s. Giving up parsing.", lineno, filename); + endptr = NULL; // force failure below + break; + } if (!endptr || !isspace((int) (unsigned char) *endptr)) { error("Parse error on line #%d of %s. Giving up parsing.", lineno, filename); break; @@ -130,7 +161,7 @@ static void mac_prefix_init() { MacTable[pfx] = cp_strdup(vendor); } else { if (o.debugging > 1) - error("MAC prefix %06X is duplicated in %s; ignoring duplicates.", pfx, filename); + error("MAC prefix %09lX is duplicated in %s; ignoring duplicates.", pfx, filename); } } @@ -140,8 +171,8 @@ static void mac_prefix_init() { } -static const char *findMACEntry(int prefix) { - std::map::iterator i; +static const char *findMACEntry(u64 prefix) { + std::map::iterator i; i = MacTable.find(prefix); if (i == MacTable.end()) @@ -150,25 +181,43 @@ static const char *findMACEntry(int prefix) { return i->second; } -/* Takes a three byte MAC address prefix (passing the whole MAC is OK - too) and returns the company which has registered the prefix. +/* Takes 6-byte MAC address and returns the company which has registered the 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) { + u64 key = 0; + const char *corp = NULL; + if (!prefix) fatal("%s called with a NULL prefix", __func__); mac_prefix_init(); - return findMACEntry(MacCharPrefix2Key(prefix)); + /* MA-S: 36 bits (9 nibbles)*/ + key = ((u64)prefix[0] << 28) + (prefix[1] << 20) + (prefix[2] << 12) + (prefix[3] << 4) + (prefix[4] >> 4); + corp = findMACEntry(((u64)9 << 36) + key); + if (corp) + return corp; + + /* MA-M: 28 bits (7 nibbles) */ + key = key >> 8; + corp = findMACEntry(((u64)7 << 36) + key); + if (corp) + return corp; + + /* MA-L: 24 bits (6 nibbles)*/ + key = key >> 4; + corp = findMACEntry(((u64)6 << 36) + key); + + return corp; } /* Takes a string and looks through the table for a vendor name which - contains that string. Sets the first three bytes in mac_data and - returns true for the first matching entry found. If no entries - match, leaves mac_data untouched and returns false. Note that this + contains that string. Sets the initial bytes in mac_data and returns the + number of nibbles (half-bytes) set for the first matching entry found. If no + entries match, leaves mac_data untouched and returns false. Note that this is not particularly efficient and so should be rewritten if it is called often */ -bool MACCorp2Prefix(const char *vendorstr, u8 *mac_data) { - std::map::iterator i; +int MACCorp2Prefix(const char *vendorstr, u8 *mac_data) { + std::map::iterator i; if (!vendorstr) fatal("%s: vendorstr is NULL", __func__); if (!mac_data) fatal("%s: mac_data is NULL", __func__); @@ -176,11 +225,26 @@ bool MACCorp2Prefix(const char *vendorstr, u8 *mac_data) { 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; + int len = i->first >> 36; + int j = 0; + u64 pfx = i->first; + switch (len) { + case 9: + mac_data[j++] = (pfx >> 28) & 0xff; + case 7: + mac_data[j++] = (pfx >> 20) & 0xff; + pfx = pfx << 4; + case 6: + mac_data[j++] = (pfx >> 16) & 0xff; + mac_data[j++] = (pfx >> 8) & 0xff; + mac_data[j++] = (pfx) & 0xff; + break; + default: + break; + } + assert(j == (len + 1) / 2); + return len; } } - return false; + return 0; } diff --git a/MACLookup.h b/MACLookup.h index 425db29de..126c7232d 100644 --- a/MACLookup.h +++ b/MACLookup.h @@ -68,19 +68,18 @@ #include -/* Takes a three byte MAC address prefix (passing the whole MAC is OK - too) and returns the company which has registered the prefix. +/* Takes a MAC address and returns the company which has registered the 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); /* Takes a string and looks through the table for a vendor name which - contains that string. Sets the first three bytes in mac_data and - returns true for the first matching entry found. If no entries - match, leaves mac_data untouched and returns false. Note that this + contains that string. Sets the initial bytes in mac_data and returns the + number of nibbles (half-bytes) set for the first matching entry found. If no + entries match, leaves mac_data untouched and returns false. Note that this is not particularly efficient and so should be rewritten if it is called often */ -bool MACCorp2Prefix(const char *vendorstr, u8 *mac_data); +int MACCorp2Prefix(const char *vendorstr, u8 *mac_data); #endif /* MACLOOKUP_H */ diff --git a/nmap.cc b/nmap.cc index 84d5e53eb..c3c2b37cb 100644 --- a/nmap.cc +++ b/nmap.cc @@ -1633,9 +1633,10 @@ void apply_delayed_options() { } if (*p) { /* Failed to parse it as a MAC prefix -- treating as a vendor substring instead */ - if (!MACCorp2Prefix(delayed_options.spoofmac, mac_data)) + if (!(pos = MACCorp2Prefix(delayed_options.spoofmac, mac_data))) fatal("Could not parse as a prefix nor find as a vendor substring the given --spoof-mac argument: %s. If you are giving hex digits, there must be an even number of them.", delayed_options.spoofmac); - pos = 3; + /* pos is number of nibbles; convert to bytes */ + pos = (pos + 1) / 2; } } if (pos < 6) {