summaryrefslogtreecommitdiffstats
path: root/capture/capture_ifinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'capture/capture_ifinfo.c')
-rw-r--r--capture/capture_ifinfo.c540
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