diff options
author | John Thacker <johnthacker@gmail.com> | 2023-11-29 21:29:24 -0500 |
---|---|---|
committer | John Thacker <johnthacker@gmail.com> | 2023-12-01 00:37:27 +0000 |
commit | e200051eda67cad02d7c4871ea6a2742c2c7631b (patch) | |
tree | 5a1be16be1b9beba4c3760f46d587396831e72e4 /epan/addr_resolv.c | |
parent | 17acb9541e04904b296dfa7004274eabf28129a0 (diff) |
manuf: Resolving of MA-M, MA-S, 28 and 36 bit OUIs
Some protocols specifically have 24-bit OUI fields, not
contained within a EUI-48 or EUI-64. Don't return the MA-M
or MA-S that starts with those 24 bits and has 4th and 5th
octet zero when looking up a 24-bit OUI.
When finding a MA-M or MA-S in the global manuf hash tables
(whether from a 24-bit OUI or from a EUI-48 or EUI-64), don't
store the results in the used manuf hashtable, which results
in incorrectly matching other MA-M and MA-S with the same
first 24 bits.
We probably do want to eventually store all MA-M and MA-S used
in some sort of resolved hash table for the Resolved Addresses
dialog.
We also eventually should go through and determine which cases of
tvb_get_manuf_name_if_known are really 24-bit OUIs (e.g.,
roaming consortium in IEEE 802.11) and which are looking
up EUI-48s (e.g., packet-pw-eth.c)
Fix the label writing for the MA-M and MA-S so as not to include
the proper number of nibbles, splitting a byte if appropriate.
Fix #15300
Diffstat (limited to 'epan/addr_resolv.c')
-rw-r--r-- | epan/addr_resolv.c | 155 |
1 files changed, 115 insertions, 40 deletions
diff --git a/epan/addr_resolv.c b/epan/addr_resolv.c index e5e1bf1c00..fc64253adb 100644 --- a/epan/addr_resolv.c +++ b/epan/addr_resolv.c @@ -222,7 +222,12 @@ struct cb_serv_data { }; // Maps guint -> hashmanuf_t* +// XXX: Note that hashmanuf_t* only accommodates 24-bit OUIs. +// We might want to store vendor names from MA-M and MA-S to +// present in the Resolved Addresses dialog. static wmem_map_t *manuf_hashtable = NULL; + +// Maps address -> hashether_t* static wmem_map_t *wka_hashtable = NULL; static wmem_map_t *eth_hashtable = NULL; // Maps guint -> serv_port_t* @@ -1665,6 +1670,11 @@ add_manuf_name(const guint8 *addr, unsigned int mask, gchar *name, gchar *longna } } /* add_manuf_name */ +/* XXX: manuf_name_lookup returns a hashmanuf_t*, which cannot hold a 28 or + * 36 bit MA-M or MA-S. So it returns those as unresolved. For EUI-48 and + * EUI-64, MA-M and MA-S should be checked for separately in the global + * tables. + */ static hashmanuf_t * manuf_name_lookup(const guint8 *addr, size_t size) { @@ -1672,7 +1682,7 @@ manuf_name_lookup(const guint8 *addr, size_t size) guint8 oct; hashmanuf_t *manuf_value; - ws_return_val_if(size < 6, NULL); + ws_return_val_if(size < 3, NULL); /* manuf needs only the 3 most significant octets of the ethernet address */ manuf_key = addr[0]; @@ -1705,7 +1715,8 @@ manuf_name_lookup(const guint8 *addr, size_t size) /* Try the global manuf tables. */ const char *short_name, *long_name; - short_name = ws_manuf_lookup_str(addr, &long_name); + /* We can't insert a 28 or 36 bit entry into the used hash table. */ + short_name = ws_manuf_lookup_oui24(addr, &long_name); if (short_name != NULL) { /* Found it */ return manuf_hash_new_entry(addr, short_name, long_name); @@ -1863,6 +1874,48 @@ ethers_cleanup(void) g_wka_path = NULL; } +static void +eth_resolved_name_fill(hashether_t *tp, const char *name, unsigned mask, const guint8 *addr) +{ + switch (mask) { + case 24: + snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x", + name, addr[3], addr[4], addr[5]); + break; + case 28: + snprintf(tp->resolved_name, MAXNAMELEN, "%s_%01x:%02x:%02x", + name, addr[3] & 0x0F, addr[4], addr[5]); + break; + case 36: + snprintf(tp->resolved_name, MAXNAMELEN, "%s_%01x:%02x", + name, addr[4] & 0x0F, addr[5]); + break; + default: // Future-proof generic algorithm + { + unsigned bytes = mask / 8; + unsigned bitmask = mask % 8; + + int pos = snprintf(tp->resolved_name, MAXNAMELEN, "%s", name); + if (pos >= MAXNAMELEN) return; + + if (bytes < 6) { + pos += snprintf(tp->resolved_name + pos, MAXNAMELEN - pos, + bitmask >= 4 ? "_%01x" : "_%02x", + addr[bytes] & (0xFF >> bitmask)); + bitmask = 0; + bytes++; + } + + while (bytes < 6) { + if (pos >= MAXNAMELEN) return; + pos += snprintf(tp->resolved_name + pos, MAXNAMELEN - pos, ":%02x", + addr[bytes]); + bytes++; + } + } + } +} + /* Resolve ethernet address */ static hashether_t * eth_addr_resolve(hashether_t *tp) { @@ -1962,6 +2015,23 @@ eth_addr_resolve(hashether_t *tp) { } } while (--mask); /* Work down to the last bit */ + /* Now try looking in the global manuf data for a MA-M or MA-S + * match. We do this last so that the other files override this + * result. + */ + const char *short_name, *long_name; + short_name = ws_manuf_lookup(addr, &long_name, &mask); + if (short_name != NULL) { + if (mask == 24) { + /* This shouldn't happen as it should be handled above, + * but it doesn't hurt. + */ + manuf_hash_new_entry(addr, short_name, long_name); + } + eth_resolved_name_fill(tp, short_name, mask, addr); + tp->status = HASHETHER_STATUS_RESOLVED_DUMMY; + return tp; + } /* No match whatsoever. */ set_address(ðer_addr, AT_ETHER, 6, addr); address_to_str_buf(ðer_addr, tp->resolved_name, MAXNAMELEN); @@ -3493,7 +3563,7 @@ get_manuf_name(const guint8 *addr, size_t size) const gchar * tvb_get_manuf_name(tvbuff_t *tvb, gint offset) { - guint8 buf[6] = { 0 }; + guint8 buf[3] = { 0 }; tvb_memcpy(tvb, buf, offset, 3); return get_manuf_name(buf, sizeof(buf)); } @@ -3502,31 +3572,22 @@ const gchar * get_manuf_name_if_known(const guint8 *addr, size_t size) { hashmanuf_t *manuf_value; - guint manuf_key; - guint8 oct; - ws_return_val_if(size != 6, NULL); + ws_return_val_if(size < 3, NULL); - /* manuf needs only the 3 most significant octets of the ethernet address */ - manuf_key = addr[0]; - manuf_key = manuf_key<<8; - oct = addr[1]; - manuf_key = manuf_key | oct; - manuf_key = manuf_key<<8; - oct = addr[2]; - manuf_key = manuf_key | oct; - - manuf_value = (hashmanuf_t *)wmem_map_lookup(manuf_hashtable, GUINT_TO_POINTER(manuf_key)); + manuf_value = manuf_name_lookup(addr, size); if (manuf_value != NULL && manuf_value->status != HASHETHER_STATUS_UNRESOLVED) { return manuf_value->resolved_longname; } - /* Try the global manuf tables. */ - const char *short_name, *long_name; - short_name = ws_manuf_lookup_str(addr, &long_name); - if (short_name != NULL) { - /* Found it */ - return long_name; + if (size >= 6) { + /* Try the global manuf tables. */ + const char *short_name, *long_name; + short_name = ws_manuf_lookup_str(addr, &long_name); + if (short_name != NULL) { + /* Found it */ + return long_name; + } } return NULL; @@ -3536,33 +3597,18 @@ get_manuf_name_if_known(const guint8 *addr, size_t size) const gchar * uint_get_manuf_name_if_known(const guint32 manuf_key) { - hashmanuf_t *manuf_value; guint8 addr[6] = { 0 }; - - manuf_value = (hashmanuf_t *)wmem_map_lookup(manuf_hashtable, GUINT_TO_POINTER(manuf_key)); - if (manuf_value != NULL && manuf_value->status != HASHETHER_STATUS_UNRESOLVED) { - return manuf_value->resolved_longname; - } - addr[0] = (manuf_key >> 16) & 0xFF; addr[1] = (manuf_key >> 8) & 0xFF; addr[2] = manuf_key & 0xFF; - /* Try the global manuf tables. */ - const char *short_name, *long_name; - short_name = ws_manuf_lookup_str(addr, &long_name); - if (short_name != NULL) { - /* Found it */ - return long_name; - } - - return NULL; + return get_manuf_name_if_known(addr, sizeof(addr)); } const gchar * tvb_get_manuf_name_if_known(tvbuff_t *tvb, gint offset) { - guint8 buf[6] = { 0 }; + guint8 buf[3] = { 0 }; tvb_memcpy(tvb, buf, offset, 3); return get_manuf_name_if_known(buf, sizeof(buf)); } @@ -3582,9 +3628,38 @@ eui64_to_display(wmem_allocator_t *allocator, const guint64 addr_eui64) /* Copy and convert the address to network byte order. */ *(guint64 *)(void *)(addr) = pntoh64(&(addr_eui64)); + /* manuf_name_lookup returns a hashmanuf_t* that covers an entire /24, + * so we can't properly use it for MA-M and MA-S. We do want to check + * it first so it also covers the user-defined tables. + */ manuf_value = manuf_name_lookup(addr, 8); if (!gbl_resolv_flags.mac_name || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) { - ret = wmem_strdup_printf(allocator, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]); + /* Now try looking in the global manuf data for a MA-M or MA-S match. + */ + const char *short_name, *long_name; + unsigned mask; + short_name = ws_manuf_lookup(addr, &long_name, &mask); + if (short_name != NULL) { + switch (mask) { + case 24: + /* This shouldn't happen as it should be handled above. */ + manuf_hash_new_entry(addr, short_name, long_name); + ret = wmem_strdup_printf(allocator, "%s_%02x:%02x:%02x:%02x:%02x", short_name, addr[3], addr[4], addr[5], addr[6], addr[7]); + break; + case 28: + ret = wmem_strdup_printf(allocator, "%s_%01x:%02x:%02x:%02x:%02x", short_name, addr[3] & 0x0F, addr[4], addr[5], addr[6], addr[7]); + break; + case 36: + ret = wmem_strdup_printf(allocator, "%s_%01x:%02x:%02x:%02x", short_name, addr[4] & 0x0F, addr[5], addr[6], addr[7]); + break; + default: + /* Doesn't happen, ignore for now. */ + ret = wmem_strdup_printf(allocator, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]); + break; + } + } else { + ret = wmem_strdup_printf(allocator, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]); + } } else { ret = wmem_strdup_printf(allocator, "%s_%02x:%02x:%02x:%02x:%02x", manuf_value->resolved_name, addr[3], addr[4], addr[5], addr[6], addr[7]); } |