From a1da75c554881667dd92e11f098630f2d604872b Mon Sep 17 00:00:00 2001 From: Gerald Combs Date: Thu, 8 Feb 2018 17:20:26 -0800 Subject: Transition from GeoIP Legacy to MaxMindDB. MaxMind is discontinuing its legacy databases in April in favor of GeoIP2, which use a newer database format (MaxMind DB). The reference C library (libmaxminddb) is available under the Apache 2.0 license which isn't quite compatible with ours. Add mmdbresolve, a utility that reads IPv4 and IPv6 addresses on stdin and prints resolved information on stdout. Place it under a liberal license (MIT) so that we can keep libmaxminddb at arm's length. Add epan/maxmind_db.[ch], which spawns mmdbresolve and communicates with it via stdio. Migrate the preferences and documentation to MaxMindDB. Change the IPv4 and IPv6 asnum fields to FT_UINT32s. Change the geographic coordinate fields to FT_DOUBLEs. Bug: 10658 Change-Id: I24aeed637bea1b41d173270bda413af230f4425f Reviewed-on: https://code.wireshark.org/review/26214 Petri-Dish: Gerald Combs Tested-by: Petri Dish Buildbot Reviewed-by: Gerald Combs --- epan/CMakeLists.txt | 9 +- epan/Makefile.am | 9 +- epan/addr_resolv.c | 10 +- epan/addr_resolv.h | 6 + epan/dissectors/Makefile.am | 2 +- epan/dissectors/packet-ip.c | 271 ++++++++---------- epan/dissectors/packet-ipv6.c | 285 ++++++++----------- epan/epan.c | 10 +- epan/geoip_db.c | 638 ------------------------------------------ epan/geoip_db.h | 104 ------- epan/maxmind_db.c | 513 +++++++++++++++++++++++++++++++++ epan/maxmind_db.h | 93 ++++++ epan/prefs.c | 8 +- 13 files changed, 876 insertions(+), 1082 deletions(-) delete mode 100644 epan/geoip_db.c delete mode 100644 epan/geoip_db.h create mode 100644 epan/maxmind_db.c create mode 100644 epan/maxmind_db.h (limited to 'epan') diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 5bd3d40e4e..f0196fc57f 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -105,7 +105,7 @@ set(LIBWIRESHARK_PUBLIC_HEADERS frame_data_sequence.h funnel.h garrayfix.h - geoip_db.h + #geoip_db.h golay.h guid-utils.h iana_charsets.h @@ -117,6 +117,7 @@ set(LIBWIRESHARK_PUBLIC_HEADERS ipv6.h lapd_sapi.h llcsaps.h + maxmind_db.h media_params.h next_tvb.h nlpid.h @@ -208,12 +209,13 @@ set(LIBWIRESHARK_NONGENERATED_FILES frame_data.c frame_data_sequence.c funnel.c - geoip_db.c + #geoip_db.c golay.c guid-utils.c iana_charsets.c in_cksum.c ipproto.c + maxmind_db.c media_params.c next_tvb.c oids.c @@ -278,8 +280,9 @@ set(epan_LIBS wsutil ${CARES_LIBRARIES} ${GCRYPT_LIBRARIES} - ${GEOIP_LIBRARIES} + #${GEOIP_LIBRARIES} ${GLIB2_LIBRARIES} + ${GIO2_LIBRARIES} ${GTHREAD2_LIBRARIES} ${GNUTLS_LIBRARIES} ${KERBEROS_LIBRARIES} diff --git a/epan/Makefile.am b/epan/Makefile.am index d22d68e18b..c85fcd2d52 100644 --- a/epan/Makefile.am +++ b/epan/Makefile.am @@ -31,8 +31,8 @@ SUBDIRS = crypt ftypes dfilter dissectors wmem $(wslua_dir) AM_CPPFLAGS = $(INCLUDEDIRS) $(WS_CPPFLAGS) \ $(GLIB_CFLAGS) $(PCAP_CFLAGS) $(LUA_CFLAGS) $(LIBGNUTLS_CFLAGS) \ - $(LIBGCRYPT_CFLAGS) $(LIBSMI_CFLAGS) $(LIBGEOIP_CFLAGS) \ - $(LZ4_CFLAGS) $(KRB5_CFLAGS) $(SNAPPY_CFLAGS) $(LIBXML2_CFLAGS) + $(LIBGCRYPT_CFLAGS) $(LIBSMI_CFLAGS) $(LZ4_CFLAGS) $(KRB5_CFLAGS) \ + $(SNAPPY_CFLAGS) $(LIBXML2_CFLAGS) lib_LTLIBRARIES = libwireshark.la @@ -71,12 +71,12 @@ LIBWIRESHARK_NONGENERATED_SRC = \ frame_data.c \ frame_data_sequence.c \ funnel.c \ - geoip_db.c \ golay.c \ guid-utils.c \ iana_charsets.c \ in_cksum.c \ ipproto.c \ + maxmind_db.c \ media_params.c \ next_tvb.c \ oids.c \ @@ -212,7 +212,6 @@ LIBWIRESHARK_INCLUDES_PUBLIC = \ frame_data_sequence.h \ funnel.h \ garrayfix.h \ - geoip_db.h \ golay.h \ guid-utils.h \ iana_charsets.h \ @@ -224,6 +223,7 @@ LIBWIRESHARK_INCLUDES_PUBLIC = \ ipv6.h \ lapd_sapi.h \ llcsaps.h \ + maxmind_db.h \ media_params.h \ next_tvb.h \ nlpid.h \ @@ -321,7 +321,6 @@ libwireshark_la_LIBADD = \ ${top_builddir}/wiretap/libwiretap.la \ ${top_builddir}/wsutil/libwsutil.la \ @C_ARES_LIBS@ \ - @GEOIP_LIBS@ \ @KRB5_LIBS@ \ @LIBGCRYPT_LIBS@ \ @LIBGNUTLS_LIBS@ \ diff --git a/epan/addr_resolv.c b/epan/addr_resolv.c index 1cae8a5733..56da73bf69 100644 --- a/epan/addr_resolv.c +++ b/epan/addr_resolv.c @@ -92,6 +92,7 @@ #include #include +#include #include #define ENAME_HOSTS "hosts" @@ -245,12 +246,12 @@ static void add_serv_port_cb(const guint32 port, gpointer ptr); /* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx#existing * One-at-a-Time hash */ -static guint32 +guint ipv6_oat_hash(gconstpointer key) { int len = 16; const unsigned char *p = (const unsigned char *)key; - guint32 h = 0; + guint h = 0; int i; for ( i = 0; i < len; i++ ) { @@ -266,7 +267,7 @@ ipv6_oat_hash(gconstpointer key) return h; } -static gboolean +gboolean ipv6_equal(gconstpointer v1, gconstpointer v2) { @@ -2519,6 +2520,7 @@ host_name_lookup_process(void) { wmem_list_frame_t* head; new_resolved_objects = FALSE; + nro |= maxmind_db_lookup_process(); if (!async_dns_initialized) /* c-ares not initialized. Bail out and cancel timers. */ @@ -2579,6 +2581,8 @@ host_name_lookup_process(void) { new_resolved_objects = FALSE; + nro |= maxmind_db_lookup_process(); + return nro; } diff --git a/epan/addr_resolv.h b/epan/addr_resolv.h index cfac1fc5c1..bc1d78d61a 100644 --- a/epan/addr_resolv.h +++ b/epan/addr_resolv.h @@ -381,6 +381,12 @@ gboolean str_to_ip(const char *str, void *dst); WS_DLL_PUBLIC gboolean str_to_ip6(const char *str, void *dst); +WS_DLL_LOCAL +guint ipv6_oat_hash(gconstpointer key); + +WS_DLL_LOCAL +gboolean ipv6_equal(gconstpointer v1, gconstpointer v2); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/epan/dissectors/Makefile.am b/epan/dissectors/Makefile.am index 423a5dda34..0367141e8e 100644 --- a/epan/dissectors/Makefile.am +++ b/epan/dissectors/Makefile.am @@ -22,7 +22,7 @@ include $(top_srcdir)/Makefile.am.inc AM_CPPFLAGS = $(INCLUDEDIRS) -I$(top_srcdir)/epan $(WS_CPPFLAGS) \ $(GLIB_CFLAGS) $(LIBGNUTLS_CFLAGS) $(LIBGCRYPT_CFLAGS) \ - $(LIBGEOIP_CFLAGS) $(KRB5_CFLAGS) $(LIBXML2_CFLAGS) + $(KRB5_CFLAGS) $(LIBXML2_CFLAGS) include Custom.common diff --git a/epan/dissectors/packet-ip.c b/epan/dissectors/packet-ip.c index 1ab1b25812..02432764f1 100644 --- a/epan/dissectors/packet-ip.c +++ b/epan/dissectors/packet-ip.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -48,11 +49,6 @@ #include "packet-mpls.h" #include "packet-nsh.h" -#ifdef HAVE_GEOIP -#include -#include -#endif /* HAVE_GEOIP */ - void proto_register_ip(void); void proto_reg_handoff_ip(void); @@ -76,10 +72,8 @@ static gboolean ip_tso_supported = TRUE; /* Use heuristics to determine subdissector */ static gboolean try_heuristic_first = FALSE; -#ifdef HAVE_GEOIP -/* Look up addresses in GeoIP */ +/* Look up addresses via mmdbresolve */ static gboolean ip_use_geoip = TRUE; -#endif /* HAVE_GEOIP */ /* Interpret the reserved flag as security flag (RFC 3514) */ static gboolean ip_security_flag = FALSE; @@ -204,29 +198,26 @@ static int hf_ip_cipso_doi = -1; static int hf_ip_opt_time_stamp = -1; static int hf_ip_opt_time_stamp_addr = -1; -#ifdef HAVE_GEOIP static int hf_geoip_country = -1; static int hf_geoip_city = -1; -static int hf_geoip_org = -1; -static int hf_geoip_isp = -1; -static int hf_geoip_asnum = -1; -static int hf_geoip_lat = -1; -static int hf_geoip_lon = -1; +static int hf_geoip_as_number = -1; +static int hf_geoip_as_org = -1; +static int hf_geoip_latitude = -1; +static int hf_geoip_longitude = -1; +static int hf_geoip_src_summary = -1; static int hf_geoip_src_country = -1; static int hf_geoip_src_city = -1; -static int hf_geoip_src_org = -1; -static int hf_geoip_src_isp = -1; -static int hf_geoip_src_asnum = -1; -static int hf_geoip_src_lat = -1; -static int hf_geoip_src_lon = -1; +static int hf_geoip_src_as_number = -1; +static int hf_geoip_src_as_org = -1; +static int hf_geoip_src_latitude = -1; +static int hf_geoip_src_longitude = -1; +static int hf_geoip_dst_summary = -1; static int hf_geoip_dst_country = -1; static int hf_geoip_dst_city = -1; -static int hf_geoip_dst_org = -1; -static int hf_geoip_dst_isp = -1; -static int hf_geoip_dst_asnum = -1; -static int hf_geoip_dst_lat = -1; -static int hf_geoip_dst_lon = -1; -#endif /* HAVE_GEOIP */ +static int hf_geoip_dst_as_number = -1; +static int hf_geoip_dst_as_org = -1; +static int hf_geoip_dst_latitude = -1; +static int hf_geoip_dst_longitude = -1; static gint ett_ip = -1; static gint ett_ip_dsfield = -1; @@ -271,9 +262,7 @@ static expert_field ei_ip_bogus_ip_version = EI_INIT; static dissector_handle_t ip_handle; static dissector_table_t ip_option_table; -#ifdef HAVE_GEOIP static gint ett_geoip_info = -1; -#endif /* HAVE_GEOIP */ static const fragment_items ip_frag_items = { &ett_ip_fragment, @@ -576,110 +565,93 @@ capture_ip(const guchar *pd, int offset, int len, capture_packet_info_t *cpinfo, return try_capture_dissector("ip.proto", pd[offset + 9], pd, offset+IPH_MIN_LEN, len, cpinfo, pseudo_header); } -#ifdef HAVE_GEOIP static void -add_geoip_info_entry(proto_tree *geoip_info_tree, proto_item *geoip_info_item, tvbuff_t *tvb, gint offset, guint32 ip, int isdst) +add_geoip_info_entry(proto_tree *tree, tvbuff_t *tvb, gint offset, guint32 ip, int isdst) { - guint num_dbs = geoip_db_num_dbs(); - guint item_cnt = 0; - guint dbnum; + const mmdb_lookup_t *lookup = maxmind_db_lookup_ipv4(ip); + if (!lookup->found) return; - for (dbnum = 0; dbnum < num_dbs; dbnum++) { - char *geoip_str = geoip_db_lookup_ipv4(dbnum, ip, NULL); - int db_type = geoip_db_type(dbnum); + wmem_strbuf_t *summary = wmem_strbuf_new(wmem_packet_scope(), ""); + if (lookup->city) { + wmem_strbuf_append(summary, lookup->city); + } + if (lookup->country) { + if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", "); + wmem_strbuf_append(summary, lookup->country); + } + if (lookup->as_number > 0) { + if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", "); + wmem_strbuf_append_printf(summary, "ASN %u", lookup->as_number); + } + if (lookup->as_org) { + if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", "); + wmem_strbuf_append(summary, lookup->as_org); + } - int geoip_hf, geoip_local_hf; + int addr_offset = offset + isdst ? IPH_DST : IPH_SRC; + int dir_hf = isdst ? hf_geoip_dst_summary : hf_geoip_src_summary; + proto_item *geoip_info_item = proto_tree_add_string(tree, dir_hf, tvb, addr_offset, 4, wmem_strbuf_finalize(summary)); + PROTO_ITEM_SET_GENERATED(geoip_info_item); + proto_tree *geoip_info_tree = proto_item_add_subtree(geoip_info_item, ett_geoip_info); - switch (db_type) { - case GEOIP_COUNTRY_EDITION: - geoip_hf = hf_geoip_country; - geoip_local_hf = (isdst) ? hf_geoip_dst_country : hf_geoip_src_country; - break; - case GEOIP_CITY_EDITION_REV0: - geoip_hf = hf_geoip_city; - geoip_local_hf = (isdst) ? hf_geoip_dst_city : hf_geoip_src_city; - break; - case GEOIP_CITY_EDITION_REV1: - geoip_hf = hf_geoip_city; - geoip_local_hf = (isdst) ? hf_geoip_dst_city : hf_geoip_src_city; - break; - case GEOIP_ORG_EDITION: - geoip_hf = hf_geoip_org; - geoip_local_hf = (isdst) ? hf_geoip_dst_org : hf_geoip_src_org; - break; - case GEOIP_ISP_EDITION: - geoip_hf = hf_geoip_isp; - geoip_local_hf = (isdst) ? hf_geoip_dst_isp : hf_geoip_src_isp; - break; - case GEOIP_ASNUM_EDITION: - geoip_hf = hf_geoip_asnum; - geoip_local_hf = (isdst) ? hf_geoip_dst_asnum : hf_geoip_src_asnum; - break; - case WS_LAT_FAKE_EDITION: - geoip_hf = hf_geoip_lat; - geoip_local_hf = (isdst) ? hf_geoip_dst_lat : hf_geoip_src_lat; - break; - case WS_LON_FAKE_EDITION: - geoip_hf = hf_geoip_lon; - geoip_local_hf = (isdst) ? hf_geoip_dst_lon : hf_geoip_src_lon; - break; - default: - continue; - } + proto_item *item; - if (geoip_str) { - proto_item *item; - if (db_type == WS_LAT_FAKE_EDITION || db_type == WS_LON_FAKE_EDITION) { - /* Convert latitude, longitude to double. Fix bug #5077 */ - item = proto_tree_add_double_format_value(geoip_info_tree, geoip_local_hf, - tvb, offset, 4, g_ascii_strtod(geoip_str, NULL), "%s", geoip_str); - PROTO_ITEM_SET_GENERATED(item); - item = proto_tree_add_double_format_value(geoip_info_tree, geoip_hf, - tvb, offset, 4, g_ascii_strtod(geoip_str, NULL), "%s", geoip_str); - PROTO_ITEM_SET_GENERATED(item); - PROTO_ITEM_SET_HIDDEN(item); - } else { - item = proto_tree_add_string(geoip_info_tree, geoip_local_hf, - tvb, offset, 4, geoip_str); - PROTO_ITEM_SET_GENERATED(item); - item = proto_tree_add_string(geoip_info_tree, geoip_hf, - tvb, offset, 4, geoip_str); - PROTO_ITEM_SET_GENERATED(item); - PROTO_ITEM_SET_HIDDEN(item); - } + if (lookup->city) { + dir_hf = isdst ? hf_geoip_dst_city : hf_geoip_src_city; + item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->city); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_string(geoip_info_tree, hf_geoip_city, tvb, addr_offset, 4, lookup->city); + PROTO_ITEM_SET_GENERATED(item); + } - item_cnt++; - proto_item_append_text(geoip_info_item, "%s%s", - plurality(item_cnt, "", ", "), geoip_str); - wmem_free(NULL, geoip_str); - } + if (lookup->country) { + dir_hf = isdst ? hf_geoip_dst_country : hf_geoip_src_country; + item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->country); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_string(geoip_info_tree, hf_geoip_country, tvb, addr_offset, 4, lookup->country); + PROTO_ITEM_SET_GENERATED(item); + } + + if (lookup->as_number > 0) { + dir_hf = isdst ? hf_geoip_dst_as_number : hf_geoip_src_as_number; + item = proto_tree_add_uint(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->as_number); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(geoip_info_tree, hf_geoip_as_number, tvb, addr_offset, 4, lookup->as_number); + PROTO_ITEM_SET_GENERATED(item); + } + + if (lookup->as_org) { + dir_hf = isdst ? hf_geoip_dst_as_org : hf_geoip_src_as_org; + item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->as_org); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_string(geoip_info_tree, hf_geoip_as_org, tvb, addr_offset, 4, lookup->as_org); + PROTO_ITEM_SET_GENERATED(item); + } + + if (lookup->latitude >= -90.0 && lookup->latitude <= 90.0) { + dir_hf = isdst ? hf_geoip_dst_latitude : hf_geoip_src_latitude; + item = proto_tree_add_double(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->latitude); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_double(geoip_info_tree, hf_geoip_latitude, tvb, addr_offset, 4, lookup->latitude); + PROTO_ITEM_SET_GENERATED(item); } - if (item_cnt == 0) - proto_item_append_text(geoip_info_item, "Unknown"); + if (lookup->longitude >= -180.0 && lookup->longitude <= 180.0) { + dir_hf = isdst ? hf_geoip_dst_longitude : hf_geoip_src_longitude; + item = proto_tree_add_double(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->longitude); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_double(geoip_info_tree, hf_geoip_longitude, tvb, addr_offset, 4, lookup->longitude); + PROTO_ITEM_SET_GENERATED(item); + } } static void add_geoip_info(proto_tree *tree, tvbuff_t *tvb, gint offset, guint32 src32, guint32 dst32) { - guint num_dbs; - proto_item *geoip_info_item; - proto_tree *geoip_info_tree; - - num_dbs = geoip_db_num_dbs(); - if (num_dbs < 1) - return; - - geoip_info_tree = proto_tree_add_subtree(tree, tvb, offset + IPH_SRC, 4, ett_geoip_info, &geoip_info_item, "Source GeoIP: "); - PROTO_ITEM_SET_GENERATED(geoip_info_item); - add_geoip_info_entry(geoip_info_tree, geoip_info_item, tvb, offset + IPH_SRC, src32, 0); - - geoip_info_tree = proto_tree_add_subtree(tree, tvb, offset + IPH_DST, 4, ett_geoip_info, &geoip_info_item, "Destination GeoIP: "); - PROTO_ITEM_SET_GENERATED(geoip_info_item); - add_geoip_info_entry(geoip_info_tree, geoip_info_item, tvb, offset + IPH_DST, dst32, 1); + add_geoip_info_entry(tree, tvb, offset, g_htonl(src32), FALSE); + add_geoip_info_entry(tree, tvb, offset, g_htonl(dst32), TRUE); } -#endif /* HAVE_GEOIP */ const value_string ipopt_type_class_vals[] = { {(IPOPT_CONTROL & IPOPT_CLASS_MASK) >> 5, "Control"}, @@ -2206,13 +2178,11 @@ dissect_ip_v4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* PROTO_ITEM_SET_GENERATED(item); PROTO_ITEM_SET_HIDDEN(item); } - } -#ifdef HAVE_GEOIP - if (tree && ip_use_geoip) { - add_geoip_info(ip_tree, tvb, offset, src32, dst32); + if (ip_use_geoip) { + add_geoip_info(ip_tree, tvb, offset, src32, dst32); + } } -#endif /* Decode IP options, if any. */ if (hlen > IPH_MIN_LEN) { @@ -2522,71 +2492,66 @@ proto_register_ip(void) { "Source or Destination Host", "ip.host", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, -#ifdef HAVE_GEOIP { &hf_geoip_country, { "Source or Destination GeoIP Country", "ip.geoip.country", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, { &hf_geoip_city, { "Source or Destination GeoIP City", "ip.geoip.city", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_org, - { "Source or Destination GeoIP Organization", "ip.geoip.org", - FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_isp, - { "Source or Destination GeoIP ISP", "ip.geoip.isp", - FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_asnum, + { &hf_geoip_as_number, { "Source or Destination GeoIP AS Number", "ip.geoip.asnum", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + { &hf_geoip_as_org, + { "Source or Destination GeoIP AS Organization", "ip.geoip.org", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_lat, + { &hf_geoip_latitude, { "Source or Destination GeoIP Latitude", "ip.geoip.lat", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_lon, + { &hf_geoip_longitude, { "Source or Destination GeoIP Longitude", "ip.geoip.lon", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_geoip_src_summary, + { "Source GeoIP", "ip.geoip.src_summary", + FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, { &hf_geoip_src_country, { "Source GeoIP Country", "ip.geoip.src_country", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, { &hf_geoip_src_city, { "Source GeoIP City", "ip.geoip.src_city", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_src_org, - { "Source GeoIP Organization", "ip.geoip.src_org", - FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_src_isp, - { "Source GeoIP ISP", "ip.geoip.src_isp", - FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_src_asnum, + { &hf_geoip_src_as_number, { "Source GeoIP AS Number", "ip.geoip.src_asnum", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + { &hf_geoip_src_as_org, + { "Source GeoIP AS Organization", "ip.geoip.src_org", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_src_lat, + { &hf_geoip_src_latitude, { "Source GeoIP Latitude", "ip.geoip.src_lat", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_src_lon, + { &hf_geoip_src_longitude, { "Source GeoIP Longitude", "ip.geoip.src_lon", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_geoip_dst_summary, + { "Destination GeoIP", "ip.geoip.dst_summary", + FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, { &hf_geoip_dst_country, { "Destination GeoIP Country", "ip.geoip.dst_country", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, { &hf_geoip_dst_city, { "Destination GeoIP City", "ip.geoip.dst_city", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_dst_org, - { "Destination GeoIP Organization", "ip.geoip.dst_org", - FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_dst_isp, - { "Destination GeoIP ISP", "ip.geoip.dst_isp", - FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_dst_asnum, + { &hf_geoip_dst_as_number, { "Destination GeoIP AS Number", "ip.geoip.dst_asnum", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + { &hf_geoip_dst_as_org, + { "Destination GeoIP AS Organization", "ip.geoip.dst_org", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_dst_lat, + { &hf_geoip_dst_latitude, { "Destination GeoIP Latitude", "ip.geoip.dst_lat", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, - { &hf_geoip_dst_lon, + { &hf_geoip_dst_longitude, { "Destination GeoIP Longitude", "ip.geoip.dst_lon", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, -#endif /* HAVE_GEOIP */ { &hf_ip_flags, { "Flags", "ip.flags", FT_UINT16, BASE_HEX, @@ -2906,9 +2871,7 @@ proto_register_ip(void) &ett_ip_opt_type, &ett_ip_opt_sec_prot_auth_flags, &ett_ip_unknown_opt, -#ifdef HAVE_GEOIP &ett_geoip_info -#endif }; static ei_register_info ei[] = { { &ei_ip_opt_len_invalid, { "ip.opt.len.invalid", PI_PROTOCOL, PI_WARN, "Invalid length for option", EXPFILL }}, @@ -2970,12 +2933,10 @@ proto_register_ip(void) "Support packet-capture from IP TSO-enabled hardware", "Whether to correct for TSO-enabled (TCP segmentation offload) hardware " "captures, such as spoofing the IP packet length", &ip_tso_supported); -#ifdef HAVE_GEOIP prefs_register_bool_preference(ip_module, "use_geoip", - "Enable GeoIP lookups", - "Whether to look up IP addresses in each GeoIP database we have loaded", + "Enable IPv4 geolocation", + "Whether to look up IP addresses in each MaxMind database we have loaded", &ip_use_geoip); -#endif /* HAVE_GEOIP */ prefs_register_bool_preference(ip_module, "security_flag" , "Interpret Reserved flag as Security flag (RFC 3514)", "Whether to interpret the originally reserved flag as security flag", diff --git a/epan/dissectors/packet-ipv6.c b/epan/dissectors/packet-ipv6.c index 852cf192a6..40e11edd99 100644 --- a/epan/dissectors/packet-ipv6.c +++ b/epan/dissectors/packet-ipv6.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -43,11 +44,6 @@ #include "packet-mpls.h" #include "packet-nsh.h" -#ifdef HAVE_GEOIP_V6 -#include -#include -#endif /* HAVE_GEOIP_V6 */ - void proto_register_ipv6(void); void proto_reg_handoff_ipv6(void); @@ -269,29 +265,26 @@ static int hf_ipv6_routing_srh_flag_unused2 = -1; static int hf_ipv6_routing_srh_reserved = -1; static int hf_ipv6_routing_srh_addr = -1; -#ifdef HAVE_GEOIP_V6 static int hf_geoip_country = -1; static int hf_geoip_city = -1; -static int hf_geoip_org = -1; -static int hf_geoip_isp = -1; -static int hf_geoip_asnum = -1; -static int hf_geoip_lat = -1; -static int hf_geoip_lon = -1; +static int hf_geoip_as_number = -1; +static int hf_geoip_as_org = -1; +static int hf_geoip_latitude = -1; +static int hf_geoip_longitude = -1; +static int hf_geoip_src_summary = -1; static int hf_geoip_src_country = -1; static int hf_geoip_src_city = -1; -static int hf_geoip_src_org = -1; -static int hf_geoip_src_isp = -1; -static int hf_geoip_src_asnum = -1; -static int hf_geoip_src_lat = -1; -static int hf_geoip_src_lon = -1; +static int hf_geoip_src_as_number = -1; +static int hf_geoip_src_as_org = -1; +static int hf_geoip_src_latitude = -1; +static int hf_geoip_src_longitude = -1; +static int hf_geoip_dst_summary = -1; static int hf_geoip_dst_country = -1; static int hf_geoip_dst_city = -1; -static int hf_geoip_dst_org = -1; -static int hf_geoip_dst_isp = -1; -static int hf_geoip_dst_asnum = -1; -static int hf_geoip_dst_lat = -1; -static int hf_geoip_dst_lon = -1; -#endif /* HAVE_GEOIP_V6 */ +static int hf_geoip_dst_as_number = -1; +static int hf_geoip_dst_as_org = -1; +static int hf_geoip_dst_latitude = -1; +static int hf_geoip_dst_longitude = -1; static gint ett_ipv6_proto = -1; static gint ett_ipv6_traffic_class = -1; @@ -309,9 +302,7 @@ static gint ett_ipv6_fragments = -1; static gint ett_ipv6_fragment = -1; static gint ett_ipv6_dstopts_proto = -1; -#ifdef HAVE_GEOIP_V6 static gint ett_geoip_info = -1; -#endif /* HAVE_GEOIP_V6 */ static expert_field ei_ipv6_routing_invalid_length = EI_INIT; static expert_field ei_ipv6_routing_invalid_segleft = EI_INIT; @@ -523,10 +514,8 @@ static gboolean ipv6_reassemble = TRUE; /* Place IPv6 summary in proto tree */ static gboolean ipv6_summary_in_tree = TRUE; -#ifdef HAVE_GEOIP_V6 -/* Look up addresses in GeoIP */ +/* Look up addresses via mmdbresolve */ static gboolean ipv6_use_geoip = TRUE; -#endif /* HAVE_GEOIP_V6 */ /* Perform strict RFC adherence checking */ static gboolean g_ipv6_rpl_srh_strict_rfc_checking = FALSE; @@ -713,107 +702,92 @@ capture_ipv6_exthdr(const guchar *pd, int offset, int len, capture_packet_info_t return try_capture_dissector("ip.proto", nxt, pd, offset, len, cpinfo, pseudo_header); } -#ifdef HAVE_GEOIP_V6 static void -add_geoip_info_entry(proto_tree *geoip_info_tree, proto_item *geoip_info_item, tvbuff_t *tvb, gint offset, const ws_in6_addr *ip, int isdst) +add_geoip_info_entry(proto_tree *tree, tvbuff_t *tvb, gint offset, const ws_in6_addr *ip6, int isdst) { - guint num_dbs = geoip_db_num_dbs(); - guint item_cnt = 0; - guint dbnum; + const mmdb_lookup_t *lookup = maxmind_db_lookup_ipv6(ip6); + if (!lookup->found) return; - for (dbnum = 0; dbnum < num_dbs; dbnum++) { - char *geoip_str = geoip_db_lookup_ipv6(dbnum, *ip, NULL); - int db_type = geoip_db_type(dbnum); + wmem_strbuf_t *summary = wmem_strbuf_new(wmem_packet_scope(), ""); + if (lookup->city) { + wmem_strbuf_append(summary, lookup->city); + } + if (lookup->country) { + if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", "); + wmem_strbuf_append(summary, lookup->country); + } + if (lookup->as_number > 0) { + if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", "); + wmem_strbuf_append_printf(summary, "ASN %u", lookup->as_number); + } + if (lookup->as_org) { + if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", "); + wmem_strbuf_append(summary, lookup->as_org); + } - int geoip_hf, geoip_local_hf; + int addr_offset = offset + isdst ? IP6H_DST : IP6H_SRC; + int dir_hf = isdst ? hf_geoip_dst_summary : hf_geoip_src_summary; + proto_item *geoip_info_item = proto_tree_add_string(tree, dir_hf, tvb, addr_offset, 16, wmem_strbuf_finalize(summary)); + PROTO_ITEM_SET_GENERATED(geoip_info_item); + proto_tree *geoip_info_tree = proto_item_add_subtree(geoip_info_item, ett_geoip_info); - switch (db_type) { - case GEOIP_COUNTRY_EDITION_V6: - geoip_hf = hf_geoip_country; - geoip_local_hf = (isdst) ? hf_geoip_dst_country : hf_geoip_src_country; - break; -#if NUM_DB_TYPES > 31 - case GEOIP_CITY_EDITION_REV0_V6: - case GEOIP_CITY_EDITION_REV1_V6: - geoip_hf = hf_geoip_city; - geoip_local_hf = (isdst) ? hf_geoip_dst_city : hf_geoip_src_city; - break; - case GEOIP_ORG_EDITION_V6: - geoip_hf = hf_geoip_org; - geoip_local_hf = (isdst) ? hf_geoip_dst_org : hf_geoip_src_org; - break; - case GEOIP_ISP_EDITION_V6: - geoip_hf = hf_geoip_isp; - geoip_local_hf = (isdst) ? hf_geoip_dst_isp : hf_geoip_src_isp; - break; - case GEOIP_ASNUM_EDITION_V6: - geoip_hf = hf_geoip_asnum; - geoip_local_hf = (isdst) ? hf_geoip_dst_asnum : hf_geoip_src_asnum; - break; -#endif /* DB_NUM_TYPES */ - case WS_LAT_FAKE_EDITION: - geoip_hf = hf_geoip_lat; - geoip_local_hf = (isdst) ? hf_geoip_dst_lat : hf_geoip_src_lat; - break; - case WS_LON_FAKE_EDITION: - geoip_hf = hf_geoip_lon; - geoip_local_hf = (isdst) ? hf_geoip_dst_lon : hf_geoip_src_lon; - break; - default: - continue; - } + proto_item *item; - if (geoip_str) { - proto_item *item; - if (db_type == WS_LAT_FAKE_EDITION || db_type == WS_LON_FAKE_EDITION) { - /* Convert latitude, longitude to double. Fix bug #5077 */ - item = proto_tree_add_double_format_value(geoip_info_tree, geoip_local_hf, tvb, - offset, 16, g_ascii_strtod(geoip_str, NULL), "%s", geoip_str); - PROTO_ITEM_SET_GENERATED(item); - item = proto_tree_add_double_format_value(geoip_info_tree, geoip_hf, tvb, - offset, 16, g_ascii_strtod(geoip_str, NULL), "%s", geoip_str); - PROTO_ITEM_SET_GENERATED(item); - PROTO_ITEM_SET_HIDDEN(item); - } else { - item = proto_tree_add_string(geoip_info_tree, geoip_local_hf, tvb, - offset, 16, geoip_str); - PROTO_ITEM_SET_GENERATED(item); - item = proto_tree_add_string(geoip_info_tree, geoip_hf, tvb, - offset, 16, geoip_str); - PROTO_ITEM_SET_GENERATED(item); - PROTO_ITEM_SET_HIDDEN(item); - } + if (lookup->city) { + dir_hf = isdst ? hf_geoip_dst_city : hf_geoip_src_city; + item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 16, lookup->city); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_string(geoip_info_tree, hf_geoip_city, tvb, addr_offset, 16, lookup->city); + PROTO_ITEM_SET_GENERATED(item); + } - item_cnt++; - proto_item_append_text(geoip_info_item, "%s%s", plurality(item_cnt, "", ", "), geoip_str); - wmem_free(NULL, geoip_str); - } + if (lookup->country) { + dir_hf = isdst ? hf_geoip_dst_country : hf_geoip_src_country; + item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 16, lookup->country); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_string(geoip_info_tree, hf_geoip_country, tvb, addr_offset, 16, lookup->country); + PROTO_ITEM_SET_GENERATED(item); + } + + if (lookup->as_number > 0) { + dir_hf = isdst ? hf_geoip_dst_as_number : hf_geoip_src_as_number; + item = proto_tree_add_uint(geoip_info_tree, dir_hf, tvb, addr_offset, 16, lookup->as_number); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_uint(geoip_info_tree, hf_geoip_as_number, tvb, addr_offset, 16, lookup->as_number); + PROTO_ITEM_SET_GENERATED(item); + } + + if (lookup->as_org) { + dir_hf = isdst ? hf_geoip_dst_as_org : hf_geoip_src_as_org; + item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 16, lookup->as_org); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_string(geoip_info_tree, hf_geoip_as_org, tvb, addr_offset, 16, lookup->as_org); + PROTO_ITEM_SET_GENERATED(item); } - if (item_cnt == 0) - proto_item_append_text(geoip_info_item, "Unknown"); + if (lookup->latitude >= -90.0 && lookup->latitude <= 90.0) { + dir_hf = isdst ? hf_geoip_dst_latitude : hf_geoip_src_latitude; + item = proto_tree_add_double(geoip_info_tree, dir_hf, tvb, addr_offset, 16, lookup->latitude); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_double(geoip_info_tree, hf_geoip_latitude, tvb, addr_offset, 16, lookup->latitude); + PROTO_ITEM_SET_GENERATED(item); + } + + if (lookup->longitude >= -180.0 && lookup->longitude <= 180.0) { + dir_hf = isdst ? hf_geoip_dst_longitude : hf_geoip_src_longitude; + item = proto_tree_add_double(geoip_info_tree, dir_hf, tvb, addr_offset, 16, lookup->longitude); + PROTO_ITEM_SET_GENERATED(item); + item = proto_tree_add_double(geoip_info_tree, hf_geoip_longitude, tvb, addr_offset, 16, lookup->longitude); + PROTO_ITEM_SET_GENERATED(item); + } } static void add_geoip_info(proto_tree *tree, tvbuff_t *tvb, gint offset, const ws_in6_addr *src, const ws_in6_addr *dst) { - guint num_dbs; - proto_item *geoip_info_item; - proto_tree *geoip_info_tree; - - num_dbs = geoip_db_num_dbs(); - if (num_dbs < 1) - return; - - geoip_info_tree = proto_tree_add_subtree(tree, tvb, offset + IP6H_SRC, 16, ett_geoip_info, &geoip_info_item, "Source GeoIP: "); - PROTO_ITEM_SET_GENERATED(geoip_info_item); - add_geoip_info_entry(geoip_info_tree, geoip_info_item, tvb, offset + IP6H_SRC, src, 0); - - geoip_info_tree = proto_tree_add_subtree(tree, tvb, offset + IP6H_DST, 16, ett_geoip_info, &geoip_info_item, "Destination GeoIP: "); - PROTO_ITEM_SET_GENERATED(geoip_info_item); - add_geoip_info_entry(geoip_info_tree, geoip_info_item, tvb, offset + IP6H_DST, dst, 1); + add_geoip_info_entry(tree, tvb, offset, src, FALSE); + add_geoip_info_entry(tree, tvb, offset, dst, TRUE); } -#endif /* HAVE_GEOIP_V6 */ /* Returns TRUE if reassembled */ static gboolean @@ -2365,13 +2339,11 @@ dissect_ipv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_ add_ipv6_address_embed_ipv4(ipv6_tree, tvb, offset + IP6H_SRC, hf_ipv6_src_embed_ipv4); add_ipv6_address_embed_ipv4(ipv6_tree, tvb, offset + IP6H_DST, hf_ipv6_dst_embed_ipv4); - } -#ifdef HAVE_GEOIP_V6 - if (tree && ipv6_use_geoip) { - add_geoip_info(ipv6_tree, tvb, offset, ip6_src, ip6_dst); + if (ipv6_use_geoip) { + add_geoip_info(ipv6_tree, tvb, offset, ip6_src, ip6_dst); + } } -#endif /* Increment offset to point to next header (may be an extension header) */ offset += IPv6_HDR_SIZE; @@ -2675,7 +2647,6 @@ proto_register_ipv6(void) "IPv4-Embedded IPv6 Address with Well-Known Prefix", HFILL } }, -#ifdef HAVE_GEOIP_V6 { &hf_geoip_country, { "Source or Destination GeoIP Country", "ipv6.geoip.country", FT_STRING, STR_UNICODE, NULL, 0x0, @@ -2686,31 +2657,31 @@ proto_register_ipv6(void) FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_org, - { "Source or Destination GeoIP Organization", "ipv6.geoip.org", - FT_STRING, STR_UNICODE, NULL, 0x0, - NULL, HFILL } - }, - { &hf_geoip_isp, - { "Source or Destination GeoIP ISP", "ipv6.geoip.isp", - FT_STRING, STR_UNICODE, NULL, 0x0, + { &hf_geoip_as_number, + { "Source or Destination GeoIP AS Number", "ipv6.geoip.asnum", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_asnum, - { "Source or Destination GeoIP AS Number", "ipv6.geoip.asnum", + { &hf_geoip_as_org, + { "Source or Destination GeoIP AS Organization", "ipv6.geoip.org", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_lat, + { &hf_geoip_latitude, { "Source or Destination GeoIP Latitude", "ipv6.geoip.lat", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_lon, + { &hf_geoip_longitude, { "Source or Destination GeoIP Longitude", "ipv6.geoip.lon", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_geoip_src_summary, + { "Source GeoIP", "ipv6.geoip.src_summary", + FT_STRING, STR_UNICODE, NULL, 0x0, + NULL, HFILL } + }, { &hf_geoip_src_country, { "Source GeoIP Country", "ipv6.geoip.src_country", FT_STRING, STR_UNICODE, NULL, 0x0, @@ -2721,31 +2692,31 @@ proto_register_ipv6(void) FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_src_org, - { "Source GeoIP Organization", "ipv6.geoip.src_org", - FT_STRING, STR_UNICODE, NULL, 0x0, - NULL, HFILL } - }, - { &hf_geoip_src_isp, - { "Source GeoIP ISP", "ipv6.geoip.src_isp", - FT_STRING, STR_UNICODE, NULL, 0x0, + { &hf_geoip_src_as_number, + { "Source GeoIP AS Number", "ipv6.geoip.src_asnum", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_src_asnum, - { "Source GeoIP AS Number", "ipv6.geoip.src_asnum", + { &hf_geoip_src_as_org, + { "Source GeoIP AS Organization", "ipv6.geoip.src_org", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_src_lat, + { &hf_geoip_src_latitude, { "Source GeoIP Latitude", "ipv6.geoip.src_lat", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_src_lon, + { &hf_geoip_src_longitude, { "Source GeoIP Longitude", "ipv6.geoip.src_lon", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_geoip_dst_summary, + { "Destination GeoIP", "ipv6.geoip.dst_summary", + FT_STRING, STR_UNICODE, NULL, 0x0, + NULL, HFILL } + }, { &hf_geoip_dst_country, { "Destination GeoIP Country", "ipv6.geoip.dst_country", FT_STRING, STR_UNICODE, NULL, 0x0, @@ -2756,32 +2727,26 @@ proto_register_ipv6(void) FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_dst_org, - { "Destination GeoIP Organization", "ipv6.geoip.dst_org", - FT_STRING, STR_UNICODE, NULL, 0x0, - NULL, HFILL } - }, - { &hf_geoip_dst_isp, - { "Destination GeoIP ISP", "ipv6.geoip.dst_isp", - FT_STRING, STR_UNICODE, NULL, 0x0, + { &hf_geoip_dst_as_number, + { "Destination GeoIP AS Number", "ipv6.geoip.dst_asnum", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_dst_asnum, - { "Destination GeoIP AS Number", "ipv6.geoip.dst_asnum", + { &hf_geoip_dst_as_org, + { "Destination GeoIP AS Organization", "ipv6.geoip.dst_org", FT_STRING, STR_UNICODE, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_dst_lat, + { &hf_geoip_dst_latitude, { "Destination GeoIP Latitude", "ipv6.geoip.dst_lat", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, - { &hf_geoip_dst_lon, + { &hf_geoip_dst_longitude, { "Destination GeoIP Longitude", "ipv6.geoip.dst_lon", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, -#endif /* HAVE_GEOIP_V6 */ { &hf_ipv6_opt, { "IPv6 Option", "ipv6.opt", @@ -3369,9 +3334,7 @@ proto_register_ipv6(void) static gint *ett_ipv6[] = { &ett_ipv6_proto, &ett_ipv6_traffic_class, -#ifdef HAVE_GEOIP_V6 &ett_geoip_info, -#endif /* HAVE_GEOIP_V6 */ &ett_ipv6_opt, &ett_ipv6_opt_type, &ett_ipv6_opt_rpl, @@ -3576,12 +3539,10 @@ proto_register_ipv6(void) "Show IPv6 summary in protocol tree", "Whether the IPv6 summary line should be shown in the protocol tree", &ipv6_summary_in_tree); -#ifdef HAVE_GEOIP_V6 prefs_register_bool_preference(ipv6_module, "use_geoip" , - "Enable GeoIP lookups", - "Whether to look up IPv6 addresses in each GeoIP database we have loaded", + "Enable IPv6 geolocation", + "Whether to look up IPv6 addresses in each MaxMind database we have loaded", &ipv6_use_geoip); -#endif /* HAVE_GEOIP_V6 */ /* RPL Strict Header Checking */ prefs_register_bool_preference(ipv6_module, "perform_strict_rpl_srh_rfc_checking", diff --git a/epan/epan.c b/epan/epan.c index 076b557b5a..a1a9240a81 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -727,13 +727,13 @@ epan_get_compiled_version_info(GString *str) g_string_append(str, "without Kerberos"); #endif /* HAVE_KERBEROS */ - /* GeoIP */ + /* MaxMindDB */ g_string_append(str, ", "); -#ifdef HAVE_GEOIP - g_string_append(str, "with GeoIP"); +#ifdef HAVE_MAXMINDDB + g_string_append(str, "with MaxMind DB resolver"); #else - g_string_append(str, "without GeoIP"); -#endif /* HAVE_GEOIP */ + g_string_append(str, "without MaxMind DB resolver"); +#endif /* HAVE_MAXMINDDB */ /* nghttp2 */ g_string_append(str, ", "); diff --git a/epan/geoip_db.c b/epan/geoip_db.c deleted file mode 100644 index f79b0f677b..0000000000 --- a/epan/geoip_db.c +++ /dev/null @@ -1,638 +0,0 @@ -/* geoip_db.c - * GeoIP database support - * - * Copyright 2008, Gerald Combs - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -/* To do: - * We currently return a single string for each database. Some databases, - * e.g. GeoIPCity, can return other info such as area codes. - */ - -#include "config.h" - -#include - -#include - -#ifdef HAVE_GEOIP -#include -#include - -#include -#include -#include -#include - -#include -#include - -/* This needs to match NUM_GEOIP_COLS in hostlist_table.h */ -#define MAX_GEOIP_DBS 13 - -/* - * GeoIP_free is patched into our GeoIP distribution on Windows. - * See bug 13598. - */ -#ifndef HAVE_GEOIP_FREE -#define GeoIP_free free -#endif - -/* Column names for each database type */ -value_string geoip_type_name_vals[] = { - { GEOIP_COUNTRY_EDITION, "Country" }, - { GEOIP_REGION_EDITION_REV0, "Region" }, - { GEOIP_CITY_EDITION_REV0, "City"}, - { GEOIP_ORG_EDITION, "Organization" }, - { GEOIP_ISP_EDITION, "ISP" }, - { GEOIP_CITY_EDITION_REV1, "City" }, - { GEOIP_REGION_EDITION_REV1, "Region" }, - { GEOIP_PROXY_EDITION, "Proxy" }, - { GEOIP_ASNUM_EDITION, "AS Number" }, - { GEOIP_NETSPEED_EDITION, "Speed" }, - { GEOIP_DOMAIN_EDITION, "Domain" }, -#ifdef HAVE_GEOIP_V6 - { GEOIP_COUNTRY_EDITION_V6, "Country" }, -/* This is the closest thing to a version that GeoIP.h seems to provide. */ -#if NUM_DB_TYPES > 31 /* 1.4.7 */ - { GEOIP_CITY_EDITION_REV0_V6, "City"}, - { GEOIP_CITY_EDITION_REV1_V6, "City"}, - { GEOIP_ASNUM_EDITION_V6, "AS Number" }, - { GEOIP_ISP_EDITION_V6, "ISP" }, - { GEOIP_ORG_EDITION_V6, "Organization" }, - { GEOIP_DOMAIN_EDITION_V6, "Domain" }, -#endif /* NUM_DB_TYPES > 31 */ -#if NUM_DB_TYPES > 32 /* 1.4.8 */ - { GEOIP_NETSPEED_EDITION_REV1_V6, "Speed" }, -#endif /* NUM_DB_TYPES > 32 */ -#endif /* HAVE_GEOIP_V6 */ - { WS_LAT_FAKE_EDITION, "Latitude" }, /* fake database */ - { WS_LON_FAKE_EDITION, "Longitude" }, /* fake database */ - { 0, NULL } -}; - -static GArray *geoip_dat_arr = NULL; - -/* UAT definitions. Copied from oids.c */ -typedef struct _geoip_db_path_t { - char* path; -} geoip_db_path_t; - -static geoip_db_path_t *geoip_db_paths = NULL; -static guint num_geoip_db_paths = 0; -static const geoip_db_path_t geoip_db_system_paths[] = { -#ifdef G_OS_UNIX - { "/usr/share/GeoIP" }, -#endif - { NULL } -}; -static uat_t *geoip_db_paths_uat = NULL; -UAT_DIRECTORYNAME_CB_DEF(geoip_mod, path, geoip_db_path_t) - - -/** - * Scan a directory for GeoIP databases and load them - */ -static void -geoip_dat_scan_dir(const char *dirname) { - WS_DIR *dir; - WS_DIRENT *file; - const char *name; - char *datname; - GeoIP *gi; - - if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL) { - while ((file = ws_dir_read_name(dir)) != NULL) { - name = ws_dir_get_name(file); - if (g_str_has_prefix(file, "Geo") && g_str_has_suffix(file, ".dat")) { - datname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dirname, name); - gi = GeoIP_open(datname, GEOIP_MEMORY_CACHE); - if (gi) { - g_array_append_val(geoip_dat_arr, gi); - } - g_free(datname); - } - } - ws_dir_close (dir); - } -} - -/* UAT callbacks */ -static void* geoip_db_path_copy_cb(void* dest, const void* orig, size_t len _U_) { - const geoip_db_path_t *m = (const geoip_db_path_t *)orig; - geoip_db_path_t *d = (geoip_db_path_t *)dest; - - d->path = g_strdup(m->path); - - return d; -} - -static void geoip_db_path_free_cb(void* p) { - geoip_db_path_t *m = (geoip_db_path_t *)p; - g_free(m->path); -} - -static void geoip_dat_cleanup(void) { - GeoIP *gi; - guint i; - - /* If we have old data, clear out the whole thing - * and start again. TODO: Just update the ones that - * have changed for efficiency's sake. */ - if (geoip_dat_arr) { - /* skip the last two, as they are fake */ - for (i = 0; i < geoip_db_num_dbs() - 2; i++) { - gi = g_array_index(geoip_dat_arr, GeoIP *, i); - if (gi) { - GeoIP_delete(gi); - } - } - /* don't use GeoIP_delete() on the two fake - * databases as they weren't created by GeoIP_new() - * or GeoIP_open() */ - gi = g_array_index(geoip_dat_arr, GeoIP *, i); - g_free(gi); - gi = g_array_index(geoip_dat_arr, GeoIP *, i+1); - g_free(gi); - /* finally, free the array itself */ - g_array_free(geoip_dat_arr, TRUE); - geoip_dat_arr = NULL; - } -} - -/* called every time the user presses "Apply" or "OK in the list of - * GeoIP directories, and also once on startup */ -static void geoip_db_post_update_cb(void) { - guint i; - GeoIP* gi; - - geoip_dat_cleanup(); - - /* allocate the array */ - geoip_dat_arr = g_array_new(FALSE, FALSE, sizeof(GeoIP *)); - - /* First try the system paths */ - for (i = 0; geoip_db_system_paths[i].path != NULL; i++) { - geoip_dat_scan_dir(geoip_db_system_paths[i].path); - } - - /* Walk all the directories */ - for (i = 0; i < num_geoip_db_paths; i++) { - if (geoip_db_paths[i].path) { - geoip_dat_scan_dir(geoip_db_paths[i].path); - } - } - - /* add fake databases for latitude and longitude - * (using "City" in reality) */ - - /* latitude */ - gi = (GeoIP *)g_malloc(sizeof (GeoIP)); - gi->databaseType = WS_LAT_FAKE_EDITION; - g_array_append_val(geoip_dat_arr, gi); - - /* longitude */ - gi = (GeoIP *)g_malloc(sizeof (GeoIP)); - gi->databaseType = WS_LON_FAKE_EDITION; - g_array_append_val(geoip_dat_arr, gi); -} - -static void geoip_db_cleanup(void) -{ - geoip_dat_cleanup(); -} - -/** - * Initialize GeoIP lookups - */ -void -geoip_db_pref_init(module_t *nameres) -{ - static uat_field_t geoip_db_paths_fields[] = { - UAT_FLD_DIRECTORYNAME(geoip_mod, path, "GeoIP Database Directory", "The GeoIP database directory path"), - UAT_END_FIELDS - }; - - geoip_db_paths_uat = uat_new("GeoIP Database Paths", - sizeof(geoip_db_path_t), - "geoip_db_paths", - FALSE, - (void**)&geoip_db_paths, - &num_geoip_db_paths, - /* affects dissection of packets (as the GeoIP database is - used when dissecting), but not set of named fields */ - UAT_AFFECTS_DISSECTION, - "ChGeoIPDbPaths", - geoip_db_path_copy_cb, - NULL, - geoip_db_path_free_cb, - geoip_db_post_update_cb, - geoip_db_cleanup, - geoip_db_paths_fields); - - prefs_register_uat_preference(nameres, - "geoip_db_paths", - "GeoIP database directories", - "Search paths for GeoIP address mapping databases." - " Wireshark will look in each directory for files beginning" - " with \"Geo\" and ending with \".dat\".", - geoip_db_paths_uat); -} - -guint -geoip_db_num_dbs(void) { - return (geoip_dat_arr == NULL) ? 0 : geoip_dat_arr->len; -} - -const gchar * -geoip_db_name(guint dbnum) { - GeoIP *gi; - - gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum); - if (gi) { - return (val_to_str_const(gi->databaseType, geoip_type_name_vals, "Unknown database")); - } - return "Invalid database"; -} - -int -geoip_db_type(guint dbnum) { - GeoIP *gi; - - gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum); - if (gi) { - return (gi->databaseType); - } - return -1; -} - -static int -geoip_db_lookup_latlon4(guint32 addr, float *lat, float *lon) { - GeoIP *gi; - GeoIPRecord *gir; - guint i; - - for (i = 0; i < geoip_db_num_dbs(); i++) { - gi = g_array_index(geoip_dat_arr, GeoIP *, i); - if (gi) { - switch (gi->databaseType) { - case GEOIP_CITY_EDITION_REV0: - case GEOIP_CITY_EDITION_REV1: - gir = GeoIP_record_by_ipnum(gi, addr); - if (gir) { - *lat = gir->latitude; - *lon = gir->longitude; - GeoIPRecord_delete(gir); - return 0; - } - return -1; - /*break;*/ - - default: - break; - } - } - } - return -1; -} - -/* - * GeoIP 1.4.3 and later provide GeoIP_set_charset(), but in versions - * 1.4.3 to 1.4.6 that only applies to the City databases. I.e., it's - * possible to produce invalid UTF-8 sequences even if GeoIP_set_charset() - * is used. - */ - -/* Ensure that a given db value is UTF-8 */ -static char * -db_val_to_utf_8(const char *val, GeoIP *gi) { - - if (GeoIP_charset(gi) == GEOIP_CHARSET_ISO_8859_1) { - char *utf8_val; - utf8_val = g_convert(val, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); - if (utf8_val) { - char *ret_val = wmem_strdup(NULL, utf8_val); - g_free(utf8_val); - return ret_val; - } - } - return wmem_strdup(NULL, val); -} - -char * -geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) { - GeoIP *gi; - GeoIPRecord *gir; - char *name; - const char *country; - char *val, *ret = NULL; - - if (dbnum > geoip_db_num_dbs()) { - if (not_found == NULL) - return NULL; - - return wmem_strdup(NULL, not_found); - } - gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum); - if (gi) { - switch (gi->databaseType) { - case GEOIP_COUNTRY_EDITION: - country = GeoIP_country_name_by_ipnum(gi, addr); - if (country) { - ret = db_val_to_utf_8(country, gi); - } - break; - - case GEOIP_CITY_EDITION_REV0: - case GEOIP_CITY_EDITION_REV1: - gir = GeoIP_record_by_ipnum(gi, addr); - if (gir && gir->city && gir->region) { - val = wmem_strdup_printf(NULL, "%s, %s", gir->city, gir->region); - ret = db_val_to_utf_8(val, gi); - wmem_free(NULL, val); - } else if (gir && gir->city) { - ret = db_val_to_utf_8(gir->city, gi); - } - if (gir) - GeoIPRecord_delete(gir); - break; - - case GEOIP_ORG_EDITION: - case GEOIP_ISP_EDITION: - case GEOIP_ASNUM_EDITION: - name = GeoIP_name_by_ipnum(gi, addr); - if (name) { - ret = db_val_to_utf_8(name, gi); - GeoIP_free(name); - } - break; - - case WS_LAT_FAKE_EDITION: - { - float lat; - float lon; - char *c; - if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) { - val = wmem_strdup_printf(NULL, "%f", lat); - c = strchr(val, ','); - if (c != NULL) *c = '.'; - ret = val; - } - } - break; - - case WS_LON_FAKE_EDITION: - { - float lat; - float lon; - char *c; - if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) { - val = wmem_strdup_printf(NULL, "%f", lon); - c = strchr(val, ','); - if (c != NULL) *c = '.'; - ret = val; - } - } - break; - - default: - break; - } - } - - if (ret == NULL) { - if (not_found == NULL) - return NULL; - - return wmem_strdup(NULL, not_found); - } - - return ret; -} - -#ifdef HAVE_GEOIP_V6 - -static int -#if NUM_DB_TYPES > 31 /* 1.4.7 */ -geoip_db_lookup_latlon6(geoipv6_t addr, float *lat, float *lon) { - GeoIP *gi; - GeoIPRecord *gir; - guint i; - - for (i = 0; i < geoip_db_num_dbs(); i++) { - gi = g_array_index(geoip_dat_arr, GeoIP *, i); - if (gi) { - switch (gi->databaseType) { - case GEOIP_CITY_EDITION_REV0_V6: - case GEOIP_CITY_EDITION_REV1_V6: - gir = GeoIP_record_by_ipnum_v6(gi, addr); - if(gir) { - *lat = gir->latitude; - *lon = gir->longitude; - return 0; - } - return -1; - /*break;*/ - - default: - break; - } - } - } - return -1; -} -#else /* NUM_DB_TYPES */ -geoip_db_lookup_latlon6(geoipv6_t addr _U_, float *lat _U_, float *lon _U_) { - return -1; -} -#endif /* NUM_DB_TYPES */ - -char * -geoip_db_lookup_ipv6(guint dbnum, ws_in6_addr addr, const char *not_found) { - GeoIP *gi; - geoipv6_t gaddr; - char *name; - const char *country; - char *val, *ret = NULL; -#if NUM_DB_TYPES > 31 - GeoIPRecord *gir; -#endif - if (dbnum > geoip_db_num_dbs()) { - if (not_found == NULL) - return NULL; - - return wmem_strdup(NULL, not_found); - } - - memcpy(&gaddr, &addr, sizeof(addr)); - - gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum); - if (gi) { - switch (gi->databaseType) { - case GEOIP_COUNTRY_EDITION_V6: - country = GeoIP_country_name_by_ipnum_v6(gi, gaddr); - if (country) { - ret = db_val_to_utf_8(country, gi); - } - break; - -#if NUM_DB_TYPES > 31 - case GEOIP_CITY_EDITION_REV0_V6: - case GEOIP_CITY_EDITION_REV1_V6: - gir = GeoIP_record_by_ipnum_v6(gi, gaddr); - if (gir && gir->city && gir->region) { - val = wmem_strdup_printf(NULL, "%s, %s", gir->city, gir->region); - ret = db_val_to_utf_8(val, gi); - wmem_free(NULL, val); - } else if (gir && gir->city) { - ret = db_val_to_utf_8(gir->city, gi); - } - break; - - case GEOIP_ORG_EDITION_V6: - case GEOIP_ISP_EDITION_V6: - case GEOIP_ASNUM_EDITION_V6: - name = GeoIP_name_by_ipnum_v6(gi, gaddr); - if (name) { - ret = db_val_to_utf_8(name, gi); - GeoIP_free(name); - } - break; -#endif /* NUM_DB_TYPES */ - - case WS_LAT_FAKE_EDITION: - { - float lat; - float lon; - char *c; - if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) { - val = wmem_strdup_printf(NULL, "%f", lat); - c = strchr(val, ','); - if (c != NULL) *c = '.'; - ret = val; - } - } - break; - - case WS_LON_FAKE_EDITION: - { - float lat; - float lon; - char *c; - if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) { - val = wmem_strdup_printf(NULL, "%f", lon); - c = strchr(val, ','); - if (c != NULL) *c = '.'; - ret = val; - } - } - break; - - default: - break; - } - } - - if (ret == NULL) { - if (not_found == NULL) - return NULL; - - return wmem_strdup(NULL, not_found); - } - - return ret; -} - -#else /* HAVE_GEOIP_V6 */ - -char * -geoip_db_lookup_ipv6(guint dbnum _U_, ws_in6_addr addr _U_, const char *not_found) { - if (not_found == NULL) - return NULL; - - return wmem_strdup(NULL, not_found); -} - -#endif /* HAVE_GEOIP_V6 */ - -gchar * -geoip_db_get_paths(void) { - GString* path_str = NULL; - guint i; - - path_str = g_string_new(""); - - for (i = 0; geoip_db_system_paths[i].path != NULL; i++) { - g_string_append_printf(path_str, - "%s" G_SEARCHPATH_SEPARATOR_S, geoip_db_system_paths[i].path); - } - - for (i = 0; i < num_geoip_db_paths; i++) { - if (geoip_db_paths[i].path) { - g_string_append_printf(path_str, - "%s" G_SEARCHPATH_SEPARATOR_S, geoip_db_paths[i].path); - } - } - - g_string_truncate(path_str, path_str->len-1); - - return g_string_free(path_str, FALSE); -} - -#else /* HAVE_GEOIP */ -guint -geoip_db_num_dbs(void) { - return 0; -} - -const gchar * -geoip_db_name(guint dbnum _U_) { - return "Unsupported"; -} - -int -geoip_db_type(guint dbnum _U_) { - return -1; -} - -char * -geoip_db_lookup_ipv4(guint dbnum _U_, guint32 addr _U_, const char *not_found) { - if (not_found == NULL) - return NULL; - - return (char *)wmem_strdup(NULL, not_found); -} - -char * -geoip_db_lookup_ipv6(guint dbnum _U_, guint32 addr _U_, const char *not_found) { - if (not_found == NULL) - return NULL; - - return (char *)wmem_strdup(NULL, not_found); -} - -gchar * -geoip_db_get_paths(void) { - return g_strdup(""); -} - -#endif /* HAVE_GEOIP */ - -/* - * Editor modelines - * - * Local Variables: - * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - * - * ex: set shiftwidth=4 tabstop=8 expandtab: - * :indentSize=4:tabSize=8:noTabs=true: - */ diff --git a/epan/geoip_db.h b/epan/geoip_db.h deleted file mode 100644 index 20aa46a8c6..0000000000 --- a/epan/geoip_db.h +++ /dev/null @@ -1,104 +0,0 @@ -/* geoip_db.h - * GeoIP database support - * - * Copyright 2008, Gerald Combs - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#ifndef __GEOIP_DB_H__ -#define __GEOIP_DB_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include -#include -#include "ws_symbol_export.h" - -/* Fake databases to make lat/lon values available */ -/* XXX - find a better way to interface */ -#define WS_LAT_FAKE_EDITION (NUM_DB_TYPES+1) -#define WS_LON_FAKE_EDITION (NUM_DB_TYPES+2) - - -/** - * Init function called from epan.h - */ -extern void geoip_db_pref_init(module_t *nameres); - -/** - * Number of databases we have loaded - * - * @return The number GeoIP databases successfully loaded - */ -WS_DLL_PUBLIC guint geoip_db_num_dbs(void); - -/** - * Fetch the name of a database - * - * @param dbnum Database index - * @return The database name or "Invalid database" - */ -WS_DLL_PUBLIC const gchar *geoip_db_name(guint dbnum); - -/** - * Fetch the database type. Types are enumerated in GeoIPDBTypes in GeoIP.h. - * - * @param dbnum Database index - * @return The database type or -1 - */ -WS_DLL_PUBLIC int geoip_db_type(guint dbnum); - -/** - * Look up an IPv4 address in a database - * - * @param dbnum Database index - * @param addr IPv4 address to look up - * @param not_found The string to return if the lookup fails. May be NULL. - * - * @return The database entry if found, else not_found. Return value must be freed with wmem_free. - */ -WS_DLL_PUBLIC char *geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found); - -/** - * Look up an IPv6 address in a database - * - * @param dbnum Database index - * @param addr IPv6 address to look up - * @param not_found The string to return if the lookup fails. May be NULL. - * - * @return The database entry if found, else not_found. Return value must be freed with wmem_free. - */ -WS_DLL_PUBLIC char *geoip_db_lookup_ipv6(guint dbnum, ws_in6_addr addr, const char *not_found); - -/** - * Get all configured paths - * - * @return String with all paths separated by a path separator - */ -WS_DLL_PUBLIC gchar *geoip_db_get_paths(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __GEOIP_DB_H__ */ - -/* - * Editor modelines - * - * Local Variables: - * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - * - * ex: set shiftwidth=4 tabstop=8 expandtab: - * :indentSize=4:tabSize=8:noTabs=true: - */ diff --git a/epan/maxmind_db.c b/epan/maxmind_db.c new file mode 100644 index 0000000000..03e705660d --- /dev/null +++ b/epan/maxmind_db.c @@ -0,0 +1,513 @@ +/* maxmind_db.c + * GeoIP database support + * + * Copyright 2018, Gerald Combs + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include + +#include + +static mmdb_lookup_t mmdb_not_found; + +#ifdef HAVE_MAXMINDDB + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +// To do: +// - If we can't reliably do non-blocking reads, move process_mmdbr_stdout to a worker thread. +// - Add RBL lookups? Along with the "is this a spammer" information that most RBL databases +// provide, you can also fetch AS information: http://www.team-cymru.org/IP-ASN-mapping.html +// - Switch to a different format? I was going to use g_key_file_* to parse +// the mmdbresolve output, but it was easier to just parse it directly. + +// Hashes of mmdb_lookup_t +static wmem_map_t *mmdb_ipv4_map; +static wmem_map_t *mmdb_ipv6_map; + +// Interned strings +static wmem_map_t *mmdb_str_chunk; + +/* Child mmdbresolve process */ +static char cur_addr[WS_INET6_ADDRSTRLEN]; +static mmdb_lookup_t cur_lookup; +static ws_pipe_t mmdbr_pipe; + +/* UAT definitions. Copied from oids.c */ +typedef struct _maxmind_db_path_t { + char* path; +} maxmind_db_path_t; + +static maxmind_db_path_t *maxmind_db_paths; +static guint num_maxmind_db_paths; +static const maxmind_db_path_t maxmind_db_system_paths[] = { +#ifdef _WIN32 + // XXX Properly expand "%ProgramData%\GeoIP". + { "C:\\ProgramData\\GeoIP" }, + { "C:\\GeoIP" }, +#else + { "/usr/share/GeoIP" }, + { "/var/lib/GeoIP" }, +#endif + { NULL } +}; +static uat_t *maxmind_db_paths_uat; +UAT_DIRECTORYNAME_CB_DEF(maxmind_mod, path, maxmind_db_path_t) + +static GPtrArray *mmdb_file_arr; // .mmdb files + +#if 0 +#define MMDB_DEBUG(...) { \ + char *MMDB_DEBUG_MSG = g_strdup_printf(__VA_ARGS__); \ + g_warning("mmdb: %s:%d %s", G_STRFUNC, __LINE__, MMDB_DEBUG_MSG); \ + g_free(MMDB_DEBUG_MSG); \ +} +#else +#define MMDB_DEBUG(...) +#endif + +static void mmdb_resolve_stop(void); + +// Hopefully scanning a few lines asynchronously has less overhead than +// reading in a child thread. +#define RES_STATUS_ERROR "mmdbresolve.status: false" +#define RES_COUNTRY_ISO_CODE "country.iso_code" // Unused. +#define RES_COUNTRY_NAMES_EN "country.names.en" +#define RES_CITY_NAMES_EN "city.names.en" +#define RES_ASN_ORG "autonomous_system_organization" +#define RES_ASN_NUMBER "autonomous_system_number" +#define RES_LOCATION_LATITUDE "location.latitude" +#define RES_LOCATION_LONGITUDE "location.longitude" +#define RES_END "# End " + +// Interned strings, similar to GLib's string chunks. +static const char *chunkify_string(char *key) { + g_strstrip(key); + char *chunk_string = (char *) wmem_map_lookup(mmdb_str_chunk, key); + + if (!chunk_string) { + chunk_string = wmem_strdup(wmem_epan_scope(), key); + wmem_map_insert(mmdb_str_chunk, key, chunk_string); + } + + return chunk_string; +} + +static gboolean +process_mmdbr_stdout(int fd) { + + size_t read_buf_size = 65536; + char *read_buf = (char *) g_malloc((gsize) read_buf_size); + gboolean new_entries = FALSE; + + MMDB_DEBUG("start %d", ws_pipe_data_available(fd)); + + while (ws_pipe_data_available(fd)) { + read_buf[0] = '\0'; + ssize_t read_status = ws_read(fd, read_buf, read_buf_size); + if (read_status < 1) { + MMDB_DEBUG("read error %s", g_strerror(errno)); + mmdb_resolve_stop(); + break; + } + + size_t read_len = strlen(read_buf); + MMDB_DEBUG("read %zd bytes", read_len); + if (read_len < 1) { + break; + } + + char **lines = g_strsplit(read_buf, "\n", -1); + for (size_t idx = 0; lines[idx]; idx++) { + char *line = lines[idx]; + size_t line_len = strlen(line); + char *val_start = strchr(line, ':'); + + if (val_start) val_start++; + + if (line_len < 1) continue; + MMDB_DEBUG("line %s", line); + + if (line[0] == '[') { + // [init] or resolved address in square brackets. + line[line_len - 1] = '\0'; + g_strlcpy(cur_addr, line + 1, WS_INET6_ADDRSTRLEN); + memset(&cur_lookup, 0, sizeof(cur_lookup)); + } else if (strcmp(line, RES_STATUS_ERROR) == 0) { + // Error during init. + cur_addr[0] = '\0'; + memset(&cur_lookup, 0, sizeof(cur_lookup)); + mmdb_resolve_stop(); + } else if (val_start && g_str_has_prefix(line, RES_COUNTRY_NAMES_EN)) { + cur_lookup.found = TRUE; + cur_lookup.country = chunkify_string(val_start); + } else if (g_str_has_prefix(line, RES_CITY_NAMES_EN)) { + cur_lookup.found = TRUE; + cur_lookup.city = chunkify_string(val_start); + } else if (g_str_has_prefix(line, RES_ASN_ORG)) { + cur_lookup.found = TRUE; + cur_lookup.as_org = chunkify_string(val_start); + } else if (g_str_has_prefix(line, RES_ASN_NUMBER)) { + cur_lookup.found = TRUE; + cur_lookup.as_number = (unsigned int) strtoul(val_start, NULL, 10); + } else if (g_str_has_prefix(line, RES_LOCATION_LATITUDE)) { + cur_lookup.found = TRUE; + cur_lookup.latitude = strtod(val_start, NULL); + } else if (g_str_has_prefix(line, RES_LOCATION_LONGITUDE)) { + cur_lookup.found = TRUE; + cur_lookup.longitude = strtod(val_start, NULL); + } else if (g_str_has_prefix(line, RES_END)) { + if (cur_lookup.found) { + mmdb_lookup_t *mmdb_val = (mmdb_lookup_t *) wmem_memdup(wmem_epan_scope(), &cur_lookup, sizeof(cur_lookup)); + if (strstr(cur_addr, ".")) { + MMDB_DEBUG("inserting v4 %p %s: city %s country %s", (void *) mmdb_val, cur_addr, mmdb_val->city, mmdb_val->country); + guint32 addr; + ws_inet_pton4(cur_addr, &addr); + wmem_map_insert(mmdb_ipv4_map, GUINT_TO_POINTER(addr), mmdb_val); + new_entries = TRUE; + } else if (strstr(cur_addr, ":")) { + MMDB_DEBUG("inserting v6 %p %s: city %s country %s", (void *) mmdb_val, cur_addr, mmdb_val->city, mmdb_val->country); + ws_in6_addr addr; + ws_inet_pton6(cur_addr, &addr); + wmem_map_insert(mmdb_ipv6_map, addr.bytes, mmdb_val); + new_entries = TRUE; + } + } + cur_addr[0] = '\0'; + memset(&cur_lookup, 0, sizeof(cur_lookup)); + } + } + g_strfreev(lines); + } + return new_entries; +} + +/** + * Stop our mmdbresolve process. + */ +static void mmdb_resolve_stop(void) { + if (!mmdbr_pipe.pid) return; + + ws_close(mmdbr_pipe.stdin_fd); + MMDB_DEBUG("closing pid %d", mmdbr_pipe.pid); + g_spawn_close_pid(mmdbr_pipe.pid); + mmdbr_pipe.pid = WS_INVALID_PID; +} + +/** + * Start an mmdbresolve process. + */ +static void mmdb_resolve_start(void) { + if (!mmdb_ipv4_map) { + mmdb_ipv4_map = wmem_map_new(wmem_epan_scope(), g_direct_hash, g_direct_equal); + } + if (!mmdb_ipv6_map) { + mmdb_ipv6_map = wmem_map_new(wmem_epan_scope(), ipv6_oat_hash, ipv6_equal); + } + + if (!mmdb_str_chunk) { + mmdb_str_chunk = wmem_map_new(wmem_epan_scope(), wmem_str_hash, g_str_equal); + } + + if (!mmdb_file_arr) return; + + mmdb_resolve_stop(); + + GPtrArray *args = g_ptr_array_new(); + char *mmdbresolve = g_strdup_printf("%s%c%s", get_progfile_dir(), G_DIR_SEPARATOR, "mmdbresolve"); + g_ptr_array_add(args, mmdbresolve); + for (guint i = 0; i < mmdb_file_arr->len; i++) { + g_ptr_array_add(args, g_strdup("-f")); + g_ptr_array_add(args, g_strdup(g_ptr_array_index(mmdb_file_arr, i))); + } + g_ptr_array_add(args, NULL); + + ws_pipe_init(&mmdbr_pipe); + GPid pipe_pid = ws_pipe_spawn_async(&mmdbr_pipe, args); + MMDB_DEBUG("spawned %s pid %d", mmdbresolve, pipe_pid); + + for (guint i = 0; i < args->len; i++) { + g_free(g_ptr_array_index(args, i)); + } + g_ptr_array_free(args, TRUE); + + if (pipe_pid == WS_INVALID_PID) { + ws_pipe_init(&mmdbr_pipe); + return; + } + + // [init] + process_mmdbr_stdout(mmdbr_pipe.stdout_fd); +} + +/** + * Scan a directory for GeoIP databases and load them + */ +static void +maxmind_db_scan_dir(const char *dirname) { + WS_DIR *dir; + WS_DIRENT *file; + + if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL) { + while ((file = ws_dir_read_name(dir)) != NULL) { + const char *name = ws_dir_get_name(file); + if (g_str_has_suffix(file, ".mmdb")) { + char *datname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dirname, name); + FILE *mmdb_f = ws_fopen(datname, "r"); + if (mmdb_f) { + g_ptr_array_add(mmdb_file_arr, datname); + fclose(mmdb_f); + } else { + g_free(datname); + } + } + } + ws_dir_close (dir); + } +} + +/* UAT callbacks */ +static void* maxmind_db_path_copy_cb(void* dest, const void* orig, size_t len _U_) { + const maxmind_db_path_t *m = (const maxmind_db_path_t *)orig; + maxmind_db_path_t *d = (maxmind_db_path_t *)dest; + + d->path = g_strdup(m->path); + + return d; +} + +static void maxmind_db_path_free_cb(void* p) { + maxmind_db_path_t *m = (maxmind_db_path_t *)p; + g_free(m->path); +} + +static void maxmind_db_cleanup(void) { + guint i; + + mmdb_resolve_stop(); + + /* If we have old data, clear out the whole thing + * and start again. TODO: Just update the ones that + * have changed for efficiency's sake. */ + if (mmdb_file_arr) { + for (i = 0; i < mmdb_file_arr->len; i++) { + g_free(g_ptr_array_index(mmdb_file_arr, i)); + } + /* finally, free the array itself */ + g_ptr_array_free(mmdb_file_arr, TRUE); + mmdb_file_arr = NULL; + } +} + +/* called every time the user presses "Apply" or "OK in the list of + * GeoIP directories, and also once on startup */ +static void maxmind_db_post_update_cb(void) { + guint i; + + maxmind_db_cleanup(); + + /* allocate the array */ + mmdb_file_arr = g_ptr_array_new(); + + /* First try the system paths */ + for (i = 0; maxmind_db_system_paths[i].path != NULL; i++) { + maxmind_db_scan_dir(maxmind_db_system_paths[i].path); + } + + /* Walk all the directories */ + for (i = 0; i < num_maxmind_db_paths; i++) { + if (maxmind_db_paths[i].path) { + maxmind_db_scan_dir(maxmind_db_paths[i].path); + } + } + + mmdb_resolve_start(); +} + +/** + * Initialize GeoIP lookups + */ +void +maxmind_db_pref_init(module_t *nameres) +{ + static uat_field_t maxmind_db_paths_fields[] = { + UAT_FLD_DIRECTORYNAME(maxmind_mod, path, "MaxMind Database Directory", "The MaxMind database directory path"), + UAT_END_FIELDS + }; + + maxmind_db_paths_uat = uat_new("MaxMind Database Paths", + sizeof(maxmind_db_path_t), + "maxmind_db_paths", + FALSE, // Global, not per-profile + (void**)&maxmind_db_paths, + &num_maxmind_db_paths, + UAT_AFFECTS_DISSECTION, // Affects IP4 and IPv6 packets. + "ChMaxMindDbPaths", + maxmind_db_path_copy_cb, + NULL, // update_cb + maxmind_db_path_free_cb, + maxmind_db_post_update_cb, + maxmind_db_cleanup, + maxmind_db_paths_fields); + + prefs_register_uat_preference(nameres, + "maxmind_db_paths", + "MaxMind database directories", + "Search paths for MaxMind address mapping databases." + " Wireshark will look in each directory for files ending" + " with \".mmdb\".", + maxmind_db_paths_uat); +} + +void maxmind_db_pref_cleanup(void) +{ + mmdb_resolve_stop(); +} + +/** + * Public API + */ + +gboolean maxmind_db_lookup_process(void) +{ + if (mmdbr_pipe.pid == WS_INVALID_PID) return FALSE; + + return process_mmdbr_stdout(mmdbr_pipe.stdout_fd); +} + +const mmdb_lookup_t * +maxmind_db_lookup_ipv4(guint32 addr) { + mmdb_lookup_t *result = (mmdb_lookup_t *) wmem_map_lookup(mmdb_ipv4_map, GUINT_TO_POINTER(addr)); + + if (!result) { + if (mmdbr_pipe.stdin_fd) { + char addr_str[WS_INET_ADDRSTRLEN + 1]; + ws_inet_ntop4(&addr, addr_str, WS_INET_ADDRSTRLEN); + MMDB_DEBUG("looking up %s", addr_str); + g_strlcat(addr_str, "\n", (gsize) sizeof(addr_str)); + ssize_t write_status = ws_write(mmdbr_pipe.stdin_fd, addr_str, strlen(addr_str)); + if (write_status < 0) { + MMDB_DEBUG("write error %s", g_strerror(errno)); + mmdb_resolve_stop(); + } + } + + result = &mmdb_not_found; + wmem_map_insert(mmdb_ipv4_map, GUINT_TO_POINTER(addr), result); + } + + return result; +} + +const mmdb_lookup_t * +maxmind_db_lookup_ipv6(const ws_in6_addr *addr) { + mmdb_lookup_t * result = (mmdb_lookup_t *) wmem_map_lookup(mmdb_ipv6_map, addr->bytes); + + if (!result) { + if (mmdbr_pipe.stdin_fd) { + char addr_str[WS_INET6_ADDRSTRLEN + 1]; + ws_inet_ntop6(addr, addr_str, WS_INET6_ADDRSTRLEN); + MMDB_DEBUG("looking up %s", addr_str); + g_strlcat(addr_str, "\n", (gsize) sizeof(addr_str)); + ssize_t write_status = ws_write(mmdbr_pipe.stdin_fd, addr_str, strlen(addr_str)); + if (write_status < 0) { + MMDB_DEBUG("write error %s", g_strerror(errno)); + mmdb_resolve_stop(); + } + } + + result = &mmdb_not_found; + wmem_map_insert(mmdb_ipv6_map, addr->bytes, result); + } + + return result; +} + +gchar * +maxmind_db_get_paths(void) { + GString* path_str = NULL; + guint i; + + path_str = g_string_new(""); + + for (i = 0; maxmind_db_system_paths[i].path != NULL; i++) { + g_string_append_printf(path_str, + "%s" G_SEARCHPATH_SEPARATOR_S, maxmind_db_system_paths[i].path); + } + + for (i = 0; i < num_maxmind_db_paths; i++) { + if (maxmind_db_paths[i].path) { + g_string_append_printf(path_str, + "%s" G_SEARCHPATH_SEPARATOR_S, maxmind_db_paths[i].path); + } + } + + g_string_truncate(path_str, path_str->len-1); + + return g_string_free(path_str, FALSE); +} + +#else // HAVE_MAXMINDDB + +void +maxmind_db_pref_init(module_t *nameres _U_) {} + +void +maxmind_db_pref_cleanup(void) {} + + +gboolean +maxmind_db_lookup_process(void) +{ + return FALSE; +} + +const mmdb_lookup_t * +maxmind_db_lookup_ipv4(guint32 addr _U_) { + return &mmdb_not_found; +} + +const mmdb_lookup_t * +maxmind_db_lookup_ipv6(const ws_in6_addr *addr _U_) { + return &mmdb_not_found; +} + +gchar * +maxmind_db_get_paths(void) { + return g_strdup(""); +} +#endif // HAVE_MAXMINDDB + + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/maxmind_db.h b/epan/maxmind_db.h new file mode 100644 index 0000000000..1b8e5fed0a --- /dev/null +++ b/epan/maxmind_db.h @@ -0,0 +1,93 @@ +/* maxmind_db.h + * Maxmind database support + * + * Copyright 2018, Gerald Combs + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef __MAXMIND_DB_H__ +#define __MAXMIND_DB_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include "ws_symbol_export.h" + +typedef struct _mmdb_lookup_t { + gboolean found; + const char *country; + const char *city; + unsigned int as_number; + const char *as_org; + double latitude; + double longitude; +} mmdb_lookup_t; + +/** + * Init function called from epan.h + */ +WS_DLL_LOCAL void maxmind_db_pref_init(module_t *nameres); + +/** + * Cleanup function called from epan.h + */ +WS_DLL_LOCAL void maxmind_db_pref_cleanup(void); + +/** + * Look up an IPv4 address in a database + * + * @param addr IPv4 address to look up + * + * @return The database entry if found, else NULL. + */ +WS_DLL_PUBLIC WS_RETNONNULL const mmdb_lookup_t *maxmind_db_lookup_ipv4(guint32 addr); + +/** + * Look up an IPv6 address in a database + * + * @param addr IPv6 address to look up + * + * @return The database entry if found, else NULL. + */ +WS_DLL_PUBLIC WS_RETNONNULL const mmdb_lookup_t *maxmind_db_lookup_ipv6(const ws_in6_addr *addr); + +/** + * Get all configured paths + * + * @return String with all paths separated by a path separator + */ +WS_DLL_PUBLIC gchar *maxmind_db_get_paths(void); + +/** + * Process outstanding requests. + * + * @return True if any new addresses were resolved. + */ +WS_DLL_LOCAL gboolean maxmind_db_lookup_process(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MAXMIND_DB_H__ */ + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/prefs.c b/epan/prefs.c index 1ccf5ac185..eb30c1628a 100644 --- a/epan/prefs.c +++ b/epan/prefs.c @@ -21,9 +21,7 @@ #include #include #include -#ifdef HAVE_GEOIP -#include -#endif +#include #include #include #include @@ -3506,9 +3504,7 @@ prefs_register_modules(void) "Name Resolution", NULL, TRUE); addr_resolve_pref_init(nameres_module); oid_pref_init(nameres_module); -#ifdef HAVE_GEOIP - geoip_db_pref_init(nameres_module); -#endif + maxmind_db_pref_init(nameres_module); /* Printing */ printing = prefs_register_module(NULL, "print", "Printing", -- cgit v1.2.3