geoip_test.c revision 8e5fce1f9ceba17dd7e3ff0eb287e1e999c14249
/*
* Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
/*! \file */
#include <config.h>
#include <atf-c.h>
#include <unistd.h>
#include <isc/types.h>
#include <dns/geoip.h>
#include "dnstest.h"
#ifdef HAVE_GEOIP
#include <GeoIP.h>
/* We use GeoIP databases from the 'geoip' system test */
#define GEOIP_DATA "../../../bin/tests/system/geoip/data"
/*
* Helper functions
* (Mostly copied from bin/named/geoip.c)
*/
static dns_geoip_databases_t geoip = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static void
init_geoip_db(GeoIP **dbp, GeoIPDBTypes edition,
GeoIPOptions method, const char *name)
{
char *info;
GeoIP *db;
REQUIRE(dbp != NULL);
db = *dbp;
if (db != NULL) {
GeoIP_delete(db);
db = *dbp = NULL;
}
if (! GeoIP_db_avail(edition)) {
fprintf(stderr, "GeoIP %s DB not available\n", name);
return;
}
fprintf(stderr, "initializing GeoIP %s DB\n", name);
db = GeoIP_open_type(edition, method);
if (db == NULL) {
fprintf(stderr, "failed to initialize GeoIP %s DB; "
"geoip matches using this database will fail\n",
name);
return;
}
info = GeoIP_database_info(db);
if (info != NULL)
fprintf(stderr, "%s\n", info);
*dbp = db;
}
static GeoIPDBTypes
choose_rev(GeoIPDBTypes primary, GeoIPDBTypes secondary, const char *name) {
if (GeoIP_db_avail(primary))
return (primary);
if (GeoIP_db_avail(secondary))
return (secondary);
fprintf(stderr, "GeoIP %s DB: neither revision available\n", name);
return (0);
}
static void
load_geoip(const char *dir) {
GeoIPOptions method;
GeoIPDBTypes edition;
#ifdef _WIN32
method = GEOIP_STANDARD;
#else
method = GEOIP_MMAP_CACHE;
#endif
if (dir != NULL) {
char *p;
DE_CONST(dir, p);
GeoIP_setup_custom_directory(p);
}
init_geoip_db(&geoip.country_v4, GEOIP_COUNTRY_EDITION,
method, "Country (IPv4)");
#ifdef HAVE_GEOIP_V6
init_geoip_db(&geoip.country_v6, GEOIP_COUNTRY_EDITION_V6,
method, "Country (IPv6)");
#endif
edition = choose_rev(GEOIP_CITY_EDITION_REV0,
GEOIP_CITY_EDITION_REV1, "City (IPv4)");
if (edition != 0)
init_geoip_db(&geoip.city_v4, edition, method, "City (IPv4)");
#if defined(HAVE_GEOIP_V6) && defined(HAVE_GEOIP_CITY_V6)
edition = choose_rev(GEOIP_CITY_EDITION_REV0_V6,
GEOIP_CITY_EDITION_REV1_V6, "City (IPv6)");
if (edition != 0)
init_geoip_db(&geoip.city_v6, edition, method, "City (IPv6)");
#endif
edition = choose_rev(GEOIP_REGION_EDITION_REV0,
GEOIP_REGION_EDITION_REV1, "Region");
if (edition != 0)
init_geoip_db(&geoip.region, edition, method, "Region");
init_geoip_db(&geoip.isp, GEOIP_ISP_EDITION,
method, "ISP");
init_geoip_db(&geoip.org, GEOIP_ORG_EDITION,
method, "Org");
init_geoip_db(&geoip.as, GEOIP_ASNUM_EDITION,
method, "AS");
init_geoip_db(&geoip.domain, GEOIP_DOMAIN_EDITION,
method, "Domain");
init_geoip_db(&geoip.netspeed, GEOIP_NETSPEED_EDITION,
method, "NetSpeed");
}
static isc_boolean_t
do_lookup_string(const char *addr, dns_geoip_subtype_t subtype,
const char *string)
{
dns_geoip_elem_t elt;
struct in_addr in4;
isc_netaddr_t na;
inet_pton(AF_INET, addr, &in4);
isc_netaddr_fromin(&na, &in4);
elt.subtype = subtype;
strcpy(elt.as_string, string);
return (dns_geoip_match(&na, &geoip, &elt));
}
static isc_boolean_t
do_lookup_string_v6(const char *addr, dns_geoip_subtype_t subtype,
const char *string)
{
dns_geoip_elem_t elt;
struct in6_addr in6;
isc_netaddr_t na;
inet_pton(AF_INET6, addr, &in6);
isc_netaddr_fromin6(&na, &in6);
elt.subtype = subtype;
strcpy(elt.as_string, string);
return (dns_geoip_match(&na, &geoip, &elt));
}
static isc_boolean_t
do_lookup_int(const char *addr, dns_geoip_subtype_t subtype, int id) {
dns_geoip_elem_t elt;
struct in_addr in4;
isc_netaddr_t na;
inet_pton(AF_INET, addr, &in4);
isc_netaddr_fromin(&na, &in4);
elt.subtype = subtype;
elt.as_int = id;
return (dns_geoip_match(&na, &geoip, &elt));
}
/*
* Individual unit tests
*/
/* GeoIP country matching */
ATF_TC(country);
ATF_TC_HEAD(country, tc) {
atf_tc_set_md_var(tc, "descr", "test country database matching");
}
ATF_TC_BODY(country, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.country_v4 == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.1", dns_geoip_country_code, "AU");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_country_code3, "AUS");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_country_name, "Australia");
ATF_CHECK(match);
dns_test_end();
}
/* GeoIP country (ipv6) matching */
ATF_TC(country_v6);
ATF_TC_HEAD(country_v6, tc) {
atf_tc_set_md_var(tc, "descr", "test country (ipv6) database matching");
}
ATF_TC_BODY(country_v6, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.country_v6 == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_country_code, "AU");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_country_code3, "AUS");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_country_name, "Australia");
ATF_CHECK(match);
dns_test_end();
}
/* GeoIP city (ipv4) matching */
ATF_TC(city);
ATF_TC_HEAD(city, tc) {
atf_tc_set_md_var(tc, "descr", "test city database matching");
}
ATF_TC_BODY(city, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.city_v4 == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.1",
dns_geoip_city_continentcode, "NA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_city_countrycode, "US");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_city_countrycode3, "USA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_city_countryname, "United States");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_city_region, "CA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_city_regionname, "California");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_city_name, "Redwood City");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_city_postalcode, "94063");
ATF_CHECK(match);
match = do_lookup_int("10.53.0.1", dns_geoip_city_areacode, 650);
ATF_CHECK(match);
match = do_lookup_int("10.53.0.1", dns_geoip_city_metrocode, 807);
ATF_CHECK(match);
dns_test_end();
}
/* GeoIP city (ipv6) matching */
ATF_TC(city_v6);
ATF_TC_HEAD(city_v6, tc) {
atf_tc_set_md_var(tc, "descr", "test city (ipv6) database matching");
}
ATF_TC_BODY(city_v6, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.city_v6 == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_city_continentcode, "NA");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_city_countrycode, "US");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_city_countrycode3, "USA");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_city_countryname,
"United States");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_city_region, "CA");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_city_regionname, "California");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_city_name, "Redwood City");
ATF_CHECK(match);
match = do_lookup_string_v6("fd92:7065:b8e:ffff::1",
dns_geoip_city_postalcode, "94063");
ATF_CHECK(match);
dns_test_end();
}
/* GeoIP region matching */
ATF_TC(region);
ATF_TC_HEAD(region, tc) {
atf_tc_set_md_var(tc, "descr", "test region database matching");
}
ATF_TC_BODY(region, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.region == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.1",
dns_geoip_region_code, "CA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_region_name, "California");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.1",
dns_geoip_region_countrycode, "US");
ATF_CHECK(match);
dns_test_end();
}
/*
* GeoIP best-database matching
* (With no specified databse and a city database available, answers
* should come from city database. With city database unavailable, region
* database. Region database unavailable, country database.)
*/
ATF_TC(best);
ATF_TC_HEAD(best, tc) {
atf_tc_set_md_var(tc, "descr", "test best database matching");
}
ATF_TC_BODY(best, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.region == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.4",
dns_geoip_countrycode, "US");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
dns_geoip_countrycode3, "USA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
dns_geoip_countryname, "United States");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
dns_geoip_regionname, "Virginia");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
dns_geoip_region, "VA");
ATF_CHECK(match);
GeoIP_delete(geoip.city_v4);
geoip.city_v4 = NULL;
match = do_lookup_string("10.53.0.4",
dns_geoip_countrycode, "AU");
ATF_CHECK(match);
/*
* Note, region doesn't support code3 or countryname, so
* the next two would be answered from the country database instead
*/
match = do_lookup_string("10.53.0.4",
dns_geoip_countrycode3, "CAN");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
dns_geoip_countryname, "Canada");
ATF_CHECK(match);
GeoIP_delete(geoip.region);
geoip.region = NULL;
match = do_lookup_string("10.53.0.4",
dns_geoip_countrycode, "CA");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
dns_geoip_countrycode3, "CAN");
ATF_CHECK(match);
match = do_lookup_string("10.53.0.4",
dns_geoip_countryname, "Canada");
ATF_CHECK(match);
dns_test_end();
}
/* GeoIP asnum matching */
ATF_TC(asnum);
ATF_TC_HEAD(asnum, tc) {
atf_tc_set_md_var(tc, "descr", "test asnum database matching");
}
ATF_TC_BODY(asnum, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.as == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.3", dns_geoip_as_asnum,
"AS100003 Three Network Labs");
ATF_CHECK(match);
dns_test_end();
}
/* GeoIP isp matching */
ATF_TC(isp);
ATF_TC_HEAD(isp, tc) {
atf_tc_set_md_var(tc, "descr", "test isp database matching");
}
ATF_TC_BODY(isp, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.isp == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.1", dns_geoip_isp_name,
"One Systems, Inc.");
ATF_CHECK(match);
dns_test_end();
}
/* GeoIP org matching */
ATF_TC(org);
ATF_TC_HEAD(org, tc) {
atf_tc_set_md_var(tc, "descr", "test org database matching");
}
ATF_TC_BODY(org, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.org == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.2", dns_geoip_org_name,
"Two Technology Ltd.");
ATF_CHECK(match);
dns_test_end();
}
/* GeoIP domain matching */
ATF_TC(domain);
ATF_TC_HEAD(domain, tc) {
atf_tc_set_md_var(tc, "descr", "test domain database matching");
}
ATF_TC_BODY(domain, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.domain == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_string("10.53.0.4",
dns_geoip_domain_name, "four.com");
ATF_CHECK(match);
dns_test_end();
}
/* GeoIP netspeed matching */
ATF_TC(netspeed);
ATF_TC_HEAD(netspeed, tc) {
atf_tc_set_md_var(tc, "descr", "test netspeed database matching");
}
ATF_TC_BODY(netspeed, tc) {
isc_result_t result;
isc_boolean_t match;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE(result == ISC_R_SUCCESS);
/* Use databases from the geoip system test */
load_geoip(GEOIP_DATA);
if (geoip.netspeed == NULL) {
dns_test_end();
atf_tc_skip("Database not available");
}
match = do_lookup_int("10.53.0.1", dns_geoip_netspeed_id, 0);
ATF_CHECK(match);
match = do_lookup_int("10.53.0.2", dns_geoip_netspeed_id, 1);
ATF_CHECK(match);
match = do_lookup_int("10.53.0.3", dns_geoip_netspeed_id, 2);
ATF_CHECK(match);
match = do_lookup_int("10.53.0.4", dns_geoip_netspeed_id, 3);
ATF_CHECK(match);
dns_test_end();
}
#else
ATF_TC(untested);
ATF_TC_HEAD(untested, tc) {
atf_tc_set_md_var(tc, "descr", "skipping geoip test");
}
ATF_TC_BODY(untested, tc) {
UNUSED(tc);
atf_tc_skip("GeoIP not available");
}
#endif
/*
* Main
*/
ATF_TP_ADD_TCS(tp) {
#ifdef HAVE_GEOIP
ATF_TP_ADD_TC(tp, country);
ATF_TP_ADD_TC(tp, country_v6);
ATF_TP_ADD_TC(tp, city);
ATF_TP_ADD_TC(tp, city_v6);
ATF_TP_ADD_TC(tp, region);
ATF_TP_ADD_TC(tp, best);
ATF_TP_ADD_TC(tp, asnum);
ATF_TP_ADD_TC(tp, isp);
ATF_TP_ADD_TC(tp, org);
ATF_TP_ADD_TC(tp, domain);
ATF_TP_ADD_TC(tp, netspeed);
#else
ATF_TP_ADD_TC(tp, untested);
#endif
return (atf_no_error());
}