Skip to content

Commit

Permalink
header_rewrite: allow for use of maxminddb as source of geo truth
Browse files Browse the repository at this point in the history
  • Loading branch information
randall committed Apr 12, 2021
1 parent a5a8523 commit bd52837
Show file tree
Hide file tree
Showing 14 changed files with 504 additions and 198 deletions.
10 changes: 7 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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" ])
Expand Down
4 changes: 2 additions & 2 deletions doc/admin-guide/plugins/header_rewrite.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ GEO
cond %{GEO:<part>} <operand>

Perform a GeoIP lookup of the client-IP, using a 3rd party library and
DB. Currently only the MaxMind GeoIP API is supported. The default is to
DB. Currently the MaxMind GeoIP and MaxMindDB APIs are supported. The default is to
do a Country lookup, but the following qualifiers are supported::

%{GEO:COUNTRY} The country code (e.g. "US")
Expand Down Expand Up @@ -495,7 +495,7 @@ TCP-INFO
~~~~~~~~
::

cond %{<name>}
cond %{<name>}
add-header @PropertyName "%{TCP-INFO}"

This operation records TCP Info struct field values as an Internal remap as well as global header at the event hook specified by the condition. Supported hook conditions include TXN_START_HOOK, SEND_RESPONSE_HEADER_HOOK and TXN_CLOSE_HOOK in the Global plugin and REMAP_PSEUDO_HOOK, SEND_RESPONSE_HEADER_HOOK and TXN_CLOSE_HOOK in the Remap plugin. Conditions supported as request headers include TXN_START_HOOK and REMAP_PSEUDO_HOOK. The other conditions are supported as response headers. TCP Info fields currently recorded include rtt, rto, snd_cwnd and all_retrans. This operation is not supported on transactions originated within Traffic Server (for e.g using the |TS| :c:func:`TSHttpTxnIsInternal`)
Expand Down
4 changes: 3 additions & 1 deletion plugins/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion plugins/experimental/geoip_acl/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
26 changes: 24 additions & 2 deletions plugins/header_rewrite/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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
150 changes: 3 additions & 147 deletions plugins/header_rewrite/conditions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 <sys/time.h>
#include <unistd.h>
#include <arpa/inet.h>
Expand Down Expand Up @@ -740,151 +742,7 @@ ConditionNow::eval(const Resources &res)
return static_cast<const MatcherType *>(_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<const struct sockaddr_in *>(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<const struct sockaddr_in6 *>(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<const struct sockaddr_in *>(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<const struct sockaddr_in6 *>(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<const struct sockaddr_in *>(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<const struct sockaddr_in6 *>(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<const struct sockaddr_in *>(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<const struct sockaddr_in6 *>(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

// 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);
Expand All @@ -898,8 +756,6 @@ ConditionGeo::get_geo_int(const sockaddr *addr) const
return 0;
}

#endif

void
ConditionGeo::initialize(Parser &p)
{
Expand Down
8 changes: 4 additions & 4 deletions plugins/header_rewrite/conditions.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,12 +437,12 @@ class ConditionGeo : public Condition
_int_type = flag;
}

private:
virtual int64_t get_geo_int(const sockaddr *addr) const;
virtual std::string get_geo_string(const sockaddr *addr) const;

protected:
bool eval(const Resources &res) override;

private:
int64_t get_geo_int(const sockaddr *addr) const;
const char *get_geo_string(const sockaddr *addr) const;
GeoQualifiers _geo_qual = GEO_QUAL_COUNTRY;
bool _int_type = false;
};
Expand Down
46 changes: 46 additions & 0 deletions plugins/header_rewrite/conditions_geo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
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.
*/

#include <arpa/inet.h>
#include <string>

#include "conditions.h"

class MMConditionGeo : public ConditionGeo
{
public:
MMConditionGeo() {}
virtual ~MMConditionGeo() {}

static void initLibrary(const std::string &path);

virtual int64_t get_geo_int(const sockaddr *addr) const override;
virtual std::string get_geo_string(const sockaddr *addr) const override;
};

class GeoIPConditionGeo : public ConditionGeo
{
public:
GeoIPConditionGeo() {}
virtual ~GeoIPConditionGeo() {}

static void initLibrary(const std::string &path);

virtual int64_t get_geo_int(const sockaddr *addr) const override;
virtual std::string get_geo_string(const sockaddr *addr) const override;
};
Loading

0 comments on commit bd52837

Please sign in to comment.