From e1d54cfc3e8223bb4334e5aeed019dab35528e9b Mon Sep 17 00:00:00 2001 From: Uli Heilmeier Date: Sun, 13 Mar 2016 23:16:20 +0100 Subject: [PATCH] IEEE 802.1Q/VLAN: Resolve ID to a describing name A vlans file in the personal preference directory add an option to resolve VLAN IDs to a describing name. Format of vlan file is 123\tName of VLAN To enable the resolving the preference nameres.vlan_name must be set to TRUE. Bug: 11209 Change-Id: I3f00b4897aace89c03c57b68b6c4b6c8b7d4685a Reviewed-on: https://code.wireshark.org/review/14471 Reviewed-by: Michael Mann Reviewed-by: Alexis La Goutte --- epan/addr_resolv.c | 199 +++++++++++++++++++++++++++++++++- epan/addr_resolv.h | 12 ++ epan/dissectors/packet-vlan.c | 15 +++ epan/prefs.c | 3 + ui/gtk/main.c | 3 +- 5 files changed, 230 insertions(+), 2 deletions(-) diff --git a/epan/addr_resolv.c b/epan/addr_resolv.c index db96820a17..f1c3d79335 100644 --- a/epan/addr_resolv.c +++ b/epan/addr_resolv.c @@ -3,6 +3,9 @@ * * Laurent Deniel * + * Add option to resolv VLAN ID to describing name + * Uli Heilmeier, March 2016 + * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs @@ -125,6 +128,7 @@ #define ENAME_IPXNETS "ipxnets" #define ENAME_MANUF "manuf" #define ENAME_SERVICES "services" +#define ENAME_VLANS "vlans" #define HASHETHSIZE 2048 #define HASHHOSTSIZE 2048 @@ -164,6 +168,12 @@ typedef struct hashipxnet { gchar name[MAXNAMELEN]; } hashipxnet_t; +typedef struct hashvlan { + guint id; +/* struct hashvlan *next; */ + gchar name[MAXVLANNAMELEN]; +} hashvlan_t; + /* hash tables used for ethernet and manufacturer lookup */ #define HASHETHER_STATUS_UNRESOLVED 1 #define HASHETHER_STATUS_RESOLVED_DUMMY 2 @@ -197,9 +207,17 @@ typedef struct _ipxnet char name[MAXNAMELEN]; } ipxnet_t; +/* internal vlan type */ +typedef struct _vlan +{ + guint id; + char name[MAXVLANNAMELEN]; +} vlan_t; + static GHashTable *ipxnet_hash_table = NULL; static GHashTable *ipv4_hash_table = NULL; static GHashTable *ipv6_hash_table = NULL; +static GHashTable *vlan_hash_table = NULL; static GSList *manually_resolved_ipv4_list = NULL; static GSList *manually_resolved_ipv6_list = NULL; @@ -283,7 +301,8 @@ e_addr_resolve gbl_resolv_flags = { TRUE, /* concurrent_dns */ TRUE, /* dns_pkt_addr_resolution */ TRUE, /* use_external_net_name_resolver */ - FALSE /* load_hosts_file_from_profile_only */ + FALSE, /* load_hosts_file_from_profile_only */ + FALSE /* vlan_name */ }; #if defined(HAVE_C_ARES) || defined(HAVE_GNU_ADNS) static guint name_resolve_concurrency = 500; @@ -301,6 +320,7 @@ gchar *g_ipxnets_path = NULL; /* global ipxnets file */ gchar *g_pipxnets_path = NULL; /* personal ipxnets file */ gchar *g_services_path = NULL; /* global services file */ gchar *g_pservices_path = NULL; /* personal services file */ +gchar *g_pvlan_path = NULL; /* personal vlans file */ /* first resolving call */ /* c-ares */ @@ -1947,6 +1967,153 @@ ipxnet_addr_lookup(const gchar *name _U_, gboolean *success) #endif } /* ipxnet_addr_lookup */ +/* VLANS */ +static int +parse_vlan_line(char *line, vlan_t *vlan) +{ + gchar *cp; + guint16 id; + + if ((cp = strchr(line, '#'))) + *cp = '\0'; + + if ((cp = strtok(line, " \t\n")) == NULL) + return -1; + + if (sscanf(cp, "%" G_GUINT16_FORMAT, &id) == 1) { + vlan->id = id; + } + else { + return -1; + } + + if ((cp = strtok(NULL, "\t\n")) == NULL) + return -1; + + g_strlcpy(vlan->name, cp, MAXVLANNAMELEN); + + return 0; + +} /* parse_vlan_line */ + +static FILE *vlan_p = NULL; + +static void +set_vlanent(char *path) +{ + if (vlan_p) + rewind(vlan_p); + else + vlan_p = ws_fopen(path, "r"); +} + +static void +end_vlanent(void) +{ + if (vlan_p) { + fclose(vlan_p); + vlan_p = NULL; + } +} + +static vlan_t * +get_vlanent(void) +{ + + static vlan_t vlan; + static int size = 0; + static char *buf = NULL; + + if (vlan_p == NULL) + return NULL; + + while (fgetline(&buf, &size, vlan_p) >= 0) { + if (parse_vlan_line(buf, &vlan) == 0) { + return &vlan; + } + } + + return NULL; + +} /* get_vlanent */ + +static vlan_t * +get_vlannamebyid(guint16 id) +{ + vlan_t *vlan; + + set_vlanent(g_pvlan_path); + + while (((vlan = get_vlanent()) != NULL) && (id != vlan->id) ) ; + + if (vlan == NULL) { + end_vlanent(); + + } + + return vlan; + +} /* get_vlannamebyid */ + +static void +initialize_vlans(void) +{ + g_assert(vlan_hash_table == NULL); + vlan_hash_table = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); + + /* Set g_pipxnets_path here, but don't actually do anything + * with it. It's used in get_ipxnetbyname() and get_ipxnetbyaddr() + */ + if (g_pvlan_path == NULL) + g_pvlan_path = get_persconffile_path(ENAME_VLANS, FALSE); + +} /* initialize_vlans */ + +static void +vlan_name_lookup_cleanup(void) +{ + if (vlan_hash_table) { + g_hash_table_destroy(vlan_hash_table); + vlan_hash_table = NULL; + } + +} + +static const gchar * +vlan_name_lookup(const guint id) +{ + hashvlan_t *tp; + vlan_t *vlan; + + tp = (hashvlan_t *)g_hash_table_lookup(vlan_hash_table, &id); + if (tp == NULL) { + int *key; + + key = (int *)g_new(int, 1); + *key = id; + tp = g_new(hashvlan_t, 1); + g_hash_table_insert(vlan_hash_table, key, tp); + } else { + return tp->name; + } + + /* fill in a new entry */ + + tp->id = id; + + if ( (vlan = get_vlannamebyid(id)) == NULL) { + /* unknown name */ + g_snprintf(tp->name, MAXVLANNAMELEN, "<%u>", id); + + } else { + g_strlcpy(tp->name, vlan->name, MAXVLANNAMELEN); + } + + return tp->name; + +} /* vlan_name_lookup */ +/* VLAN END */ + static gboolean read_hosts_file (const char *hostspath, gboolean store_entries) { @@ -2374,6 +2541,15 @@ addr_resolve_pref_init(module_t *nameres) " Checking this box only loads the \"hosts\" in the current profile.", &gbl_resolv_flags.load_hosts_file_from_profile_only); + prefs_register_bool_preference(nameres, "vlan_name", + "Resolve VLAN IDs", + "Resolve VLAN IDs to describing names." + " To do so you need a file called vlans in your" + " user preference directory. Format of the file is:" + " \"IDName\"" + " One line per VLAN.", + &gbl_resolv_flags.vlan_name); + } void @@ -2384,6 +2560,7 @@ disable_name_resolution(void) { gbl_resolv_flags.concurrent_dns = FALSE; gbl_resolv_flags.dns_pkt_addr_resolution = FALSE; gbl_resolv_flags.use_external_net_name_resolver = FALSE; + gbl_resolv_flags.vlan_name = FALSE; } #ifdef HAVE_C_ARES @@ -3045,6 +3222,18 @@ get_ipxnet_addr(const gchar *name, gboolean *known) } /* get_ipxnet_addr */ +gchar * +get_vlan_name(wmem_allocator_t *allocator, const guint16 id) +{ + + if (!gbl_resolv_flags.vlan_name) { + return NULL; + } + + return wmem_strdup(allocator, vlan_name_lookup(id)); + +} /* get_vlan_name */ + const gchar * get_manuf_name(const guint8 *addr) { @@ -3433,6 +3622,12 @@ get_ipxnet_hash_table(void) return ipxnet_hash_table; } +GHashTable * +get_vlan_hash_table(void) +{ + return vlan_hash_table; +} + GHashTable * get_ipv4_hash_table(void) { @@ -3451,6 +3646,7 @@ addr_resolv_init(void) initialize_services(); initialize_ethers(); initialize_ipxnets(); + initialize_vlans(); /* host name initialization is done on a per-capture-file basis */ /*host_name_lookup_init();*/ } @@ -3462,6 +3658,7 @@ addr_resolv_cleanup(void) service_name_lookup_cleanup(); eth_name_lookup_cleanup(); ipx_name_lookup_cleanup(); + vlan_name_lookup_cleanup(); /* host name initialization is done on a per-capture-file basis */ /*host_name_lookup_cleanup();*/ } diff --git a/epan/addr_resolv.h b/epan/addr_resolv.h index f5ee82901d..876aff2bc9 100644 --- a/epan/addr_resolv.h +++ b/epan/addr_resolv.h @@ -47,6 +47,10 @@ extern "C" { #define MAXNAMELEN 64 /* max name length (hostname and port name) */ #endif +#ifndef MAXVLANNAMELEN +#define MAXVLANNAMELEN 128 /* max vlan name length */ +#endif + /** * @brief Flags to control name resolution. */ @@ -58,6 +62,7 @@ typedef struct _e_addr_resolve { gboolean dns_pkt_addr_resolution; /**< Whether to resolve addresses using captured DNS packets */ gboolean use_external_net_name_resolver; /**< Whether to system's configured DNS server to resolve names */ gboolean load_hosts_file_from_profile_only; /**< Whether to only load the hosts in the current profile, not hosts files */ + gboolean vlan_name; /**< Whether to resolve VLAN IDs to names */ } e_addr_resolve; #define ADDR_RESOLV_MACADDR(at) \ @@ -240,6 +245,10 @@ extern gchar *eui64_to_display(wmem_allocator_t *allocator, const guint64 addr); * or a string formatted with "%X" if not */ extern gchar *get_ipxnet_name(wmem_allocator_t *allocator, const guint32 addr); +/* get_vlan_name returns the logical name if found in a vlans file, + * or the VLAN ID itself as a string if not found*/ +extern gchar *get_vlan_name(wmem_allocator_t *allocator, const guint16 id); + WS_DLL_PUBLIC guint get_hash_ether_status(hashether_t* ether); WS_DLL_PUBLIC char* get_hash_ether_hexaddr(hashether_t* ether); WS_DLL_PUBLIC char* get_hash_ether_resolved_name(hashether_t* ether); @@ -338,6 +347,9 @@ GHashTable *get_serv_port_hashtable(void); WS_DLL_PUBLIC GHashTable *get_ipxnet_hash_table(void); +WS_DLL_PUBLIC +GHashTable *get_vlan_hash_table(void); + WS_DLL_PUBLIC GHashTable *get_ipv4_hash_table(void); diff --git a/epan/dissectors/packet-vlan.c b/epan/dissectors/packet-vlan.c index 05ba381dac..915129b573 100644 --- a/epan/dissectors/packet-vlan.c +++ b/epan/dissectors/packet-vlan.c @@ -34,6 +34,7 @@ #include #include #include +#include void proto_register_vlan(void); void proto_reg_handoff_vlan(void); @@ -81,6 +82,10 @@ static header_field_info hfi_vlan_id VLAN_HFI_INIT = { "ID", "vlan.id", FT_UINT16, BASE_DEC, NULL, 0x0FFF, "VLAN ID", HFILL }; +static header_field_info hfi_vlan_id_name VLAN_HFI_INIT = { + "Name", "vlan.id_name", FT_STRING, STR_UNICODE, + NULL, 0x0, "VLAN ID Name", HFILL }; + static header_field_info hfi_vlan_etype VLAN_HFI_INIT = { "Type", "vlan.etype", FT_UINT16, BASE_HEX, VALS(etype_vals), 0x0, "Ethertype", HFILL }; @@ -141,6 +146,7 @@ dissect_vlan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_ guint16 encap_proto; gboolean is_802_2; proto_tree *vlan_tree; + proto_item *item; col_set_str(pinfo->cinfo, COL_PROTOCOL, "VLAN"); col_clear(pinfo->cinfo, COL_INFO); @@ -169,6 +175,14 @@ dissect_vlan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_ proto_tree_add_item(vlan_tree, &hfi_vlan_priority, tvb, 0, 2, ENC_BIG_ENDIAN); proto_tree_add_item(vlan_tree, &hfi_vlan_cfi, tvb, 0, 2, ENC_BIG_ENDIAN); proto_tree_add_item(vlan_tree, &hfi_vlan_id, tvb, 0, 2, ENC_BIG_ENDIAN); + + if (gbl_resolv_flags.vlan_name) { + item = proto_tree_add_string(vlan_tree, &hfi_vlan_id_name, tvb, 0, 2, + get_vlan_name(wmem_packet_scope(), vlan_id)); + PROTO_ITEM_SET_GENERATED(item); + + } + } encap_proto = tvb_get_ntohs(tvb, 2); @@ -214,6 +228,7 @@ proto_register_vlan(void) &hfi_vlan_priority, &hfi_vlan_cfi, &hfi_vlan_id, + &hfi_vlan_id_name, &hfi_vlan_etype, &hfi_vlan_len, &hfi_vlan_trailer, diff --git a/epan/prefs.c b/epan/prefs.c index 063e9c6268..fb99675ba0 100644 --- a/epan/prefs.c +++ b/epan/prefs.c @@ -3914,6 +3914,9 @@ string_to_name_resolve(const char *string, e_addr_resolve *name_resolve) case 'd': name_resolve->dns_pkt_addr_resolution = TRUE; break; + case 'v': + name_resolve->vlan_name = TRUE; + break; default: /* * Unrecognized letter. diff --git a/ui/gtk/main.c b/ui/gtk/main.c index 42215a4afb..b2e096d483 100644 --- a/ui/gtk/main.c +++ b/ui/gtk/main.c @@ -936,7 +936,8 @@ void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) TRUE, /* concurrent_dns */ TRUE, /* dns_pkt_addr_resolution */ TRUE, /* use_external_net_name_resolver */ - FALSE /* load_hosts_file_from_profile_only */ + FALSE, /* load_hosts_file_from_profile_only */ + FALSE /* vlan_name */ }; if (cfile.edt->tree) {