1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Support MA-S, MA-M, and MA-L reg lookups for OUI/MAC/EUI-48

This commit is contained in:
dmiller
2022-09-08 23:37:54 +00:00
parent ecf3b63189
commit 7013eefb05
3 changed files with 93 additions and 29 deletions

View File

@@ -75,10 +75,10 @@
extern NmapOps o;
std::map<int, char *> MacTable;
std::map<u64, char *> 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<int, char *>::iterator i;
static const char *findMACEntry(u64 prefix) {
std::map<u64, char *>::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<int, char *>::iterator i;
int MACCorp2Prefix(const char *vendorstr, u8 *mac_data) {
std::map<u64, char *>::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;
}

View File

@@ -68,19 +68,18 @@
#include <nbase.h>
/* 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 */

View File

@@ -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) {