diff --git a/extensions/geoip/data-pool.c b/extensions/geoip/data-pool.c index 1a9f9d03f5..3bc63286b2 100644 --- a/extensions/geoip/data-pool.c +++ b/extensions/geoip/data-pool.c @@ -1,5 +1,5 @@ #ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L + #define _POSIX_C_SOURCE 200809L #endif #include "data-pool.h" @@ -146,8 +146,8 @@ MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const pool) { #ifdef TEST_DATA_POOL -#include -#include + #include + #include static void test_can_multiply(void); @@ -158,9 +158,13 @@ int main(void) { } static void test_can_multiply(void) { - { ok(can_multiply(SIZE_MAX, 1, SIZE_MAX), "1*SIZE_MAX is ok"); } + { + ok(can_multiply(SIZE_MAX, 1, SIZE_MAX), "1*SIZE_MAX is ok"); + } - { ok(!can_multiply(SIZE_MAX, 2, SIZE_MAX), "2*SIZE_MAX is not ok"); } + { + ok(!can_multiply(SIZE_MAX, 2, SIZE_MAX), "2*SIZE_MAX is not ok"); + } { ok(can_multiply(SIZE_MAX, 10240, sizeof(MMDB_entry_data_list_s)), diff --git a/extensions/geoip/extension.cpp b/extensions/geoip/extension.cpp index 2b86986335..241873f10e 100644 --- a/extensions/geoip/extension.cpp +++ b/extensions/geoip/extension.cpp @@ -55,36 +55,35 @@ bool GeoIP_Extension::SDK_OnLoad(char *error, size_t maxlength, bool late) return true; } - char m_GeoipDir[PLATFORM_MAX_PATH]; + char m_GeoipDir[PLATFORM_MAX_PATH], m_GeoipDb[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_SM, m_GeoipDir, sizeof(m_GeoipDir), "configs/geoip"); - bool hasEntry = false; - + time_t modTime = 0; IDirectory *dir = libsys->OpenDirectory(m_GeoipDir); + if (dir) { + const char *name; + size_t len; + char database[PLATFORM_MAX_PATH]; + time_t mtime; + while (dir->MoreFiles()) { if (dir->IsEntryFile()) { - const char *name = dir->GetEntryName(); - size_t len = strlen(name); + name = dir->GetEntryName(); + len = strlen(name); + if (len >= 5 && strcmp(&name[len-5], ".mmdb") == 0) { - char database[PLATFORM_MAX_PATH]; libsys->PathFormat(database, sizeof(database), "%s/%s", m_GeoipDir, name); - int status = MMDB_open(database, MMDB_MODE_MMAP, &mmdb); - - if (status != MMDB_SUCCESS) + if (libsys->FileTime(database, FileTime_LastChange, &mtime) && mtime > modTime) { - ke::SafeSprintf(error, maxlength, "Failed to open GeoIP2 database %s: %s", database, MMDB_strerror(status)); - libsys->CloseDirectory(dir); - return false; + modTime = mtime; + ke::SafeStrcpy(m_GeoipDb, sizeof(m_GeoipDb), database); } - - hasEntry = true; - break; } } dir->NextEntry(); @@ -92,7 +91,17 @@ bool GeoIP_Extension::SDK_OnLoad(char *error, size_t maxlength, bool late) libsys->CloseDirectory(dir); } - if (!hasEntry) + if (m_GeoipDb[0] != '\0') + { + int status = MMDB_open(m_GeoipDb, MMDB_MODE_MMAP, &mmdb); + + if (status != MMDB_SUCCESS) + { + ke::SafeSprintf(error, maxlength, "Failed to open GeoIP2 database %s: %s", m_GeoipDb, MMDB_strerror(status)); + return false; + } + } + else { ke::SafeStrcpy(error, maxlength, "Could not find GeoIP2 database."); return false; diff --git a/extensions/geoip/maxminddb.c b/extensions/geoip/maxminddb.c index 55a3ce20be..5aa3b25494 100644 --- a/extensions/geoip/maxminddb.c +++ b/extensions/geoip/maxminddb.c @@ -1,9 +1,9 @@ #ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L + #define _POSIX_C_SOURCE 200809L #endif #if HAVE_CONFIG_H -#include + #include #endif #include "data-pool.h" #include "maxminddb-compat-util.h" @@ -18,43 +18,43 @@ #include #ifdef _WIN32 -#ifndef UNICODE -#define UNICODE -#endif -#include -#include -#ifndef SSIZE_MAX -#define SSIZE_MAX INTPTR_MAX -#endif + #ifndef UNICODE + #define UNICODE + #endif + #include + #include + #ifndef SSIZE_MAX + #define SSIZE_MAX INTPTR_MAX + #endif typedef ADDRESS_FAMILY sa_family_t; #else -#include -#include -#include + #include + #include + #include #endif #define MMDB_DATA_SECTION_SEPARATOR (16) #define MAXIMUM_DATA_STRUCTURE_DEPTH (512) #ifdef MMDB_DEBUG -#define DEBUG_MSG(msg) fprintf(stderr, msg "\n") -#define DEBUG_MSGF(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__) -#define DEBUG_BINARY(fmt, byte) \ - do { \ - char *binary = byte_to_binary(byte); \ - if (NULL == binary) { \ - fprintf(stderr, "Calloc failed in DEBUG_BINARY\n"); \ - abort(); \ - } \ - fprintf(stderr, fmt "\n", binary); \ - free(binary); \ - } while (0) -#define DEBUG_NL fprintf(stderr, "\n") + #define DEBUG_MSG(msg) fprintf(stderr, msg "\n") + #define DEBUG_MSGF(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__) + #define DEBUG_BINARY(fmt, byte) \ + do { \ + char *binary = byte_to_binary(byte); \ + if (NULL == binary) { \ + fprintf(stderr, "Calloc failed in DEBUG_BINARY\n"); \ + abort(); \ + } \ + fprintf(stderr, fmt "\n", binary); \ + free(binary); \ + } while (0) + #define DEBUG_NL fprintf(stderr, "\n") #else -#define DEBUG_MSG(...) -#define DEBUG_MSGF(...) -#define DEBUG_BINARY(...) -#define DEBUG_NL + #define DEBUG_MSG(...) + #define DEBUG_MSGF(...) + #define DEBUG_BINARY(...) + #define DEBUG_NL #endif #ifdef MMDB_DEBUG @@ -116,12 +116,12 @@ char *type_num_to_name(uint8_t num) { * platforms where SIZE_MAX is a 64-bit integer, this would be a no-op, and it * makes the compiler complain if we do the check anyway. */ #if SIZE_MAX == UINT32_MAX -#define MAYBE_CHECK_SIZE_OVERFLOW(lhs, rhs, error) \ - if ((lhs) > (rhs)) { \ - return error; \ - } + #define MAYBE_CHECK_SIZE_OVERFLOW(lhs, rhs, error) \ + if ((lhs) > (rhs)) { \ + return error; \ + } #else -#define MAYBE_CHECK_SIZE_OVERFLOW(...) + #define MAYBE_CHECK_SIZE_OVERFLOW(...) #endif typedef struct record_info_s { @@ -178,7 +178,8 @@ static int lookup_path_in_map(const char *path_elem, const MMDB_s *const mmdb, MMDB_entry_data_s *entry_data); static int skip_map_or_array(const MMDB_s *const mmdb, - MMDB_entry_data_s *entry_data); + MMDB_entry_data_s *entry_data, + int depth); static int decode_one_follow(const MMDB_s *const mmdb, uint32_t offset, MMDB_entry_data_s *entry_data); @@ -366,7 +367,7 @@ static LPWSTR utf8_to_utf16(const char *utf8_str) { } static int map_file(MMDB_s *const mmdb) { - DWORD size; + ssize_t size; int status = MMDB_SUCCESS; HANDLE mmh = NULL; HANDLE fd = INVALID_HANDLE_VALUE; @@ -386,12 +387,17 @@ static int map_file(MMDB_s *const mmdb) { status = MMDB_FILE_OPEN_ERROR; goto cleanup; } - size = GetFileSize(fd, NULL); - if (size == INVALID_FILE_SIZE) { - status = MMDB_FILE_OPEN_ERROR; + LARGE_INTEGER file_size; + if (!GetFileSizeEx(fd, &file_size)) { + status = MMDB_IO_ERROR; goto cleanup; } - mmh = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, size, NULL); + if (file_size.QuadPart < 0 || file_size.QuadPart > SSIZE_MAX) { + status = MMDB_IO_ERROR; + goto cleanup; + } + size = (ssize_t)file_size.QuadPart; + mmh = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, 0, NULL); /* Microsoft documentation for CreateFileMapping indicates this returns NULL not INVALID_HANDLE_VALUE on error */ if (NULL == mmh) { @@ -428,21 +434,21 @@ static int map_file(MMDB_s *const mmdb) { int status = MMDB_SUCCESS; int o_flags = O_RDONLY; -#ifdef O_CLOEXEC + #ifdef O_CLOEXEC o_flags |= O_CLOEXEC; -#endif + #endif int fd = open(mmdb->filename, o_flags); if (fd < 0) { status = MMDB_FILE_OPEN_ERROR; goto cleanup; } -#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC) + #if defined(FD_CLOEXEC) && !defined(O_CLOEXEC) int fd_flags = fcntl(fd, F_GETFD); if (fd_flags >= 0) { fcntl(fd, F_SETFD, fd_flags | FD_CLOEXEC); } -#endif + #endif struct stat s; if (fstat(fd, &s)) { @@ -744,12 +750,14 @@ static int populate_languages_metadata(MMDB_s *mmdb, mmdb->metadata.languages.count = 0; mmdb->metadata.languages.names = calloc(array_size, sizeof(char *)); if (NULL == mmdb->metadata.languages.names) { + MMDB_free_entry_data_list(first_member); return MMDB_OUT_OF_MEMORY_ERROR; } for (uint32_t i = 0; i < array_size; i++) { member = member->next; if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) { + MMDB_free_entry_data_list(first_member); return MMDB_INVALID_METADATA_ERROR; } @@ -757,6 +765,7 @@ static int populate_languages_metadata(MMDB_s *mmdb, member->entry_data.utf8_string, member->entry_data.data_size); if (NULL == mmdb->metadata.languages.names[i]) { + MMDB_free_entry_data_list(first_member); return MMDB_OUT_OF_MEMORY_ERROR; } // We assign this as we go so that if we fail a calloc and need to @@ -879,6 +888,11 @@ MMDB_lookup_result_s MMDB_lookup_string(const MMDB_s *const mmdb, if (!*gai_error) { result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, mmdb_error); + } else { + /* No MMDB error occurred; the GAI failure is reported via + * *gai_error. Set *mmdb_error to a defined value so callers + * don't read indeterminate memory. */ + *mmdb_error = MMDB_SUCCESS; } if (NULL != addresses) { @@ -976,7 +990,7 @@ static int find_address_in_search_tree(const MMDB_s *const mmdb, result->netmask = current_bit; - if (value >= node_count + mmdb->data_section_size) { + if (value >= (uint64_t)node_count + mmdb->data_section_size) { // The pointer points off the end of the database. return MMDB_CORRUPT_SEARCH_TREE_ERROR; } @@ -1036,7 +1050,8 @@ static int find_ipv4_start_node(MMDB_s *const mmdb) { uint32_t node_count = mmdb->metadata.node_count; for (netmask = 0; netmask < 96 && node_value < node_count; netmask++) { - record_pointer = &search_tree[node_value * record_info.record_length]; + record_pointer = + &search_tree[(uint64_t)node_value * record_info.record_length]; if (record_pointer + record_info.record_length > mmdb->data_section) { return MMDB_CORRUPT_SEARCH_TREE_ERROR; } @@ -1094,13 +1109,16 @@ int MMDB_read_node(const MMDB_s *const mmdb, return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; } - if (node_number > mmdb->metadata.node_count) { + if (node_number >= mmdb->metadata.node_count) { return MMDB_INVALID_NODE_NUMBER_ERROR; } const uint8_t *search_tree = mmdb->file_content; const uint8_t *record_pointer = - &search_tree[node_number * record_info.record_length]; + &search_tree[(uint64_t)node_number * record_info.record_length]; + if (record_pointer + record_info.record_length > mmdb->data_section) { + return MMDB_CORRUPT_SEARCH_TREE_ERROR; + } node->left_record = record_info.left_record_getter(record_pointer); record_pointer += record_info.right_record_offset; node->right_record = record_info.right_record_getter(record_pointer); @@ -1269,7 +1287,7 @@ static int lookup_path_in_array(const char *path_elem, /* We don't want to follow a pointer here. If the next element is a * pointer we simply skip it and keep going */ CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); - int status = skip_map_or_array(mmdb, entry_data); + int status = skip_map_or_array(mmdb, entry_data, 0); if (MMDB_SUCCESS != status) { return status; } @@ -1311,7 +1329,7 @@ static int lookup_path_in_map(const char *path_elem, /* We don't want to follow a pointer here. If the next element is * a pointer we simply skip it and keep going */ CHECKED_DECODE_ONE(mmdb, offset_to_value, &value); - int status = skip_map_or_array(mmdb, &value); + int status = skip_map_or_array(mmdb, &value, 0); if (MMDB_SUCCESS != status) { return status; } @@ -1324,7 +1342,13 @@ static int lookup_path_in_map(const char *path_elem, } static int skip_map_or_array(const MMDB_s *const mmdb, - MMDB_entry_data_s *entry_data) { + MMDB_entry_data_s *entry_data, + int depth) { + if (depth >= MAXIMUM_DATA_STRUCTURE_DEPTH) { + DEBUG_MSG("reached the maximum data structure depth"); + return MMDB_INVALID_DATA_ERROR; + } + if (entry_data->type == MMDB_DATA_TYPE_MAP) { uint32_t size = entry_data->data_size; while (size-- > 0) { @@ -1332,7 +1356,7 @@ static int skip_map_or_array(const MMDB_s *const mmdb, mmdb, entry_data->offset_to_next, entry_data); // key CHECKED_DECODE_ONE( mmdb, entry_data->offset_to_next, entry_data); // value - int status = skip_map_or_array(mmdb, entry_data); + int status = skip_map_or_array(mmdb, entry_data, depth + 1); if (MMDB_SUCCESS != status) { return status; } @@ -1342,7 +1366,7 @@ static int skip_map_or_array(const MMDB_s *const mmdb, while (size-- > 0) { CHECKED_DECODE_ONE( mmdb, entry_data->offset_to_next, entry_data); // value - int status = skip_map_or_array(mmdb, entry_data); + int status = skip_map_or_array(mmdb, entry_data, depth + 1); if (MMDB_SUCCESS != status) { return status; } @@ -1633,6 +1657,8 @@ int MMDB_get_metadata_as_entry_data_list( int MMDB_get_entry_data_list(MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list) { + *entry_data_list = NULL; + MMDB_data_pool_s *const pool = data_pool_new(MMDB_POOL_INIT_SIZE); if (!pool) { return MMDB_OUT_OF_MEMORY_ERROR; @@ -1646,6 +1672,10 @@ int MMDB_get_entry_data_list(MMDB_entry_s *start, int const status = get_entry_data_list(start->mmdb, start->offset, list, pool, 0); + if (MMDB_SUCCESS != status) { + data_pool_destroy(pool); + return status; + } *entry_data_list = data_pool_to_list(pool); if (!*entry_data_list) { @@ -1698,6 +1728,12 @@ static int get_entry_data_list(const MMDB_s *const mmdb, case MMDB_DATA_TYPE_ARRAY: { uint32_t array_size = entry_data_list->entry_data.data_size; uint32_t array_offset = entry_data_list->entry_data.offset_to_next; + /* Each array element needs at least 1 byte. */ + if (array_offset > mmdb->data_section_size || + array_size > mmdb->data_section_size - array_offset) { + DEBUG_MSG("array size exceeds remaining data section"); + return MMDB_INVALID_DATA_ERROR; + } while (array_size-- > 0) { MMDB_entry_data_list_s *entry_data_list_to = data_pool_alloc(pool); @@ -1721,6 +1757,12 @@ static int get_entry_data_list(const MMDB_s *const mmdb, uint32_t size = entry_data_list->entry_data.data_size; offset = entry_data_list->entry_data.offset_to_next; + /* Each map entry needs at least a key and a value (1 byte each). */ + if (offset > mmdb->data_section_size || + size > (mmdb->data_section_size - offset) / 2) { + DEBUG_MSG("map size exceeds remaining data section"); + return MMDB_INVALID_DATA_ERROR; + } while (size-- > 0) { MMDB_entry_data_list_s *list_key = data_pool_alloc(pool); if (!list_key) { @@ -1758,38 +1800,63 @@ static int get_entry_data_list(const MMDB_s *const mmdb, return MMDB_SUCCESS; } -static float get_ieee754_float(const uint8_t *restrict p) { - volatile float f; - volatile uint8_t *q = (volatile void *)&f; -/* Windows builds don't use autoconf but we can assume they're all - * little-endian. */ -#if MMDB_LITTLE_ENDIAN || _WIN32 - q[3] = p[0]; - q[2] = p[1]; - q[1] = p[2]; - q[0] = p[3]; +#ifndef __has_builtin + #define __has_builtin(x) 0 +#endif + +static inline uint32_t mmdb_bswap32(uint32_t x) { +#if defined(_MSC_VER) + return _byteswap_ulong(x); +#elif __has_builtin(__builtin_bswap32) + return __builtin_bswap32(x); #else - memcpy(q, p, 4); + x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF); + return (x << 16) | (x >> 16); #endif +} + +static inline uint64_t mmdb_bswap64(uint64_t x) { +#if defined(_MSC_VER) + return _byteswap_uint64(x); +#elif __has_builtin(__builtin_bswap64) + return __builtin_bswap64(x); +#else + x = ((x & 0x00000000FFFFFFFFULL) << 32) | + ((x & 0xFFFFFFFF00000000ULL) >> 32); + x = ((x & 0x0000FFFF0000FFFFULL) << 16) | + ((x & 0xFFFF0000FFFF0000ULL) >> 16); + return ((x & 0x00FF00FF00FF00FFULL) << 8) | + ((x & 0xFF00FF00FF00FF00ULL) >> 8); +#endif +} + +static float get_ieee754_float(const uint8_t *restrict p) { + float f; + uint32_t i; + + memcpy(&i, p, sizeof(uint32_t)); + +#if MMDB_LITTLE_ENDIAN + i = mmdb_bswap32(i); +#endif + + memcpy(&f, &i, sizeof(float)); + return f; } static double get_ieee754_double(const uint8_t *restrict p) { - volatile double d; - volatile uint8_t *q = (volatile void *)&d; -#if MMDB_LITTLE_ENDIAN || _WIN32 - q[7] = p[0]; - q[6] = p[1]; - q[5] = p[2]; - q[4] = p[3]; - q[3] = p[4]; - q[2] = p[5]; - q[1] = p[6]; - q[0] = p[7]; -#else - memcpy(q, p, 8); + double d; + uint64_t i; + + memcpy(&i, p, sizeof(uint64_t)); + +#if MMDB_LITTLE_ENDIAN + i = mmdb_bswap64(i); #endif + memcpy(&d, &i, sizeof(double)); + return d; } @@ -1832,14 +1899,14 @@ static void free_mmdb_struct(MMDB_s *const mmdb) { if (NULL != mmdb->filename) { #if defined(__clang__) -// This is a const char * that we need to free, which isn't valid. However it -// would mean changing the public API to fix this. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-qual" + // This is a const char * that we need to free, which isn't valid. However + // it would mean changing the public API to fix this. + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcast-qual" #endif FREE_AND_SET_NULL(mmdb->filename); #if defined(__clang__) -#pragma clang diagnostic pop + #pragma clang diagnostic pop #endif } if (NULL != mmdb->file_content) { @@ -1849,29 +1916,35 @@ static void free_mmdb_struct(MMDB_s *const mmdb) { * to cleanup then. */ WSACleanup(); #else -#if defined(__clang__) -// This is a const char * that we need to free, which isn't valid. However it -// would mean changing the public API to fix this. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-qual" -#endif + #if defined(__clang__) + // This is a const char * that we need to free, which isn't valid. + // However it would mean changing the public API to fix this. + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcast-qual" + #endif munmap((void *)mmdb->file_content, (size_t)mmdb->file_size); -#if defined(__clang__) -#pragma clang diagnostic pop -#endif + #if defined(__clang__) + #pragma clang diagnostic pop + #endif #endif + mmdb->file_content = NULL; + mmdb->file_size = 0; + mmdb->data_section = NULL; + mmdb->data_section_size = 0; + mmdb->metadata_section = NULL; + mmdb->metadata_section_size = 0; } if (NULL != mmdb->metadata.database_type) { #if defined(__clang__) -// This is a const char * that we need to free, which isn't valid. However it -// would mean changing the public API to fix this. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-qual" + // This is a const char * that we need to free, which isn't valid. However + // it would mean changing the public API to fix this. + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcast-qual" #endif FREE_AND_SET_NULL(mmdb->metadata.database_type); #if defined(__clang__) -#pragma clang diagnostic pop + #pragma clang diagnostic pop #endif } @@ -1886,17 +1959,18 @@ static void free_languages_metadata(MMDB_s *mmdb) { for (size_t i = 0; i < mmdb->metadata.languages.count; i++) { #if defined(__clang__) -// This is a const char * that we need to free, which isn't valid. However it -// would mean changing the public API to fix this. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-qual" + // This is a const char * that we need to free, which isn't valid. However + // it would mean changing the public API to fix this. + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcast-qual" #endif FREE_AND_SET_NULL(mmdb->metadata.languages.names[i]); #if defined(__clang__) -#pragma clang diagnostic pop + #pragma clang diagnostic pop #endif } FREE_AND_SET_NULL(mmdb->metadata.languages.names); + mmdb->metadata.languages.count = 0; } static void free_descriptions_metadata(MMDB_s *mmdb) { @@ -1908,30 +1982,30 @@ static void free_descriptions_metadata(MMDB_s *mmdb) { if (NULL != mmdb->metadata.description.descriptions[i]) { if (NULL != mmdb->metadata.description.descriptions[i]->language) { #if defined(__clang__) -// This is a const char * that we need to free, which isn't valid. However it -// would mean changing the public API to fix this. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-qual" + // This is a const char * that we need to free, which isn't valid. However + // it would mean changing the public API to fix this. + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcast-qual" #endif FREE_AND_SET_NULL( mmdb->metadata.description.descriptions[i]->language); #if defined(__clang__) -#pragma clang diagnostic pop + #pragma clang diagnostic pop #endif } if (NULL != mmdb->metadata.description.descriptions[i]->description) { #if defined(__clang__) -// This is a const char * that we need to free, which isn't valid. However it -// would mean changing the public API to fix this. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-qual" + // This is a const char * that we need to free, which isn't valid. However + // it would mean changing the public API to fix this. + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcast-qual" #endif FREE_AND_SET_NULL( mmdb->metadata.description.descriptions[i]->description); #if defined(__clang__) -#pragma clang diagnostic pop + #pragma clang diagnostic pop #endif } FREE_AND_SET_NULL(mmdb->metadata.description.descriptions[i]); @@ -1939,6 +2013,7 @@ static void free_descriptions_metadata(MMDB_s *mmdb) { } FREE_AND_SET_NULL(mmdb->metadata.description.descriptions); + mmdb->metadata.description.count = 0; } const char *MMDB_lib_version(void) { return PACKAGE_VERSION; } @@ -2124,7 +2199,7 @@ dump_entry_data_list(FILE *stream, static void print_indentation(FILE *stream, int i) { char buffer[1024]; - int size = i >= 1024 ? 1023 : i; + int size = i < 0 ? 0 : (i >= 1024 ? 1023 : i); memset(buffer, 32, (size_t)size); buffer[size] = '\0'; fputs(buffer, stream); diff --git a/extensions/geoip/maxminddb.h b/extensions/geoip/maxminddb.h index 1455be91be..9c1a96b9d2 100644 --- a/extensions/geoip/maxminddb.h +++ b/extensions/geoip/maxminddb.h @@ -3,80 +3,97 @@ extern "C" { #endif #ifndef MAXMINDDB_H -#define MAXMINDDB_H - -#include "maxminddb_config.h" -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include -/* libmaxminddb package version from configure */ - -#if defined(_MSC_VER) -/* MSVC doesn't define signed size_t, copy it from configure */ -#define ssize_t SSIZE_T - -/* MSVC doesn't support restricted pointers */ -#define restrict -#endif -#else -#include -#include -#include -#endif + #define MAXMINDDB_H + + #include "maxminddb_config.h" + #include + #include + #include + #include + #include + + #ifdef __has_include + #if __has_include() + #include + #elif __has_include() + #include + #endif + #endif + + #ifdef _WIN32 + #include + #include + /* libmaxminddb package version from configure */ + + #if defined(_MSC_VER) + /* MSVC doesn't define signed size_t, copy it from configure */ + #define ssize_t SSIZE_T + + #endif + #else + #include + #include + #include + #endif + + #if !defined(MMDB_LITTLE_ENDIAN) + #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) + #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define MMDB_LITTLE_ENDIAN 1 + #endif + #elif defined(_WIN32) || defined(_WIN64) + // We assume modern Windows targets are little endian + #define MMDB_LITTLE_ENDIAN 1 + #endif + #endif -#define MMDB_DATA_TYPE_EXTENDED (0) -#define MMDB_DATA_TYPE_POINTER (1) -#define MMDB_DATA_TYPE_UTF8_STRING (2) -#define MMDB_DATA_TYPE_DOUBLE (3) -#define MMDB_DATA_TYPE_BYTES (4) -#define MMDB_DATA_TYPE_UINT16 (5) -#define MMDB_DATA_TYPE_UINT32 (6) -#define MMDB_DATA_TYPE_MAP (7) -#define MMDB_DATA_TYPE_INT32 (8) -#define MMDB_DATA_TYPE_UINT64 (9) -#define MMDB_DATA_TYPE_UINT128 (10) -#define MMDB_DATA_TYPE_ARRAY (11) -#define MMDB_DATA_TYPE_CONTAINER (12) -#define MMDB_DATA_TYPE_END_MARKER (13) -#define MMDB_DATA_TYPE_BOOLEAN (14) -#define MMDB_DATA_TYPE_FLOAT (15) - -#define MMDB_RECORD_TYPE_SEARCH_NODE (0) -#define MMDB_RECORD_TYPE_EMPTY (1) -#define MMDB_RECORD_TYPE_DATA (2) -#define MMDB_RECORD_TYPE_INVALID (3) - -/* flags for open */ -#define MMDB_MODE_MMAP (1) -#define MMDB_MODE_MASK (7) - -/* error codes */ -#define MMDB_SUCCESS (0) -#define MMDB_FILE_OPEN_ERROR (1) -#define MMDB_CORRUPT_SEARCH_TREE_ERROR (2) -#define MMDB_INVALID_METADATA_ERROR (3) -#define MMDB_IO_ERROR (4) -#define MMDB_OUT_OF_MEMORY_ERROR (5) -#define MMDB_UNKNOWN_DATABASE_FORMAT_ERROR (6) -#define MMDB_INVALID_DATA_ERROR (7) -#define MMDB_INVALID_LOOKUP_PATH_ERROR (8) -#define MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR (9) -#define MMDB_INVALID_NODE_NUMBER_ERROR (10) -#define MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR (11) - -#if !(MMDB_UINT128_IS_BYTE_ARRAY) -#if MMDB_UINT128_USING_MODE + #define MMDB_DATA_TYPE_EXTENDED (0) + #define MMDB_DATA_TYPE_POINTER (1) + #define MMDB_DATA_TYPE_UTF8_STRING (2) + #define MMDB_DATA_TYPE_DOUBLE (3) + #define MMDB_DATA_TYPE_BYTES (4) + #define MMDB_DATA_TYPE_UINT16 (5) + #define MMDB_DATA_TYPE_UINT32 (6) + #define MMDB_DATA_TYPE_MAP (7) + #define MMDB_DATA_TYPE_INT32 (8) + #define MMDB_DATA_TYPE_UINT64 (9) + #define MMDB_DATA_TYPE_UINT128 (10) + #define MMDB_DATA_TYPE_ARRAY (11) + #define MMDB_DATA_TYPE_CONTAINER (12) + #define MMDB_DATA_TYPE_END_MARKER (13) + #define MMDB_DATA_TYPE_BOOLEAN (14) + #define MMDB_DATA_TYPE_FLOAT (15) + + #define MMDB_RECORD_TYPE_SEARCH_NODE (0) + #define MMDB_RECORD_TYPE_EMPTY (1) + #define MMDB_RECORD_TYPE_DATA (2) + #define MMDB_RECORD_TYPE_INVALID (3) + + /* flags for open */ + #define MMDB_MODE_MMAP (1) + #define MMDB_MODE_MASK (7) + + /* error codes */ + #define MMDB_SUCCESS (0) + #define MMDB_FILE_OPEN_ERROR (1) + #define MMDB_CORRUPT_SEARCH_TREE_ERROR (2) + #define MMDB_INVALID_METADATA_ERROR (3) + #define MMDB_IO_ERROR (4) + #define MMDB_OUT_OF_MEMORY_ERROR (5) + #define MMDB_UNKNOWN_DATABASE_FORMAT_ERROR (6) + #define MMDB_INVALID_DATA_ERROR (7) + #define MMDB_INVALID_LOOKUP_PATH_ERROR (8) + #define MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR (9) + #define MMDB_INVALID_NODE_NUMBER_ERROR (10) + #define MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR (11) + + #if !(MMDB_UINT128_IS_BYTE_ARRAY) + #if MMDB_UINT128_USING_MODE typedef unsigned int mmdb_uint128_t __attribute__((__mode__(TI))); -#else + #else typedef unsigned __int128 mmdb_uint128_t; -#endif -#endif + #endif + #endif /* This is a pointer into the data section for a given IP address lookup */ typedef struct MMDB_entry_s { @@ -101,11 +118,11 @@ typedef struct MMDB_entry_data_s { uint32_t uint32; int32_t int32; uint64_t uint64; -#if MMDB_UINT128_IS_BYTE_ARRAY + #if MMDB_UINT128_IS_BYTE_ARRAY uint8_t uint128[16]; -#else + #else mmdb_uint128_t uint128; -#endif + #endif bool boolean; float float_value; }; diff --git a/extensions/geoip/maxminddb_config.h b/extensions/geoip/maxminddb_config.h index d668fff763..f595bfa2bd 100644 --- a/extensions/geoip/maxminddb_config.h +++ b/extensions/geoip/maxminddb_config.h @@ -11,6 +11,6 @@ #define MMDB_UINT128_USING_MODE 0 #define MMDB_UINT128_IS_BYTE_ARRAY 1 -#define PACKAGE_VERSION "1.10.0" +#define PACKAGE_VERSION "1.13.3" #endif /* MAXMINDDB_CONFIG_H */