#include "maxminddb_test_helper.h" static void test_big_lookup(void); /* These globals are gross but it's the easiest way to mix calling * for_all_modes() and for_all_record_sizes() */ static int Current_Mode; static const char *Current_Mode_Description; void test_one_result(MMDB_s *mmdb, MMDB_lookup_result_s result, const char *ip, const char *expect, const char *function, const char *filename, const char *mode_desc) { int is_ok = ok(result.found_entry, "got a result for an IP in the database - %s - %s - %s - %s", function, ip, filename, mode_desc); if (!is_ok) { return; } MMDB_entry_data_s data = data_ok(&result, MMDB_DATA_TYPE_UTF8_STRING, "result{ip}", "ip", NULL); char *string = mmdb_strndup(data.utf8_string, data.data_size); char *real_expect; if (mmdb->metadata.ip_version == 4 || strncmp(expect, "::", 2) == 0) { real_expect = mmdb_strndup(expect, strlen(expect)); } else { // When looking up IPv4 addresses in a mixed DB the result will be // something like "::1.2.3.4", not just "1.2.3.4". int maxlen = strlen(expect) + 3; real_expect = malloc(maxlen); if (!real_expect) { BAIL_OUT("could not allocate memory"); } snprintf(real_expect, maxlen, "::%s", expect); } is(string, real_expect, "found expected result for ip key - %s - %s - %s - %s", function, ip, filename, mode_desc); free(real_expect); free(string); } void test_one_ip(MMDB_s *mmdb, const char *ip, const char *expect, const char *filename, const char *mode_desc) { MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); test_one_result( mmdb, result, ip, expect, "MMDB_lookup_string", filename, mode_desc); result = lookup_sockaddr_ok(mmdb, ip, filename, mode_desc); test_one_result( mmdb, result, ip, expect, "MMDB_lookup_addrinfo", filename, mode_desc); } void run_ipX_tests(const char *filename, const char **missing_ips, int missing_ips_length, const char *pairs[][2], int pairs_rows) { const char *path = test_database_path(filename); int mode = Current_Mode; const char *mode_desc = Current_Mode_Description; MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); char desc_suffix[500]; snprintf(desc_suffix, 500, "%s - %s", filename, mode_desc); for (int i = 0; i < missing_ips_length; i++) { const char *ip = missing_ips[i]; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); ok(!result.found_entry, "no result entry struct returned for IP address not in the database " "(string lookup) - %s - %s - %s", ip, filename, mode_desc); result = lookup_sockaddr_ok(mmdb, ip, filename, mode_desc); ok(!result.found_entry, "no result entry struct returned for IP address not in the database " "(ipv4 lookup) - %s - %s - %s", ip, filename, mode_desc); } for (int i = 0; i < pairs_rows; i += 1) { const char *ip_to_lookup = pairs[i][0]; const char *expect = pairs[i][1]; test_one_ip(mmdb, ip_to_lookup, expect, filename, mode_desc); } MMDB_close(mmdb); free(mmdb); } void run_ipv4_tests(int UNUSED(record_size), const char *filename, const char *UNUSED(ignored)) { const char *pairs[9][2] = { {"1.1.1.1", "1.1.1.1"}, {"1.1.1.2", "1.1.1.2"}, {"1.1.1.3", "1.1.1.2"}, {"1.1.1.7", "1.1.1.4"}, {"1.1.1.9", "1.1.1.8"}, {"1.1.1.15", "1.1.1.8"}, {"1.1.1.17", "1.1.1.16"}, {"1.1.1.31", "1.1.1.16"}, {"1.1.1.32", "1.1.1.32"}, }; const char *missing[1] = {"2.3.4.5"}; run_ipX_tests(filename, missing, 1, pairs, 9); } void run_ipv6_tests(int UNUSED(record_size), const char *filename, const char *UNUSED(ignored)) { const char *pairs[9][2] = { {"::1:ffff:ffff", "::1:ffff:ffff"}, {"::2:0:0", "::2:0:0"}, {"::2:0:1a", "::2:0:0"}, {"::2:0:40", "::2:0:40"}, {"::2:0:4f", "::2:0:40"}, {"::2:0:50", "::2:0:50"}, {"::2:0:52", "::2:0:50"}, {"::2:0:58", "::2:0:58"}, {"::2:0:59", "::2:0:58"}, }; const char *missing[2] = {"2.3.4.5", "::abcd"}; run_ipX_tests(filename, missing, 2, pairs, 9); } void all_record_sizes(int mode, const char *description) { const char *ipv4_filename_fmts[] = {"MaxMind-DB-test-ipv4-%i.mmdb", "MaxMind-DB-test-mixed-%i.mmdb"}; Current_Mode = mode; Current_Mode_Description = description; for (int i = 0; i < 2; i++) { for_all_record_sizes(ipv4_filename_fmts[i], &run_ipv4_tests); } const char *ipv6_filename_fmts[] = {"MaxMind-DB-test-ipv6-%i.mmdb", "MaxMind-DB-test-mixed-%i.mmdb"}; for (int i = 0; i < 2; i++) { for_all_record_sizes(ipv6_filename_fmts[i], &run_ipv6_tests); } } static void test_big_lookup(void) { const char *const db_filename = "GeoIP2-Precision-Enterprise-Test.mmdb"; const char *const db_path = test_database_path(db_filename); ok(db_path != NULL, "got database path"); MMDB_s *const mmdb = open_ok(db_path, MMDB_MODE_MMAP, "mmap mode"); ok(mmdb != NULL, "opened MMDB"); free((char *)db_path); int gai_err = 0, mmdb_err = 0; const char *const ip_address = "81.2.69.160"; MMDB_lookup_result_s result = MMDB_lookup_string(mmdb, ip_address, &gai_err, &mmdb_err); ok(gai_err == 0, "no getaddrinfo error"); ok(mmdb_err == MMDB_SUCCESS, "no error from maxminddb library"); ok(result.found_entry, "found IP"); MMDB_entry_data_list_s *entry_data_list = NULL; ok(MMDB_get_entry_data_list(&result.entry, &entry_data_list) == MMDB_SUCCESS, "successfully looked up entry data list"); ok(entry_data_list != NULL, "got an entry_data_list"); MMDB_free_entry_data_list(entry_data_list); MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&all_record_sizes); test_big_lookup(); done_testing(); }