diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-09-19 04:14:26 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-09-19 04:14:26 +0000 |
commit | c4e8a3222648fcf22ca207f1815ebbf7cd144eeb (patch) | |
tree | 93d5c6aa93d9987680dd1adad5685e2ad698f223 /capture/capture_ifinfo.c | |
parent | Adding upstream version 4.2.6. (diff) | |
download | wireshark-c4e8a3222648fcf22ca207f1815ebbf7cd144eeb.tar.xz wireshark-c4e8a3222648fcf22ca207f1815ebbf7cd144eeb.zip |
Adding upstream version 4.4.0.upstream/4.4.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'capture/capture_ifinfo.c')
-rw-r--r-- | capture/capture_ifinfo.c | 540 |
1 files changed, 391 insertions, 149 deletions
diff --git a/capture/capture_ifinfo.c b/capture/capture_ifinfo.c index 45201b88..af1c136b 100644 --- a/capture/capture_ifinfo.c +++ b/capture/capture_ifinfo.c @@ -24,13 +24,16 @@ #include "capture/capture_sync.h" #include "extcap.h" +#include <capture/capture-pcap-util.h> +#include <capture/capture-pcap-util-int.h> #include <capture/capture_ifinfo.h> #include <wsutil/inet_addr.h> +#include <wsutil/wsjson.h> #ifdef HAVE_PCAP_REMOTE -static GList *remote_interface_list = NULL; +static GList *remote_interface_list; -static GList * append_remote_list(GList *iflist) +GList * append_remote_list(GList *iflist) { GSList *list; GList *rlist; @@ -68,26 +71,266 @@ static GList * append_remote_list(GList *iflist) } #endif +static if_capabilities_t * +deserialize_if_capability(char* data, jsmntok_t *inf_tok) +{ + if_capabilities_t *caps; + GList *linktype_list = NULL, *timestamp_list = NULL; + GList *linktype_rfmon_list = NULL; + int err, i; + char *val_s; + double val_d; + jsmntok_t *array_tok, *cur_tok; + + /* + * Allocate the interface capabilities structure. + */ + caps = (if_capabilities_t *)g_malloc0(sizeof *caps); + + if (inf_tok == NULL || !json_get_double(data, inf_tok, "status", &val_d)) { + ws_info("Capture Interface Capabilities failed with invalid JSON."); + caps->primary_msg = g_strdup("Dumpcap returned bad JSON"); + return caps; + } + + err = (int)val_d; + if (err != 0) { + caps->primary_msg = json_get_string(data, inf_tok, "primary_msg"); + if (caps->primary_msg) { + caps->primary_msg = g_strdup(caps->primary_msg); + caps->secondary_msg = get_pcap_failure_secondary_error_message(err, caps->primary_msg); + } else { + caps->primary_msg = g_strdup("Failed with no message"); + } + ws_info("Capture Interface Capabilities failed. Error %d, %s", + err, caps->primary_msg ? caps->primary_msg : "no message"); + return caps; + } + + bool rfmon; + if (!json_get_boolean(data, inf_tok, "rfmon", &rfmon)) { + ws_message("Capture Interface Capabilities returned bad information."); + ws_message("Didn't return monitor-mode cap"); + caps->primary_msg = g_strdup("Dumpcap didn't return monitor-mode capability"); + return caps; + } + + caps->can_set_rfmon = rfmon; + + /* + * The following are link-layer types. + */ + array_tok = json_get_array(data, inf_tok, "data_link_types"); + if (!array_tok) { + ws_info("Capture Interface Capabilities returned bad data_link information."); + caps->primary_msg = g_strdup("Dumpcap didn't return data link types capability"); + return caps; + } + for (i = 0; i < json_get_array_len(array_tok); i++) { + cur_tok = json_get_array_index(array_tok, i); + + if (!json_get_double(data, cur_tok, "dlt", &val_d)) { + continue; + } + + data_link_info_t *data_link_info; + data_link_info = g_new(data_link_info_t,1); + + data_link_info->dlt = (int)val_d; + val_s = json_get_string(data, cur_tok, "name"); + data_link_info->name = val_s ? g_strdup(val_s) : NULL; + val_s = json_get_string(data, cur_tok, "description"); + if (!val_s || strcmp(val_s, "(not supported)") == 0) { + data_link_info->description = NULL; + } else { + data_link_info->description = g_strdup(val_s); + } + linktype_list = g_list_append(linktype_list, data_link_info); + } + + if (rfmon) { + array_tok = json_get_array(data, inf_tok, "data_link_types_rfmon"); + + if (!array_tok) { + ws_info("Capture Interface Capabilities returned bad data_link information for monitor mode."); + caps->primary_msg = g_strdup("Dumpcap claimed that interface supported monitor mode, but didn't return data link types when in monitor mode"); + caps->can_set_rfmon = false; + } else for (i = 0; i < json_get_array_len(array_tok); i++) { + cur_tok = json_get_array_index(array_tok, i); + + if (!json_get_double(data, cur_tok, "dlt", &val_d)) { + continue; + } + + data_link_info_t *data_link_info; + data_link_info = g_new(data_link_info_t,1); + + data_link_info->dlt = (int)val_d; + val_s = json_get_string(data, cur_tok, "name"); + data_link_info->name = val_s ? g_strdup(val_s) : NULL; + val_s = json_get_string(data, cur_tok, "description"); + if (!val_s || strcmp(val_s, "(not supported)") == 0) { + data_link_info->description = NULL; + } else { + data_link_info->description = g_strdup(val_s); + } + linktype_rfmon_list = g_list_append(linktype_rfmon_list, data_link_info); + } + } + + array_tok = json_get_array(data, inf_tok, "timestamp_types"); + if (array_tok) { + for (i = 0; i < json_get_array_len(array_tok); i++) { + cur_tok = json_get_array_index(array_tok, i); + + timestamp_info_t *timestamp_info; + timestamp_info = g_new(timestamp_info_t,1); + val_s = json_get_string(data, cur_tok, "name"); + timestamp_info->name = val_s ? g_strdup(val_s) : NULL; + val_s = json_get_string(data, cur_tok, "description"); + timestamp_info->description = val_s ? g_strdup(val_s) : NULL; + + timestamp_list = g_list_append(timestamp_list, timestamp_info); + } + } + + caps->data_link_types = linktype_list; + /* Should be NULL if rfmon unsupported. */ + caps->data_link_types_rfmon = linktype_rfmon_list; + /* Might be NULL. Not all systems report timestamp types */ + caps->timestamp_types = timestamp_list; + + return caps; +} + +GList * +deserialize_interface_list(char *data, int *err, char **err_str) +{ + int i, j; + char *name, *addr; + char *val_s; + double val_d; + bool loopback; + if_info_t *if_info; + interface_type type; + if_addr_t *if_addr; + jsmntok_t *tokens, *if_tok, *addrs_tok, *cur_tok; + GList *if_list = NULL; + + if (data == NULL) { + ws_info("Passed NULL capture interface list"); + *err = CANT_GET_INTERFACE_LIST; + return if_list; + } + + int num_tokens = json_parse(data, NULL, 0); + if (num_tokens <= 0) { + ws_info("Capture Interface List failed with invalid JSON."); + if (err_str) { + *err_str = g_strdup("Dumpcap returned bad JSON."); + } + g_free(data); + *err = CANT_GET_INTERFACE_LIST; + return NULL; + } + + tokens = wmem_alloc_array(NULL, jsmntok_t, num_tokens); + if (json_parse(data, tokens, num_tokens) <= 0) { + ws_info("Capture Interface List failed with invalid JSON."); + if (err_str) { + *err_str = g_strdup("Dumpcap returned bad JSON."); + } + wmem_free(NULL, tokens); + g_free(data); + *err = CANT_GET_INTERFACE_LIST; + return NULL; + } + + for (i = 0; i < json_get_array_len(tokens); i++) { + if_tok = json_get_array_index(tokens, i); + if (if_tok && if_tok->type == JSMN_OBJECT) { + if_tok++; // Key + name = g_strndup(&data[if_tok->start], if_tok->end - if_tok->start); + if (!json_decode_string_inplace(name)) { + g_free(name); + continue; + } + if_tok++; + + if (!json_get_double(data, if_tok, "type", &val_d)) { + g_free(name); + continue; + } + type = (interface_type)val_d; + + if (!json_get_boolean(data, if_tok, "loopback", &loopback)) { + g_free(name); + continue; + } + + if_info = g_new0(if_info_t,1); + if_info->name = name; + val_s = json_get_string(data, if_tok, "friendly_name"); + if_info->friendly_name = g_strdup(val_s); + val_s = json_get_string(data, if_tok, "vendor_description"); + if_info->vendor_description = g_strdup(val_s); + if_info->type = type; + + addrs_tok = json_get_array(data, if_tok, "addrs"); + for (cur_tok = addrs_tok + 1, j = 0; j < json_get_array_len(addrs_tok); cur_tok++, j++) { + addr = g_strndup(&data[cur_tok->start], cur_tok->end - cur_tok->start); + if (json_decode_string_inplace(addr)) { + if_addr = g_new0(if_addr_t, 1); + if (ws_inet_pton4(addr, &if_addr->addr.ip4_addr)) { + if_addr->ifat_type = IF_AT_IPv4; + } else if (ws_inet_pton6(addr, (ws_in6_addr *)&if_addr->addr.ip6_addr)) { + if_addr->ifat_type = IF_AT_IPv6; + } else { + g_free(if_addr); + if_addr = NULL; + } + if (if_addr) { + if_info->addrs = g_slist_append(if_info->addrs, if_addr); + } + } + g_free(addr); + } + + if_info->loopback = loopback; + + val_s = json_get_string(data, if_tok, "extcap"); + /* if_info->extcap is never NULL, unlike the friendly name + * and vendor description. (see if_info_new) + */ + if_info->extcap = val_s ? g_strdup(val_s) : ""; + + cur_tok = json_get_object(data, if_tok, "caps"); + if (cur_tok) { + if_info->caps = deserialize_if_capability(data, cur_tok); + } + + if_list = g_list_append(if_list, if_info); + } + } + + wmem_free(NULL, tokens); + g_free(data); + + return if_list; +} + /** * Fetch the interface list from a child process (dumpcap). * * @return A GList containing if_info_t structs if successful, NULL (with err and possibly err_str set) otherwise. * */ - -/* XXX - We parse simple text output to get our interface list. Should - * we use "real" data serialization instead, e.g. via XML? */ GList * capture_interface_list(int *err, char **err_str, void (*update_cb)(void)) { int ret; GList *if_list = NULL; - int i, j; - char *data, *primary_msg, *secondary_msg; - char **raw_list, **if_parts, **addr_parts; - char *name; - if_info_t *if_info; - if_addr_t *if_addr; + char *data, *primary_msg, *secondary_msg; *err = 0; if (err_str) { @@ -112,67 +355,12 @@ capture_interface_list(int *err, char **err_str, void (*update_cb)(void)) * Add the extcap interfaces that can exist; they may exist * even if no native interfaces have been found. */ - ws_info("Loading External Capture Interface List ..."); + ws_debug("Loading External Capture Interface List ..."); if_list = append_extcap_interface_list(if_list); return if_list; } - /* Split our lines */ -#ifdef _WIN32 - raw_list = g_strsplit(data, "\r\n", 0); -#else - raw_list = g_strsplit(data, "\n", 0); -#endif - g_free(data); - - for (i = 0; raw_list[i] != NULL; i++) { - if_parts = g_strsplit(raw_list[i], "\t", 7); - if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL || - if_parts[3] == NULL || if_parts[4] == NULL || if_parts[5] == NULL || - if_parts[6] == NULL) { - g_strfreev(if_parts); - continue; - } - - /* Number followed by the name, e.g "1. eth0" */ - name = strchr(if_parts[0], ' '); - if (name) { - name++; - } else { - g_strfreev(if_parts); - continue; - } - - if_info = g_new0(if_info_t,1); - if_info->name = g_strdup(name); - if (strlen(if_parts[1]) > 0) - if_info->vendor_description = g_strdup(if_parts[1]); - if (strlen(if_parts[2]) > 0) - if_info->friendly_name = g_strdup(if_parts[2]); - if_info->type = (interface_type)(int)strtol(if_parts[3], NULL, 10); - addr_parts = g_strsplit(if_parts[4], ",", 0); - for (j = 0; addr_parts[j] != NULL; j++) { - if_addr = g_new0(if_addr_t,1); - if (ws_inet_pton4(addr_parts[j], &if_addr->addr.ip4_addr)) { - if_addr->ifat_type = IF_AT_IPv4; - } else if (ws_inet_pton6(addr_parts[j], (ws_in6_addr *)&if_addr->addr.ip6_addr)) { - if_addr->ifat_type = IF_AT_IPv6; - } else { - g_free(if_addr); - if_addr = NULL; - } - if (if_addr) { - if_info->addrs = g_slist_append(if_info->addrs, if_addr); - } - } - if (strcmp(if_parts[5], "loopback") == 0) - if_info->loopback = true; - if_info->extcap = g_strdup(if_parts[6]); - g_strfreev(if_parts); - g_strfreev(addr_parts); - if_list = g_list_append(if_list, if_info); - } - g_strfreev(raw_list); + if_list = deserialize_interface_list(data, err, err_str); #ifdef HAVE_PCAP_REMOTE /* Add the remote interface list */ @@ -182,14 +370,12 @@ capture_interface_list(int *err, char **err_str, void (*update_cb)(void)) #endif /* Add the extcap interfaces after the native and remote interfaces */ - ws_info("Loading External Capture Interface List ..."); + ws_debug("Loading External Capture Interface List ..."); if_list = append_extcap_interface_list(if_list); return if_list; } -/* XXX - We parse simple text output to get our interface list. Should - * we use "real" data serialization instead, e.g. via XML? */ if_capabilities_t * capture_get_if_capabilities(const char *ifname, bool monitor_mode, const char *auth_string, @@ -197,19 +383,20 @@ capture_get_if_capabilities(const char *ifname, bool monitor_mode, void (*update_cb)(void)) { if_capabilities_t *caps; - GList *linktype_list = NULL, *timestamp_list = NULL; - int err, i; - char *data, *primary_msg, *secondary_msg; - char **raw_list; + int err; + char *data, *primary_msg, *secondary_msg; + jsmntok_t *tokens, *inf_tok; /* see if the interface is from extcap */ caps = extcap_get_if_dlts(ifname, err_primary_msg); - if (caps != NULL) + if (caps != NULL) { + /* return if the extcap interface generated an error */ + if (caps->primary_msg) { + free_if_capabilities(caps); + caps = NULL; + } return caps; - - /* return if the extcap interface generated an error */ - if (err_primary_msg != NULL && *err_primary_msg != NULL) - return NULL; + } /* Try to get our interface list */ err = sync_if_capabilities_open(ifname, monitor_mode, auth_string, &data, @@ -228,100 +415,155 @@ capture_get_if_capabilities(const char *ifname, bool monitor_mode, return NULL; } - /* Split our lines */ -#ifdef _WIN32 - raw_list = g_strsplit(data, "\r\n", 0); -#else - raw_list = g_strsplit(data, "\n", 0); -#endif - g_free(data); + int num_tokens = json_parse(data, NULL, 0); + if (num_tokens <= 0) { + ws_info("Capture Interface Capabilities failed with invalid JSON."); + if (err_primary_msg) { + *err_primary_msg = g_strdup("Dumpcap returned bad JSON."); + } + g_free(data); + return NULL; + } - /* - * First line is 0 if monitor mode isn't supported, 1 if it is. - */ - if (raw_list[0] == NULL || *raw_list[0] == '\0') { + tokens = wmem_alloc_array(NULL, jsmntok_t, num_tokens); + if (json_parse(data, tokens, num_tokens) <= 0) { ws_info("Capture Interface Capabilities returned no information."); if (err_primary_msg) { *err_primary_msg = g_strdup("Dumpcap returned no interface capability information"); } - g_strfreev(raw_list); + wmem_free(NULL, tokens); + g_free(data); return NULL; } - /* - * Allocate the interface capabilities structure. - */ - caps = (if_capabilities_t *)g_malloc(sizeof *caps); - switch (*raw_list[0]) { + inf_tok = json_get_array_index(tokens, 0); + if (inf_tok && inf_tok->type == JSMN_OBJECT) { + inf_tok++; // Key + char *ifname2 = g_strndup(&data[inf_tok->start], inf_tok->end - inf_tok->start); + if (json_decode_string_inplace(ifname2) && g_strcmp0(ifname2, ifname) == 0) { + inf_tok++; + caps = deserialize_if_capability(data, inf_tok); + if (caps->primary_msg) { + if (err_primary_msg) { + *err_primary_msg = caps->primary_msg; + caps->primary_msg = NULL; + } + if (caps->secondary_msg && err_secondary_msg) { + *err_secondary_msg = g_strdup(caps->secondary_msg); + } + free_if_capabilities(caps); + caps = NULL; + } + } else if (err_primary_msg) { + *err_primary_msg = g_strdup("Dumpcap returned bad JSON."); + } + g_free(ifname2); + } else if (err_primary_msg) { + *err_primary_msg = g_strdup("Dumpcap returned bad JSON."); + } - case '0': - caps->can_set_rfmon = false; - break; + wmem_free(NULL, tokens); + g_free(data); - case '1': - caps->can_set_rfmon = true; - break; + return caps; +} - default: - ws_info("Capture Interface Capabilities returned bad information."); - if (err_primary_msg) { - *err_primary_msg = ws_strdup_printf("Dumpcap returned \"%s\" for monitor-mode capability", - raw_list[0]); - } - g_free(caps); - g_strfreev(raw_list); - return NULL; +static void +free_if_capabilities_cb(void *data) +{ + if (data != NULL) { + free_if_capabilities((if_capabilities_t*)data); } +} - /* - * The following are link-layer types. - */ - for (i = 1; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) { - data_link_info_t *data_link_info; - /* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */ - char **lt_parts = g_strsplit(raw_list[i], "\t", 3); - if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) { - g_strfreev(lt_parts); - continue; +GHashTable* +capture_get_if_list_capabilities(GList *if_cap_queries, + char **err_primary_msg, char **err_secondary_msg, + void (*update_cb)(void)) +{ + if_cap_query_t *query; + if_capabilities_t *caps; + GHashTable *caps_hash; + GList *local_queries = NULL; + int err, i; + char *data, *primary_msg, *secondary_msg; + jsmntok_t *tokens, *inf_tok; + + caps_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_if_capabilities_cb); + for (GList *li = if_cap_queries; li != NULL; li = g_list_next(li)) { + + query = (if_cap_query_t *)li->data; + /* see if the interface is from extcap */ + caps = extcap_get_if_dlts(query->name, NULL); + /* if the extcap interface generated an error, it was from extcap */ + if (caps != NULL) { + g_hash_table_replace(caps_hash, g_strdup(query->name), caps); + } else { + local_queries = g_list_prepend(local_queries, query); } + } - data_link_info = g_new(data_link_info_t,1); - data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10); - data_link_info->name = g_strdup(lt_parts[1]); - if (strcmp(lt_parts[2], "(not supported)") != 0) - data_link_info->description = g_strdup(lt_parts[2]); + if (local_queries == NULL) + return caps_hash; + + local_queries = g_list_reverse(local_queries); + + /* Try to get our interface list */ + err = sync_if_list_capabilities_open(local_queries, &data, + &primary_msg, &secondary_msg, update_cb); + g_list_free(local_queries); + if (err != 0) { + ws_info("Capture Interface Capabilities failed. Error %d, %s", + err, primary_msg ? primary_msg : "no message"); + if (err_primary_msg) + *err_primary_msg = primary_msg; else - data_link_info->description = NULL; - g_strfreev(lt_parts); + g_free(primary_msg); + if (err_secondary_msg) + *err_secondary_msg = secondary_msg; + else + g_free(secondary_msg); + return caps_hash; + } - linktype_list = g_list_append(linktype_list, data_link_info); + int num_tokens = json_parse(data, NULL, 0); + if (num_tokens <= 0) { + ws_info("Capture Interface Capabilities failed with invalid JSON."); + g_free(data); + return caps_hash; } - if (raw_list[i]) { /* Oh, timestamp types! */ - for (i++; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) { - timestamp_info_t *timestamp_info; - char **tt_parts = g_strsplit(raw_list[i], "\t", 2); - if (tt_parts[0] == NULL || tt_parts[1] == NULL) { - g_strfreev(tt_parts); + tokens = wmem_alloc_array(NULL, jsmntok_t, num_tokens); + if (json_parse(data, tokens, num_tokens) <= 0) { + ws_info("Capture Interface Capabilities returned no information."); + if (err_primary_msg) { + *err_primary_msg = g_strdup("Dumpcap returned no interface capability information"); + } + wmem_free(NULL, tokens); + g_free(data); + return caps_hash; + } + + char *ifname; + for (i = 0; i < json_get_array_len(tokens); i++) { + inf_tok = json_get_array_index(tokens, i); + if (inf_tok && inf_tok->type == JSMN_OBJECT) { + inf_tok++; // Key + ifname = g_strndup(&data[inf_tok->start], inf_tok->end - inf_tok->start); + if (!json_decode_string_inplace(ifname)) { + g_free(ifname); continue; } - - timestamp_info = g_new(timestamp_info_t,1); - timestamp_info->name = g_strdup(tt_parts[0]); - timestamp_info->description = g_strdup(tt_parts[1]); - g_strfreev(tt_parts); - - timestamp_list = g_list_append(timestamp_list, timestamp_info); + inf_tok++; + caps = deserialize_if_capability(data, inf_tok); + g_hash_table_replace(caps_hash, ifname, caps); } } - g_strfreev(raw_list); - - caps->data_link_types = linktype_list; - /* Might be NULL. Not all systems report timestamp types */ - caps->timestamp_types = timestamp_list; + wmem_free(NULL, tokens); + g_free(data); - return caps; + return caps_hash; } #ifdef HAVE_PCAP_REMOTE |