LCOV - code coverage report
Current view: top level - source/extensions/geoip_providers/maxmind - geoip_provider.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 208 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 13 0.0 %

          Line data    Source code
       1             : #include "source/extensions/geoip_providers/maxmind/geoip_provider.h"
       2             : 
       3             : #include "source/common/common/assert.h"
       4             : #include "source/common/protobuf/protobuf.h"
       5             : 
       6             : namespace Envoy {
       7             : namespace Extensions {
       8             : namespace GeoipProviders {
       9             : namespace Maxmind {
      10             : 
      11             : namespace {
      12             : static constexpr const char* MMDB_CITY_LOOKUP_ARGS[] = {"city", "names", "en"};
      13             : static constexpr const char* MMDB_REGION_LOOKUP_ARGS[] = {"subdivisions", "0", "iso_code"};
      14             : static constexpr const char* MMDB_COUNTRY_LOOKUP_ARGS[] = {"country", "iso_code"};
      15             : static constexpr const char* MMDB_ASN_LOOKUP_ARGS[] = {"autonomous_system_number"};
      16             : static constexpr const char* MMDB_ANON_LOOKUP_ARGS[] = {"is_anonymous", "is_anonymous_vpn",
      17             :                                                         "is_hosting_provider", "is_tor_exit_node",
      18             :                                                         "is_public_proxy"};
      19             : } // namespace
      20             : 
      21             : GeoipProviderConfig::GeoipProviderConfig(
      22             :     const envoy::extensions::geoip_providers::maxmind::v3::MaxMindConfig& config,
      23             :     const std::string& stat_prefix, Stats::Scope& scope)
      24             :     : city_db_path_(!config.city_db_path().empty() ? absl::make_optional(config.city_db_path())
      25             :                                                    : absl::nullopt),
      26             :       isp_db_path_(!config.isp_db_path().empty() ? absl::make_optional(config.isp_db_path())
      27             :                                                  : absl::nullopt),
      28             :       anon_db_path_(!config.anon_db_path().empty() ? absl::make_optional(config.anon_db_path())
      29             :                                                    : absl::nullopt),
      30             :       stats_scope_(scope.createScope(absl::StrCat(stat_prefix, "maxmind."))),
      31           0 :       stat_name_set_(stats_scope_->symbolTable().makeSet("Maxmind")) {
      32           0 :   auto geo_headers_to_add = config.common_provider_config().geo_headers_to_add();
      33           0 :   country_header_ = !geo_headers_to_add.country().empty()
      34           0 :                         ? absl::make_optional(geo_headers_to_add.country())
      35           0 :                         : absl::nullopt;
      36           0 :   city_header_ = !geo_headers_to_add.city().empty() ? absl::make_optional(geo_headers_to_add.city())
      37           0 :                                                     : absl::nullopt;
      38           0 :   region_header_ = !geo_headers_to_add.region().empty()
      39           0 :                        ? absl::make_optional(geo_headers_to_add.region())
      40           0 :                        : absl::nullopt;
      41           0 :   asn_header_ = !geo_headers_to_add.asn().empty() ? absl::make_optional(geo_headers_to_add.asn())
      42           0 :                                                   : absl::nullopt;
      43           0 :   anon_header_ = !geo_headers_to_add.is_anon().empty()
      44           0 :                      ? absl::make_optional(geo_headers_to_add.is_anon())
      45           0 :                      : absl::nullopt;
      46           0 :   anon_vpn_header_ = !geo_headers_to_add.anon_vpn().empty()
      47           0 :                          ? absl::make_optional(geo_headers_to_add.anon_vpn())
      48           0 :                          : absl::nullopt;
      49           0 :   anon_hosting_header_ = !geo_headers_to_add.anon_hosting().empty()
      50           0 :                              ? absl::make_optional(geo_headers_to_add.anon_hosting())
      51           0 :                              : absl::nullopt;
      52           0 :   anon_tor_header_ = !geo_headers_to_add.anon_tor().empty()
      53           0 :                          ? absl::make_optional(geo_headers_to_add.anon_tor())
      54           0 :                          : absl::nullopt;
      55           0 :   anon_proxy_header_ = !geo_headers_to_add.anon_proxy().empty()
      56           0 :                            ? absl::make_optional(geo_headers_to_add.anon_proxy())
      57           0 :                            : absl::nullopt;
      58           0 :   if (!city_db_path_ && !isp_db_path_ && !anon_db_path_) {
      59           0 :     throw EnvoyException("At least one geolocation database path needs to be configured: "
      60           0 :                          "city_db_path, isp_db_path or anon_db_path");
      61           0 :   }
      62           0 :   if (city_db_path_) {
      63           0 :     registerGeoDbStats("city_db");
      64           0 :   }
      65           0 :   if (isp_db_path_) {
      66           0 :     registerGeoDbStats("isp_db");
      67           0 :   }
      68           0 :   if (anon_db_path_) {
      69           0 :     registerGeoDbStats("anon_db");
      70           0 :   }
      71           0 : };
      72             : 
      73           0 : void GeoipProviderConfig::registerGeoDbStats(const std::string& db_type) {
      74           0 :   stat_name_set_->rememberBuiltin(absl::StrCat(db_type, ".total"));
      75           0 :   stat_name_set_->rememberBuiltin(absl::StrCat(db_type, ".hit"));
      76           0 :   stat_name_set_->rememberBuiltin(absl::StrCat(db_type, ".lookup_error"));
      77           0 : }
      78             : 
      79           0 : bool GeoipProviderConfig::isLookupEnabledForHeader(const absl::optional<std::string>& header) {
      80           0 :   return (header && !header.value().empty());
      81           0 : }
      82             : 
      83           0 : void GeoipProviderConfig::incCounter(Stats::StatName name) {
      84           0 :   stats_scope_->counterFromStatName(name).inc();
      85           0 : }
      86             : 
      87           0 : GeoipProvider::~GeoipProvider() {
      88           0 :   ENVOY_LOG(debug, "Shutting down Maxmind geolocation provider");
      89           0 :   if (city_db_) {
      90           0 :     MMDB_close(city_db_.get());
      91           0 :   }
      92           0 :   if (isp_db_) {
      93           0 :     MMDB_close(isp_db_.get());
      94           0 :   }
      95           0 :   if (anon_db_) {
      96           0 :     MMDB_close(anon_db_.get());
      97           0 :   }
      98           0 : }
      99             : 
     100           0 : MaxmindDbPtr GeoipProvider::initMaxMindDb(const absl::optional<std::string>& db_path) {
     101           0 :   if (db_path) {
     102           0 :     MMDB_s maxmind_db;
     103           0 :     int result_code = MMDB_open(db_path.value().c_str(), MMDB_MODE_MMAP, &maxmind_db);
     104           0 :     RELEASE_ASSERT(MMDB_SUCCESS == result_code,
     105           0 :                    fmt::format("Unable to open Maxmind database file {}. Error {}", db_path.value(),
     106           0 :                                std::string(MMDB_strerror(result_code))));
     107           0 :     return std::make_unique<MMDB_s>(maxmind_db);
     108           0 :   } else {
     109           0 :     ENVOY_LOG(debug, "Geolocation database path is empty, skipping database creation");
     110           0 :     return nullptr;
     111           0 :   }
     112           0 : }
     113             : 
     114             : void GeoipProvider::lookup(Geolocation::LookupRequest&& request,
     115           0 :                            Geolocation::LookupGeoHeadersCallback&& cb) const {
     116           0 :   auto& remote_address = request.remoteAddress();
     117           0 :   auto lookup_result = absl::flat_hash_map<std::string, std::string>{};
     118           0 :   lookupInCityDb(remote_address, lookup_result);
     119           0 :   lookupInAsnDb(remote_address, lookup_result);
     120           0 :   lookupInAnonDb(remote_address, lookup_result);
     121           0 :   cb(std::move(lookup_result));
     122           0 : }
     123             : 
     124             : void GeoipProvider::lookupInCityDb(
     125             :     const Network::Address::InstanceConstSharedPtr& remote_address,
     126           0 :     absl::flat_hash_map<std::string, std::string>& lookup_result) const {
     127           0 :   if (config_->isLookupEnabledForHeader(config_->cityHeader()) ||
     128           0 :       config_->isLookupEnabledForHeader(config_->regionHeader()) ||
     129           0 :       config_->isLookupEnabledForHeader(config_->countryHeader())) {
     130           0 :     ASSERT(city_db_, "Maxmind city database is not initialised for performing lookups");
     131           0 :     int mmdb_error;
     132           0 :     const uint32_t n_prev_hits = lookup_result.size();
     133           0 :     MMDB_lookup_result_s mmdb_lookup_result = MMDB_lookup_sockaddr(
     134           0 :         city_db_.get(), reinterpret_cast<const sockaddr*>(remote_address->sockAddr()), &mmdb_error);
     135           0 :     if (!mmdb_error) {
     136           0 :       MMDB_entry_data_list_s* entry_data_list;
     137           0 :       int status = MMDB_get_entry_data_list(&mmdb_lookup_result.entry, &entry_data_list);
     138           0 :       if (status == MMDB_SUCCESS) {
     139           0 :         if (config_->isLookupEnabledForHeader(config_->cityHeader())) {
     140           0 :           populateGeoLookupResult(mmdb_lookup_result, lookup_result, config_->cityHeader().value(),
     141           0 :                                   MMDB_CITY_LOOKUP_ARGS[0], MMDB_CITY_LOOKUP_ARGS[1],
     142           0 :                                   MMDB_CITY_LOOKUP_ARGS[2]);
     143           0 :         }
     144           0 :         if (config_->isLookupEnabledForHeader(config_->regionHeader())) {
     145           0 :           populateGeoLookupResult(mmdb_lookup_result, lookup_result,
     146           0 :                                   config_->regionHeader().value(), MMDB_REGION_LOOKUP_ARGS[0],
     147           0 :                                   MMDB_REGION_LOOKUP_ARGS[1], MMDB_REGION_LOOKUP_ARGS[2]);
     148           0 :         }
     149           0 :         if (config_->isLookupEnabledForHeader(config_->countryHeader())) {
     150           0 :           populateGeoLookupResult(mmdb_lookup_result, lookup_result,
     151           0 :                                   config_->countryHeader().value(), MMDB_COUNTRY_LOOKUP_ARGS[0],
     152           0 :                                   MMDB_COUNTRY_LOOKUP_ARGS[1]);
     153           0 :         }
     154           0 :         if (lookup_result.size() > n_prev_hits) {
     155           0 :           config_->incHit("city_db");
     156           0 :         }
     157           0 :         MMDB_free_entry_data_list(entry_data_list);
     158           0 :       }
     159             : 
     160           0 :     } else {
     161           0 :       config_->incLookupError("city_db");
     162           0 :     }
     163           0 :     config_->incTotal("city_db");
     164           0 :   }
     165           0 : }
     166             : 
     167             : void GeoipProvider::lookupInAsnDb(
     168             :     const Network::Address::InstanceConstSharedPtr& remote_address,
     169           0 :     absl::flat_hash_map<std::string, std::string>& lookup_result) const {
     170           0 :   if (config_->isLookupEnabledForHeader(config_->asnHeader())) {
     171           0 :     RELEASE_ASSERT(isp_db_, "Maxmind asn database is not initialized for performing lookups");
     172           0 :     int mmdb_error;
     173           0 :     const uint32_t n_prev_hits = lookup_result.size();
     174           0 :     MMDB_lookup_result_s mmdb_lookup_result = MMDB_lookup_sockaddr(
     175           0 :         isp_db_.get(), reinterpret_cast<const sockaddr*>(remote_address->sockAddr()), &mmdb_error);
     176           0 :     if (!mmdb_error) {
     177           0 :       MMDB_entry_data_list_s* entry_data_list;
     178           0 :       int status = MMDB_get_entry_data_list(&mmdb_lookup_result.entry, &entry_data_list);
     179           0 :       if (status == MMDB_SUCCESS && entry_data_list) {
     180           0 :         populateGeoLookupResult(mmdb_lookup_result, lookup_result, config_->asnHeader().value(),
     181           0 :                                 MMDB_ASN_LOOKUP_ARGS[0]);
     182           0 :         MMDB_free_entry_data_list(entry_data_list);
     183           0 :         if (lookup_result.size() > n_prev_hits) {
     184           0 :           config_->incHit("isp_db");
     185           0 :         }
     186           0 :       } else {
     187           0 :         config_->incLookupError("isp_db");
     188           0 :       }
     189           0 :     }
     190           0 :     config_->incTotal("isp_db");
     191           0 :   }
     192           0 : }
     193             : 
     194             : void GeoipProvider::lookupInAnonDb(
     195             :     const Network::Address::InstanceConstSharedPtr& remote_address,
     196           0 :     absl::flat_hash_map<std::string, std::string>& lookup_result) const {
     197           0 :   if (config_->isLookupEnabledForHeader(config_->anonHeader()) || config_->anonVpnHeader()) {
     198           0 :     ASSERT(anon_db_, "Maxmind city database is not initialised for performing lookups");
     199           0 :     int mmdb_error;
     200           0 :     const uint32_t n_prev_hits = lookup_result.size();
     201           0 :     MMDB_lookup_result_s mmdb_lookup_result = MMDB_lookup_sockaddr(
     202           0 :         anon_db_.get(), reinterpret_cast<const sockaddr*>(remote_address->sockAddr()), &mmdb_error);
     203           0 :     if (!mmdb_error) {
     204           0 :       MMDB_entry_data_list_s* entry_data_list;
     205           0 :       int status = MMDB_get_entry_data_list(&mmdb_lookup_result.entry, &entry_data_list);
     206           0 :       if (status == MMDB_SUCCESS) {
     207           0 :         if (config_->isLookupEnabledForHeader(config_->anonHeader())) {
     208           0 :           populateGeoLookupResult(mmdb_lookup_result, lookup_result, config_->anonHeader().value(),
     209           0 :                                   MMDB_ANON_LOOKUP_ARGS[0]);
     210           0 :         }
     211           0 :         if (config_->isLookupEnabledForHeader(config_->anonVpnHeader())) {
     212           0 :           populateGeoLookupResult(mmdb_lookup_result, lookup_result,
     213           0 :                                   config_->anonVpnHeader().value(), MMDB_ANON_LOOKUP_ARGS[1]);
     214           0 :         }
     215           0 :         if (config_->isLookupEnabledForHeader(config_->anonHostingHeader())) {
     216           0 :           populateGeoLookupResult(mmdb_lookup_result, lookup_result,
     217           0 :                                   config_->anonHostingHeader().value(), MMDB_ANON_LOOKUP_ARGS[2]);
     218           0 :         }
     219           0 :         if (config_->isLookupEnabledForHeader(config_->anonTorHeader())) {
     220           0 :           populateGeoLookupResult(mmdb_lookup_result, lookup_result,
     221           0 :                                   config_->anonTorHeader().value(), MMDB_ANON_LOOKUP_ARGS[3]);
     222           0 :         }
     223           0 :         if (config_->isLookupEnabledForHeader(config_->anonProxyHeader())) {
     224           0 :           populateGeoLookupResult(mmdb_lookup_result, lookup_result,
     225           0 :                                   config_->anonProxyHeader().value(), MMDB_ANON_LOOKUP_ARGS[4]);
     226           0 :         }
     227           0 :         if (lookup_result.size() > n_prev_hits) {
     228           0 :           config_->incHit("anon_db");
     229           0 :         }
     230           0 :         MMDB_free_entry_data_list(entry_data_list);
     231           0 :       } else {
     232           0 :         config_->incLookupError("anon_db");
     233           0 :       }
     234           0 :     }
     235           0 :     config_->incTotal("anon_db");
     236           0 :   }
     237           0 : }
     238             : 
     239             : template <class... Params>
     240             : void GeoipProvider::populateGeoLookupResult(
     241             :     MMDB_lookup_result_s& mmdb_lookup_result,
     242             :     absl::flat_hash_map<std::string, std::string>& lookup_result, const std::string& result_key,
     243           0 :     Params... lookup_params) const {
     244           0 :   MMDB_entry_data_s entry_data;
     245           0 :   if ((MMDB_get_value(&mmdb_lookup_result.entry, &entry_data, lookup_params..., NULL)) ==
     246           0 :       MMDB_SUCCESS) {
     247           0 :     std::string result_value;
     248           0 :     if (entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
     249           0 :       result_value = std::string(entry_data.utf8_string, entry_data.data_size);
     250           0 :     } else if (entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_UINT32 &&
     251           0 :                entry_data.uint32 > 0) {
     252           0 :       result_value = std::to_string(entry_data.uint32);
     253           0 :     } else if (entry_data.has_data && entry_data.type == MMDB_DATA_TYPE_BOOLEAN) {
     254           0 :       result_value = entry_data.boolean ? "true" : "false";
     255           0 :     }
     256           0 :     if (!result_value.empty()) {
     257           0 :       lookup_result.insert(std::make_pair(result_key, result_value));
     258           0 :     }
     259           0 :   }
     260           0 : }
     261             : 
     262             : } // namespace Maxmind
     263             : } // namespace GeoipProviders
     264             : } // namespace Extensions
     265             : } // namespace Envoy

Generated by: LCOV version 1.15