geoip2_compat 0.0.3

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