#include "orconfig.h"
#define GEOIP_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
#include "lib/geoip/geoip.h"
#include "feature/stats/geoip_stats.h"
#include "test/test.h"
#define SET_TEST_ADDRESS(i) do { \
if ((i) & 1) { \
SET_TEST_IPV6(i); \
tor_addr_from_in6(&addr, &in6); \
} else { \
tor_addr_from_ipv4h(&addr, (uint32_t) i); \
} \
} while (0)
#define SET_TEST_IPV6(i) \
do { \
set_uint32(in6.s6_addr + 12, htonl((uint32_t) (i))); \
} while (0)
#define CHECK_COUNTRY(country, val) do { \
\
tt_str_op(country, OP_EQ, \
geoip_get_country_name(geoip_get_country_by_ipv4(val))); \
\
SET_TEST_IPV6(val); \
tt_str_op(country, OP_EQ, \
geoip_get_country_name(geoip_get_country_by_ipv6(&in6))); \
} while (0)
static void
test_geoip(void *arg)
{
int i, j;
time_t now = 1281533250;
char *s = NULL, *v = NULL;
const char *bridge_stats_1 =
"bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"bridge-ips zz=24,xy=8\n"
"bridge-ip-versions v4=16,v6=16\n"
"bridge-ip-transports <OR>=24\n",
*dirreq_stats_1 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips ab=8\n"
"dirreq-v3-reqs ab=8\n"
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_2 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
"dirreq-v3-reqs \n"
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_3 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
"dirreq-v3-reqs \n"
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_4 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
"dirreq-v3-reqs \n"
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n",
*entry_stats_1 =
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"entry-ips ab=8\n",
*entry_stats_2 =
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"entry-ips \n";
tor_addr_t addr;
struct in6_addr in6;
(void)arg;
tt_int_op(0,OP_EQ, geoip_parse_entry("10,50,AB", AF_INET));
tt_int_op(0,OP_EQ, geoip_parse_entry("52,90,XY", AF_INET));
tt_int_op(0,OP_EQ, geoip_parse_entry("95,100,AB", AF_INET));
tt_int_op(0,OP_EQ, geoip_parse_entry("\"105\",\"140\",\"ZZ\"", AF_INET));
tt_int_op(0,OP_EQ, geoip_parse_entry("\"150\",\"190\",\"XY\"", AF_INET));
tt_int_op(0,OP_EQ, geoip_parse_entry("\"200\",\"250\",\"AB\"", AF_INET));
tt_int_op(0,OP_EQ, geoip_parse_entry("::a,::32,AB", AF_INET6));
tt_int_op(0,OP_EQ, geoip_parse_entry("::34,::5a,XY", AF_INET6));
tt_int_op(0,OP_EQ, geoip_parse_entry("::5f,::64,AB", AF_INET6));
tt_int_op(0,OP_EQ, geoip_parse_entry("::69,::8c,ZZ", AF_INET6));
tt_int_op(0,OP_EQ, geoip_parse_entry("::96,::be,XY", AF_INET6));
tt_int_op(0,OP_EQ, geoip_parse_entry("::c8,::fa,AB", AF_INET6));
tt_int_op(4,OP_EQ, geoip_get_n_countries());
memset(&in6, 0, sizeof(in6));
CHECK_COUNTRY("??", 3);
CHECK_COUNTRY("ab", 32);
CHECK_COUNTRY("??", 5);
CHECK_COUNTRY("??", 51);
CHECK_COUNTRY("xy", 150);
CHECK_COUNTRY("xy", 190);
CHECK_COUNTRY("??", 2000);
tt_int_op(0,OP_EQ, geoip_get_country_by_ipv4(3));
SET_TEST_IPV6(3);
tt_int_op(0,OP_EQ, geoip_get_country_by_ipv6(&in6));
get_options_mutable()->BridgeRelay = 1;
get_options_mutable()->BridgeRecordUsageByCountry = 1;
for (i=32; i < 40; ++i) {
SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
}
SET_TEST_ADDRESS(225);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
for (j=0; j < 10; ++j)
for (i=52; i < 55; ++i) {
SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-3600);
}
for (i=110; i < 127; ++i) {
SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
}
geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
tt_assert(s);
tt_assert(v);
tt_str_op("zz=24,ab=16,xy=8",OP_EQ, s);
tt_str_op("v4=16,v6=16",OP_EQ, v);
tor_free(s);
tor_free(v);
geoip_remove_old_clients(now-6000);
geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
tt_assert(s);
tt_assert(v);
tt_str_op("zz=24,xy=8",OP_EQ, s);
tt_str_op("v4=16,v6=16",OP_EQ, v);
tor_free(s);
tor_free(v);
s = geoip_format_bridge_stats(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
geoip_bridge_stats_init(now);
s = geoip_format_bridge_stats(now + 86400);
tt_assert(s);
tt_str_op(bridge_stats_1,OP_EQ, s);
tor_free(s);
geoip_bridge_stats_term();
s = geoip_format_bridge_stats(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
geoip_bridge_stats_term();
get_options_mutable()->BridgeRelay = 0;
get_options_mutable()->BridgeRecordUsageByCountry = 0;
get_options_mutable()->DirReqStatistics = 1;
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
geoip_dirreq_stats_init(now);
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
tt_str_op(dirreq_stats_1,OP_EQ, s);
tor_free(s);
geoip_dirreq_stats_term();
SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
geoip_dirreq_stats_init(now);
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
geoip_reset_dirreq_stats(now);
s = geoip_format_dirreq_stats(now + 86400);
tt_str_op(dirreq_stats_2,OP_EQ, s);
tor_free(s);
geoip_note_ns_response(GEOIP_SUCCESS);
s = geoip_format_dirreq_stats(now + 86400);
tt_str_op(dirreq_stats_3,OP_EQ, s);
tor_free(s);
geoip_start_dirreq((uint64_t) 1, 1024, DIRREQ_TUNNELED);
s = geoip_format_dirreq_stats(now + 86400);
tt_str_op(dirreq_stats_4,OP_EQ, s);
tor_free(s);
geoip_dirreq_stats_term();
get_options_mutable()->DirReqStatistics = 0;
get_options_mutable()->EntryStatistics = 1;
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
geoip_entry_stats_init(now);
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
tt_str_op(entry_stats_1,OP_EQ, s);
tor_free(s);
geoip_entry_stats_term();
SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
geoip_entry_stats_init(now);
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
geoip_reset_entry_stats(now);
s = geoip_format_entry_stats(now + 86400);
tt_str_op(entry_stats_2,OP_EQ, s);
tor_free(s);
geoip_entry_stats_init(now);
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL,
now - (12 * 60 * 60));
size_t bytes_removed = geoip_client_cache_handle_oom(now, 1000);
tt_size_op(bytes_removed, OP_GT, 0);
geoip_entry_stats_init(now);
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL,
now - (3 * 60 * 60));
bytes_removed = geoip_client_cache_handle_oom(now, 1000);
tt_size_op(bytes_removed, OP_EQ, 0);
geoip_entry_stats_term();
get_options_mutable()->EntryStatistics = 0;
done:
tor_free(s);
tor_free(v);
}
static void
test_geoip_with_pt(void *arg)
{
time_t now = 1281533250;
char *s = NULL;
int i;
tor_addr_t addr;
struct in6_addr in6;
(void)arg;
get_options_mutable()->BridgeRelay = 1;
get_options_mutable()->BridgeRecordUsageByCountry = 1;
memset(&in6, 0, sizeof(in6));
s = geoip_get_transport_history();
tor_assert(!s);
for (i=0; i < 4; ++i) {
SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
}
for (i=4; i < 13; ++i) {
SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "alpha", now-7200);
}
SET_TEST_ADDRESS(13);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "beta", now-7200);
for (i=14; i < 28; ++i) {
SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "charlie", now-7200);
}
for (i=28; i < 159; ++i) {
SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "ddr", now-7200);
}
for (i=159; i < 167; ++i) {
SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "entropy", now-7200);
}
SET_TEST_ADDRESS(++i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "fire", now-7200);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "google", now-7200);
s = geoip_get_transport_history();
tor_assert(s);
tt_str_op(s,OP_EQ, "<OR>=8,alpha=16,beta=8,charlie=16,ddr=136,"
"entropy=8,fire=8,google=8");
geoip_entry_stats_term();
get_options_mutable()->EntryStatistics = 0;
done:
tor_free(s);
}
#undef SET_TEST_ADDRESS
#undef SET_TEST_IPV6
#undef CHECK_COUNTRY
static const char GEOIP_CONTENT[] =
"134445936,134445939,MP\n"
"134445940,134447103,GU\n"
"134447104,134738943,US\n"
"134738944,134739199,CA\n"
"134739200,135192575,US\n"
"135192576,135200767,MX\n"
"135200768,135430143,US\n"
"135430144,135430399,CA\n"
"135430400,135432191,US\n";
static void
test_geoip_load_file(void *arg)
{
(void)arg;
char *contents = NULL;
char *dhex = NULL;
tt_int_op(-1, OP_EQ,
geoip_load_file(AF_INET, "/you/did/not/put/a/file/here/I/hope",
LOG_INFO));
tt_int_op(1, OP_EQ, geoip_get_n_countries());
tt_str_op("??", OP_EQ, geoip_get_country_name(0));
tt_int_op(-1, OP_EQ, geoip_get_country_by_ipv4(0x01020304));
tt_str_op("0000000000000000000000000000000000000000", OP_EQ,
geoip_db_digest(AF_INET));
const char *fname = get_fname("geoip");
tt_int_op(0, OP_EQ, write_str_to_file(fname, GEOIP_CONTENT, 1));
int rv = geoip_load_file(AF_INET, fname, LOG_WARN);
if (rv != 0) {
TT_GRIPE(("Unable to load geoip from %s", escaped(fname)));
}
tt_int_op(0, OP_EQ, rv);
tt_int_op(geoip_get_n_countries(), OP_GE, 5);
int country = geoip_get_country_by_ipv4(0x08080808);
tt_int_op(country, OP_GE, 1);
const char *cc = geoip_get_country_name(country);
tt_int_op(strlen(cc), OP_EQ, 2);
tt_str_op("0000000000000000000000000000000000000000", OP_NE,
geoip_db_digest(AF_INET));
contents = read_file_to_str(fname, RFTS_BIN, NULL);
uint8_t d[DIGEST_LEN];
crypto_digest((char*)d, contents, strlen(contents));
dhex = tor_strdup(hex_str((char*)d, DIGEST_LEN));
tt_str_op(dhex, OP_EQ, geoip_db_digest(AF_INET));
geoip_free_all();
tt_int_op(1, OP_EQ, geoip_get_n_countries());
tt_str_op("??", OP_EQ, geoip_get_country_name(0));
tt_int_op(-1, OP_EQ, geoip_get_country_by_ipv4(0x01020304));
tt_str_op("0000000000000000000000000000000000000000", OP_EQ,
geoip_db_digest(AF_INET));
done:
tor_free(contents);
tor_free(dhex);
}
static void
test_geoip6_load_file(void *arg)
{
(void)arg;
struct in6_addr iaddr6;
char *contents = NULL;
char *dhex = NULL;
tt_int_op(-1, OP_EQ,
geoip_load_file(AF_INET6, "/you/did/not/put/a/file/here/I/hope",
LOG_INFO));
tor_inet_pton(AF_INET6, "2001:4860:4860::8888", &iaddr6);
tt_int_op(-1, OP_EQ, geoip_get_country_by_ipv6(&iaddr6));
const char *fname6 = get_fname("geoip6");
const char CONTENT[] =
"2001:4830:6010::,2001:4830:601f:ffff:ffff:ffff:ffff:ffff,GB\n"
"2001:4830:6020::,2001:4830:ffff:ffff:ffff:ffff:ffff:ffff,US\n"
"2001:4838::,2001:4838:ffff:ffff:ffff:ffff:ffff:ffff,US\n"
"2001:4840::,2001:4840:ffff:ffff:ffff:ffff:ffff:ffff,XY\n"
"2001:4848::,2001:4848:ffff:ffff:ffff:ffff:ffff:ffff,ZD\n"
"2001:4850::,2001:4850:ffff:ffff:ffff:ffff:ffff:ffff,RO\n"
"2001:4858::,2001:4858:ffff:ffff:ffff:ffff:ffff:ffff,TC\n"
"2001:4860::,2001:4860:ffff:ffff:ffff:ffff:ffff:ffff,US\n"
"2001:4868::,2001:4868:ffff:ffff:ffff:ffff:ffff:ffff,US\n"
"2001:4870::,2001:4871:ffff:ffff:ffff:ffff:ffff:ffff,NB\n"
"2001:4878::,2001:4878:128:ffff:ffff:ffff:ffff:ffff,US\n"
"2001:4878:129::,2001:4878:129:ffff:ffff:ffff:ffff:ffff,CR\n"
"2001:4878:12a::,2001:4878:203:ffff:ffff:ffff:ffff:ffff,US\n"
"2001:4878:204::,2001:4878:204:ffff:ffff:ffff:ffff:ffff,DE\n"
"2001:4878:205::,2001:4878:214:ffff:ffff:ffff:ffff:ffff,US\n";
tt_int_op(0, OP_EQ, write_str_to_file(fname6, CONTENT, 1));
tt_int_op(0, OP_EQ, geoip_load_file(AF_INET6, fname6, LOG_WARN));
tt_int_op(geoip_get_n_countries(), OP_GE, 5);
const char *caddr6 = "2001:4860:4860::8888";
tor_inet_pton(AF_INET6, caddr6, &iaddr6);
int country6 = geoip_get_country_by_ipv6(&iaddr6);
tt_int_op(country6, OP_GE, 1);
const char *cc6 = geoip_get_country_name(country6);
tt_int_op(strlen(cc6), OP_EQ, 2);
tt_str_op("0000000000000000000000000000000000000000", OP_NE,
geoip_db_digest(AF_INET6));
contents = read_file_to_str(fname6, RFTS_BIN, NULL);
uint8_t d[DIGEST_LEN];
crypto_digest((char*)d, contents, strlen(contents));
dhex = tor_strdup(hex_str((char*)d, DIGEST_LEN));
tt_str_op(dhex, OP_EQ, geoip_db_digest(AF_INET6));
geoip_free_all();
tt_int_op(1, OP_EQ, geoip_get_n_countries());
tt_str_op("??", OP_EQ, geoip_get_country_name(0));
tor_inet_pton(AF_INET6, "::1:2:3:4", &iaddr6);
tt_int_op(-1, OP_EQ, geoip_get_country_by_ipv6(&iaddr6));
tt_str_op("0000000000000000000000000000000000000000", OP_EQ,
geoip_db_digest(AF_INET6));
done:
tor_free(contents);
tor_free(dhex);
}
static void
test_geoip_load_2nd_file(void *arg)
{
(void)arg;
char *fname_geoip = tor_strdup(get_fname("geoip_data"));
char *fname_empty = tor_strdup(get_fname("geoip_empty"));
tt_int_op(0, OP_EQ, write_str_to_file(fname_geoip, GEOIP_CONTENT, 1));
tt_int_op(0, OP_EQ, write_str_to_file(fname_empty, "\n", 1));
tt_int_op(0, OP_EQ, geoip_load_file(AF_INET, fname_geoip, LOG_WARN));
tt_int_op(0, OP_EQ, geoip_load_file(AF_INET, fname_empty, LOG_WARN));
int country = geoip_get_country_by_ipv4(0x08080808);
tt_int_op(country, OP_EQ, 0);
done:
tor_free(fname_geoip);
tor_free(fname_empty);
}
#define ENT(name) \
{ #name, test_ ## name , 0, NULL, NULL }
#define FORK(name) \
{ #name, test_ ## name , TT_FORK, NULL, NULL }
struct testcase_t geoip_tests[] = {
{ "geoip", test_geoip, TT_FORK, NULL, NULL },
{ "geoip_with_pt", test_geoip_with_pt, TT_FORK, NULL, NULL },
{ "load_file", test_geoip_load_file, TT_FORK, NULL, NULL },
{ "load_file6", test_geoip6_load_file, TT_FORK, NULL, NULL },
{ "load_2nd_file", test_geoip_load_2nd_file, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};