"Fossies" - the Fresh Open Source Software Archive

Member "libmaxminddb-1.5.2/src/maxminddb.c" (18 Feb 2021, 72145 Bytes) of package /linux/misc/libmaxminddb-1.5.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "maxminddb.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.0_vs_1.5.2.

    1 #if HAVE_CONFIG_H
    2 #include <config.h>
    3 #endif
    4 #include "data-pool.h"
    5 #include "maxminddb-compat-util.h"
    6 #include "maxminddb.h"
    7 #include <assert.h>
    8 #include <errno.h>
    9 #include <fcntl.h>
   10 #include <inttypes.h>
   11 #include <stdint.h>
   12 #include <stdlib.h>
   13 #include <string.h>
   14 #include <sys/stat.h>
   15 
   16 #ifdef _WIN32
   17 #ifndef UNICODE
   18 #define UNICODE
   19 #endif
   20 #include <windows.h>
   21 #include <ws2ipdef.h>
   22 #else
   23 #include <arpa/inet.h>
   24 #include <sys/mman.h>
   25 #include <unistd.h>
   26 #endif
   27 
   28 #define MMDB_DATA_SECTION_SEPARATOR (16)
   29 #define MAXIMUM_DATA_STRUCTURE_DEPTH (512)
   30 
   31 #ifdef MMDB_DEBUG
   32 #define DEBUG_MSG(msg) fprintf(stderr, msg "\n")
   33 #define DEBUG_MSGF(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__)
   34 #define DEBUG_BINARY(fmt, byte)                                                \
   35     do {                                                                       \
   36         char *binary = byte_to_binary(byte);                                   \
   37         if (NULL == binary) {                                                  \
   38             fprintf(stderr, "Calloc failed in DEBUG_BINARY\n");                \
   39             abort();                                                           \
   40         }                                                                      \
   41         fprintf(stderr, fmt "\n", binary);                                     \
   42         free(binary);                                                          \
   43     } while (0)
   44 #define DEBUG_NL fprintf(stderr, "\n")
   45 #else
   46 #define DEBUG_MSG(...)
   47 #define DEBUG_MSGF(...)
   48 #define DEBUG_BINARY(...)
   49 #define DEBUG_NL
   50 #endif
   51 
   52 #ifdef MMDB_DEBUG
   53 char *byte_to_binary(uint8_t byte) {
   54     char *bits = calloc(9, sizeof(char));
   55     if (NULL == bits) {
   56         return bits;
   57     }
   58 
   59     for (uint8_t i = 0; i < 8; i++) {
   60         bits[i] = byte & (128 >> i) ? '1' : '0';
   61     }
   62     bits[8] = '\0';
   63 
   64     return bits;
   65 }
   66 
   67 char *type_num_to_name(uint8_t num) {
   68     switch (num) {
   69         case 0:
   70             return "extended";
   71         case 1:
   72             return "pointer";
   73         case 2:
   74             return "utf8_string";
   75         case 3:
   76             return "double";
   77         case 4:
   78             return "bytes";
   79         case 5:
   80             return "uint16";
   81         case 6:
   82             return "uint32";
   83         case 7:
   84             return "map";
   85         case 8:
   86             return "int32";
   87         case 9:
   88             return "uint64";
   89         case 10:
   90             return "uint128";
   91         case 11:
   92             return "array";
   93         case 12:
   94             return "container";
   95         case 13:
   96             return "end_marker";
   97         case 14:
   98             return "boolean";
   99         case 15:
  100             return "float";
  101         default:
  102             return "unknown type";
  103     }
  104 }
  105 #endif
  106 
  107 /* None of the values we check on the lhs are bigger than uint32_t, so on
  108  * platforms where SIZE_MAX is a 64-bit integer, this would be a no-op, and it
  109  * makes the compiler complain if we do the check anyway. */
  110 #if SIZE_MAX == UINT32_MAX
  111 #define MAYBE_CHECK_SIZE_OVERFLOW(lhs, rhs, error)                             \
  112     if ((lhs) > (rhs)) {                                                       \
  113         return error;                                                          \
  114     }
  115 #else
  116 #define MAYBE_CHECK_SIZE_OVERFLOW(...)
  117 #endif
  118 
  119 typedef struct record_info_s {
  120     uint16_t record_length;
  121     uint32_t (*left_record_getter)(const uint8_t *);
  122     uint32_t (*right_record_getter)(const uint8_t *);
  123     uint8_t right_record_offset;
  124 } record_info_s;
  125 
  126 #define METADATA_MARKER "\xab\xcd\xefMaxMind.com"
  127 /* This is 128kb */
  128 #define METADATA_BLOCK_MAX_SIZE 131072
  129 
  130 // 64 leads us to allocating 4 KiB on a 64bit system.
  131 #define MMDB_POOL_INIT_SIZE 64
  132 
  133 static int map_file(MMDB_s *const mmdb);
  134 static const uint8_t *find_metadata(const uint8_t *file_content,
  135                                     ssize_t file_size,
  136                                     uint32_t *metadata_size);
  137 static int read_metadata(MMDB_s *mmdb);
  138 static MMDB_s make_fake_metadata_db(const MMDB_s *const mmdb);
  139 static int
  140 value_for_key_as_uint16(MMDB_entry_s *start, char *key, uint16_t *value);
  141 static int
  142 value_for_key_as_uint32(MMDB_entry_s *start, char *key, uint32_t *value);
  143 static int
  144 value_for_key_as_uint64(MMDB_entry_s *start, char *key, uint64_t *value);
  145 static int
  146 value_for_key_as_string(MMDB_entry_s *start, char *key, char const **value);
  147 static int populate_languages_metadata(MMDB_s *mmdb,
  148                                        MMDB_s *metadata_db,
  149                                        MMDB_entry_s *metadata_start);
  150 static int populate_description_metadata(MMDB_s *mmdb,
  151                                          MMDB_s *metadata_db,
  152                                          MMDB_entry_s *metadata_start);
  153 static int resolve_any_address(const char *ipstr, struct addrinfo **addresses);
  154 static int find_address_in_search_tree(const MMDB_s *const mmdb,
  155                                        uint8_t *address,
  156                                        sa_family_t address_family,
  157                                        MMDB_lookup_result_s *result);
  158 static record_info_s record_info_for_database(const MMDB_s *const mmdb);
  159 static int find_ipv4_start_node(MMDB_s *const mmdb);
  160 static uint8_t record_type(const MMDB_s *const mmdb, uint64_t record);
  161 static uint32_t get_left_28_bit_record(const uint8_t *record);
  162 static uint32_t get_right_28_bit_record(const uint8_t *record);
  163 static uint32_t data_section_offset_for_record(const MMDB_s *const mmdb,
  164                                                uint64_t record);
  165 static int path_length(va_list va_path);
  166 static int lookup_path_in_array(const char *path_elem,
  167                                 const MMDB_s *const mmdb,
  168                                 MMDB_entry_data_s *entry_data);
  169 static int lookup_path_in_map(const char *path_elem,
  170                               const MMDB_s *const mmdb,
  171                               MMDB_entry_data_s *entry_data);
  172 static int skip_map_or_array(const MMDB_s *const mmdb,
  173                              MMDB_entry_data_s *entry_data);
  174 static int decode_one_follow(const MMDB_s *const mmdb,
  175                              uint32_t offset,
  176                              MMDB_entry_data_s *entry_data);
  177 static int decode_one(const MMDB_s *const mmdb,
  178                       uint32_t offset,
  179                       MMDB_entry_data_s *entry_data);
  180 static int get_ext_type(int raw_ext_type);
  181 static uint32_t
  182 get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, int ptr_size);
  183 static int get_entry_data_list(const MMDB_s *const mmdb,
  184                                uint32_t offset,
  185                                MMDB_entry_data_list_s *const entry_data_list,
  186                                MMDB_data_pool_s *const pool,
  187                                int depth);
  188 static float get_ieee754_float(const uint8_t *restrict p);
  189 static double get_ieee754_double(const uint8_t *restrict p);
  190 static uint32_t get_uint32(const uint8_t *p);
  191 static uint32_t get_uint24(const uint8_t *p);
  192 static uint32_t get_uint16(const uint8_t *p);
  193 static uint64_t get_uintX(const uint8_t *p, int length);
  194 static int32_t get_sintX(const uint8_t *p, int length);
  195 static void free_mmdb_struct(MMDB_s *const mmdb);
  196 static void free_languages_metadata(MMDB_s *mmdb);
  197 static void free_descriptions_metadata(MMDB_s *mmdb);
  198 static MMDB_entry_data_list_s *
  199 dump_entry_data_list(FILE *stream,
  200                      MMDB_entry_data_list_s *entry_data_list,
  201                      int indent,
  202                      int *status);
  203 static void print_indentation(FILE *stream, int i);
  204 static char *bytes_to_hex(uint8_t *bytes, uint32_t size);
  205 
  206 #define CHECKED_DECODE_ONE(mmdb, offset, entry_data)                           \
  207     do {                                                                       \
  208         int status = decode_one(mmdb, offset, entry_data);                     \
  209         if (MMDB_SUCCESS != status) {                                          \
  210             DEBUG_MSGF("CHECKED_DECODE_ONE failed."                            \
  211                        " status = %d (%s)",                                    \
  212                        status,                                                 \
  213                        MMDB_strerror(status));                                 \
  214             return status;                                                     \
  215         }                                                                      \
  216     } while (0)
  217 
  218 #define CHECKED_DECODE_ONE_FOLLOW(mmdb, offset, entry_data)                    \
  219     do {                                                                       \
  220         int status = decode_one_follow(mmdb, offset, entry_data);              \
  221         if (MMDB_SUCCESS != status) {                                          \
  222             DEBUG_MSGF("CHECKED_DECODE_ONE_FOLLOW failed."                     \
  223                        " status = %d (%s)",                                    \
  224                        status,                                                 \
  225                        MMDB_strerror(status));                                 \
  226             return status;                                                     \
  227         }                                                                      \
  228     } while (0)
  229 
  230 #define FREE_AND_SET_NULL(p)                                                   \
  231     {                                                                          \
  232         free((void *)(p));                                                     \
  233         (p) = NULL;                                                            \
  234     }
  235 
  236 int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) {
  237     int status = MMDB_SUCCESS;
  238 
  239     mmdb->file_content = NULL;
  240     mmdb->data_section = NULL;
  241     mmdb->metadata.database_type = NULL;
  242     mmdb->metadata.languages.count = 0;
  243     mmdb->metadata.languages.names = NULL;
  244     mmdb->metadata.description.count = 0;
  245 
  246     mmdb->filename = mmdb_strdup(filename);
  247     if (NULL == mmdb->filename) {
  248         status = MMDB_OUT_OF_MEMORY_ERROR;
  249         goto cleanup;
  250     }
  251 
  252     if ((flags & MMDB_MODE_MASK) == 0) {
  253         flags |= MMDB_MODE_MMAP;
  254     }
  255     mmdb->flags = flags;
  256 
  257     if (MMDB_SUCCESS != (status = map_file(mmdb))) {
  258         goto cleanup;
  259     }
  260 
  261 #ifdef _WIN32
  262     WSADATA wsa;
  263     WSAStartup(MAKEWORD(2, 2), &wsa);
  264 #endif
  265 
  266     uint32_t metadata_size = 0;
  267     const uint8_t *metadata =
  268         find_metadata(mmdb->file_content, mmdb->file_size, &metadata_size);
  269     if (NULL == metadata) {
  270         status = MMDB_INVALID_METADATA_ERROR;
  271         goto cleanup;
  272     }
  273 
  274     mmdb->metadata_section = metadata;
  275     mmdb->metadata_section_size = metadata_size;
  276 
  277     status = read_metadata(mmdb);
  278     if (MMDB_SUCCESS != status) {
  279         goto cleanup;
  280     }
  281 
  282     if (mmdb->metadata.binary_format_major_version != 2) {
  283         status = MMDB_UNKNOWN_DATABASE_FORMAT_ERROR;
  284         goto cleanup;
  285     }
  286 
  287     uint32_t search_tree_size =
  288         mmdb->metadata.node_count * mmdb->full_record_byte_size;
  289 
  290     mmdb->data_section =
  291         mmdb->file_content + search_tree_size + MMDB_DATA_SECTION_SEPARATOR;
  292     if (search_tree_size + MMDB_DATA_SECTION_SEPARATOR >
  293         (uint32_t)mmdb->file_size) {
  294         status = MMDB_INVALID_METADATA_ERROR;
  295         goto cleanup;
  296     }
  297     mmdb->data_section_size = (uint32_t)mmdb->file_size - search_tree_size -
  298                               MMDB_DATA_SECTION_SEPARATOR;
  299 
  300     // Although it is likely not possible to construct a database with valid
  301     // valid metadata, as parsed above, and a data_section_size less than 3,
  302     // we do this check as later we assume it is at least three when doing
  303     // bound checks.
  304     if (mmdb->data_section_size < 3) {
  305         status = MMDB_INVALID_DATA_ERROR;
  306         goto cleanup;
  307     }
  308 
  309     mmdb->metadata_section = metadata;
  310     mmdb->ipv4_start_node.node_value = 0;
  311     mmdb->ipv4_start_node.netmask = 0;
  312 
  313     // We do this immediately as otherwise there is a race to set
  314     // ipv4_start_node.node_value and ipv4_start_node.netmask.
  315     if (mmdb->metadata.ip_version == 6) {
  316         status = find_ipv4_start_node(mmdb);
  317         if (status != MMDB_SUCCESS) {
  318             goto cleanup;
  319         }
  320     }
  321 
  322 cleanup:
  323     if (MMDB_SUCCESS != status) {
  324         int saved_errno = errno;
  325         free_mmdb_struct(mmdb);
  326         errno = saved_errno;
  327     }
  328     return status;
  329 }
  330 
  331 #ifdef _WIN32
  332 
  333 static LPWSTR utf8_to_utf16(const char *utf8_str) {
  334     int wide_chars = MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, NULL, 0);
  335     wchar_t *utf16_str = (wchar_t *)calloc(wide_chars, sizeof(wchar_t));
  336     if (!utf16_str) {
  337         return NULL;
  338     }
  339 
  340     if (MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, utf16_str, wide_chars) <
  341         1) {
  342         free(utf16_str);
  343         return NULL;
  344     }
  345 
  346     return utf16_str;
  347 }
  348 
  349 static int map_file(MMDB_s *const mmdb) {
  350     DWORD size;
  351     int status = MMDB_SUCCESS;
  352     HANDLE mmh = NULL;
  353     HANDLE fd = INVALID_HANDLE_VALUE;
  354     LPWSTR utf16_filename = utf8_to_utf16(mmdb->filename);
  355     if (!utf16_filename) {
  356         status = MMDB_FILE_OPEN_ERROR;
  357         goto cleanup;
  358     }
  359     fd = CreateFileW(utf16_filename,
  360                      GENERIC_READ,
  361                      FILE_SHARE_READ,
  362                      NULL,
  363                      OPEN_EXISTING,
  364                      FILE_ATTRIBUTE_NORMAL,
  365                      NULL);
  366     if (fd == INVALID_HANDLE_VALUE) {
  367         status = MMDB_FILE_OPEN_ERROR;
  368         goto cleanup;
  369     }
  370     size = GetFileSize(fd, NULL);
  371     if (size == INVALID_FILE_SIZE) {
  372         status = MMDB_FILE_OPEN_ERROR;
  373         goto cleanup;
  374     }
  375     mmh = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, size, NULL);
  376     /* Microsoft documentation for CreateFileMapping indicates this returns
  377         NULL not INVALID_HANDLE_VALUE on error */
  378     if (NULL == mmh) {
  379         status = MMDB_IO_ERROR;
  380         goto cleanup;
  381     }
  382     uint8_t *file_content =
  383         (uint8_t *)MapViewOfFile(mmh, FILE_MAP_READ, 0, 0, 0);
  384     if (file_content == NULL) {
  385         status = MMDB_IO_ERROR;
  386         goto cleanup;
  387     }
  388 
  389     mmdb->file_size = size;
  390     mmdb->file_content = file_content;
  391 
  392 cleanup:;
  393     int saved_errno = errno;
  394     if (INVALID_HANDLE_VALUE != fd) {
  395         CloseHandle(fd);
  396     }
  397     if (NULL != mmh) {
  398         CloseHandle(mmh);
  399     }
  400     errno = saved_errno;
  401     free(utf16_filename);
  402 
  403     return status;
  404 }
  405 
  406 #else // _WIN32
  407 
  408 static int map_file(MMDB_s *const mmdb) {
  409     ssize_t size;
  410     int status = MMDB_SUCCESS;
  411 
  412     int flags = O_RDONLY;
  413 #ifdef O_CLOEXEC
  414     flags |= O_CLOEXEC;
  415 #endif
  416     int fd = open(mmdb->filename, flags);
  417     struct stat s;
  418     if (fd < 0 || fstat(fd, &s)) {
  419         status = MMDB_FILE_OPEN_ERROR;
  420         goto cleanup;
  421     }
  422 
  423     size = s.st_size;
  424     if (size < 0 || size != s.st_size) {
  425         status = MMDB_OUT_OF_MEMORY_ERROR;
  426         goto cleanup;
  427     }
  428 
  429     uint8_t *file_content =
  430         (uint8_t *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
  431     if (MAP_FAILED == file_content) {
  432         if (ENOMEM == errno) {
  433             status = MMDB_OUT_OF_MEMORY_ERROR;
  434         } else {
  435             status = MMDB_IO_ERROR;
  436         }
  437         goto cleanup;
  438     }
  439 
  440     mmdb->file_size = size;
  441     mmdb->file_content = file_content;
  442 
  443 cleanup:;
  444     int saved_errno = errno;
  445     if (fd >= 0) {
  446         close(fd);
  447     }
  448     errno = saved_errno;
  449 
  450     return status;
  451 }
  452 
  453 #endif // _WIN32
  454 
  455 static const uint8_t *find_metadata(const uint8_t *file_content,
  456                                     ssize_t file_size,
  457                                     uint32_t *metadata_size) {
  458     const ssize_t marker_len = sizeof(METADATA_MARKER) - 1;
  459     ssize_t max_size = file_size > METADATA_BLOCK_MAX_SIZE
  460                            ? METADATA_BLOCK_MAX_SIZE
  461                            : file_size;
  462 
  463     uint8_t *search_area = (uint8_t *)(file_content + (file_size - max_size));
  464     uint8_t *start = search_area;
  465     uint8_t *tmp;
  466     do {
  467         tmp = mmdb_memmem(search_area, max_size, METADATA_MARKER, marker_len);
  468 
  469         if (NULL != tmp) {
  470             max_size -= tmp - search_area;
  471             search_area = tmp;
  472 
  473             /* Continue searching just after the marker we just read, in case
  474              * there are multiple markers in the same file. This would be odd
  475              * but is certainly not impossible. */
  476             max_size -= marker_len;
  477             search_area += marker_len;
  478         }
  479     } while (NULL != tmp);
  480 
  481     if (search_area == start) {
  482         return NULL;
  483     }
  484 
  485     *metadata_size = (uint32_t)max_size;
  486 
  487     return search_area;
  488 }
  489 
  490 static int read_metadata(MMDB_s *mmdb) {
  491     /* We need to create a fake MMDB_s struct in order to decode values from
  492        the metadata. The metadata is basically just like the data section, so we
  493        want to use the same functions we use for the data section to get
  494        metadata values. */
  495     MMDB_s metadata_db = make_fake_metadata_db(mmdb);
  496 
  497     MMDB_entry_s metadata_start = {.mmdb = &metadata_db, .offset = 0};
  498 
  499     int status = value_for_key_as_uint32(
  500         &metadata_start, "node_count", &mmdb->metadata.node_count);
  501     if (MMDB_SUCCESS != status) {
  502         return status;
  503     }
  504     if (!mmdb->metadata.node_count) {
  505         DEBUG_MSG("could not find node_count value in metadata");
  506         return MMDB_INVALID_METADATA_ERROR;
  507     }
  508 
  509     status = value_for_key_as_uint16(
  510         &metadata_start, "record_size", &mmdb->metadata.record_size);
  511     if (MMDB_SUCCESS != status) {
  512         return status;
  513     }
  514     if (!mmdb->metadata.record_size) {
  515         DEBUG_MSG("could not find record_size value in metadata");
  516         return MMDB_INVALID_METADATA_ERROR;
  517     }
  518 
  519     if (mmdb->metadata.record_size != 24 && mmdb->metadata.record_size != 28 &&
  520         mmdb->metadata.record_size != 32) {
  521         DEBUG_MSGF("bad record size in metadata: %i",
  522                    mmdb->metadata.record_size);
  523         return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR;
  524     }
  525 
  526     status = value_for_key_as_uint16(
  527         &metadata_start, "ip_version", &mmdb->metadata.ip_version);
  528     if (MMDB_SUCCESS != status) {
  529         return status;
  530     }
  531     if (!mmdb->metadata.ip_version) {
  532         DEBUG_MSG("could not find ip_version value in metadata");
  533         return MMDB_INVALID_METADATA_ERROR;
  534     }
  535     if (!(mmdb->metadata.ip_version == 4 || mmdb->metadata.ip_version == 6)) {
  536         DEBUG_MSGF("ip_version value in metadata is not 4 or 6 - it was %i",
  537                    mmdb->metadata.ip_version);
  538         return MMDB_INVALID_METADATA_ERROR;
  539     }
  540 
  541     status = value_for_key_as_string(
  542         &metadata_start, "database_type", &mmdb->metadata.database_type);
  543     if (MMDB_SUCCESS != status) {
  544         DEBUG_MSG("error finding database_type value in metadata");
  545         return status;
  546     }
  547 
  548     status = populate_languages_metadata(mmdb, &metadata_db, &metadata_start);
  549     if (MMDB_SUCCESS != status) {
  550         DEBUG_MSG("could not populate languages from metadata");
  551         return status;
  552     }
  553 
  554     status =
  555         value_for_key_as_uint16(&metadata_start,
  556                                 "binary_format_major_version",
  557                                 &mmdb->metadata.binary_format_major_version);
  558     if (MMDB_SUCCESS != status) {
  559         return status;
  560     }
  561     if (!mmdb->metadata.binary_format_major_version) {
  562         DEBUG_MSG(
  563             "could not find binary_format_major_version value in metadata");
  564         return MMDB_INVALID_METADATA_ERROR;
  565     }
  566 
  567     status =
  568         value_for_key_as_uint16(&metadata_start,
  569                                 "binary_format_minor_version",
  570                                 &mmdb->metadata.binary_format_minor_version);
  571     if (MMDB_SUCCESS != status) {
  572         return status;
  573     }
  574 
  575     status = value_for_key_as_uint64(
  576         &metadata_start, "build_epoch", &mmdb->metadata.build_epoch);
  577     if (MMDB_SUCCESS != status) {
  578         return status;
  579     }
  580     if (!mmdb->metadata.build_epoch) {
  581         DEBUG_MSG("could not find build_epoch value in metadata");
  582         return MMDB_INVALID_METADATA_ERROR;
  583     }
  584 
  585     status = populate_description_metadata(mmdb, &metadata_db, &metadata_start);
  586     if (MMDB_SUCCESS != status) {
  587         DEBUG_MSG("could not populate description from metadata");
  588         return status;
  589     }
  590 
  591     mmdb->full_record_byte_size = mmdb->metadata.record_size * 2 / 8U;
  592 
  593     mmdb->depth = mmdb->metadata.ip_version == 4 ? 32 : 128;
  594 
  595     return MMDB_SUCCESS;
  596 }
  597 
  598 static MMDB_s make_fake_metadata_db(const MMDB_s *const mmdb) {
  599     MMDB_s fake_metadata_db = {.data_section = mmdb->metadata_section,
  600                                .data_section_size =
  601                                    mmdb->metadata_section_size};
  602 
  603     return fake_metadata_db;
  604 }
  605 
  606 static int
  607 value_for_key_as_uint16(MMDB_entry_s *start, char *key, uint16_t *value) {
  608     MMDB_entry_data_s entry_data;
  609     const char *path[] = {key, NULL};
  610     int status = MMDB_aget_value(start, &entry_data, path);
  611     if (MMDB_SUCCESS != status) {
  612         return status;
  613     }
  614     if (MMDB_DATA_TYPE_UINT16 != entry_data.type) {
  615         DEBUG_MSGF("expect uint16 for %s but received %s",
  616                    key,
  617                    type_num_to_name(entry_data.type));
  618         return MMDB_INVALID_METADATA_ERROR;
  619     }
  620     *value = entry_data.uint16;
  621     return MMDB_SUCCESS;
  622 }
  623 
  624 static int
  625 value_for_key_as_uint32(MMDB_entry_s *start, char *key, uint32_t *value) {
  626     MMDB_entry_data_s entry_data;
  627     const char *path[] = {key, NULL};
  628     int status = MMDB_aget_value(start, &entry_data, path);
  629     if (MMDB_SUCCESS != status) {
  630         return status;
  631     }
  632     if (MMDB_DATA_TYPE_UINT32 != entry_data.type) {
  633         DEBUG_MSGF("expect uint32 for %s but received %s",
  634                    key,
  635                    type_num_to_name(entry_data.type));
  636         return MMDB_INVALID_METADATA_ERROR;
  637     }
  638     *value = entry_data.uint32;
  639     return MMDB_SUCCESS;
  640 }
  641 
  642 static int
  643 value_for_key_as_uint64(MMDB_entry_s *start, char *key, uint64_t *value) {
  644     MMDB_entry_data_s entry_data;
  645     const char *path[] = {key, NULL};
  646     int status = MMDB_aget_value(start, &entry_data, path);
  647     if (MMDB_SUCCESS != status) {
  648         return status;
  649     }
  650     if (MMDB_DATA_TYPE_UINT64 != entry_data.type) {
  651         DEBUG_MSGF("expect uint64 for %s but received %s",
  652                    key,
  653                    type_num_to_name(entry_data.type));
  654         return MMDB_INVALID_METADATA_ERROR;
  655     }
  656     *value = entry_data.uint64;
  657     return MMDB_SUCCESS;
  658 }
  659 
  660 static int
  661 value_for_key_as_string(MMDB_entry_s *start, char *key, char const **value) {
  662     MMDB_entry_data_s entry_data;
  663     const char *path[] = {key, NULL};
  664     int status = MMDB_aget_value(start, &entry_data, path);
  665     if (MMDB_SUCCESS != status) {
  666         return status;
  667     }
  668     if (MMDB_DATA_TYPE_UTF8_STRING != entry_data.type) {
  669         DEBUG_MSGF("expect string for %s but received %s",
  670                    key,
  671                    type_num_to_name(entry_data.type));
  672         return MMDB_INVALID_METADATA_ERROR;
  673     }
  674     *value = mmdb_strndup((char *)entry_data.utf8_string, entry_data.data_size);
  675     if (NULL == *value) {
  676         return MMDB_OUT_OF_MEMORY_ERROR;
  677     }
  678     return MMDB_SUCCESS;
  679 }
  680 
  681 static int populate_languages_metadata(MMDB_s *mmdb,
  682                                        MMDB_s *metadata_db,
  683                                        MMDB_entry_s *metadata_start) {
  684     MMDB_entry_data_s entry_data;
  685 
  686     const char *path[] = {"languages", NULL};
  687     int status = MMDB_aget_value(metadata_start, &entry_data, path);
  688     if (MMDB_SUCCESS != status) {
  689         return status;
  690     }
  691     if (MMDB_DATA_TYPE_ARRAY != entry_data.type) {
  692         return MMDB_INVALID_METADATA_ERROR;
  693     }
  694 
  695     MMDB_entry_s array_start = {.mmdb = metadata_db,
  696                                 .offset = entry_data.offset};
  697 
  698     MMDB_entry_data_list_s *member;
  699     status = MMDB_get_entry_data_list(&array_start, &member);
  700     if (MMDB_SUCCESS != status) {
  701         return status;
  702     }
  703 
  704     MMDB_entry_data_list_s *first_member = member;
  705 
  706     uint32_t array_size = member->entry_data.data_size;
  707     MAYBE_CHECK_SIZE_OVERFLOW(
  708         array_size, SIZE_MAX / sizeof(char *), MMDB_INVALID_METADATA_ERROR);
  709 
  710     mmdb->metadata.languages.count = 0;
  711     mmdb->metadata.languages.names = calloc(array_size, sizeof(char *));
  712     if (NULL == mmdb->metadata.languages.names) {
  713         return MMDB_OUT_OF_MEMORY_ERROR;
  714     }
  715 
  716     for (uint32_t i = 0; i < array_size; i++) {
  717         member = member->next;
  718         if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) {
  719             return MMDB_INVALID_METADATA_ERROR;
  720         }
  721 
  722         mmdb->metadata.languages.names[i] =
  723             mmdb_strndup((char *)member->entry_data.utf8_string,
  724                          member->entry_data.data_size);
  725 
  726         if (NULL == mmdb->metadata.languages.names[i]) {
  727             return MMDB_OUT_OF_MEMORY_ERROR;
  728         }
  729         // We assign this as we go so that if we fail a calloc and need to
  730         // free it, the count is right.
  731         mmdb->metadata.languages.count = i + 1;
  732     }
  733 
  734     MMDB_free_entry_data_list(first_member);
  735 
  736     return MMDB_SUCCESS;
  737 }
  738 
  739 static int populate_description_metadata(MMDB_s *mmdb,
  740                                          MMDB_s *metadata_db,
  741                                          MMDB_entry_s *metadata_start) {
  742     MMDB_entry_data_s entry_data;
  743 
  744     const char *path[] = {"description", NULL};
  745     int status = MMDB_aget_value(metadata_start, &entry_data, path);
  746     if (MMDB_SUCCESS != status) {
  747         return status;
  748     }
  749 
  750     if (MMDB_DATA_TYPE_MAP != entry_data.type) {
  751         DEBUG_MSGF("Unexpected entry_data type: %d", entry_data.type);
  752         return MMDB_INVALID_METADATA_ERROR;
  753     }
  754 
  755     MMDB_entry_s map_start = {.mmdb = metadata_db, .offset = entry_data.offset};
  756 
  757     MMDB_entry_data_list_s *member;
  758     status = MMDB_get_entry_data_list(&map_start, &member);
  759     if (MMDB_SUCCESS != status) {
  760         DEBUG_MSGF(
  761             "MMDB_get_entry_data_list failed while populating description."
  762             " status = %d (%s)",
  763             status,
  764             MMDB_strerror(status));
  765         return status;
  766     }
  767 
  768     MMDB_entry_data_list_s *first_member = member;
  769 
  770     uint32_t map_size = member->entry_data.data_size;
  771     mmdb->metadata.description.count = 0;
  772     if (0 == map_size) {
  773         mmdb->metadata.description.descriptions = NULL;
  774         goto cleanup;
  775     }
  776     MAYBE_CHECK_SIZE_OVERFLOW(map_size,
  777                               SIZE_MAX / sizeof(MMDB_description_s *),
  778                               MMDB_INVALID_METADATA_ERROR);
  779 
  780     mmdb->metadata.description.descriptions =
  781         calloc(map_size, sizeof(MMDB_description_s *));
  782     if (NULL == mmdb->metadata.description.descriptions) {
  783         status = MMDB_OUT_OF_MEMORY_ERROR;
  784         goto cleanup;
  785     }
  786 
  787     for (uint32_t i = 0; i < map_size; i++) {
  788         mmdb->metadata.description.descriptions[i] =
  789             calloc(1, sizeof(MMDB_description_s));
  790         if (NULL == mmdb->metadata.description.descriptions[i]) {
  791             status = MMDB_OUT_OF_MEMORY_ERROR;
  792             goto cleanup;
  793         }
  794 
  795         mmdb->metadata.description.count = i + 1;
  796         mmdb->metadata.description.descriptions[i]->language = NULL;
  797         mmdb->metadata.description.descriptions[i]->description = NULL;
  798 
  799         member = member->next;
  800 
  801         if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) {
  802             status = MMDB_INVALID_METADATA_ERROR;
  803             goto cleanup;
  804         }
  805 
  806         mmdb->metadata.description.descriptions[i]->language =
  807             mmdb_strndup((char *)member->entry_data.utf8_string,
  808                          member->entry_data.data_size);
  809 
  810         if (NULL == mmdb->metadata.description.descriptions[i]->language) {
  811             status = MMDB_OUT_OF_MEMORY_ERROR;
  812             goto cleanup;
  813         }
  814 
  815         member = member->next;
  816 
  817         if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) {
  818             status = MMDB_INVALID_METADATA_ERROR;
  819             goto cleanup;
  820         }
  821 
  822         mmdb->metadata.description.descriptions[i]->description =
  823             mmdb_strndup((char *)member->entry_data.utf8_string,
  824                          member->entry_data.data_size);
  825 
  826         if (NULL == mmdb->metadata.description.descriptions[i]->description) {
  827             status = MMDB_OUT_OF_MEMORY_ERROR;
  828             goto cleanup;
  829         }
  830     }
  831 
  832 cleanup:
  833     MMDB_free_entry_data_list(first_member);
  834 
  835     return status;
  836 }
  837 
  838 MMDB_lookup_result_s MMDB_lookup_string(const MMDB_s *const mmdb,
  839                                         const char *const ipstr,
  840                                         int *const gai_error,
  841                                         int *const mmdb_error) {
  842     MMDB_lookup_result_s result = {.found_entry = false,
  843                                    .netmask = 0,
  844                                    .entry = {.mmdb = mmdb, .offset = 0}};
  845 
  846     struct addrinfo *addresses = NULL;
  847     *gai_error = resolve_any_address(ipstr, &addresses);
  848 
  849     if (!*gai_error) {
  850         result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, mmdb_error);
  851     }
  852 
  853     if (NULL != addresses) {
  854         freeaddrinfo(addresses);
  855     }
  856 
  857     return result;
  858 }
  859 
  860 static int resolve_any_address(const char *ipstr, struct addrinfo **addresses) {
  861     struct addrinfo hints = {
  862         .ai_family = AF_UNSPEC,
  863         .ai_flags = AI_NUMERICHOST,
  864         // We set ai_socktype so that we only get one result back
  865         .ai_socktype = SOCK_STREAM};
  866 
  867     int gai_status = getaddrinfo(ipstr, NULL, &hints, addresses);
  868     if (gai_status) {
  869         return gai_status;
  870     }
  871 
  872     return 0;
  873 }
  874 
  875 MMDB_lookup_result_s MMDB_lookup_sockaddr(const MMDB_s *const mmdb,
  876                                           const struct sockaddr *const sockaddr,
  877                                           int *const mmdb_error) {
  878     MMDB_lookup_result_s result = {.found_entry = false,
  879                                    .netmask = 0,
  880                                    .entry = {.mmdb = mmdb, .offset = 0}};
  881 
  882     uint8_t mapped_address[16], *address;
  883     if (mmdb->metadata.ip_version == 4) {
  884         if (sockaddr->sa_family == AF_INET6) {
  885             *mmdb_error = MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR;
  886             return result;
  887         }
  888         address = (uint8_t *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
  889     } else {
  890         if (sockaddr->sa_family == AF_INET6) {
  891             address = (uint8_t *)&((struct sockaddr_in6 *)sockaddr)
  892                           ->sin6_addr.s6_addr;
  893         } else {
  894             address = mapped_address;
  895             memset(address, 0, 12);
  896             memcpy(address + 12,
  897                    &((struct sockaddr_in *)sockaddr)->sin_addr.s_addr,
  898                    4);
  899         }
  900     }
  901 
  902     *mmdb_error = find_address_in_search_tree(
  903         mmdb, address, sockaddr->sa_family, &result);
  904 
  905     return result;
  906 }
  907 
  908 static int find_address_in_search_tree(const MMDB_s *const mmdb,
  909                                        uint8_t *address,
  910                                        sa_family_t address_family,
  911                                        MMDB_lookup_result_s *result) {
  912     record_info_s record_info = record_info_for_database(mmdb);
  913     if (0 == record_info.right_record_offset) {
  914         return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR;
  915     }
  916 
  917     uint32_t value = 0;
  918     uint16_t current_bit = 0;
  919     if (mmdb->metadata.ip_version == 6 && address_family == AF_INET) {
  920         value = mmdb->ipv4_start_node.node_value;
  921         current_bit = mmdb->ipv4_start_node.netmask;
  922     }
  923 
  924     uint32_t node_count = mmdb->metadata.node_count;
  925     const uint8_t *search_tree = mmdb->file_content;
  926     const uint8_t *record_pointer;
  927     for (; current_bit < mmdb->depth && value < node_count; current_bit++) {
  928         uint8_t bit =
  929             1U & (address[current_bit >> 3] >> (7 - (current_bit % 8)));
  930 
  931         record_pointer = &search_tree[value * record_info.record_length];
  932         if (record_pointer + record_info.record_length > mmdb->data_section) {
  933             return MMDB_CORRUPT_SEARCH_TREE_ERROR;
  934         }
  935         if (bit) {
  936             record_pointer += record_info.right_record_offset;
  937             value = record_info.right_record_getter(record_pointer);
  938         } else {
  939             value = record_info.left_record_getter(record_pointer);
  940         }
  941     }
  942 
  943     result->netmask = current_bit;
  944 
  945     if (value >= node_count + mmdb->data_section_size) {
  946         // The pointer points off the end of the database.
  947         return MMDB_CORRUPT_SEARCH_TREE_ERROR;
  948     }
  949 
  950     if (value == node_count) {
  951         // record is empty
  952         result->found_entry = false;
  953         return MMDB_SUCCESS;
  954     }
  955     result->found_entry = true;
  956     result->entry.offset = data_section_offset_for_record(mmdb, value);
  957 
  958     return MMDB_SUCCESS;
  959 }
  960 
  961 static record_info_s record_info_for_database(const MMDB_s *const mmdb) {
  962     record_info_s record_info = {.record_length = mmdb->full_record_byte_size,
  963                                  .right_record_offset = 0};
  964 
  965     if (record_info.record_length == 6) {
  966         record_info.left_record_getter = &get_uint24;
  967         record_info.right_record_getter = &get_uint24;
  968         record_info.right_record_offset = 3;
  969     } else if (record_info.record_length == 7) {
  970         record_info.left_record_getter = &get_left_28_bit_record;
  971         record_info.right_record_getter = &get_right_28_bit_record;
  972         record_info.right_record_offset = 3;
  973     } else if (record_info.record_length == 8) {
  974         record_info.left_record_getter = &get_uint32;
  975         record_info.right_record_getter = &get_uint32;
  976         record_info.right_record_offset = 4;
  977     } else {
  978         assert(false);
  979     }
  980 
  981     return record_info;
  982 }
  983 
  984 static int find_ipv4_start_node(MMDB_s *const mmdb) {
  985     /* In a pathological case of a database with a single node search tree,
  986      * this check will be true even after we've found the IPv4 start node, but
  987      * that doesn't seem worth trying to fix. */
  988     if (mmdb->ipv4_start_node.node_value != 0) {
  989         return MMDB_SUCCESS;
  990     }
  991 
  992     record_info_s record_info = record_info_for_database(mmdb);
  993 
  994     const uint8_t *search_tree = mmdb->file_content;
  995     uint32_t node_value = 0;
  996     const uint8_t *record_pointer;
  997     uint16_t netmask;
  998     uint32_t node_count = mmdb->metadata.node_count;
  999 
 1000     for (netmask = 0; netmask < 96 && node_value < node_count; netmask++) {
 1001         record_pointer = &search_tree[node_value * record_info.record_length];
 1002         if (record_pointer + record_info.record_length > mmdb->data_section) {
 1003             return MMDB_CORRUPT_SEARCH_TREE_ERROR;
 1004         }
 1005         node_value = record_info.left_record_getter(record_pointer);
 1006     }
 1007 
 1008     mmdb->ipv4_start_node.node_value = node_value;
 1009     mmdb->ipv4_start_node.netmask = netmask;
 1010 
 1011     return MMDB_SUCCESS;
 1012 }
 1013 
 1014 static uint8_t record_type(const MMDB_s *const mmdb, uint64_t record) {
 1015     uint32_t node_count = mmdb->metadata.node_count;
 1016 
 1017     /* Ideally we'd check to make sure that a record never points to a
 1018      * previously seen value, but that's more complicated. For now, we can
 1019      * at least check that we don't end up at the top of the tree again. */
 1020     if (record == 0) {
 1021         DEBUG_MSG("record has a value of 0");
 1022         return MMDB_RECORD_TYPE_INVALID;
 1023     }
 1024 
 1025     if (record < node_count) {
 1026         return MMDB_RECORD_TYPE_SEARCH_NODE;
 1027     }
 1028 
 1029     if (record == node_count) {
 1030         return MMDB_RECORD_TYPE_EMPTY;
 1031     }
 1032 
 1033     if (record - node_count < mmdb->data_section_size) {
 1034         return MMDB_RECORD_TYPE_DATA;
 1035     }
 1036 
 1037     DEBUG_MSG("record has a value that points outside of the database");
 1038     return MMDB_RECORD_TYPE_INVALID;
 1039 }
 1040 
 1041 static uint32_t get_left_28_bit_record(const uint8_t *record) {
 1042     return record[0] * 65536 + record[1] * 256 + record[2] +
 1043            ((record[3] & 0xf0) << 20);
 1044 }
 1045 
 1046 static uint32_t get_right_28_bit_record(const uint8_t *record) {
 1047     uint32_t value = get_uint32(record);
 1048     return value & 0xfffffff;
 1049 }
 1050 
 1051 int MMDB_read_node(const MMDB_s *const mmdb,
 1052                    uint32_t node_number,
 1053                    MMDB_search_node_s *const node) {
 1054     record_info_s record_info = record_info_for_database(mmdb);
 1055     if (0 == record_info.right_record_offset) {
 1056         return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR;
 1057     }
 1058 
 1059     if (node_number > mmdb->metadata.node_count) {
 1060         return MMDB_INVALID_NODE_NUMBER_ERROR;
 1061     }
 1062 
 1063     const uint8_t *search_tree = mmdb->file_content;
 1064     const uint8_t *record_pointer =
 1065         &search_tree[node_number * record_info.record_length];
 1066     node->left_record = record_info.left_record_getter(record_pointer);
 1067     record_pointer += record_info.right_record_offset;
 1068     node->right_record = record_info.right_record_getter(record_pointer);
 1069 
 1070     node->left_record_type = record_type(mmdb, node->left_record);
 1071     node->right_record_type = record_type(mmdb, node->right_record);
 1072 
 1073     // Note that offset will be invalid if the record type is not
 1074     // MMDB_RECORD_TYPE_DATA, but that's ok. Any use of the record entry
 1075     // for other data types is a programming error.
 1076     node->left_record_entry = (struct MMDB_entry_s){
 1077         .mmdb = mmdb,
 1078         .offset = data_section_offset_for_record(mmdb, node->left_record),
 1079     };
 1080     node->right_record_entry = (struct MMDB_entry_s){
 1081         .mmdb = mmdb,
 1082         .offset = data_section_offset_for_record(mmdb, node->right_record),
 1083     };
 1084 
 1085     return MMDB_SUCCESS;
 1086 }
 1087 
 1088 static uint32_t data_section_offset_for_record(const MMDB_s *const mmdb,
 1089                                                uint64_t record) {
 1090     return (uint32_t)record - mmdb->metadata.node_count -
 1091            MMDB_DATA_SECTION_SEPARATOR;
 1092 }
 1093 
 1094 int MMDB_get_value(MMDB_entry_s *const start,
 1095                    MMDB_entry_data_s *const entry_data,
 1096                    ...) {
 1097     va_list path;
 1098     va_start(path, entry_data);
 1099     int status = MMDB_vget_value(start, entry_data, path);
 1100     va_end(path);
 1101     return status;
 1102 }
 1103 
 1104 int MMDB_vget_value(MMDB_entry_s *const start,
 1105                     MMDB_entry_data_s *const entry_data,
 1106                     va_list va_path) {
 1107     int length = path_length(va_path);
 1108     const char *path_elem;
 1109     int i = 0;
 1110 
 1111     MAYBE_CHECK_SIZE_OVERFLOW(length,
 1112                               SIZE_MAX / sizeof(const char *) - 1,
 1113                               MMDB_INVALID_METADATA_ERROR);
 1114 
 1115     const char **path = calloc(length + 1, sizeof(const char *));
 1116     if (NULL == path) {
 1117         return MMDB_OUT_OF_MEMORY_ERROR;
 1118     }
 1119 
 1120     while (NULL != (path_elem = va_arg(va_path, char *))) {
 1121         path[i] = path_elem;
 1122         i++;
 1123     }
 1124     path[i] = NULL;
 1125 
 1126     int status = MMDB_aget_value(start, entry_data, path);
 1127 
 1128     free((char **)path);
 1129 
 1130     return status;
 1131 }
 1132 
 1133 static int path_length(va_list va_path) {
 1134     int i = 0;
 1135     const char *ignore;
 1136     va_list path_copy;
 1137     va_copy(path_copy, va_path);
 1138 
 1139     while (NULL != (ignore = va_arg(path_copy, char *))) {
 1140         i++;
 1141     }
 1142 
 1143     va_end(path_copy);
 1144 
 1145     return i;
 1146 }
 1147 
 1148 int MMDB_aget_value(MMDB_entry_s *const start,
 1149                     MMDB_entry_data_s *const entry_data,
 1150                     const char *const *const path) {
 1151     const MMDB_s *const mmdb = start->mmdb;
 1152     uint32_t offset = start->offset;
 1153 
 1154     memset(entry_data, 0, sizeof(MMDB_entry_data_s));
 1155     DEBUG_NL;
 1156     DEBUG_MSG("looking up value by path");
 1157 
 1158     CHECKED_DECODE_ONE_FOLLOW(mmdb, offset, entry_data);
 1159 
 1160     DEBUG_NL;
 1161     DEBUG_MSGF("top level element is a %s", type_num_to_name(entry_data->type));
 1162 
 1163     /* Can this happen? It'd probably represent a pathological case under
 1164      * normal use, but there's nothing preventing someone from passing an
 1165      * invalid MMDB_entry_s struct to this function */
 1166     if (!entry_data->has_data) {
 1167         return MMDB_INVALID_LOOKUP_PATH_ERROR;
 1168     }
 1169 
 1170     const char *path_elem;
 1171     int i = 0;
 1172     while (NULL != (path_elem = path[i++])) {
 1173         DEBUG_NL;
 1174         DEBUG_MSGF("path elem = %s", path_elem);
 1175 
 1176         /* XXX - it'd be good to find a quicker way to skip through these
 1177            entries that doesn't involve decoding them
 1178            completely. Basically we need to just use the size from the
 1179            control byte to advance our pointer rather than calling
 1180            decode_one(). */
 1181         if (entry_data->type == MMDB_DATA_TYPE_ARRAY) {
 1182             int status = lookup_path_in_array(path_elem, mmdb, entry_data);
 1183             if (MMDB_SUCCESS != status) {
 1184                 memset(entry_data, 0, sizeof(MMDB_entry_data_s));
 1185                 return status;
 1186             }
 1187         } else if (entry_data->type == MMDB_DATA_TYPE_MAP) {
 1188             int status = lookup_path_in_map(path_elem, mmdb, entry_data);
 1189             if (MMDB_SUCCESS != status) {
 1190                 memset(entry_data, 0, sizeof(MMDB_entry_data_s));
 1191                 return status;
 1192             }
 1193         } else {
 1194             /* Once we make the code traverse maps & arrays without calling
 1195              * decode_one() we can get rid of this. */
 1196             memset(entry_data, 0, sizeof(MMDB_entry_data_s));
 1197             return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
 1198         }
 1199     }
 1200 
 1201     return MMDB_SUCCESS;
 1202 }
 1203 
 1204 static int lookup_path_in_array(const char *path_elem,
 1205                                 const MMDB_s *const mmdb,
 1206                                 MMDB_entry_data_s *entry_data) {
 1207     uint32_t size = entry_data->data_size;
 1208     char *first_invalid;
 1209 
 1210     int saved_errno = errno;
 1211     errno = 0;
 1212     int array_index = strtol(path_elem, &first_invalid, 10);
 1213     if (ERANGE == errno) {
 1214         errno = saved_errno;
 1215         return MMDB_INVALID_LOOKUP_PATH_ERROR;
 1216     }
 1217     errno = saved_errno;
 1218 
 1219     if (array_index < 0) {
 1220         array_index += size;
 1221 
 1222         if (array_index < 0) {
 1223             return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
 1224         }
 1225     }
 1226 
 1227     if (*first_invalid || (uint32_t)array_index >= size) {
 1228         return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
 1229     }
 1230 
 1231     for (int i = 0; i < array_index; i++) {
 1232         /* We don't want to follow a pointer here. If the next element is a
 1233          * pointer we simply skip it and keep going */
 1234         CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data);
 1235         int status = skip_map_or_array(mmdb, entry_data);
 1236         if (MMDB_SUCCESS != status) {
 1237             return status;
 1238         }
 1239     }
 1240 
 1241     MMDB_entry_data_s value;
 1242     CHECKED_DECODE_ONE_FOLLOW(mmdb, entry_data->offset_to_next, &value);
 1243     memcpy(entry_data, &value, sizeof(MMDB_entry_data_s));
 1244 
 1245     return MMDB_SUCCESS;
 1246 }
 1247 
 1248 static int lookup_path_in_map(const char *path_elem,
 1249                               const MMDB_s *const mmdb,
 1250                               MMDB_entry_data_s *entry_data) {
 1251     uint32_t size = entry_data->data_size;
 1252     uint32_t offset = entry_data->offset_to_next;
 1253     size_t path_elem_len = strlen(path_elem);
 1254 
 1255     while (size-- > 0) {
 1256         MMDB_entry_data_s key, value;
 1257         CHECKED_DECODE_ONE_FOLLOW(mmdb, offset, &key);
 1258 
 1259         uint32_t offset_to_value = key.offset_to_next;
 1260 
 1261         if (MMDB_DATA_TYPE_UTF8_STRING != key.type) {
 1262             return MMDB_INVALID_DATA_ERROR;
 1263         }
 1264 
 1265         if (key.data_size == path_elem_len &&
 1266             !memcmp(path_elem, key.utf8_string, path_elem_len)) {
 1267 
 1268             DEBUG_MSG("found key matching path elem");
 1269 
 1270             CHECKED_DECODE_ONE_FOLLOW(mmdb, offset_to_value, &value);
 1271             memcpy(entry_data, &value, sizeof(MMDB_entry_data_s));
 1272             return MMDB_SUCCESS;
 1273         } else {
 1274             /* We don't want to follow a pointer here. If the next element is
 1275              * a pointer we simply skip it and keep going */
 1276             CHECKED_DECODE_ONE(mmdb, offset_to_value, &value);
 1277             int status = skip_map_or_array(mmdb, &value);
 1278             if (MMDB_SUCCESS != status) {
 1279                 return status;
 1280             }
 1281             offset = value.offset_to_next;
 1282         }
 1283     }
 1284 
 1285     memset(entry_data, 0, sizeof(MMDB_entry_data_s));
 1286     return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
 1287 }
 1288 
 1289 static int skip_map_or_array(const MMDB_s *const mmdb,
 1290                              MMDB_entry_data_s *entry_data) {
 1291     if (entry_data->type == MMDB_DATA_TYPE_MAP) {
 1292         uint32_t size = entry_data->data_size;
 1293         while (size-- > 0) {
 1294             CHECKED_DECODE_ONE(
 1295                 mmdb, entry_data->offset_to_next, entry_data); // key
 1296             CHECKED_DECODE_ONE(
 1297                 mmdb, entry_data->offset_to_next, entry_data); // value
 1298             int status = skip_map_or_array(mmdb, entry_data);
 1299             if (MMDB_SUCCESS != status) {
 1300                 return status;
 1301             }
 1302         }
 1303     } else if (entry_data->type == MMDB_DATA_TYPE_ARRAY) {
 1304         uint32_t size = entry_data->data_size;
 1305         while (size-- > 0) {
 1306             CHECKED_DECODE_ONE(
 1307                 mmdb, entry_data->offset_to_next, entry_data); // value
 1308             int status = skip_map_or_array(mmdb, entry_data);
 1309             if (MMDB_SUCCESS != status) {
 1310                 return status;
 1311             }
 1312         }
 1313     }
 1314 
 1315     return MMDB_SUCCESS;
 1316 }
 1317 
 1318 static int decode_one_follow(const MMDB_s *const mmdb,
 1319                              uint32_t offset,
 1320                              MMDB_entry_data_s *entry_data) {
 1321     CHECKED_DECODE_ONE(mmdb, offset, entry_data);
 1322     if (entry_data->type == MMDB_DATA_TYPE_POINTER) {
 1323         uint32_t next = entry_data->offset_to_next;
 1324         CHECKED_DECODE_ONE(mmdb, entry_data->pointer, entry_data);
 1325         /* Pointers to pointers are illegal under the spec */
 1326         if (entry_data->type == MMDB_DATA_TYPE_POINTER) {
 1327             DEBUG_MSG("pointer points to another pointer");
 1328             return MMDB_INVALID_DATA_ERROR;
 1329         }
 1330 
 1331         /* The pointer could point to any part of the data section but the
 1332          * next entry for this particular offset may be the one after the
 1333          * pointer, not the one after whatever the pointer points to. This
 1334          * depends on whether the pointer points to something that is a simple
 1335          * value or a compound value. For a compound value, the next one is
 1336          * the one after the pointer result, not the one after the pointer. */
 1337         if (entry_data->type != MMDB_DATA_TYPE_MAP &&
 1338             entry_data->type != MMDB_DATA_TYPE_ARRAY) {
 1339 
 1340             entry_data->offset_to_next = next;
 1341         }
 1342     }
 1343 
 1344     return MMDB_SUCCESS;
 1345 }
 1346 
 1347 #if !MMDB_UINT128_IS_BYTE_ARRAY
 1348 static mmdb_uint128_t get_uint128(const uint8_t *p, int length) {
 1349     mmdb_uint128_t value = 0;
 1350     while (length-- > 0) {
 1351         value <<= 8;
 1352         value += *p++;
 1353     }
 1354     return value;
 1355 }
 1356 #endif
 1357 
 1358 static int decode_one(const MMDB_s *const mmdb,
 1359                       uint32_t offset,
 1360                       MMDB_entry_data_s *entry_data) {
 1361     const uint8_t *mem = mmdb->data_section;
 1362 
 1363     // We subtract rather than add as it possible that offset + 1
 1364     // could overflow for a corrupt database while an underflow
 1365     // from data_section_size - 1 should not be possible.
 1366     if (offset > mmdb->data_section_size - 1) {
 1367         DEBUG_MSGF("Offset (%d) past data section (%d)",
 1368                    offset,
 1369                    mmdb->data_section_size);
 1370         return MMDB_INVALID_DATA_ERROR;
 1371     }
 1372 
 1373     entry_data->offset = offset;
 1374     entry_data->has_data = true;
 1375 
 1376     DEBUG_NL;
 1377     DEBUG_MSGF("Offset: %i", offset);
 1378 
 1379     uint8_t ctrl = mem[offset++];
 1380     DEBUG_BINARY("Control byte: %s", ctrl);
 1381 
 1382     int type = (ctrl >> 5) & 7;
 1383     DEBUG_MSGF("Type: %i (%s)", type, type_num_to_name(type));
 1384 
 1385     if (type == MMDB_DATA_TYPE_EXTENDED) {
 1386         // Subtracting 1 to avoid possible overflow on offset + 1
 1387         if (offset > mmdb->data_section_size - 1) {
 1388             DEBUG_MSGF("Extended type offset (%d) past data section (%d)",
 1389                        offset,
 1390                        mmdb->data_section_size);
 1391             return MMDB_INVALID_DATA_ERROR;
 1392         }
 1393         type = get_ext_type(mem[offset++]);
 1394         DEBUG_MSGF("Extended type: %i (%s)", type, type_num_to_name(type));
 1395     }
 1396 
 1397     entry_data->type = type;
 1398 
 1399     if (type == MMDB_DATA_TYPE_POINTER) {
 1400         uint8_t psize = ((ctrl >> 3) & 3) + 1;
 1401         DEBUG_MSGF("Pointer size: %i", psize);
 1402 
 1403         // We check that the offset does not extend past the end of the
 1404         // database and that the subtraction of psize did not underflow.
 1405         if (offset > mmdb->data_section_size - psize ||
 1406             mmdb->data_section_size < psize) {
 1407             DEBUG_MSGF("Pointer offset (%d) past data section (%d)",
 1408                        offset + psize,
 1409                        mmdb->data_section_size);
 1410             return MMDB_INVALID_DATA_ERROR;
 1411         }
 1412         entry_data->pointer = get_ptr_from(ctrl, &mem[offset], psize);
 1413         DEBUG_MSGF("Pointer to: %i", entry_data->pointer);
 1414 
 1415         entry_data->data_size = psize;
 1416         entry_data->offset_to_next = offset + psize;
 1417         return MMDB_SUCCESS;
 1418     }
 1419 
 1420     uint32_t size = ctrl & 31;
 1421     switch (size) {
 1422         case 29:
 1423             // We subtract when checking offset to avoid possible overflow
 1424             if (offset > mmdb->data_section_size - 1) {
 1425                 DEBUG_MSGF("String end (%d, case 29) past data section (%d)",
 1426                            offset,
 1427                            mmdb->data_section_size);
 1428                 return MMDB_INVALID_DATA_ERROR;
 1429             }
 1430             size = 29 + mem[offset++];
 1431             break;
 1432         case 30:
 1433             // We subtract when checking offset to avoid possible overflow
 1434             if (offset > mmdb->data_section_size - 2) {
 1435                 DEBUG_MSGF("String end (%d, case 30) past data section (%d)",
 1436                            offset,
 1437                            mmdb->data_section_size);
 1438                 return MMDB_INVALID_DATA_ERROR;
 1439             }
 1440             size = 285 + get_uint16(&mem[offset]);
 1441             offset += 2;
 1442             break;
 1443         case 31:
 1444             // We subtract when checking offset to avoid possible overflow
 1445             if (offset > mmdb->data_section_size - 3) {
 1446                 DEBUG_MSGF("String end (%d, case 31) past data section (%d)",
 1447                            offset,
 1448                            mmdb->data_section_size);
 1449                 return MMDB_INVALID_DATA_ERROR;
 1450             }
 1451             size = 65821 + get_uint24(&mem[offset]);
 1452             offset += 3;
 1453         default:
 1454             break;
 1455     }
 1456 
 1457     DEBUG_MSGF("Size: %i", size);
 1458 
 1459     if (type == MMDB_DATA_TYPE_MAP || type == MMDB_DATA_TYPE_ARRAY) {
 1460         entry_data->data_size = size;
 1461         entry_data->offset_to_next = offset;
 1462         return MMDB_SUCCESS;
 1463     }
 1464 
 1465     if (type == MMDB_DATA_TYPE_BOOLEAN) {
 1466         entry_data->boolean = size ? true : false;
 1467         entry_data->data_size = 0;
 1468         entry_data->offset_to_next = offset;
 1469         DEBUG_MSGF("boolean value: %s", entry_data->boolean ? "true" : "false");
 1470         return MMDB_SUCCESS;
 1471     }
 1472 
 1473     // Check that the data doesn't extend past the end of the memory
 1474     // buffer and that the calculation in doing this did not underflow.
 1475     if (offset > mmdb->data_section_size - size ||
 1476         mmdb->data_section_size < size) {
 1477         DEBUG_MSGF("Data end (%d) past data section (%d)",
 1478                    offset + size,
 1479                    mmdb->data_section_size);
 1480         return MMDB_INVALID_DATA_ERROR;
 1481     }
 1482 
 1483     if (type == MMDB_DATA_TYPE_UINT16) {
 1484         if (size > 2) {
 1485             DEBUG_MSGF("uint16 of size %d", size);
 1486             return MMDB_INVALID_DATA_ERROR;
 1487         }
 1488         entry_data->uint16 = (uint16_t)get_uintX(&mem[offset], size);
 1489         DEBUG_MSGF("uint16 value: %u", entry_data->uint16);
 1490     } else if (type == MMDB_DATA_TYPE_UINT32) {
 1491         if (size > 4) {
 1492             DEBUG_MSGF("uint32 of size %d", size);
 1493             return MMDB_INVALID_DATA_ERROR;
 1494         }
 1495         entry_data->uint32 = (uint32_t)get_uintX(&mem[offset], size);
 1496         DEBUG_MSGF("uint32 value: %u", entry_data->uint32);
 1497     } else if (type == MMDB_DATA_TYPE_INT32) {
 1498         if (size > 4) {
 1499             DEBUG_MSGF("int32 of size %d", size);
 1500             return MMDB_INVALID_DATA_ERROR;
 1501         }
 1502         entry_data->int32 = get_sintX(&mem[offset], size);
 1503         DEBUG_MSGF("int32 value: %i", entry_data->int32);
 1504     } else if (type == MMDB_DATA_TYPE_UINT64) {
 1505         if (size > 8) {
 1506             DEBUG_MSGF("uint64 of size %d", size);
 1507             return MMDB_INVALID_DATA_ERROR;
 1508         }
 1509         entry_data->uint64 = get_uintX(&mem[offset], size);
 1510         DEBUG_MSGF("uint64 value: %" PRIu64, entry_data->uint64);
 1511     } else if (type == MMDB_DATA_TYPE_UINT128) {
 1512         if (size > 16) {
 1513             DEBUG_MSGF("uint128 of size %d", size);
 1514             return MMDB_INVALID_DATA_ERROR;
 1515         }
 1516 #if MMDB_UINT128_IS_BYTE_ARRAY
 1517         memset(entry_data->uint128, 0, 16);
 1518         if (size > 0) {
 1519             memcpy(entry_data->uint128 + 16 - size, &mem[offset], size);
 1520         }
 1521 #else
 1522         entry_data->uint128 = get_uint128(&mem[offset], size);
 1523 #endif
 1524     } else if (type == MMDB_DATA_TYPE_FLOAT) {
 1525         if (size != 4) {
 1526             DEBUG_MSGF("float of size %d", size);
 1527             return MMDB_INVALID_DATA_ERROR;
 1528         }
 1529         size = 4;
 1530         entry_data->float_value = get_ieee754_float(&mem[offset]);
 1531         DEBUG_MSGF("float value: %f", entry_data->float_value);
 1532     } else if (type == MMDB_DATA_TYPE_DOUBLE) {
 1533         if (size != 8) {
 1534             DEBUG_MSGF("double of size %d", size);
 1535             return MMDB_INVALID_DATA_ERROR;
 1536         }
 1537         size = 8;
 1538         entry_data->double_value = get_ieee754_double(&mem[offset]);
 1539         DEBUG_MSGF("double value: %f", entry_data->double_value);
 1540     } else if (type == MMDB_DATA_TYPE_UTF8_STRING) {
 1541         entry_data->utf8_string = size == 0 ? "" : (char *)&mem[offset];
 1542         entry_data->data_size = size;
 1543 #ifdef MMDB_DEBUG
 1544         char *string =
 1545             mmdb_strndup(entry_data->utf8_string, size > 50 ? 50 : size);
 1546         if (NULL == string) {
 1547             abort();
 1548         }
 1549         DEBUG_MSGF("string value: %s", string);
 1550         free(string);
 1551 #endif
 1552     } else if (type == MMDB_DATA_TYPE_BYTES) {
 1553         entry_data->bytes = &mem[offset];
 1554         entry_data->data_size = size;
 1555     }
 1556 
 1557     entry_data->offset_to_next = offset + size;
 1558 
 1559     return MMDB_SUCCESS;
 1560 }
 1561 
 1562 static int get_ext_type(int raw_ext_type) { return 7 + raw_ext_type; }
 1563 
 1564 static uint32_t
 1565 get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, int ptr_size) {
 1566     uint32_t new_offset;
 1567     switch (ptr_size) {
 1568         case 1:
 1569             new_offset = ((ctrl & 7) << 8) + ptr[0];
 1570             break;
 1571         case 2:
 1572             new_offset = 2048 + ((ctrl & 7) << 16) + (ptr[0] << 8) + ptr[1];
 1573             break;
 1574         case 3:
 1575             new_offset = 2048 + 524288 + ((ctrl & 7) << 24) + get_uint24(ptr);
 1576             break;
 1577         case 4:
 1578         default:
 1579             new_offset = get_uint32(ptr);
 1580             break;
 1581     }
 1582     return new_offset;
 1583 }
 1584 
 1585 int MMDB_get_metadata_as_entry_data_list(
 1586     const MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list) {
 1587     MMDB_s metadata_db = make_fake_metadata_db(mmdb);
 1588 
 1589     MMDB_entry_s metadata_start = {.mmdb = &metadata_db, .offset = 0};
 1590 
 1591     return MMDB_get_entry_data_list(&metadata_start, entry_data_list);
 1592 }
 1593 
 1594 int MMDB_get_entry_data_list(MMDB_entry_s *start,
 1595                              MMDB_entry_data_list_s **const entry_data_list) {
 1596     MMDB_data_pool_s *const pool = data_pool_new(MMDB_POOL_INIT_SIZE);
 1597     if (!pool) {
 1598         return MMDB_OUT_OF_MEMORY_ERROR;
 1599     }
 1600 
 1601     MMDB_entry_data_list_s *const list = data_pool_alloc(pool);
 1602     if (!list) {
 1603         data_pool_destroy(pool);
 1604         return MMDB_OUT_OF_MEMORY_ERROR;
 1605     }
 1606 
 1607     int const status =
 1608         get_entry_data_list(start->mmdb, start->offset, list, pool, 0);
 1609 
 1610     *entry_data_list = data_pool_to_list(pool);
 1611     if (!*entry_data_list) {
 1612         data_pool_destroy(pool);
 1613         return MMDB_OUT_OF_MEMORY_ERROR;
 1614     }
 1615 
 1616     return status;
 1617 }
 1618 
 1619 static int get_entry_data_list(const MMDB_s *const mmdb,
 1620                                uint32_t offset,
 1621                                MMDB_entry_data_list_s *const entry_data_list,
 1622                                MMDB_data_pool_s *const pool,
 1623                                int depth) {
 1624     if (depth >= MAXIMUM_DATA_STRUCTURE_DEPTH) {
 1625         DEBUG_MSG("reached the maximum data structure depth");
 1626         return MMDB_INVALID_DATA_ERROR;
 1627     }
 1628     depth++;
 1629     CHECKED_DECODE_ONE(mmdb, offset, &entry_data_list->entry_data);
 1630 
 1631     switch (entry_data_list->entry_data.type) {
 1632         case MMDB_DATA_TYPE_POINTER: {
 1633             uint32_t next_offset = entry_data_list->entry_data.offset_to_next;
 1634             uint32_t last_offset;
 1635             CHECKED_DECODE_ONE(mmdb,
 1636                                last_offset =
 1637                                    entry_data_list->entry_data.pointer,
 1638                                &entry_data_list->entry_data);
 1639 
 1640             /* Pointers to pointers are illegal under the spec */
 1641             if (entry_data_list->entry_data.type == MMDB_DATA_TYPE_POINTER) {
 1642                 DEBUG_MSG("pointer points to another pointer");
 1643                 return MMDB_INVALID_DATA_ERROR;
 1644             }
 1645 
 1646             if (entry_data_list->entry_data.type == MMDB_DATA_TYPE_ARRAY ||
 1647                 entry_data_list->entry_data.type == MMDB_DATA_TYPE_MAP) {
 1648 
 1649                 int status = get_entry_data_list(
 1650                     mmdb, last_offset, entry_data_list, pool, depth);
 1651                 if (MMDB_SUCCESS != status) {
 1652                     DEBUG_MSG("get_entry_data_list on pointer failed.");
 1653                     return status;
 1654                 }
 1655             }
 1656             entry_data_list->entry_data.offset_to_next = next_offset;
 1657         } break;
 1658         case MMDB_DATA_TYPE_ARRAY: {
 1659             uint32_t array_size = entry_data_list->entry_data.data_size;
 1660             uint32_t array_offset = entry_data_list->entry_data.offset_to_next;
 1661             while (array_size-- > 0) {
 1662                 MMDB_entry_data_list_s *entry_data_list_to =
 1663                     data_pool_alloc(pool);
 1664                 if (!entry_data_list_to) {
 1665                     return MMDB_OUT_OF_MEMORY_ERROR;
 1666                 }
 1667 
 1668                 int status = get_entry_data_list(
 1669                     mmdb, array_offset, entry_data_list_to, pool, depth);
 1670                 if (MMDB_SUCCESS != status) {
 1671                     DEBUG_MSG("get_entry_data_list on array element failed.");
 1672                     return status;
 1673                 }
 1674 
 1675                 array_offset = entry_data_list_to->entry_data.offset_to_next;
 1676             }
 1677             entry_data_list->entry_data.offset_to_next = array_offset;
 1678 
 1679         } break;
 1680         case MMDB_DATA_TYPE_MAP: {
 1681             uint32_t size = entry_data_list->entry_data.data_size;
 1682 
 1683             offset = entry_data_list->entry_data.offset_to_next;
 1684             while (size-- > 0) {
 1685                 MMDB_entry_data_list_s *list_key = data_pool_alloc(pool);
 1686                 if (!list_key) {
 1687                     return MMDB_OUT_OF_MEMORY_ERROR;
 1688                 }
 1689 
 1690                 int status =
 1691                     get_entry_data_list(mmdb, offset, list_key, pool, depth);
 1692                 if (MMDB_SUCCESS != status) {
 1693                     DEBUG_MSG("get_entry_data_list on map key failed.");
 1694                     return status;
 1695                 }
 1696 
 1697                 offset = list_key->entry_data.offset_to_next;
 1698 
 1699                 MMDB_entry_data_list_s *list_value = data_pool_alloc(pool);
 1700                 if (!list_value) {
 1701                     return MMDB_OUT_OF_MEMORY_ERROR;
 1702                 }
 1703 
 1704                 status =
 1705                     get_entry_data_list(mmdb, offset, list_value, pool, depth);
 1706                 if (MMDB_SUCCESS != status) {
 1707                     DEBUG_MSG("get_entry_data_list on map element failed.");
 1708                     return status;
 1709                 }
 1710                 offset = list_value->entry_data.offset_to_next;
 1711             }
 1712             entry_data_list->entry_data.offset_to_next = offset;
 1713         } break;
 1714         default:
 1715             break;
 1716     }
 1717 
 1718     return MMDB_SUCCESS;
 1719 }
 1720 
 1721 static float get_ieee754_float(const uint8_t *restrict p) {
 1722     volatile float f;
 1723     uint8_t *q = (void *)&f;
 1724 /* Windows builds don't use autoconf but we can assume they're all
 1725  * little-endian. */
 1726 #if MMDB_LITTLE_ENDIAN || _WIN32
 1727     q[3] = p[0];
 1728     q[2] = p[1];
 1729     q[1] = p[2];
 1730     q[0] = p[3];
 1731 #else
 1732     memcpy(q, p, 4);
 1733 #endif
 1734     return f;
 1735 }
 1736 
 1737 static double get_ieee754_double(const uint8_t *restrict p) {
 1738     volatile double d;
 1739     uint8_t *q = (void *)&d;
 1740 #if MMDB_LITTLE_ENDIAN || _WIN32
 1741     q[7] = p[0];
 1742     q[6] = p[1];
 1743     q[5] = p[2];
 1744     q[4] = p[3];
 1745     q[3] = p[4];
 1746     q[2] = p[5];
 1747     q[1] = p[6];
 1748     q[0] = p[7];
 1749 #else
 1750     memcpy(q, p, 8);
 1751 #endif
 1752 
 1753     return d;
 1754 }
 1755 
 1756 static uint32_t get_uint32(const uint8_t *p) {
 1757     return p[0] * 16777216U + p[1] * 65536 + p[2] * 256 + p[3];
 1758 }
 1759 
 1760 static uint32_t get_uint24(const uint8_t *p) {
 1761     return p[0] * 65536U + p[1] * 256 + p[2];
 1762 }
 1763 
 1764 static uint32_t get_uint16(const uint8_t *p) { return p[0] * 256U + p[1]; }
 1765 
 1766 static uint64_t get_uintX(const uint8_t *p, int length) {
 1767     uint64_t value = 0;
 1768     while (length-- > 0) {
 1769         value <<= 8;
 1770         value += *p++;
 1771     }
 1772     return value;
 1773 }
 1774 
 1775 static int32_t get_sintX(const uint8_t *p, int length) {
 1776     return (int32_t)get_uintX(p, length);
 1777 }
 1778 
 1779 void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list) {
 1780     if (entry_data_list == NULL) {
 1781         return;
 1782     }
 1783     data_pool_destroy(entry_data_list->pool);
 1784 }
 1785 
 1786 void MMDB_close(MMDB_s *const mmdb) { free_mmdb_struct(mmdb); }
 1787 
 1788 static void free_mmdb_struct(MMDB_s *const mmdb) {
 1789     if (!mmdb) {
 1790         return;
 1791     }
 1792 
 1793     if (NULL != mmdb->filename) {
 1794         FREE_AND_SET_NULL(mmdb->filename);
 1795     }
 1796     if (NULL != mmdb->file_content) {
 1797 #ifdef _WIN32
 1798         UnmapViewOfFile(mmdb->file_content);
 1799         /* Winsock is only initialized if open was successful so we only have
 1800          * to cleanup then. */
 1801         WSACleanup();
 1802 #else
 1803         munmap((void *)mmdb->file_content, mmdb->file_size);
 1804 #endif
 1805     }
 1806 
 1807     if (NULL != mmdb->metadata.database_type) {
 1808         FREE_AND_SET_NULL(mmdb->metadata.database_type);
 1809     }
 1810 
 1811     free_languages_metadata(mmdb);
 1812     free_descriptions_metadata(mmdb);
 1813 }
 1814 
 1815 static void free_languages_metadata(MMDB_s *mmdb) {
 1816     if (!mmdb->metadata.languages.names) {
 1817         return;
 1818     }
 1819 
 1820     for (size_t i = 0; i < mmdb->metadata.languages.count; i++) {
 1821         FREE_AND_SET_NULL(mmdb->metadata.languages.names[i]);
 1822     }
 1823     FREE_AND_SET_NULL(mmdb->metadata.languages.names);
 1824 }
 1825 
 1826 static void free_descriptions_metadata(MMDB_s *mmdb) {
 1827     if (!mmdb->metadata.description.count) {
 1828         return;
 1829     }
 1830 
 1831     for (size_t i = 0; i < mmdb->metadata.description.count; i++) {
 1832         if (NULL != mmdb->metadata.description.descriptions[i]) {
 1833             if (NULL != mmdb->metadata.description.descriptions[i]->language) {
 1834                 FREE_AND_SET_NULL(
 1835                     mmdb->metadata.description.descriptions[i]->language);
 1836             }
 1837 
 1838             if (NULL !=
 1839                 mmdb->metadata.description.descriptions[i]->description) {
 1840                 FREE_AND_SET_NULL(
 1841                     mmdb->metadata.description.descriptions[i]->description);
 1842             }
 1843             FREE_AND_SET_NULL(mmdb->metadata.description.descriptions[i]);
 1844         }
 1845     }
 1846 
 1847     FREE_AND_SET_NULL(mmdb->metadata.description.descriptions);
 1848 }
 1849 
 1850 const char *MMDB_lib_version(void) { return PACKAGE_VERSION; }
 1851 
 1852 int MMDB_dump_entry_data_list(FILE *const stream,
 1853                               MMDB_entry_data_list_s *const entry_data_list,
 1854                               int indent) {
 1855     int status;
 1856     dump_entry_data_list(stream, entry_data_list, indent, &status);
 1857     return status;
 1858 }
 1859 
 1860 static MMDB_entry_data_list_s *
 1861 dump_entry_data_list(FILE *stream,
 1862                      MMDB_entry_data_list_s *entry_data_list,
 1863                      int indent,
 1864                      int *status) {
 1865     switch (entry_data_list->entry_data.type) {
 1866         case MMDB_DATA_TYPE_MAP: {
 1867             uint32_t size = entry_data_list->entry_data.data_size;
 1868 
 1869             print_indentation(stream, indent);
 1870             fprintf(stream, "{\n");
 1871             indent += 2;
 1872 
 1873             for (entry_data_list = entry_data_list->next;
 1874                  size && entry_data_list;
 1875                  size--) {
 1876 
 1877                 if (MMDB_DATA_TYPE_UTF8_STRING !=
 1878                     entry_data_list->entry_data.type) {
 1879                     *status = MMDB_INVALID_DATA_ERROR;
 1880                     return NULL;
 1881                 }
 1882                 char *key = mmdb_strndup(
 1883                     (char *)entry_data_list->entry_data.utf8_string,
 1884                     entry_data_list->entry_data.data_size);
 1885                 if (NULL == key) {
 1886                     *status = MMDB_OUT_OF_MEMORY_ERROR;
 1887                     return NULL;
 1888                 }
 1889 
 1890                 print_indentation(stream, indent);
 1891                 fprintf(stream, "\"%s\": \n", key);
 1892                 free(key);
 1893 
 1894                 entry_data_list = entry_data_list->next;
 1895                 entry_data_list = dump_entry_data_list(
 1896                     stream, entry_data_list, indent + 2, status);
 1897 
 1898                 if (MMDB_SUCCESS != *status) {
 1899                     return NULL;
 1900                 }
 1901             }
 1902 
 1903             indent -= 2;
 1904             print_indentation(stream, indent);
 1905             fprintf(stream, "}\n");
 1906         } break;
 1907         case MMDB_DATA_TYPE_ARRAY: {
 1908             uint32_t size = entry_data_list->entry_data.data_size;
 1909 
 1910             print_indentation(stream, indent);
 1911             fprintf(stream, "[\n");
 1912             indent += 2;
 1913 
 1914             for (entry_data_list = entry_data_list->next;
 1915                  size && entry_data_list;
 1916                  size--) {
 1917                 entry_data_list = dump_entry_data_list(
 1918                     stream, entry_data_list, indent, status);
 1919                 if (MMDB_SUCCESS != *status) {
 1920                     return NULL;
 1921                 }
 1922             }
 1923 
 1924             indent -= 2;
 1925             print_indentation(stream, indent);
 1926             fprintf(stream, "]\n");
 1927         } break;
 1928         case MMDB_DATA_TYPE_UTF8_STRING: {
 1929             char *string =
 1930                 mmdb_strndup((char *)entry_data_list->entry_data.utf8_string,
 1931                              entry_data_list->entry_data.data_size);
 1932             if (NULL == string) {
 1933                 *status = MMDB_OUT_OF_MEMORY_ERROR;
 1934                 return NULL;
 1935             }
 1936             print_indentation(stream, indent);
 1937             fprintf(stream, "\"%s\" <utf8_string>\n", string);
 1938             free(string);
 1939             entry_data_list = entry_data_list->next;
 1940         } break;
 1941         case MMDB_DATA_TYPE_BYTES: {
 1942             char *hex_string =
 1943                 bytes_to_hex((uint8_t *)entry_data_list->entry_data.bytes,
 1944                              entry_data_list->entry_data.data_size);
 1945 
 1946             if (NULL == hex_string) {
 1947                 *status = MMDB_OUT_OF_MEMORY_ERROR;
 1948                 return NULL;
 1949             }
 1950 
 1951             print_indentation(stream, indent);
 1952             fprintf(stream, "%s <bytes>\n", hex_string);
 1953             free(hex_string);
 1954 
 1955             entry_data_list = entry_data_list->next;
 1956         } break;
 1957         case MMDB_DATA_TYPE_DOUBLE:
 1958             print_indentation(stream, indent);
 1959             fprintf(stream,
 1960                     "%f <double>\n",
 1961                     entry_data_list->entry_data.double_value);
 1962             entry_data_list = entry_data_list->next;
 1963             break;
 1964         case MMDB_DATA_TYPE_FLOAT:
 1965             print_indentation(stream, indent);
 1966             fprintf(stream,
 1967                     "%f <float>\n",
 1968                     entry_data_list->entry_data.float_value);
 1969             entry_data_list = entry_data_list->next;
 1970             break;
 1971         case MMDB_DATA_TYPE_UINT16:
 1972             print_indentation(stream, indent);
 1973             fprintf(
 1974                 stream, "%u <uint16>\n", entry_data_list->entry_data.uint16);
 1975             entry_data_list = entry_data_list->next;
 1976             break;
 1977         case MMDB_DATA_TYPE_UINT32:
 1978             print_indentation(stream, indent);
 1979             fprintf(
 1980                 stream, "%u <uint32>\n", entry_data_list->entry_data.uint32);
 1981             entry_data_list = entry_data_list->next;
 1982             break;
 1983         case MMDB_DATA_TYPE_BOOLEAN:
 1984             print_indentation(stream, indent);
 1985             fprintf(stream,
 1986                     "%s <boolean>\n",
 1987                     entry_data_list->entry_data.boolean ? "true" : "false");
 1988             entry_data_list = entry_data_list->next;
 1989             break;
 1990         case MMDB_DATA_TYPE_UINT64:
 1991             print_indentation(stream, indent);
 1992             fprintf(stream,
 1993                     "%" PRIu64 " <uint64>\n",
 1994                     entry_data_list->entry_data.uint64);
 1995             entry_data_list = entry_data_list->next;
 1996             break;
 1997         case MMDB_DATA_TYPE_UINT128:
 1998             print_indentation(stream, indent);
 1999 #if MMDB_UINT128_IS_BYTE_ARRAY
 2000             char *hex_string = bytes_to_hex(
 2001                 (uint8_t *)entry_data_list->entry_data.uint128, 16);
 2002             if (NULL == hex_string) {
 2003                 *status = MMDB_OUT_OF_MEMORY_ERROR;
 2004                 return NULL;
 2005             }
 2006             fprintf(stream, "0x%s <uint128>\n", hex_string);
 2007             free(hex_string);
 2008 #else
 2009             uint64_t high = entry_data_list->entry_data.uint128 >> 64;
 2010             uint64_t low = (uint64_t)entry_data_list->entry_data.uint128;
 2011             fprintf(stream,
 2012                     "0x%016" PRIX64 "%016" PRIX64 " <uint128>\n",
 2013                     high,
 2014                     low);
 2015 #endif
 2016             entry_data_list = entry_data_list->next;
 2017             break;
 2018         case MMDB_DATA_TYPE_INT32:
 2019             print_indentation(stream, indent);
 2020             fprintf(stream, "%d <int32>\n", entry_data_list->entry_data.int32);
 2021             entry_data_list = entry_data_list->next;
 2022             break;
 2023         default:
 2024             *status = MMDB_INVALID_DATA_ERROR;
 2025             return NULL;
 2026     }
 2027 
 2028     *status = MMDB_SUCCESS;
 2029     return entry_data_list;
 2030 }
 2031 
 2032 static void print_indentation(FILE *stream, int i) {
 2033     char buffer[1024];
 2034     int size = i >= 1024 ? 1023 : i;
 2035     memset(buffer, 32, size);
 2036     buffer[size] = '\0';
 2037     fputs(buffer, stream);
 2038 }
 2039 
 2040 static char *bytes_to_hex(uint8_t *bytes, uint32_t size) {
 2041     char *hex_string;
 2042     MAYBE_CHECK_SIZE_OVERFLOW(size, SIZE_MAX / 2 - 1, NULL);
 2043 
 2044     hex_string = calloc((size * 2) + 1, sizeof(char));
 2045     if (NULL == hex_string) {
 2046         return NULL;
 2047     }
 2048 
 2049     for (uint32_t i = 0; i < size; i++) {
 2050         sprintf(hex_string + (2 * i), "%02X", bytes[i]);
 2051     }
 2052 
 2053     return hex_string;
 2054 }
 2055 
 2056 const char *MMDB_strerror(int error_code) {
 2057     switch (error_code) {
 2058         case MMDB_SUCCESS:
 2059             return "Success (not an error)";
 2060         case MMDB_FILE_OPEN_ERROR:
 2061             return "Error opening the specified MaxMind DB file";
 2062         case MMDB_CORRUPT_SEARCH_TREE_ERROR:
 2063             return "The MaxMind DB file's search tree is corrupt";
 2064         case MMDB_INVALID_METADATA_ERROR:
 2065             return "The MaxMind DB file contains invalid metadata";
 2066         case MMDB_IO_ERROR:
 2067             return "An attempt to read data from the MaxMind DB file failed";
 2068         case MMDB_OUT_OF_MEMORY_ERROR:
 2069             return "A memory allocation call failed";
 2070         case MMDB_UNKNOWN_DATABASE_FORMAT_ERROR:
 2071             return "The MaxMind DB file is in a format this library can't "
 2072                    "handle (unknown record size or binary format version)";
 2073         case MMDB_INVALID_DATA_ERROR:
 2074             return "The MaxMind DB file's data section contains bad data "
 2075                    "(unknown data type or corrupt data)";
 2076         case MMDB_INVALID_LOOKUP_PATH_ERROR:
 2077             return "The lookup path contained an invalid value (like a "
 2078                    "negative integer for an array index)";
 2079         case MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR:
 2080             return "The lookup path does not match the data (key that doesn't "
 2081                    "exist, array index bigger than the array, expected array "
 2082                    "or map where none exists)";
 2083         case MMDB_INVALID_NODE_NUMBER_ERROR:
 2084             return "The MMDB_read_node function was called with a node number "
 2085                    "that does not exist in the search tree";
 2086         case MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR:
 2087             return "You attempted to look up an IPv6 address in an IPv4-only "
 2088                    "database";
 2089         default:
 2090             return "Unknown error code";
 2091     }
 2092 }