From e9feaa9dc096260587a43ccb69cf1a01fa08b787 Mon Sep 17 00:00:00 2001 From: Randall Meyer Date: Wed, 7 Apr 2021 16:22:45 -0700 Subject: [PATCH] header_rewrite: allow for use of maxminddb as source of geo truth --- configure.ac | 10 +- plugins/Makefile.am | 4 +- plugins/experimental/geoip_acl/Makefile.inc | 2 +- plugins/header_rewrite/Makefile.inc | 26 ++- plugins/header_rewrite/conditions.cc | 160 ++------------- plugins/header_rewrite/conditions.h | 4 +- .../header_rewrite/conditions_geo_geoip.cc | 190 ++++++++++++++++++ .../header_rewrite/conditions_geo_maxmind.cc | 165 +++++++++++++++ plugins/header_rewrite/header_rewrite.cc | 80 ++++---- plugins/header_rewrite/resources.h | 5 - plugins/healthchecks/Makefile.inc | 4 - 11 files changed, 456 insertions(+), 194 deletions(-) create mode 100644 plugins/header_rewrite/conditions_geo_geoip.cc create mode 100644 plugins/header_rewrite/conditions_geo_maxmind.cc diff --git a/configure.ac b/configure.ac index d18b3c5e2a3..8e863ca40df 100644 --- a/configure.ac +++ b/configure.ac @@ -1697,12 +1697,16 @@ AC_SUBST(use_hwloc) # AC_CHECK_HEADERS([GeoIP.h], [ AC_CHECK_LIB([GeoIP], [GeoIP_new], [ - AC_SUBST([GEO_LIBS], ["-lGeoIP"]) + AC_SUBST([GEOIP_LIBS], ["-lGeoIP"]) + AC_SUBST(has_geoip, 1) ], [ - AC_SUBST([GEO_LIBS], [""]) + AC_SUBST([GEOIP_LIBS], [""]) + AC_SUBST(has_geoip, 0) ]) ]) +AM_CONDITIONAL([HAS_GEOIP], [test "x${has_geoip}" = "x1" ]) + # # Check for libmaxmind. This is the maxmind v2 API where GeoIP is the legacy # v1 dat file based API @@ -1717,7 +1721,7 @@ AC_CHECK_HEADERS([maxminddb.h], [ ]) ]) -AM_CONDITIONAL([BUILD_MAXMIND_ACL_PLUGIN], [test "x${has_maxmind}" = "x1" ]) +AM_CONDITIONAL([HAS_MAXMINDDB], [test "x${has_maxmind}" = "x1" ]) # Right now, the healthcheck plugins requires inotify_init (and friends) AM_CONDITIONAL([BUILD_HEALTHCHECK_PLUGIN], [ test "$ac_cv_func_inotify_init" = "yes" ]) diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 52ce5d8bfdc..88e50c915e2 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -39,7 +39,9 @@ include esi/Makefile.inc include generator/Makefile.inc include compress/Makefile.inc include header_rewrite/Makefile.inc +if BUILD_HEALTHCHECK_PLUGIN include healthchecks/Makefile.inc +endif include libloader/Makefile.inc if HAS_LUAJIT include lua/Makefile.inc @@ -70,7 +72,7 @@ include experimental/hook-trace/Makefile.inc include experimental/icap/Makefile.inc include experimental/inliner/Makefile.inc -if BUILD_MAXMIND_ACL_PLUGIN +if HAS_MAXMINDDB include experimental/maxmind_acl/Makefile.inc endif diff --git a/plugins/experimental/geoip_acl/Makefile.inc b/plugins/experimental/geoip_acl/Makefile.inc index 3ff84f67f7b..150b3c3bf19 100644 --- a/plugins/experimental/geoip_acl/Makefile.inc +++ b/plugins/experimental/geoip_acl/Makefile.inc @@ -20,4 +20,4 @@ experimental_geoip_acl_geoip_acl_la_SOURCES = \ experimental/geoip_acl/acl.cc \ experimental/geoip_acl/geoip_acl.cc -experimental_geoip_acl_geoip_acl_la_LIBADD = $(GEO_LIBS) +experimental_geoip_acl_geoip_acl_la_LIBADD = $(GEOIP_LIBS) diff --git a/plugins/header_rewrite/Makefile.inc b/plugins/header_rewrite/Makefile.inc index 0b5cfe8bb62..a64fffa93d6 100644 --- a/plugins/header_rewrite/Makefile.inc +++ b/plugins/header_rewrite/Makefile.inc @@ -44,16 +44,38 @@ header_rewrite_header_rewrite_la_SOURCES = \ header_rewrite/value.cc \ header_rewrite/value.h +if HAS_MAXMINDDB +header_rewrite_header_rewrite_la_SOURCES += header_rewrite/conditions_geo_maxmind.cc +endif + +if HAS_GEOIP +header_rewrite_header_rewrite_la_SOURCES += header_rewrite/conditions_geo_geoip.cc +endif + header_rewrite_parser_la_SOURCES = \ header_rewrite/parser.cc \ header_rewrite/parser.h header_rewrite_header_rewrite_la_LIBADD = \ - header_rewrite/parser.la \ - $(GEO_LIBS) + header_rewrite/parser.la + +if HAS_GEOIP +header_rewrite_header_rewrite_la_LIBADD += $(GEOIP_LIBS) +endif + +if HAS_MAXMINDDB +header_rewrite_header_rewrite_la_LIBADD += $(MAXMINDDB_LIBS) +endif check_PROGRAMS += header_rewrite/header_rewrite_test header_rewrite_header_rewrite_test_SOURCES = \ header_rewrite/header_rewrite_test.cc header_rewrite_header_rewrite_test_LDADD = \ header_rewrite/parser.la +if HAS_GEOIP +header_rewrite_header_rewrite_test_LDADD += $(GEOIP_LIBS) +endif + +if HAS_MAXMINDDB +header_rewrite_header_rewrite_test_LDADD += $(MAXMINDDB_LIBS) +endif diff --git a/plugins/header_rewrite/conditions.cc b/plugins/header_rewrite/conditions.cc index 66c3e5d9173..ec5a657f71b 100644 --- a/plugins/header_rewrite/conditions.cc +++ b/plugins/header_rewrite/conditions.cc @@ -15,10 +15,12 @@ See the License for the specific language governing permissions and limitations under the License. */ + ////////////////////////////////////////////////////////////////////////////////////////////// // conditions.cc: Implementation of the condition classes // // + #include #include #include @@ -43,6 +45,14 @@ #endif #endif +#if HAVE_GEOIP_H +#define HAVE_GEO_LIB 1 +#endif + +#if HAVE_MAXMINDDB_H +#define HAVE_GEO_LIB 1 +#endif + // ConditionStatus void ConditionStatus::initialize(Parser &p) @@ -740,151 +750,10 @@ ConditionNow::eval(const Resources &res) return static_cast(_matcher)->test(now); } -// ConditionGeo: Geo-based information (integer). See ConditionGeoCountry for the string version. -#if HAVE_GEOIP_H -const char * -ConditionGeo::get_geo_string(const sockaddr *addr) const -{ - const char *ret = "(unknown)"; - int v = 4; - - if (addr) { - switch (_geo_qual) { - // Country database - case GEO_QUAL_COUNTRY: - switch (addr->sa_family) { - case AF_INET: - if (gGeoIP[GEOIP_COUNTRY_EDITION]) { - uint32_t ip = ntohl(reinterpret_cast(addr)->sin_addr.s_addr); - - ret = GeoIP_country_code_by_ipnum(gGeoIP[GEOIP_COUNTRY_EDITION], ip); - } - break; - case AF_INET6: { - if (gGeoIP[GEOIP_COUNTRY_EDITION_V6]) { - geoipv6_t ip = reinterpret_cast(addr)->sin6_addr; - - v = 6; - ret = GeoIP_country_code_by_ipnum_v6(gGeoIP[GEOIP_COUNTRY_EDITION_V6], ip); - } - } break; - default: - break; - } - TSDebug(PLUGIN_NAME, "eval(): Client IPv%d seems to come from Country: %s", v, ret); - break; - - // ASN database - case GEO_QUAL_ASN_NAME: - switch (addr->sa_family) { - case AF_INET: - if (gGeoIP[GEOIP_ASNUM_EDITION]) { - uint32_t ip = ntohl(reinterpret_cast(addr)->sin_addr.s_addr); - - ret = GeoIP_name_by_ipnum(gGeoIP[GEOIP_ASNUM_EDITION], ip); - } - break; - case AF_INET6: { - if (gGeoIP[GEOIP_ASNUM_EDITION_V6]) { - geoipv6_t ip = reinterpret_cast(addr)->sin6_addr; - - v = 6; - ret = GeoIP_name_by_ipnum_v6(gGeoIP[GEOIP_ASNUM_EDITION_V6], ip); - } - } break; - default: - break; - } - TSDebug(PLUGIN_NAME, "eval(): Client IPv%d seems to come from ASN Name: %s", v, ret); - break; - - default: - break; - } - } - - return ret ? ret : "(unknown)"; -} - -int64_t -ConditionGeo::get_geo_int(const sockaddr *addr) const -{ - int64_t ret = -1; - int v = 4; - - if (!addr) { - return 0; - } - - switch (_geo_qual) { - // Country Database - case GEO_QUAL_COUNTRY_ISO: - switch (addr->sa_family) { - case AF_INET: - if (gGeoIP[GEOIP_COUNTRY_EDITION]) { - uint32_t ip = ntohl(reinterpret_cast(addr)->sin_addr.s_addr); - - ret = GeoIP_id_by_ipnum(gGeoIP[GEOIP_COUNTRY_EDITION], ip); - } - break; - case AF_INET6: { - if (gGeoIP[GEOIP_COUNTRY_EDITION_V6]) { - geoipv6_t ip = reinterpret_cast(addr)->sin6_addr; - - v = 6; - ret = GeoIP_id_by_ipnum_v6(gGeoIP[GEOIP_COUNTRY_EDITION_V6], ip); - } - } break; - default: - break; - } - TSDebug(PLUGIN_NAME, "eval(): Client IPv%d seems to come from Country ISO: %" PRId64, v, ret); - break; - - case GEO_QUAL_ASN: { - const char *asn_name = nullptr; - - switch (addr->sa_family) { - case AF_INET: - if (gGeoIP[GEOIP_ASNUM_EDITION]) { - uint32_t ip = ntohl(reinterpret_cast(addr)->sin_addr.s_addr); - - asn_name = GeoIP_name_by_ipnum(gGeoIP[GEOIP_ASNUM_EDITION], ip); - } - break; - case AF_INET6: - if (gGeoIP[GEOIP_ASNUM_EDITION_V6]) { - geoipv6_t ip = reinterpret_cast(addr)->sin6_addr; - - v = 6; - asn_name = GeoIP_name_by_ipnum_v6(gGeoIP[GEOIP_ASNUM_EDITION_V6], ip); - } - break; - } - if (asn_name) { - // This is a little odd, but the strings returned are e.g. "AS1234 Acme Inc" - while (*asn_name && !(isdigit(*asn_name))) { - ++asn_name; - } - ret = strtol(asn_name, nullptr, 10); - } - } - TSDebug(PLUGIN_NAME, "eval(): Client IPv%d seems to come from ASN #: %" PRId64, v, ret); - break; - - // Likely shouldn't trip, should we assert? - default: - break; - } - - return ret; -} - -#else - +#ifndef HAVE_GEO_LIB // No Geo library available, these are just stubs. -const char * +std::string ConditionGeo::get_geo_string(const sockaddr *addr) const { TSError("[%s] No Geo library available!", PLUGIN_NAME); @@ -898,6 +767,11 @@ ConditionGeo::get_geo_int(const sockaddr *addr) const return 0; } +void +ConditionGeo::initLibrary(const std::string &path) +{ + TSError("[%s] No Geo library available!", PLUGIN_NAME); +} #endif void diff --git a/plugins/header_rewrite/conditions.h b/plugins/header_rewrite/conditions.h index ed6c61fc9c9..c9b3fe7f35f 100644 --- a/plugins/header_rewrite/conditions.h +++ b/plugins/header_rewrite/conditions.h @@ -424,6 +424,8 @@ class ConditionGeo : public Condition void set_qualifier(const std::string &q) override; void append_value(std::string &s, const Resources &res) override; + static void initLibrary(const std::string &path); + // Make sure we know if the type is an int-type or a string. bool is_int_type() const @@ -442,7 +444,7 @@ class ConditionGeo : public Condition private: int64_t get_geo_int(const sockaddr *addr) const; - const char *get_geo_string(const sockaddr *addr) const; + std::string get_geo_string(const sockaddr *addr) const; GeoQualifiers _geo_qual = GEO_QUAL_COUNTRY; bool _int_type = false; }; diff --git a/plugins/header_rewrite/conditions_geo_geoip.cc b/plugins/header_rewrite/conditions_geo_geoip.cc new file mode 100644 index 00000000000..2dff5192207 --- /dev/null +++ b/plugins/header_rewrite/conditions_geo_geoip.cc @@ -0,0 +1,190 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +////////////////////////////////////////////////////////////////////////////////////////////// +// conditions_geo_geoip.cc: Implementation of the ConditionGeo class based on the GeoIP library +// +// + +#include +#include +#include + +#include "ts/ts.h" + +#include "conditions.h" + +#include + +GeoIP *gGeoIP[NUM_DB_TYPES]; + +void +ConditionGeo::initLibrary(const std::string &) +{ + GeoIPDBTypes dbs[] = {GEOIP_COUNTRY_EDITION, GEOIP_COUNTRY_EDITION_V6, GEOIP_ASNUM_EDITION, GEOIP_ASNUM_EDITION_V6}; + + for (auto &db : dbs) { + if (!gGeoIP[db] && GeoIP_db_avail(db)) { + // GEOIP_STANDARD seems to break threaded apps... + gGeoIP[db] = GeoIP_open_type(db, GEOIP_MMAP_CACHE); + + char *db_info = GeoIP_database_info(gGeoIP[db]); + TSDebug(PLUGIN_NAME, "initialized GeoIP-DB[%d] %s", db, db_info); + free(db_info); + } + } +} + +// ConditionGeo: Geo-based information (integer). See ConditionGeoCountry for the string version. +std::string +ConditionGeo::get_geo_string(const sockaddr *addr) const +{ + std::string = "(unknown)"; + int v = 4; + + if (addr) { + switch (_geo_qual) { + // Country database + case GEO_QUAL_COUNTRY: + switch (addr->sa_family) { + case AF_INET: + if (gGeoIP[GEOIP_COUNTRY_EDITION]) { + uint32_t ip = ntohl(reinterpret_cast(addr)->sin_addr.s_addr); + + ret = GeoIP_country_code_by_ipnum(gGeoIP[GEOIP_COUNTRY_EDITION], ip); + } + break; + case AF_INET6: { + if (gGeoIP[GEOIP_COUNTRY_EDITION_V6]) { + geoipv6_t ip = reinterpret_cast(addr)->sin6_addr; + + v = 6; + ret = GeoIP_country_code_by_ipnum_v6(gGeoIP[GEOIP_COUNTRY_EDITION_V6], ip); + } + } break; + default: + break; + } + TSDebug(PLUGIN_NAME, "eval(): Client IPv%d seems to come from Country: %s", v, ret); + break; + + // ASN database + case GEO_QUAL_ASN_NAME: + switch (addr->sa_family) { + case AF_INET: + if (gGeoIP[GEOIP_ASNUM_EDITION]) { + uint32_t ip = ntohl(reinterpret_cast(addr)->sin_addr.s_addr); + + ret = GeoIP_name_by_ipnum(gGeoIP[GEOIP_ASNUM_EDITION], ip); + } + break; + case AF_INET6: { + if (gGeoIP[GEOIP_ASNUM_EDITION_V6]) { + geoipv6_t ip = reinterpret_cast(addr)->sin6_addr; + + v = 6; + ret = GeoIP_name_by_ipnum_v6(gGeoIP[GEOIP_ASNUM_EDITION_V6], ip); + } + } break; + default: + break; + } + TSDebug(PLUGIN_NAME, "eval(): Client IPv%d seems to come from ASN Name: %s", v, ret); + break; + + default: + break; + } + } + + return ret ? ret : "(unknown)"; +} + +int64_t +ConditionGeo::get_geo_int(const sockaddr *addr) const +{ + int64_t ret = -1; + int v = 4; + + if (!addr) { + return 0; + } + + switch (_geo_qual) { + // Country Database + case GEO_QUAL_COUNTRY_ISO: + switch (addr->sa_family) { + case AF_INET: + if (gGeoIP[GEOIP_COUNTRY_EDITION]) { + uint32_t ip = ntohl(reinterpret_cast(addr)->sin_addr.s_addr); + + ret = GeoIP_id_by_ipnum(gGeoIP[GEOIP_COUNTRY_EDITION], ip); + } + break; + case AF_INET6: { + if (gGeoIP[GEOIP_COUNTRY_EDITION_V6]) { + geoipv6_t ip = reinterpret_cast(addr)->sin6_addr; + + v = 6; + ret = GeoIP_id_by_ipnum_v6(gGeoIP[GEOIP_COUNTRY_EDITION_V6], ip); + } + } break; + default: + break; + } + TSDebug(PLUGIN_NAME, "eval(): Client IPv%d seems to come from Country ISO: %" PRId64, v, ret); + break; + + case GEO_QUAL_ASN: { + const char *asn_name = nullptr; + + switch (addr->sa_family) { + case AF_INET: + if (gGeoIP[GEOIP_ASNUM_EDITION]) { + uint32_t ip = ntohl(reinterpret_cast(addr)->sin_addr.s_addr); + + asn_name = GeoIP_name_by_ipnum(gGeoIP[GEOIP_ASNUM_EDITION], ip); + } + break; + case AF_INET6: + if (gGeoIP[GEOIP_ASNUM_EDITION_V6]) { + geoipv6_t ip = reinterpret_cast(addr)->sin6_addr; + + v = 6; + asn_name = GeoIP_name_by_ipnum_v6(gGeoIP[GEOIP_ASNUM_EDITION_V6], ip); + } + break; + } + if (asn_name) { + // This is a little odd, but the strings returned are e.g. "AS1234 Acme Inc" + while (*asn_name && !(isdigit(*asn_name))) { + ++asn_name; + } + ret = strtol(asn_name, nullptr, 10); + } + } + TSDebug(PLUGIN_NAME, "eval(): Client IPv%d seems to come from ASN #: %" PRId64, v, ret); + break; + + // Likely shouldn't trip, should we assert? + default: + break; + } + + return ret; +} diff --git a/plugins/header_rewrite/conditions_geo_maxmind.cc b/plugins/header_rewrite/conditions_geo_maxmind.cc new file mode 100644 index 00000000000..722cbf63215 --- /dev/null +++ b/plugins/header_rewrite/conditions_geo_maxmind.cc @@ -0,0 +1,165 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +////////////////////////////////////////////////////////////////////////////////////////////// +// conditions_geo_maxmind.cc: Implementation of the ConditionGeo class based on MaxMindDB +// +// + +#include +#include + +#include "ts/ts.h" + +#include "conditions.h" + +#include + +MMDB_s gMaxMindDB; + +void +ConditionGeo::initLibrary(const std::string &path) +{ + if (path.empty()) { + return; + } + + int status = MMDB_open(path.c_str(), MMDB_MODE_MMAP, &gMaxMindDB); + if (MMDB_SUCCESS != status) { + TSDebug(PLUGIN_NAME, "Cannot open %s - %s", path.c_str(), MMDB_strerror(status)); + return; + } + TSDebug(PLUGIN_NAME, "Loaded %s", path.c_str()); +} + +std::string +ConditionGeo::get_geo_string(const sockaddr *addr) const +{ + std::string ret = "(unknown)"; + int mmdb_error; + + MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&gMaxMindDB, addr, &mmdb_error); + + if (MMDB_SUCCESS != mmdb_error) { + TSDebug(PLUGIN_NAME, "Error during sockaddr lookup: %s", MMDB_strerror(mmdb_error)); + return ret; + } + + MMDB_entry_data_list_s *entry_data_list = nullptr; + if (!result.found_entry) { + TSDebug(PLUGIN_NAME, "No entry for this IP was found"); + return ret; + } + + int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); + if (MMDB_SUCCESS != status) { + TSDebug(PLUGIN_NAME, "Error looking up entry data: %s", MMDB_strerror(status)); + return ret; + } + + if (entry_data_list == nullptr) { + TSDebug(PLUGIN_NAME, "No data found"); + return ret; + } + + const char *field_name; + switch (_geo_qual) { + case GEO_QUAL_COUNTRY: + field_name = "country_code"; + break; + case GEO_QUAL_ASN_NAME: + field_name = "autonomous_system_organization"; + break; + default: + TSDebug(PLUGIN_NAME, "Unsupported field %d", _geo_qual); + return ret; + break; + } + + MMDB_entry_data_s entry_data; + + status = MMDB_get_value(&result.entry, &entry_data, field_name, NULL); + if (MMDB_SUCCESS != status) { + TSDebug(PLUGIN_NAME, "ERROR on get value asn value: %s", MMDB_strerror(status)); + return ret; + } + ret = std::string(entry_data.utf8_string, entry_data.data_size); + + if (NULL != entry_data_list) { + MMDB_free_entry_data_list(entry_data_list); + } + + return ret; +} + +int64_t +ConditionGeo::get_geo_int(const sockaddr *addr) const +{ + int64_t ret = -1; + int mmdb_error; + + MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&gMaxMindDB, addr, &mmdb_error); + + if (MMDB_SUCCESS != mmdb_error) { + TSDebug(PLUGIN_NAME, "Error during sockaddr lookup: %s", MMDB_strerror(mmdb_error)); + return ret; + } + + MMDB_entry_data_list_s *entry_data_list = nullptr; + if (!result.found_entry) { + TSDebug(PLUGIN_NAME, "No entry for this IP was found"); + return ret; + } + + int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); + if (MMDB_SUCCESS != status) { + TSDebug(PLUGIN_NAME, "Error looking up entry data: %s", MMDB_strerror(status)); + return ret; + } + + if (entry_data_list == nullptr) { + TSDebug(PLUGIN_NAME, "No data found"); + return ret; + } + + const char *field_name; + switch (_geo_qual) { + case GEO_QUAL_ASN: + field_name = "autonomous_system"; + break; + default: + TSDebug(PLUGIN_NAME, "Unsupported field %d", _geo_qual); + return ret; + break; + } + + MMDB_entry_data_s entry_data; + + status = MMDB_get_value(&result.entry, &entry_data, field_name, NULL); + if (MMDB_SUCCESS != status) { + TSDebug(PLUGIN_NAME, "ERROR on get value asn value: %s", MMDB_strerror(status)); + return ret; + } + ret = entry_data.uint32; + + if (NULL != entry_data_list) { + MMDB_free_entry_data_list(entry_data_list); + } + + return ret; +} diff --git a/plugins/header_rewrite/header_rewrite.cc b/plugins/header_rewrite/header_rewrite.cc index 85e0feebf72..9ae2c9e429b 100644 --- a/plugins/header_rewrite/header_rewrite.cc +++ b/plugins/header_rewrite/header_rewrite.cc @@ -15,9 +15,12 @@ See the License for the specific language governing permissions and limitations under the License. */ + #include +#include #include #include +#include #include "ts/ts.h" #include "ts/remap.h" @@ -25,41 +28,13 @@ #include "parser.h" #include "ruleset.h" #include "resources.h" +#include "conditions.h" // Debugs const char PLUGIN_NAME[] = "header_rewrite"; const char PLUGIN_NAME_DBG[] = "dbg_header_rewrite"; -// Geo information, currently only Maxmind. These have to be initialized when the plugin loads. -#if HAVE_GEOIP_H -#include - -GeoIP *gGeoIP[NUM_DB_TYPES]; - -static void -initGeoIP() -{ - GeoIPDBTypes dbs[] = {GEOIP_COUNTRY_EDITION, GEOIP_COUNTRY_EDITION_V6, GEOIP_ASNUM_EDITION, GEOIP_ASNUM_EDITION_V6}; - - for (auto &db : dbs) { - if (!gGeoIP[db] && GeoIP_db_avail(db)) { - // GEOIP_STANDARD seems to break threaded apps... - gGeoIP[db] = GeoIP_open_type(db, GEOIP_MMAP_CACHE); - - char *db_info = GeoIP_database_info(gGeoIP[db]); - TSDebug(PLUGIN_NAME, "initialized GeoIP-DB[%d] %s", db, db_info); - free(db_info); - } - } -} - -#else - -static void -initGeoIP() -{ -} -#endif +std::once_flag initGeoLibs; // Forward declaration for the main continuation. static int cont_rewrite_headers(TSCont, TSEvent, void *); @@ -315,6 +290,8 @@ cont_rewrite_headers(TSCont contp, TSEvent event, void *edata) return 0; } +static const struct option longopt[] = {{"db-path", required_argument, NULL, 'm'}, {NULL, no_argument, NULL, '\0'}}; + /////////////////////////////////////////////////////////////////////////////// // Initialize the InkAPI plugin for the global hooks we support. // @@ -329,6 +306,21 @@ TSPluginInit(int argc, const char *argv[]) if (TS_SUCCESS != TSPluginRegister(&info)) { TSError("[%s] plugin registration failed", PLUGIN_NAME); + return; + } + + std::string dbPath; + while (true) { + int opt = getopt_long(argc, (char *const *)argv, "m:", longopt, NULL); + + switch (opt) { + case 'm': { + dbPath = optarg; + } break; + } + if (opt == -1) { + break; + } } // Parse the global config file(s). All rules are just appended @@ -336,9 +328,9 @@ TSPluginInit(int argc, const char *argv[]) RulesConfig *conf = new RulesConfig; bool got_config = false; - initGeoIP(); + std::call_once(initGeoLibs, [&dbPath]() { ConditionGeo::initLibrary(dbPath); }); - for (int i = 1; i < argc; ++i) { + for (int i = optind; i < argc; ++i) { // Parse the config file(s). Note that multiple config files are // just appended to the configurations. TSDebug(PLUGIN_NAME, "Loading global configuration file %s", argv[i]); @@ -389,7 +381,6 @@ TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size) return TS_ERROR; } - initGeoIP(); TSDebug(PLUGIN_NAME, "Remap plugin is successfully initialized"); return TS_SUCCESS; @@ -405,9 +396,30 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf ATS_UNUSE return TS_ERROR; } + // argv contains the "to" and "from" URLs. Skip the first so that the + // second one poses as the program name. + --argc; + ++argv; + + std::string dbPath; + while (true) { + int opt = getopt_long(argc, (char *const *)argv, "m:", longopt, NULL); + + switch (opt) { + case 'm': { + dbPath = optarg; + } break; + } + if (opt == -1) { + break; + } + } + + std::call_once(initGeoLibs, [&dbPath]() { ConditionGeo::initLibrary(dbPath); }); + RulesConfig *conf = new RulesConfig; - for (int i = 2; i < argc; ++i) { + for (int i = optind; i < argc; ++i) { TSDebug(PLUGIN_NAME, "Loading remap configuration file %s", argv[i]); if (!conf->parse_config(argv[i], TS_REMAP_PSEUDO_HOOK)) { TSError("[%s] Unable to create remap instance", PLUGIN_NAME); diff --git a/plugins/header_rewrite/resources.h b/plugins/header_rewrite/resources.h index ee5e0f0e6ee..c3ddfa0a675 100644 --- a/plugins/header_rewrite/resources.h +++ b/plugins/header_rewrite/resources.h @@ -28,11 +28,6 @@ #include "lulu.h" -#if HAVE_GEOIP_H -#include -extern GeoIP *gGeoIP[NUM_DB_TYPES]; -#endif - enum ResourceIDs { RSRC_NONE = 0, RSRC_SERVER_RESPONSE_HEADERS = 1, diff --git a/plugins/healthchecks/Makefile.inc b/plugins/healthchecks/Makefile.inc index 2121b723176..f9c027c3da4 100644 --- a/plugins/healthchecks/Makefile.inc +++ b/plugins/healthchecks/Makefile.inc @@ -14,9 +14,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -if BUILD_HEALTHCHECK_PLUGIN - pkglib_LTLIBRARIES += healthchecks/healthchecks.la healthchecks_healthchecks_la_SOURCES = healthchecks/healthchecks.c - -endif