wireshark/ui/traffic_table_ui.c

221 lines
7.3 KiB
C

/* traffic_table_ui.c
* Helper routines common to conversation/endpoint tables.
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <glib.h>
#include "traffic_table_ui.h"
#include <wsutil/utf8_entities.h>
#ifdef HAVE_MAXMINDDB
#include <errno.h>
#include "wsutil/filesystem.h"
#include "wsutil/file_util.h"
#include "wsutil/json_dumper.h"
#endif
const char *conv_column_titles[CONV_NUM_COLUMNS] = {
"Address A",
"Port A",
"Address B",
"Port B",
"Packets",
"Bytes",
"Packets A " UTF8_RIGHTWARDS_ARROW " B",
"Bytes A " UTF8_RIGHTWARDS_ARROW " B",
"Packets B " UTF8_RIGHTWARDS_ARROW " A",
"Bytes B " UTF8_RIGHTWARDS_ARROW " A",
"Rel Start",
"Duration",
"Bits/s A " UTF8_RIGHTWARDS_ARROW " B",
"Bits/s B " UTF8_RIGHTWARDS_ARROW " A"
};
const char *conv_conn_a_title = "Connection A";
const char *conv_conn_b_title = "Connection B";
const char *conv_abs_start_title = "Abs Start";
const char *endp_column_titles[ENDP_NUM_GEO_COLUMNS] = {
"Address",
"Port",
"Packets",
"Bytes",
"Tx Packets",
"Tx Bytes",
"Rx Packets",
"Rx Bytes",
"Country",
"City",
"AS Number",
"AS Organization"
};
const char *endp_conn_title = "Connection";
#ifdef HAVE_MAXMINDDB
gboolean
write_endpoint_geoip_map(FILE *fp, gboolean json_only, hostlist_talker_t *const *hosts, gchar **err_str)
{
if (!json_only) {
char *base_html_path = get_datafile_path("ipmap.html");
FILE *base_html_fp = ws_fopen(base_html_path, "rb");
if (!base_html_fp) {
*err_str = g_strdup_printf("Could not open base file %s for reading: %s",
base_html_path, g_strerror(errno));
g_free(base_html_path);
return FALSE;
}
g_free(base_html_path);
/* Copy ipmap.html to map file. */
size_t n;
char buf[4096];
while ((n = fread(buf, 1, sizeof(buf), base_html_fp)) != 0) {
if (fwrite(buf, 1, n, fp) != n) {
*err_str = g_strdup_printf("Failed to write to map file: %s", g_strerror(errno));
fclose(base_html_fp);
return FALSE;
}
}
if (ferror(base_html_fp)) {
*err_str = g_strdup_printf("Failed to read base file: %s", g_strerror(errno));
fclose(base_html_fp);
return FALSE;
}
fclose(base_html_fp);
fputs("<script id=\"ipmap-data\" type=\"application/json\">\n", fp);
}
/*
* Writes a feature for each resolved address, the output will look like:
* {
* "type": "FeatureCollection",
* "features": [
* {
* "type": "Feature",
* "geometry": {
* "type": "Point",
* "coordinates": [ -97.821999, 37.750999 ]
* },
* "properties": {
* "ip": "8.8.4.4",
* "autonomous_system_number": 15169,
* "autonomous_system_organization": "Google LLC",
* "city": "(omitted, but key is shown for documentation reasons)",
* "country": "United States",
* "radius": 1000,
* "packets": 1,
* "bytes": 1543
* }
* }
* ]
* }
*/
json_dumper dumper = {
.output_file = fp,
.flags = JSON_DUMPER_FLAGS_PRETTY_PRINT
};
json_dumper_begin_object(&dumper);
json_dumper_set_member_name(&dumper, "type");
json_dumper_value_string(&dumper, "FeatureCollection");
json_dumper_set_member_name(&dumper, "features");
json_dumper_begin_array(&dumper);
/* Append map data. */
size_t count = 0;
const hostlist_talker_t *host;
for (hostlist_talker_t *const *iter = hosts; (host = *iter) != NULL; ++iter) {
char addr[WS_INET6_ADDRSTRLEN];
const mmdb_lookup_t *result = NULL;
if (host->myaddress.type == AT_IPv4) {
const ws_in4_addr *ip4 = (const ws_in4_addr *)host->myaddress.data;
result = maxmind_db_lookup_ipv4(ip4);
ws_inet_ntop4(ip4, addr, sizeof(addr));
} else if (host->myaddress.type == AT_IPv6) {
const ws_in6_addr *ip6 = (const ws_in6_addr *)host->myaddress.data;
result = maxmind_db_lookup_ipv6(ip6);
ws_inet_ntop6(ip6, addr, sizeof(addr));
}
if (!maxmind_db_has_coords(result)) {
// result could be NULL if the caller did not trigger a lookup
// before. result->found could be FALSE if no MMDB entry exists.
continue;
}
++count;
json_dumper_begin_object(&dumper);
json_dumper_set_member_name(&dumper, "type");
json_dumper_value_string(&dumper, "Feature");
json_dumper_set_member_name(&dumper, "geometry");
{
json_dumper_begin_object(&dumper);
json_dumper_set_member_name(&dumper, "type");
json_dumper_value_string(&dumper, "Point");
json_dumper_set_member_name(&dumper, "coordinates");
json_dumper_begin_array(&dumper);
json_dumper_value_double(&dumper, result->longitude);
json_dumper_value_double(&dumper, result->latitude);
json_dumper_end_array(&dumper); // end coordinates
}
json_dumper_end_object(&dumper); // end geometry
json_dumper_set_member_name(&dumper, "properties");
json_dumper_begin_object(&dumper);
{
json_dumper_set_member_name(&dumper, "ip");
json_dumper_value_string(&dumper, addr);
if (result->as_number && result->as_org) {
json_dumper_set_member_name(&dumper, "autonomous_system_number");
json_dumper_value_anyf(&dumper, "%u", result->as_number);
json_dumper_set_member_name(&dumper, "autonomous_system_organization");
json_dumper_value_string(&dumper, result->as_org);
}
if (result->city) {
json_dumper_set_member_name(&dumper, "city");
json_dumper_value_string(&dumper, result->city);
}
if (result->country) {
json_dumper_set_member_name(&dumper, "country");
json_dumper_value_string(&dumper, result->country);
}
if (result->accuracy) {
json_dumper_set_member_name(&dumper, "radius");
json_dumper_value_anyf(&dumper, "%u", result->accuracy);
}
json_dumper_set_member_name(&dumper, "packets");
json_dumper_value_anyf(&dumper, "%" G_GUINT64_FORMAT, host->rx_frames + host->tx_frames);
json_dumper_set_member_name(&dumper, "bytes");
json_dumper_value_anyf(&dumper, "%" G_GUINT64_FORMAT, host->rx_bytes + host->tx_bytes);
}
json_dumper_end_object(&dumper); // end properties
json_dumper_end_object(&dumper);
}
json_dumper_end_array(&dumper); // end features
json_dumper_end_object(&dumper);
json_dumper_finish(&dumper);
if (!json_only) {
fputs("</script>\n", fp);
}
if (count == 0) {
*err_str = g_strdup("No endpoints available to map");
return FALSE;
}
return TRUE;
}
#endif