diff --git a/third_party/libmaxminddb/maxminddb.c b/third_party/libmaxminddb/maxminddb.c index fc110e3d..c08b35ba 100644 --- a/third_party/libmaxminddb/maxminddb.c +++ b/third_party/libmaxminddb/maxminddb.c @@ -3,6 +3,7 @@ #endif #include "maxminddb.h" #include "maxminddb-compat-util.h" +#include #include #include #include @@ -19,7 +20,6 @@ #include #endif - #define MMDB_DATA_SECTION_SEPARATOR (16) #ifdef MMDB_DEBUG @@ -118,6 +118,7 @@ typedef struct record_info_s { /* *INDENT-OFF* */ /* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */ +LOCAL int map_file(MMDB_s *const mmdb); LOCAL const uint8_t *find_metadata(const uint8_t *file_content, ssize_t file_size, uint32_t *metadata_size); LOCAL int read_metadata(MMDB_s *mmdb); @@ -194,6 +195,8 @@ LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size); int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) { + int status = MMDB_SUCCESS; + mmdb->file_content = NULL; mmdb->data_section = NULL; mmdb->metadata.database_type = NULL; @@ -202,85 +205,17 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) mmdb->filename = mmdb_strdup(filename); if (NULL == mmdb->filename) { - free_mmdb_struct(mmdb); - return MMDB_OUT_OF_MEMORY_ERROR; + status = MMDB_OUT_OF_MEMORY_ERROR; + goto cleanup; } - ssize_t size; -#ifdef _WIN32 - HANDLE fd = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (fd == INVALID_HANDLE_VALUE) { - free_mmdb_struct(mmdb); - return MMDB_FILE_OPEN_ERROR; - } - size = GetFileSize(fd, NULL); - if (size == INVALID_FILE_SIZE) { - free_mmdb_struct(mmdb); - CloseHandle(fd); - return MMDB_FILE_OPEN_ERROR; - } -#else - int fd = open(filename, O_RDONLY); - if (fd < 0) { - free_mmdb_struct(mmdb); - return MMDB_FILE_OPEN_ERROR; - } - - struct stat s; - if (fstat(fd, &s) ) { - free_mmdb_struct(mmdb); - close(fd); - return MMDB_FILE_OPEN_ERROR; - } - size = s.st_size; -#endif - if ((flags & MMDB_MODE_MASK) == 0) { flags |= MMDB_MODE_MMAP; } mmdb->flags = flags; - mmdb->file_size = size; -#ifdef _WIN32 - HANDLE mmh = CreateFileMappingA(fd, NULL, PAGE_READONLY, 0, size, NULL); - uint8_t *file_content = - (uint8_t *)MapViewOfFile(mmh, FILE_MAP_READ, 0, 0, 0); - CloseHandle(fd); - if (file_content == NULL) { - CloseHandle(mmh); - free_mmdb_struct(mmdb); - return MMDB_IO_ERROR; - } -#else - uint8_t *file_content = - (uint8_t *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - close(fd); - if (MAP_FAILED == file_content) { - free_mmdb_struct(mmdb); - return MMDB_IO_ERROR; - } -#endif - - uint32_t metadata_size = 0; - const uint8_t *metadata = find_metadata(file_content, size, &metadata_size); - if (NULL == metadata) { - free_mmdb_struct(mmdb); - return MMDB_INVALID_METADATA_ERROR; - } - - mmdb->metadata_section = metadata; - mmdb->metadata_section_size = metadata_size; - - int status = read_metadata(mmdb); - if (MMDB_SUCCESS != status) { - free_mmdb_struct(mmdb); - return status; - } - - if (mmdb->metadata.binary_format_major_version != 2) { - free_mmdb_struct(mmdb); - return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; + if (MMDB_SUCCESS != (status = map_file(mmdb)) ) { + goto cleanup; } #ifdef _WIN32 @@ -288,17 +223,117 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) WSAStartup(MAKEWORD(2, 2), &wsa); #endif + uint32_t metadata_size = 0; + const uint8_t *metadata = find_metadata(mmdb->file_content, mmdb->file_size, + &metadata_size); + if (NULL == metadata) { + status = MMDB_INVALID_METADATA_ERROR; + goto cleanup; + } + + mmdb->metadata_section = metadata; + mmdb->metadata_section_size = metadata_size; + + status = read_metadata(mmdb); + if (MMDB_SUCCESS != status) { + goto cleanup; + } + + if (mmdb->metadata.binary_format_major_version != 2) { + status = MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; + goto cleanup; + } + uint32_t search_tree_size = mmdb->metadata.node_count * mmdb->full_record_byte_size; - mmdb->file_content = file_content; - mmdb->data_section = file_content + search_tree_size; + mmdb->data_section = mmdb->file_content + search_tree_size; mmdb->data_section_size = mmdb->file_size - search_tree_size; mmdb->metadata_section = metadata; mmdb->ipv4_start_node.node_value = 0; mmdb->ipv4_start_node.netmask = 0; - return MMDB_SUCCESS; + cleanup: + if (MMDB_SUCCESS != status) { + int saved_errno = errno; + free_mmdb_struct(mmdb); + errno = saved_errno; + } + return status; +} + +LOCAL int map_file(MMDB_s *const mmdb) +{ + ssize_t size; + int status = MMDB_SUCCESS; +#ifdef _WIN32 + HANDLE fd = INVALID_HANDLE_VALUE; + HANDLE mmh = NULL; + + fd = CreateFileA(mmdb->filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fd == INVALID_HANDLE_VALUE) { + status = MMDB_FILE_OPEN_ERROR; + goto cleanup; + } + size = GetFileSize(fd, NULL); + if (size == INVALID_FILE_SIZE) { + status = MMDB_FILE_OPEN_ERROR; + goto cleanup; + } + mmh = CreateFileMappingA(fd, NULL, PAGE_READONLY, 0, size, NULL); + if (NULL == mmh) { /* Microsoft documentation for CreateFileMapping indicates this returns NULL not INVALID_HANDLE_VALUE on error */ + status = MMDB_IO_ERROR; + goto cleanup; + } + uint8_t *file_content = + (uint8_t *)MapViewOfFile(mmh, FILE_MAP_READ, 0, 0, 0); + if (file_content == NULL) { + status = MMDB_IO_ERROR; + goto cleanup; + } +#else + int fd = open(mmdb->filename, O_RDONLY); + struct stat s; + if (fd < 0 || fstat(fd, &s)) { + status = MMDB_FILE_OPEN_ERROR; + goto cleanup; + } + + size = s.st_size; + + uint8_t *file_content = + (uint8_t *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (MAP_FAILED == file_content) { + if (ENOMEM == errno) { + status = MMDB_OUT_OF_MEMORY_ERROR; + } else { + status = MMDB_IO_ERROR; + } + goto cleanup; + } +#endif + + mmdb->file_size = size; + mmdb->file_content = file_content; + + cleanup:; + int saved_errno = errno; +#ifdef _WIN32 + if (INVALID_HANDLE_VALUE != fd) { + CloseHandle(fd); + } + if (NULL != mmh) { + CloseHandle(mmh); + } +#else + if (fd >= 0) { + close(fd); + } +#endif + errno = saved_errno; + + return status; } LOCAL const uint8_t *find_metadata(const uint8_t *file_content, @@ -309,7 +344,7 @@ LOCAL const uint8_t *find_metadata(const uint8_t *file_content, file_size; uint8_t *search_area = (uint8_t *)(file_content + (file_size - max_size)); - uint8_t *tmp = search_area; + uint8_t *tmp; do { tmp = mmdb_memmem(search_area, max_size, METADATA_MARKER, strlen(METADATA_MARKER)); @@ -535,6 +570,11 @@ LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, uint32_t map_size = member->entry_data.data_size; mmdb->metadata.description.count = 0; + if (0 == map_size) { + mmdb->metadata.description.descriptions = NULL; + goto cleanup; + } + mmdb->metadata.description.descriptions = malloc(map_size * sizeof(MMDB_description_s *)); if (NULL == mmdb->metadata.description.descriptions) { @@ -581,6 +621,7 @@ LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, } } + cleanup: MMDB_free_entry_data_list(first_member); return MMDB_SUCCESS; @@ -604,23 +645,22 @@ MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb, *gai_error = resolve_any_address(ipstr, &addresses); if (*gai_error) { - if (NULL != addresses) { - freeaddrinfo(addresses); - } - return result; + goto cleanup; } if (mmdb->metadata.ip_version == 4 && addresses->ai_addr->sa_family == AF_INET6) { *mmdb_error = MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR; - freeaddrinfo(addresses); - return result; + goto cleanup; } result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, mmdb_error); - freeaddrinfo(addresses); + cleanup: + if (NULL != addresses) { + freeaddrinfo(addresses); + } return result; } @@ -783,6 +823,8 @@ LOCAL record_info_s record_info_for_database(MMDB_s *mmdb) record_info.left_record_getter = &get_uint32; record_info.right_record_getter = &get_uint32; record_info.right_record_offset = 4; + } else { + assert(false); } return record_info; diff --git a/third_party/libmaxminddb/maxminddb.h b/third_party/libmaxminddb/maxminddb.h index de76c473..40f15a95 100644 --- a/third_party/libmaxminddb/maxminddb.h +++ b/third_party/libmaxminddb/maxminddb.h @@ -36,7 +36,7 @@ typedef ADDRESS_FAMILY sa_family_t; #endif /* libmaxminddb package version from configure */ -#define PACKAGE_VERSION "1.0.4" +#define PACKAGE_VERSION "1.1.0" #define MMDB_DATA_TYPE_EXTENDED (0) #define MMDB_DATA_TYPE_POINTER (1)