pax_global_header00006660000000000000000000000064124516062150014514gustar00rootroot0000000000000052 comment=03ac93269ac42772ec0908019ecd96d630da501e libmaxminddb-1.0.4/000077500000000000000000000000001245160621500141505ustar00rootroot00000000000000libmaxminddb-1.0.4/.gitignore000066400000000000000000000005261245160621500161430ustar00rootroot00000000000000*.la *.lo *.o *.so */.deps */.libs *~ .\#* .gh-pages /INSTALL /autom4te.cache /bin/country_lookup /bin/mmdbdump /bin/mmdblookup /compile /config.* /configure /depcomp /include/maxminddb_config.h /install-sh /libmaxminddb-* /libtool /ltmain.sh /man /missing /t/*.log /t/*.trs /t/*_t /test-driver Makefile Makefile.in \#*\# aclocal.m4 stamp-h* libmaxminddb-1.0.4/.gitmodules000066400000000000000000000004151245160621500163250ustar00rootroot00000000000000[submodule "maxmind-db"] path = maxmind-db url = git://github.com/maxmind/MaxMind-DB.git [submodule "t/libtap"] path = t/libtap url = git://github.com/zorgnax/libtap.git [submodule "t/maxmind-db"] path = t/maxmind-db url = git://github.com/maxmind/MaxMind-DB.git libmaxminddb-1.0.4/.perltidyrc000066400000000000000000000003251245160621500163320ustar00rootroot00000000000000--blank-lines-before-packages=0 --iterations=2 --no-outdent-long-comments -bar -boc -ci=4 -i=4 -l=78 -nolq -se -wbb="% + - * / x != == >= <= =~ !~ < > | & >= < = **= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x=" libmaxminddb-1.0.4/.travis.yml000066400000000000000000000016531245160621500162660ustar00rootroot00000000000000language: c compiler: - clang - gcc before_install: - sudo apt-get update -qq - sudo apt-get install -qq libipc-run3-perl before_script: - ./bootstrap - CFLAGS="-std=c99 -Wall -Wextra -Werror -Wno-unused-parameter" ./configure - make - git submodule update --init --recursive script: - export VERBOSE=1 - make check notifications: email: recipients: - dev@maxmind.com on_success: change on_failure: always env: global: - secure: "a2pXNVW/lGrMdJTal+pzH0J5N69RdBErwe2dHU2xDnOeNcDYmiSxmU4Fw52KPYXFzdlR9GuEyZtHtesRQthSHpylcIvfJJCih7EvwbNQ5pfplpT5ri2PKPFWB11ebr6vG23Ucgc5lrqHdgIgv+QtqVmW1IDf0hq62itMpu4MwcQ=" addons: coverity_scan: project: name: "maxmind/libmaxminddb" description: "Build submitted via Travis CI" notification_email: dev@maxmind.com build_command_prepend: "./configure; make clean" build_command: "make -j 4" branch_pattern: .*coverity.* libmaxminddb-1.0.4/.uncrustify.cfg000066400000000000000000000064101245160621500171230ustar00rootroot00000000000000# # based on uncrustify config file for the linux kernel # code_width = 80 indent_case_brace = 4 indent_columns = 4 indent_label = 2 # pos: absolute col, neg: relative column indent_with_tabs = 0 # # inter-symbol newlines # nl_brace_else = remove # "} else" vs "} \n else" - cuddle else nl_brace_while = remove # "} while" vs "} \n while" - cuddle while nl_do_brace = remove # "do {" vs "do \n {" nl_else_brace = remove # "else {" vs "else \n {" nl_enum_brace = remove # "enum {" vs "enum \n {" nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{" nl_fdef_brace = force # "int foo() {" vs "int foo()\n{" nl_for_brace = remove # "for () {" vs "for () \n {" nl_func_var_def_blk = 0 # don't add newlines after a block of var declarations nl_if_brace = remove # "if () {" vs "if () \n {" nl_multi_line_define = true nl_struct_brace = remove # "struct {" vs "struct \n {" nl_switch_brace = remove # "switch () {" vs "switch () \n {" nl_union_brace = remove # "union {" vs "union \n {" nl_while_brace = remove # "while () {" vs "while () \n {" # # Source code modifications # mod_full_brace_do = force # "do a--; while ();" vs "do { a--; } while ();" mod_full_brace_for = force # "for () a--;" vs "for () { a--; }" mod_full_brace_if = force # "if (a) a--;" vs "if (a) { a--; }" mod_full_brace_nl = 3 # don't remove if more than 3 newlines mod_full_brace_while = force # "while (a) a--;" vs "while (a) { a--; }" mod_paren_on_return = remove # "return 1;" vs "return (1);" # # inter-character spacing options # sp_after_cast = remove # "(int) a" vs "(int)a" sp_after_comma = force sp_after_sparen = force # "if () {" vs "if (){" sp_arith = force sp_assign = force sp_assign = force sp_before_comma = remove sp_before_ptr_star = force # "char *foo" vs "char* foo sp_before_sparen = force # "if (" vs "if(" sp_between_ptr_star = remove # "char * *foo" vs "char **foo" sp_bool = force sp_compare = force sp_func_call_paren = remove # "foo (" vs "foo(" sp_func_def_paren = remove # "int foo (){" vs "int foo(){" sp_func_proto_paren = remove # "int foo ();" vs "int foo();" sp_inside_braces = force # "{ 1 }" vs "{1}" sp_inside_braces_enum = force # "{ 1 }" vs "{1}" sp_inside_braces_struct = force # "{ 1 }" vs "{1}" sp_inside_sparen = remove sp_paren_brace = force sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)" # # Aligning stuff # align_enum_equ_span = 4 # '=' in enum definition align_nl_cont = true align_on_tabstop = FALSE # align on tabstops align_right_cmt_span = 3 align_struct_init_span = 1 align_struct_init_span = 3 # align stuff in a structure init '= { }' align_var_def_star_style = 2 # void *foo; align_var_struct_span = 0 align_with_tabs = FALSE # use tabs to align libmaxminddb-1.0.4/AUTHORS000066400000000000000000000000001245160621500152060ustar00rootroot00000000000000libmaxminddb-1.0.4/Changes.md000066400000000000000000000115731245160621500160510ustar00rootroot00000000000000## 1.0.4 - 2014-01-02 * If you used a non-integer string as an array index when doing a lookup with `MMDB_get_value`, `MMDB_vget_value`, or `MMDB_aget_value`, the first element of the array would be returned rather than an error. A `MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR` error will now be returned. GitHub #61. * If a number larger than `LONG_MAX` was used in the same functions, `LONG_MAX` would have been used in the lookup. Now a `MMDB_INVALID_LOOKUP_PATH_ERROR` error will be returned. * Visual Studio build files were added for unit tests and some compatibility issues with the tests were fixed. * Visual Studio project was updated to use property pages. Patch by Andre. GitHub #69. * A test failure in `t/compile_c++_t.pl` on new installs was fixed. ## 1.0.3 - 2014-12-02 * A memory and file handle leak on Win32 was fixed when getting the database size fails. Patch by Federico G. Schwindt. GitHub PR #49. * Documentation fix. Federico G. Schwindt. GitHub PR #50. * Added Visual Studio build files and fixed incorrect CreateFileMappingA usage. Patch by Andre. GitHub #52. * The includes for the Windows header files were made lowercase in order to match the actual file names on case-sensitive file systems. GitHub PR #57. * Removed `realloc()` calls that caused warnings on Windows and generally cleaned up memory allocation in `MMDB_vget_value()`. See relevant discussion in GitHub #52. * Added an `extern "C" { ... }` wrapper to maxminddb.h when compiling with a C++ compiler. GitHub #55. ## 1.0.2 - 2014-09-22 * Fixed a number of small issues found by Coverity. * When freeing the MMDB struct in `MMDB_close()` we make sure to set the pointers to NULL after freeing the memory they point to. This makes it safe to call `MMDB_close` more than once on the same `MMDB_s` struct pointer. Before this change, calling this function twice on the same pointer could cause the code to free memory that belonged to something else in the process. Patch by Shuxin Yang. GitHub PR #41. ## 1.0.1 - 2014-09-03 * Added missing LICENSE and NOTICE files to distribution. No code changes. ## 1.0.0 - 2014-09-02 * Bumped version to 1.0.0. No code changes. ## 0.5.6 - 2014-07-21 * There was a leak in the `MMDB_open()` sub when it was called against a file which did not contain any MMDB metadata. Reported by Federico G. Schwindt. GitHub issue #36. * Fixed an error that occurred when passing AI_V4MAPPED to `getaddrinfo()` on FreeBSD. Apparently this macro is defined but doesn't work the way we expected it to on that platform. * Made sure to call `freeaddrinfo()` when a call to `getaddrinfo()` fails but still allocated memory. * Fixed a segfault in the tests that occurred on FreeBSD if we passed a NULL value to `freeaddrinfo()`. * Added a missing step to the README.md file for installing from our GitHub repository. Patch by Yasith Fernando. * Added instructions for installing via Homebrew. Patch by Yasith Fernando. ## 0.5.5 - 2014-03-11 * The previous tarball failed to compile because it was missing the src/maxminddb-compat-util.h file. Reported by Günter Grodotzki. GitHub issue #18. ## 0.5.4 - 2014-03-03 * Added support for compiling in the MinGW environment. Patch by Michael Eisendle. * Added const declarations to many spots in the public API. None of these should require changes to existing code. * Various documentation improvements. * Changed the license to the Apache 2.0 license. ## 0.5.3 - 2013-12-23 * The internal value_for_key_as_uint16 method was returning a uint32_t instead of a uint16_t. Reported by Robert Wells. GitHub issue #11. * The ip_version member of the MMDB_metadata_s struct was a uint8_t, even though the docs and spec said it should be a uint16_t. Reported by Robert Wells. GitHub issue #11. * The mmdblookup_t.pl test now reports that it needs IPC::Run3 to run (which it always did, but it didn't tell you this). Patch by Elan Ruusamäe. GitHub issue #10. ## 0.5.2 - 2013-11-20 * Running `make` from the tarball failed. This is now fixed. ## 0.5.1 - 2013-11-20 * Renamed MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA define to MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR for consistency. Fixes github issue #5. Reported by Albert Strasheim. * Updated README.md to show git clone with --recursive flag so you get the needed submodules. Fixes github issue #4. Reported by Ryan Peck. * Fixed some bugs with the MMDB_get_*value functions when navigating a data structure that included pointers. Fixes github issue #3. Reported by bagadon. * Fixed compilation problems on OSX and OpenBSD. We have tested this on OSX and OpenBSD 5.4. Fixes github issue #6. * Removed some unneeded memory allocations and added const to many variable declarations. Based on patches by Timo Teräs. Github issue #8. * Added a test that uses threads to check for thread safety issue in the library. * Distro tarball now includes man pages, tests, and test data libmaxminddb-1.0.4/LICENSE000066400000000000000000000261361245160621500151650ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. libmaxminddb-1.0.4/Makefile.am000066400000000000000000000017331245160621500162100ustar00rootroot00000000000000 include_HEADERS = include/maxminddb.h src/maxminddb-compat-util.h include_execdir = $(exec_prefix)/include nodist_include_exec_HEADERS = include/maxminddb_config.h SUBDIRS = \ src \ bin \ t EXTRA_DIST = doc t Changes.md LICENSE NOTICE README.md projects/VS12 projects/VS12-tests dist-hook: dev-bin/make-man-pages.pl $(distdir) find $(distdir) -name '.git*' | xargs rm -fr safedist: dist tmpdir="$${TMPDIR-/tmp}/safedist-$$$$" \ && mkdir "$$tmpdir" \ && tar -xvf $(distdir).tar.gz --directory "$$tmpdir" \ && $(am__cd) "$$tmpdir/$(distdir)" \ && ./configure \ && make -j 4 check man1_MANS = man/man1/*.1 man3_MANS = man/man3/*.3 man/man1/*.1: if [ ! -f man/man1/mmdblookup.1 ]; then mkdir -p man/man1 && touch man/man1/mmdblookup.1; fi man/man3/*.3: if [ ! -f man/man3/libmaxminddb.3 ]; then mkdir -p man/man3 && touch man/man3/libmaxminddb.3; fi release: dev-bin/make-release.sh $(PACKAGE_VERSION) .PHONY: man/man1/*.1 man/man3/*.3 release libmaxminddb-1.0.4/NOTICE000066400000000000000000000010561245160621500150560ustar00rootroot00000000000000Copyright 2013-2014 MaxMind, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.libmaxminddb-1.0.4/README.md000066400000000000000000000075201245160621500154330ustar00rootroot00000000000000# About The libmaxminddb library provides a C library for reading MaxMind DB files, including the GeoIP2 databases from MaxMind. This is a custom binary format designed to facilitate fast lookups of IP addresses while allowing for great flexibility in the type of data associated with an address. The MaxMind DB format is an open format. The spec is available at http://maxmind.github.io/MaxMind-DB/. This spec is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. See http://dev.maxmind.com/ for more details about MaxMind's GeoIP2 products. # License This library is licensed under the Apache License, Version 2. # Building and installing from a Tarball This code is known to work with GCC 4.4+ and clang 3.2+. It should also work on other compilers that supports C99, POSIX 2011.11, and the `-fms-extensions flag` (or equivalent). The latter is needed to allow an anonymous union in a structure. To install this code, run the following commands: $ ./configure $ make $ make check $ sudo make install $ sudo ldconfig You can skip the `make check` step but it's always good to know that tests are passing on your platform. The `configure` script takes the standard options to set where files are installed such as `--prefix`, etc. See `./configure --help` for details. If after installing, you receive an error that `libmaxminddb.so.0` is missing you may need to add the `lib` directory in your `prefix` to your library path. On most Linux distributions when using the default prefix (`/usr/local`), you can do this by running the following commands: $ sudo sh -c "echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf" $ ldconfig # Building from the Git Repository To install from Git, you will need automake, autoconf, and libtool installed in addition to make and a compiler. Our public git repository is hosted on GitHub at https://github.com/maxmind/libmaxminddb You can clone this repository and build it by running: $ git clone --recursive https://github.com/maxmind/libmaxminddb After cloning, run `./bootstrap` from the `libmaxminddb directory and then follow the instructions for installing from a tarball as described above. # Building with Visual Studio 2013+ We provide a Visual Studio solution in `projects\VS12`. This can be used to build both the the library and the tests. Please see the `README.md` file in the same directory for more information. # Installing via Homebrew (on OS X) If you are on OS X and you have homebrew (see http://brew.sh/) you can install libmaxminddb via brew. $ brew install libmaxminddb # Bug Reports Please report bugs by filing an issue with our GitHub issue tracker at https://github.com/maxmind/libmaxminddb/issues # Dev Tools We have a few development tools under the `dev-bin` directory to make development easier. These are written in Perl or shell. They are: * `regen-prototypes.pl` - This regenerates the prototypes in the header and source files. This helps keep headers and code in sync. * `uncrustify-all.sh` - This runs `uncrustify` on all the code. It runs `regen-prototypes.pl` first. Please run this before submitting patches. * `valgrind-all.pl` - This runs Valgrind on the tests and `mmdblookup` to check for memory leaks. # Creating a Release Tarball Use `make safedist` to check the resulting tarball. # Copyright and License Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. libmaxminddb-1.0.4/appveyor.yml000066400000000000000000000015071245160621500165430ustar00rootroot00000000000000install: - git submodule update --init --recursive test_script: #EXES - .\projects\VS12\Debug\test_bad_pointers.exe - .\projects\VS12\Debug\test_basic_lookup.exe - .\projects\VS12\Debug\test_data_entry_list.exe - .\projects\VS12\Debug\test_data_types.exe - .\projects\VS12\Debug\test_dump.exe - .\projects\VS12\Debug\test_get_value_pointer_bug.exe - .\projects\VS12\Debug\test_get_value.exe - .\projects\VS12\Debug\test_ipv4_start_cache.exe - .\projects\VS12\Debug\test_ipv6_lookup_in_ipv4.exe - .\projects\VS12\Debug\test_metadata.exe - .\projects\VS12\Debug\test_no_map_get_value.exe - .\projects\VS12\Debug\test_read_node.exe - .\projects\VS12\Debug\test_version.exe #ENDEXES notifications: - provider: HipChat auth_token: secure: NtKXu/kGk8Td4YqCH95camAcNQtB3rMll+5DALAmbDY= room: dev libmaxminddb-1.0.4/bin/000077500000000000000000000000001245160621500147205ustar00rootroot00000000000000libmaxminddb-1.0.4/bin/Makefile.am000066400000000000000000000001551245160621500167550ustar00rootroot00000000000000include $(top_srcdir)/common.mk AM_LDFLAGS = $(top_builddir)/src/libmaxminddb.la bin_PROGRAMS = mmdblookup libmaxminddb-1.0.4/bin/mmdblookup.c000066400000000000000000000306021245160621500172360ustar00rootroot00000000000000#ifdef HAVE_CONFIG_H #include #endif #include "maxminddb.h" #include #include #include #include #include #include #ifdef _WIN32 #include #define snprintf _snprintf #undef UNICODE /* Use the non-UTF16 version of the gai_strerror */ #else #include #include #endif #define LOCAL /* *INDENT-OFF* */ /* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */ LOCAL void usage(char *program, int exit_code, const char *error); LOCAL const char **get_options(int argc, char **argv, char **mmdb_file, char **ip_address, int *verbose, int *iterations, int *lookup_path_length); LOCAL MMDB_s open_or_die(const char *fname); LOCAL void dump_meta(MMDB_s *mmdb); LOCAL int lookup_and_print(MMDB_s *mmdb, const char *ip_address, const char **lookup_path, int lookup_path_length); LOCAL int benchmark(MMDB_s *mmdb, int iterations); LOCAL MMDB_lookup_result_s lookup_or_die(MMDB_s *mmdb, const char *ipstr); LOCAL void random_ipv4(char *ip); /* --prototypes end - don't remove this comment-- */ /* *INDENT-ON* */ int main(int argc, char **argv) { char *mmdb_file = NULL; char *ip_address = NULL; int verbose = 0; int iterations = 0; int lookup_path_length = 0; const char **lookup_path = get_options(argc, argv, &mmdb_file, &ip_address, &verbose, &iterations, &lookup_path_length); MMDB_s mmdb = open_or_die(mmdb_file); if (verbose) { dump_meta(&mmdb); } if (0 == iterations) { exit(lookup_and_print(&mmdb, ip_address, lookup_path, lookup_path_length)); } else { exit(benchmark(&mmdb, iterations)); } } LOCAL void usage(char *program, int exit_code, const char *error) { if (NULL != error) { fprintf(stderr, "\n *ERROR: %s\n", error); } char *usage = "\n" " %s --file /path/to/file.mmdb --ip 1.2.3.4 [path to lookup]\n" "\n" " This application accepts the following options:\n" "\n" " --file (-f) The path to the MMDB file. Required.\n" "\n" " --ip (-i) The IP address to look up. Required.\n" "\n" " --verbose (-v) Turns on verbose output. Specifically, this causes this\n" " application to output the database metadata.\n" "\n" " --version Print the program's version number and exit.\n" "\n" " --help (-h -?) Show usage information.\n" "\n" " If an IP's data entry resolves to a map or array, you can provide\n" " a lookup path to only show part of that data.\n" "\n" " For example, given a JSON structure like this:\n" "\n" " {\n" " \"names\": {\n" " \"en\": \"Germany\",\n" " \"de\": \"Deutschland\"\n" " },\n" " \"cities\": [ \"Berlin\", \"Frankfurt\" ]\n" " }\n" "\n" " You could look up just the English name by calling mmdblookup with a lookup path of:\n" "\n" " mmdblookup --file ... --ip ... names en\n" "\n" " Or you could look up the second city in the list with:\n" "\n" " mmdblookup --file ... --ip ... cities 1\n" "\n" " Array numbering begins with zero (0).\n" "\n" " If you do not provide a path to lookup, all of the information for a given IP\n" " will be shown.\n" "\n"; fprintf(stdout, usage, program); exit(exit_code); } LOCAL const char **get_options(int argc, char **argv, char **mmdb_file, char **ip_address, int *verbose, int *iterations, int *lookup_path_length) { static int help = 0; static int version = 0; while (1) { static struct option options[] = { { "file", required_argument, 0, 'f' }, { "ip", required_argument, 0, 'i' }, { "verbose", no_argument, 0, 'v' }, { "version", no_argument, 0, 'n' }, { "benchmark", required_argument, 0, 'b' }, { "help", no_argument, 0, 'h' }, { "?", no_argument, 0, 1 }, { 0, 0, 0, 0 } }; int opt_index; int opt_char = getopt_long(argc, argv, "f:i:b:vnh?", options, &opt_index); if (-1 == opt_char) { break; } if ('f' == opt_char) { *mmdb_file = optarg; } else if ('i' == opt_char) { *ip_address = optarg; } else if ('v' == opt_char) { *verbose = 1; } else if ('n' == opt_char) { version = 1; } else if ('b' == opt_char) { *iterations = strtol(optarg, NULL, 10); } else if ('h' == opt_char || '?' == opt_char) { help = 1; } } #ifdef _WIN32 char *program = alloca(strlen(argv[0])); _splitpath(argv[0], NULL, NULL, program, NULL); _splitpath(argv[0], NULL, NULL, NULL, program + strlen(program)); #else char *program = basename(argv[0]); #endif if (help) { usage(program, 0, NULL); } if (version) { fprintf(stdout, "\n %s version %s\n\n", program, VERSION); exit(0); } if (NULL == *mmdb_file) { usage(program, 1, "You must provide a filename with --file"); } if (NULL == *ip_address && *iterations == 0) { usage(program, 1, "You must provide an IP address with --ip"); } const char **lookup_path = malloc(sizeof(const char *) * ((argc - optind) + 1)); int i; for (i = 0; i < argc - optind; i++) { lookup_path[i] = argv[i + optind]; (*lookup_path_length)++; } lookup_path[i] = NULL; return lookup_path; } LOCAL MMDB_s open_or_die(const char *fname) { MMDB_s mmdb; int status = MMDB_open(fname, MMDB_MODE_MMAP, &mmdb); if (MMDB_SUCCESS != status) { fprintf(stderr, "\n Can't open %s - %s\n", fname, MMDB_strerror(status)); if (MMDB_IO_ERROR == status) { fprintf(stderr, " IO error: %s\n", strerror(errno)); } fprintf(stderr, "\n"); exit(2); } return mmdb; } LOCAL void dump_meta(MMDB_s *mmdb) { const char *meta_dump = "\n" " Database metadata\n" " Node count: %i\n" " Record size: %i bits\n" " IP version: IPv%i\n" " Binary format: %i.%i\n" " Build epoch: %llu (%s)\n" " Type: %s\n" " Languages: "; char date[40]; strftime(date, 40, "%F %T UTC", gmtime((const time_t *)&mmdb->metadata.build_epoch)); fprintf(stdout, meta_dump, mmdb->metadata.node_count, mmdb->metadata.record_size, mmdb->metadata.ip_version, mmdb->metadata.binary_format_major_version, mmdb->metadata.binary_format_minor_version, mmdb->metadata.build_epoch, date, mmdb->metadata.database_type); for (size_t i = 0; i < mmdb->metadata.languages.count; i++) { fprintf(stdout, "%s", mmdb->metadata.languages.names[i]); if (i < mmdb->metadata.languages.count - 1) { fprintf(stdout, " "); } } fprintf(stdout, "\n"); fprintf(stdout, " Description:\n"); for (size_t i = 0; i < mmdb->metadata.description.count; i++) { fprintf(stdout, " %s: %s\n", mmdb->metadata.description.descriptions[i]->language, mmdb->metadata.description.descriptions[i]->description); } fprintf(stdout, "\n"); } LOCAL int lookup_and_print(MMDB_s *mmdb, const char *ip_address, const char **lookup_path, int lookup_path_length) { MMDB_lookup_result_s result = lookup_or_die(mmdb, ip_address); MMDB_entry_data_list_s *entry_data_list = NULL; int exit_code = 0; if (result.found_entry) { int status; if (lookup_path_length) { MMDB_entry_data_s entry_data; status = MMDB_aget_value(&result.entry, &entry_data, lookup_path); if (MMDB_SUCCESS == status) { if (entry_data.offset) { MMDB_entry_s entry = { .mmdb = mmdb, .offset = entry_data.offset }; status = MMDB_get_entry_data_list(&entry, &entry_data_list); } else { fprintf( stdout, "\n No data was found at the lookup path you provided\n\n"); } } } else { status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); } if (MMDB_SUCCESS != status) { fprintf(stderr, "Got an error looking up the entry data - %s\n", MMDB_strerror(status)); exit_code = 5; goto end; } if (NULL != entry_data_list) { fprintf(stdout, "\n"); MMDB_dump_entry_data_list(stdout, entry_data_list, 2); fprintf(stdout, "\n"); } } else { fprintf(stderr, "\n Could not find an entry for this IP address (%s)\n\n", ip_address); exit_code = 6; } end: MMDB_free_entry_data_list(entry_data_list); MMDB_close(mmdb); free(lookup_path); return exit_code; } LOCAL int benchmark(MMDB_s *mmdb, int iterations) { char ip_address[16]; int exit_code = 0; srand( time(NULL) ); clock_t time = clock(); for (int i = 0; i < iterations; i++) { random_ipv4(ip_address); MMDB_lookup_result_s result = lookup_or_die(mmdb, ip_address); MMDB_entry_data_list_s *entry_data_list = NULL; if (result.found_entry) { int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); if (MMDB_SUCCESS != status) { fprintf(stderr, "Got an error looking up the entry data - %s\n", MMDB_strerror(status)); exit_code = 5; MMDB_free_entry_data_list(entry_data_list); goto end; } } MMDB_free_entry_data_list(entry_data_list); } time = clock() - time; double seconds = ((double)time / CLOCKS_PER_SEC); fprintf( stdout, "\n Looked up %i addresses in %.2f seconds. %.2f lookups per second.\n\n", iterations, seconds, iterations / seconds); end: MMDB_close(mmdb); return exit_code; } LOCAL MMDB_lookup_result_s lookup_or_die(MMDB_s *mmdb, const char *ipstr) { int gai_error, mmdb_error; MMDB_lookup_result_s result = MMDB_lookup_string(mmdb, ipstr, &gai_error, &mmdb_error); if (0 != gai_error) { fprintf(stderr, "\n Error from call to getaddrinfo for %s - %s\n\n", ipstr, gai_strerror(gai_error)); exit(3); } if (MMDB_SUCCESS != mmdb_error) { fprintf(stderr, "\n Got an error from the maxminddb library: %s\n\n", MMDB_strerror(mmdb_error)); exit(4); } return result; } LOCAL void random_ipv4(char *ip) { // rand() is perfectly fine for this use case // coverity[dont_call] int ip_int = rand(); uint8_t *bytes = (uint8_t *)&ip_int; snprintf(ip, 16, "%u.%u.%u.%u", *bytes, *(bytes + 1), *(bytes + 2), *(bytes + 3)); } libmaxminddb-1.0.4/bootstrap000077500000000000000000000007131245160621500161140ustar00rootroot00000000000000#! /bin/sh # make sure to use the installed libtool if [ -f ltmain.sh ]; then rm ltmain.sh fi autoreconf -fiv ################################################### # the steps below may help with outdated toolsets # disable dependency trackeing for OS X with multiply arch option's # automake -i --gnu --add-missing #aclocal \ #&& automake -i --gnu --add-missing \ #&& autoconf #LIBTOOLIZE=$( which libtoolize glibtoolize | head -1 ) #$LIBTOOLIZE -f libmaxminddb-1.0.4/common.mk000066400000000000000000000001531245160621500157700ustar00rootroot00000000000000if DEBUG AM_CFLAGS=-O0 -g -Wall -Wextra else AM_CFLAGS=-O2 -g endif AM_CPPFLAGS = -I$(top_srcdir)/include libmaxminddb-1.0.4/configure.ac000066400000000000000000000075251245160621500164470ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) AC_INIT([libmaxminddb], [1.0.4], [support@maxmind.com]) AC_CONFIG_SRCDIR([include/maxminddb.h]) AC_CONFIG_HEADERS([config.h include/maxminddb_config.h]) LT_INIT AM_INIT_AUTOMAKE(foreign m4_esyscmd([case `automake --version | head -n 1` in *1.14*) echo subdir-objects;; *1.11*);; *) echo serial-tests;; esac])) AC_PROG_LIBTOOL # Checks for programs. AC_PROG_CC_C99 # Copied from http://stackoverflow.com/a/10682813/9832 and tweaked for C (as # opposed to C++) # # AX_CHECK_CFLAGS(ADDITIONAL-CFLAGS, ACTION-IF-FOUND, ACTION-IF-NOT-FOUND) # # checks whether the $(CC) compiler accepts the ADDITIONAL-CFLAGS # if so, they are added to the CXXFLAGS AC_DEFUN([AX_CHECK_CFLAGS], [ AC_MSG_CHECKING([whether compiler accepts "$1"]) cat > conftest.c << EOF int main(){ return 0; } EOF if $CC $CFLAGS -o conftest.o conftest.c [$1] > /dev/null 2>&1 then AC_MSG_RESULT([yes]) CFLAGS="${CFLAGS} [$1]" [$2] else AC_MSG_RESULT([no]) [$3] fi ])dnl AX_CHECK_CFLAGS AX_CHECK_CFLAGS([-fms-extensions]) # We will add this back for non-debug builds in the common.mk file CFLAGS=`echo ${CFLAGS} | sed 's/-O2//'` CXXFLAGS=`echo ${CXXFLAGS} | sed 's/-O2//'` # autoconf insists on giving us gnu99 if it's available CC=`echo ${CC} | sed 's/-std=gnu99/-std=c99/'` AC_C_RESTRICT AC_CHECK_HEADERS([arpa/inet.h assert.h fcntl.h inttypes.h libgen.h math.h netdb.h netinet/in.h stdarg.h stdbool.h stdint.h stdio.h stdlib.h string.h sys/mman.h sys/socket.h sys/stat.h sys/time.h sys/types.h unistd.h]) # configure generates an invalid config for MinGW because of the type checks # so we only run them on non MinGW-Systems. For MinGW we also need to link # against ws2_32. AC_CANONICAL_HOST case $host_os in mingw*) LDFLAGS="-lws2_32" ;; *) AC_TYPE_OFF_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT8_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T ;; esac # This check is backwards in order to make life easier for people writing # extensions in other languages that link to this library. If they want to # simply assume that they are using a newish compiler, they don't need to # check for this type nor do they need to define anything on the CLI. They'll # just get code that assumes this type exists. AC_CHECK_TYPE( [unsigned __int128], [AC_DEFINE([MMDB_UINT128_IS_BYTE_ARRAY], [0], [Missing the unsigned __int128 type])], [AC_CHECK_TYPE( [unsigned int __attribute__((mode(TI)))], [AC_DEFINE([MMDB_UINT128_IS_BYTE_ARRAY], [0], [Missing the unsigned __int128 type]) AC_DEFINE([MMDB_UINT128_USING_MODE], [1], [int128 types are available with __attribute__((mode(TI)))])], [AC_DEFINE([MMDB_UINT128_IS_BYTE_ARRAY], [1], [Missing the unsigned __int128 type])])]) AC_CHECK_TYPES([boolean]) AC_CHECK_FUNC( [open_memstream], [AC_DEFINE([HAVE_OPEN_MEMSTREAM], [1], [Has an open_memstream() function])]) AC_FUNC_MALLOC AC_FUNC_MMAP AC_SEARCH_LIBS([fabs], [m]) AC_SEARCH_LIBS([fabsf], [m]) AC_SEARCH_LIBS([getaddrinfo], [socket]) AC_ARG_ENABLE( [debug], [ --enable-debug Turn on debugging], [case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;; esac],[debug=false]) AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) AC_CONFIG_FILES([Makefile src/Makefile bin/Makefile t/Makefile]) AC_OUTPUT libmaxminddb-1.0.4/dev-bin/000077500000000000000000000000001245160621500154745ustar00rootroot00000000000000libmaxminddb-1.0.4/dev-bin/make-man-pages.pl000077500000000000000000000031571245160621500206250ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use autodie qw( :all ); use FindBin qw( $Bin ); use File::Path qw( mkpath ); use File::Slurp qw( edit_file read_file write_file ); use File::Temp qw( tempdir ); use File::Which qw( which ); sub main { my $target = shift || "$Bin/.."; my $pandoc = which('pandoc') or die "\n You must install pandoc in order to generate the man pages.\n\n"; _make_man( $target, 'libmaxminddb', 3 ); _make_lib_man_links($target); _make_man( $target, 'mmdblookup', 1 ); } sub _make_man { my $target = shift; my $name = shift; my $section = shift; my $man_dir = "$target/man/man$section"; mkpath($man_dir); my $tempdir = tempdir( CLEANUP => 1 ); my $markdown = <<"EOF"; % $name($section) EOF $markdown .= read_file("$Bin/../doc/$name.md"); my $tempfile = "$tempdir/$name.$section.md"; write_file( $tempfile, $markdown ); my $man_file = "$man_dir/$name.$section"; system( qw( pandoc -s -t man ), $tempfile, '-o', $man_file ); _fix_indentation($man_file); } sub _make_lib_man_links { my $target = shift; my $header = read_file("$Bin/../include/maxminddb.h"); for my $proto ( $header =~ /^ +extern.+?(\w+)\(/gsm ) { open my $fh, '>', "$target/man/man3/$proto.3"; print {$fh} ".so man3/libmaxminddb.3\n"; close $fh; } } # AFAICT there's no way to control the indentation depth for code blocks with # Pandoc. sub _fix_indentation { my $file = shift; edit_file( sub { s/^\.IP\n\.nf/.IP "" 4\n.nf/gm; }, $file ); } main(shift); libmaxminddb-1.0.4/dev-bin/make-release.sh000077500000000000000000000031411245160621500203650ustar00rootroot00000000000000#!/bin/sh set -e TAG=$1 if [ -z $TAG ]; then echo "Please specify a tag" exit 1 fi if [ -n "$(git status --porcelain)" ]; then echo ". is not clean." >&2 exit 1 fi old_version=$(perl -MFile::Slurp=read_file <&2 exit 1 fi INDEX=index.md cat < $INDEX --- layout: default title: libmaxminddb - a library for working with MaxMind DB files version: $TAG --- EOF cat ../doc/libmaxminddb.md >> $INDEX MMDBLOOKUP=mmdblookup.md cat < $MMDBLOOKUP --- layout: default title: mmdblookup - a utility to look up an IP address in a MaxMind DB file version: $TAG --- EOF cat ../doc/mmdblookup.md >> $MMDBLOOKUP if [ -n "$(git status --porcelain)" ]; then git commit -m "Updated for $TAG" -a read -p "Push to origin? (y/n) " SHOULD_PUSH if [ "$SHOULD_PUSH" != "y" ]; then echo "Aborting" exit 1 fi git push fi cd .. git tag -a -m "Release for $TAG" $TAG git push --follow-tags libmaxminddb-1.0.4/dev-bin/regen-prototypes.pl000077500000000000000000000074671245160621500214000ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use FindBin qw( $Bin ); use File::Basename qw( basename dirname ); use File::Slurp qw( read_file write_file ); sub main { _regen_prototypes( "$Bin/../src/maxminddb.c", "$Bin/../include/maxminddb.h" ); _regen_prototypes( "$Bin/../bin/mmdblookup.c", ); _regen_prototypes( "$Bin/../t/maxminddb_test_helper.c", "$Bin/../t/maxminddb_test_helper.h", ); } sub _regen_prototypes { my $c_file = shift; my $h_file = shift; my $c_code = read_file($c_file); my $h_code = $h_file ? read_file($h_file) : q{}; my $orig_c_code = $c_code; my $orig_h_code = $h_code; my $script_name = basename($0); my $dir = basename($Bin); my $indent_off = '/* *INDENT-OFF* */'; my $indent_on = '/* *INDENT-ON* */'; my $prototypes_start = "/* --prototypes automatically generated by $dir/$script_name - don't remove this comment */"; my $prototypes_end = q{/* --prototypes end - don't remove this comment-- */}; ( my $prototypes_start_re = $prototypes_start ) =~ s/ \n /\n */g; ( my $prototypes_end_re = $prototypes_end ) =~ s/\n/\n */g; for my $content ( $c_code, $h_code ) { $content =~ s{ [ ]* \Q$indent_off\E \n [ ]* \Q$prototypes_start\E .+? [ ]* \Q$prototypes_end\E \n [ ]* \Q$indent_on\E \n }{__PROTOTYPES__}sx; } my @prototypes = parse_prototypes($c_code); if ($h_file) { my $external_prototypes = join q{}, map { my $p = 'extern ' . $_->{prototype}; $p =~ s/^/ /; # first line $p =~ s/\n/\n /gm; # the rest $p . ";\n" } grep { $_->{external} } @prototypes; $h_code =~ s/__PROTOTYPES__/ $indent_off\n $prototypes_start\n$external_prototypes $prototypes_end\n $indent_on\n/; $h_code =~ s{\n *(/\* \*INDENT)}{\n $1}g; } my $internal_prototypes = join q{}, map { $_->{prototype} . ";\n" } grep { !$_->{external} } @prototypes; $c_code =~ s/__PROTOTYPES__/$indent_off\n$prototypes_start\n$internal_prototypes$prototypes_end\n$indent_on\n/; write_file( $c_file, $c_code ) if $c_code ne $orig_c_code; write_file( $h_file, $h_code ) if $h_file && $h_code ne $orig_h_code; } my $return_type_re = qr/(?:\w+\s+)+?\**?/; my $signature_re = qr/\([^\(\)]+?\)/; my $c_function_re = qr/($return_type_re(\w+)$signature_re)(?>\n{)/s; # Shamelessly stolen from Inline::C::ParseRegExp my $sp = qr{[ \t]|\n(?![ \t]*\n)}; my $re_type = qr { (?: (?: const $sp*)? \w+ $sp* )+? # words (?: (?: const $sp*)? \* $sp* )* # stars (?: const $sp*)? # optional const }x; my $re_identifier = qr{ \w+ $sp* }x; my $re_args = qr/\(.*?\)/s; # and again from Inline::C::ParseRegExp my $re_signature = qr/^($re_type ($re_identifier) $re_args) (?>[\ \t\n]*?{)/x; { my %skip = map { $_ => 1 } qw( memmem ); sub parse_prototypes { my $c_code = shift; my @protos; for my $chunk ( $c_code =~ /^(\w+.+?[;{])/gsm ) { my ( $prototype, $name ) = $chunk =~ /^$re_signature/ms or next; next if $prototype =~ /^(?:DEBUG_FUNC|NO_PROTO)/; push @protos, { name => $name, prototype => $prototype, external => $prototype =~ /^LOCAL/ ? 0 : 1, }; } return grep { !$skip{ $_->{name} } } @protos; } } main(); libmaxminddb-1.0.4/dev-bin/regen-win32-test-projs.pl000077500000000000000000000022031245160621500222010ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use FindBin qw( $Bin ); use Data::UUID; use File::Slurp qw( read_file write_file ); use Path::Iterator::Rule; sub main { my $rule = Path::Iterator::Rule->new; $rule->file->name(qr/_t.c$/); my $ug = Data::UUID->new; my $template = read_file("$Bin/../projects/test.vcxproj.template"); my @names; for my $file ( $rule->all("$Bin/../t/") ) { my ($name) = $file =~ /(\w*)_t.c$/; next unless $name; next if $name eq 'threads'; push @names, $name; my $project = $template; $project =~ s/%TESTNAME%/$name/g; my $uuid = $ug->to_string( $ug->create ); $project =~ s/%UUID%/$uuid/g; write_file( "$Bin/../projects/VS12-tests/$name.vcxproj", $project ); } _modify_yml(@names); } sub _modify_yml { my @names = @_; my $exe_block = join "\n", map { " - .\\projects\\VS12\\Debug\\test_${_}.exe" } @names; my $file = "$Bin/../appveyor.yml"; my $config = read_file($file); $config =~ s/(#EXES).*?(#ENDEXES)/$1\n$exe_block\n $2/s; write_file( $file, $config ); } main(); libmaxminddb-1.0.4/dev-bin/uncrustify-all.sh000077500000000000000000000011071245160621500210130ustar00rootroot00000000000000#!/bin/sh uncrustify="uncrustify -c .uncrustify.cfg --replace --no-backup" # We indent each thing twice because uncrustify is not idempotent - in some # cases it will flip-flop between two indentation styles. for dir in bin include src t; do c_files=`find $dir -maxdepth 1 -name '*.c'` if [ "$c_files" != "" ]; then $uncrustify $dir/*.c; $uncrustify $dir/*.c; fi h_files=`find $dir -maxdepth 1 -name '*.h'` if [ "$h_files" != "" ]; then $uncrustify $dir/*.h; $uncrustify $dir/*.h; fi done ./dev-bin/regen-prototypes.pl libmaxminddb-1.0.4/dev-bin/valgrind-all.pl000077500000000000000000000016631245160621500204160ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use File::Basename qw( basename ); use FindBin qw( $Bin ); use IPC::Run3; my $top_dir = "$Bin/.."; my $output; my @tests = glob "$top_dir/t/.libs/lt-*_t"; my @mmdblookup = ( "$top_dir/bin/mmdblookup", '--file', "$top_dir/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb", '--ip', ); # We want IPv4 and IPv6 addresses - one of each that exists in the db and one # that doesn't my @ips = ( '1.1.1.1', '10.0.0.0', 'abcd::', '0900::' ); my @cmds = ( ( map { [ @mmdblookup, $_ ] } @ips ), ( map { [$_] } @tests ), ); for my $cmd (@cmds) { my $output; run3( [ qw( valgrind --leak-check=full -- ), @{$cmd} ], \undef, \$output, \$output, ); $output =~ s/^(?!=).*\n//mg; my $marker = '-' x 60; print $marker, "\n", ( join q{ }, basename( shift @{$cmd} ), @{$cmd} ), "\n", $marker, "\n", $output, "\n\n"; } libmaxminddb-1.0.4/doc/000077500000000000000000000000001245160621500147155ustar00rootroot00000000000000libmaxminddb-1.0.4/doc/libmaxminddb.md000066400000000000000000000640571245160621500177050ustar00rootroot00000000000000# NAME libmaxminddb - a library for working with MaxMind DB files # SYNOPSIS ```c #include int MMDB_open( const char *const filename, uint32_t flags, MMDB_s *const mmdb); void MMDB_close(MMDB_s *const mmdb); MMDB_lookup_result_s MMDB_lookup_string( MMDB_s *const mmdb, const char *const ipstr, int *const gai_error, int *const mmdb_error); MMDB_lookup_result_s MMDB_lookup_sockaddr( MMDB_s *const mmdb, const struct sockaddr *const sockaddr, int *const mmdb_error); int MMDB_get_value( MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, ...); int int MMDB_vget_value( MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, va_list va_path); int MMDB_aget_value( MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, const char *const *const path); int MMDB_get_entry_data_list( MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list); void MMDB_free_entry_data_list( MMDB_entry_data_list_s *const entry_data_list); int MMDB_get_metadata_as_entry_data_list( MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list); int MMDB_dump_entry_data_list( FILE *const stream, MMDB_entry_data_list_s *const entry_data_list, int indent); int MMDB_read_node( MMDB_s *const mmdb, uint32_t node_number, MMDB_search_node_s *const node); const char *MMDB_lib_version(void); const char *MMDB_strerror(int error_code); typedef struct MMDB_lookup_result_s { bool found_entry; MMDB_entry_s entry; uint16_t netmask; } MMDB_lookup_result_s; typedef struct MMDB_entry_data_s { bool has_data; union { uint32_t pointer; const char *utf8_string; double double_value; const uint8_t *bytes; uint16_t uint16; uint32_t uint32; int32_t int32; uint64_t uint64; {mmdb_uint128_t or uint8_t[16]} uint128; bool boolean; float float_value; }; ... uint32_t data_size; uint32_t type; } MMDB_entry_data_s; typedef struct MMDB_entry_data_list_s { MMDB_entry_data_s entry_data; struct MMDB_entry_data_list_s *next; } MMDB_entry_data_list_s; ``` # DESCRIPTION The libmaxminddb library provides functions for working MaxMind DB files. See http://maxmind.github.io/MaxMind-DB/ for the MaxMind DB format specification. The database and results are all represented by different data structures. Databases are opened by calling `MMDB_open()`. You can look up IP addresses as a string with `MMDB_lookup_string()` or as a pointer to a `sockaddr` structure with `MMDB_lookup_sockaddr()`. If the lookup finds the IP address in the database, it returns a `MMDB_lookup_result_s` structure. If that structure indicates that the database has data for the IP, there are a number of functions that can be used to fetch that data. These include `MMDB_get_value()` and `MMDB_get_entry_data_list()`. See the function documentation below for more details. When you are done with the database handle you should call `MMDB_close()`. All publicly visible functions, structures, and macros begin with "MMDB_". # DATA STRUCTURES All data structures exported by this library's `maxminddb.h` header are typedef'd in the form `typedef struct foo_s { ... } foo_s` so you can refer to them without the `struct` prefix. This library provides the following data structures: ## `MMDB_s` This is the handle for a MaxMind DB file. We only document some of this structure's fields intended for public use. All other fields are subject to change and are intended only for internal use. ```c typedef struct MMDB_s { uint32_t flags; const char *filename; ... MMDB_metadata_s metadata; } MMDB_s; ``` * `uint32_t flags` - the flags this database was opened with. See the `MMDB_open()` documentation for more details. * `const char *filename` - the name of the file which was opened, as passed to `MMDB_open()`. * `MMDB_metadata_s metadata` - the metadata for the database. ## `MMDB_metadata_s` and `MMDB_description_s` This structure can be retrieved from the `MMDB_s` structure. It contains the metadata read from the database file. Note that you may find it more convenient to access this metadata by calling `MMDB_get_metadata_as_entry_data_list()` instead. ```c typedef struct MMDB_metadata_s { uint32_t node_count; uint16_t record_size; uint16_t ip_version; const char *database_type; struct { size_t count; const char **names; } languages; uint16_t binary_format_major_version; uint16_t binary_format_minor_version; uint64_t build_epoch; struct { size_t count; MMDB_description_s **descriptions; } description; } MMDB_metadata_s; typedef struct MMDB_description_s { const char *language; const char *description; } MMDB_description_s; ``` These structures should be mostly self-explanatory. The `ip_version` member should always be `4` or `6`. The `binary_format_major_version` should always be `2`. There is no requirement that the database metadata include languages or descriptions, so the `count` for these parts of the metadata can be zero. All of the other `MMDB_metadata_s` fields should be populated. ## `MMDB_lookup_result_s` This structure is returned as the result of looking up an IP address. ```c typedef struct MMDB_lookup_result_s { bool found_entry; MMDB_entry_s entry; uint16_t netmask; } MMDB_lookup_result_s; ``` If the `found_entry` member is false then the other members of this structure do not contain meaningful values. Always check that `found_entry` is true first. The `entry` member is used to look up the data associated with the IP address. The `netmask` member tells you what subnet the IP address belongs to in this database. For example, if you look up the address `1.1.1.1` in an IPv4 database and the returned `netmask` is 16, then the address is part of the `1.1.1.0/16` subnet. ## `MMDB_result_s` You don't really need to dig around in this structure. You'll get this from a `MMDB_lookup_result_s` structure and pass it to various functions. ## `MMDB_entry_data_s` This structure is used to return a single data section entry for an IP. These entries can in turn point to other entries, as is the case for things like maps and arrays. Some members of this structure are not documented as they are only for internal use. ```c typedef struct MMDB_entry_data_s { bool has_data; union { uint32_t pointer; const char *utf8_string; double double_value; const uint8_t *bytes; uint16_t uint16; uint32_t uint32; int32_t int32; uint64_t uint64; {mmdb_uint128_t or uint8_t[16]} uint128; bool boolean; float float_value; }; ... uint32_t data_size; uint32_t type; } MMDB_entry_data_s; ``` The `has_data` member is true if data was found for a given lookup. See `MMDB_get_value()` for more details. If this member is false then none of the other values in the structure are meaningful. The union at the beginning of the structure defines the actual data. To determine which union member is populated you should look at the `type` member. The `pointer` member of the union should never be populated in any data returned by the API. Pointers should always be resolved internally. The `data_size` member is only relevant for `utf8_string` and `bytes` data. `utf8_string` is not null terminated and `data_size` _must_ be used to determine its length. The `type` member can be compared to one of the `MMDB_DTYPE_*` macros. ### 128-bit Integers The handling of `uint128` data depends on how your platform supports 128-bit integers, if it does so at all. With GCC 4.4 and 4.5 we can write `unsigned int __attribute__ ((__mode__ (TI)))`. With newer versions of GCC (4.6+) and clang (3.2+) we can simply write "unsigned __int128". In order to work around these differences, this library defines an `mmdb_uint128_t` type. This type is defined in the `maxminddb.h` header so you can use it in your own code. With older compilers, we can't use an integer so we instead use a 16 byte array of `uint8_t` values. This is the raw data from the database. This library provides a public macro `MMDB_UINT128_IS_BYTE_ARRAY` macro. If this is true (1), then `uint128` values are returned as a byte array, if it is false then they are returned as a `mmdb_uint128_t` integer. ### Data Type Macros This library provides a macro for every data type defined by the MaxMind DB spec. * `MMDB_DATA_TYPE_UTF8_STRING` * `MMDB_DATA_TYPE_DOUBLE` * `MMDB_DATA_TYPE_BYTES` * `MMDB_DATA_TYPE_UINT16` * `MMDB_DATA_TYPE_UINT32` * `MMDB_DATA_TYPE_MAP` * `MMDB_DATA_TYPE_INT32` * `MMDB_DATA_TYPE_UINT64` * `MMDB_DATA_TYPE_UINT128` * `MMDB_DATA_TYPE_ARRAY` * `MMDB_DATA_TYPE_BOOLEAN` * `MMDB_DATA_TYPE_FLOAT` There are also a few types that are for internal use only: * `MMDB_DATA_TYPE_EXTENDED` * `MMDB_DATA_TYPE_POINTER` * `MMDB_DATA_TYPE_CONTAINER` * `MMDB_DATA_TYPE_END_MARKER` If you see one of these in returned data then something has gone very wrong. The database is damaged or was generated incorrectly or there is a bug in the libmaxminddb code. ### Pointer Values and `MMDB_close()` The `utf8_string`, `bytes`, and (maybe) the `uint128` members of this structure are all pointers directly into the database's data section. This can either be a `malloc`'d or `mmap`'d block of memory. In either case, these pointers will become invalid after `MMDB_close()` is called. If you need to refer to this data after that time you should copy the data with an appropriate function (`strdup`, `memcpy`, etc.). ## `MMDB_entry_data_list_s` This structure encapsulates a linked list of `MMDB_entry_data_s` structures. ```c typedef struct MMDB_entry_data_list_s { MMDB_entry_data_s entry_data; struct MMDB_entry_data_list_s *next; } MMDB_entry_data_list_s; ``` This structure lets you look at entire map or array data entry by iterating over the linked list. ## `MMDB_search_node_s` This structure encapsulates the two records in a search node. This is really only useful if you want to write code that iterates over the entire search tree as opposed to looking up a specific IP address. ```c typedef struct MMDB_search_node_s { uint64_t left_record; uint64_t right_record; } MMDB_search_node_s; ``` # STATUS CODES This library returns (or populates) status codes for many functions. These status codes are: * `MMDB_SUCCESS` - everything worked * `MMDB_FILE_OPEN_ERROR` - there was an error trying to open the MaxMind DB file. * `MMDB_IO_ERROR` - an IO operation failed. Check `errno` for more details. * `MMDB_CORRUPT_SEARCH_TREE_ERROR` - looking up an IP address in the search tree gave us an impossible result. The database is damaged or was generated incorrectly or there is a bug in the libmaxminddb code. * `MMDB_INVALID_METADATA_ERROR` - something in the database is wrong. This includes missing metadata keys as well as impossible values (like an `ip_version` of 7). * `MMDB_UNKNOWN_DATABASE_FORMAT_ERROR` - The database metadata indicates that it's major version is not 2. This library can only handle major version 2. * `MMDB_OUT_OF_MEMORY_ERROR` - a memory allocation call (`malloc`, etc.) failed. * `MMDB_INVALID_DATA_ERROR` - an entry in the data section contains invalid data. For example, a `uint16` field is claiming to be more than 2 bytes long. The database is probably damaged or was generated incorrectly. * `MMDB_INVALID_LOOKUP_PATH_ERROR` - The lookup path passed to `MMDB_get_value`, `MMDB_vget_value`, or `MMDB_aget_value` contains an array offset that is negative integer or an integer larger than LONG_MAX. * `MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR` - The lookup path passed to `MMDB_get_value`,`MMDB_vget_value`, or `MMDB_aget_value` does not match the data structure for the entry. There are number of reasons this can happen. The lookup path could include a key not in a map. The lookup path could include an array index larger than an array. It can also happen when the path expect to find a map or array where none exist. All status codes should be treated as `int` values. ## `MMDB_strerror()` ```c const char *MMDB_strerror(int error_code) ``` This function takes a status code and returns an English string explaining the status. # FUNCTIONS This library provides the following exported functions: ## `MMDB_open()` ```c int MMDB_open( const char *const filename, uint32_t flags, MMDB_s *const mmdb); ``` This function opens a handle to a MaxMind DB file. Its return value is a status code as defined above. Always check this call's return value. ```c MMDB_s mmdb; int status = MMDB_open("/path/to/file.mmdb", MMDB_MODE_MMAP, &mmdb); if (MMDB_SUCCESS != status) { ... } ... MMDB_close(&mmdb); ``` The `MMDB_s` structure you pass in can be on the stack or allocated from the heap. However, if the open is successful it will contain heap-allocated data, so you need to close it with `MMDB_close()`. If the status returned is not `MMDB_SUCCESS` then this library makes sure that all allocated memory is freed before returning. The flags currently provided are: * `MMDB_MODE_MMAP` - open the database with `mmap()`. Passing in other values for `flags` may yield unpredictable results. In the future we may add additional flags that you can bitwise-or together with the mode, as well as additional modes. You can also pass `0` as the `flags` value in which case the database will be opened with the default flags. However, these defaults may change in future releases. The current default is `MMDB_MODE_MMAP`. ## `MMDB_close()` ```c void MMDB_close(MMDB_s *const mmdb); ``` This frees any allocated or mmap'd memory that is held from the `MMDB_s` structure. *It does not free the memory allocated for the structure itself!* If you allocated the structure from the heap then you are responsible for freeing it. ## `MMDB_lookup_string()` ```c MMDB_lookup_result_s MMDB_lookup_string( MMDB_s *const mmdb, const char *const ipstr, int *const gai_error, int *const mmdb_error); ``` This function looks up an IP address that is passed in as a null-terminated string. Internally it calls `getaddrinfo()` to resolve the address into a binary form. It then calls `MMDB_lookup_sockaddr()` to look the address up in the database. If you have already resolved an address you can call `MMDB_lookup_sockaddr()` directly, rather than resolving the address twice. ```c int gai_error, mmdb_error; MMDB_lookup_result_s result = MMDB_lookup_string(mmdb, "1.2.3.4", &gai_error, &mmdb_error); if (0 != gai_error) { ... } if (MMDB_SUCCESS != mmdb_error) { ... } if (result.found_entry) { ... } ``` This function always returns an `MMDB_lookup_result_s` structure, but you should also check the `gai_error` and `mmdb_error` parameters. If either of these indicates an error then the returned structure is meaningless. If no error occurred you still need to make sure that the `found_entry` member in the returned result is true. If it's not, this means that the IP address does not have an entry in the database. This function will work with IPv4 addresses even when the database contains data for both IPv4 and IPv6 addresses. The IPv4 address will be looked up as '::xxx.xxx.xxx.xxx' rather than being remapped to the `::ffff:xxx.xxx.xxx.xxx` block allocated for IPv4-mapped IPv6 addresses. If you pass an IPv6 address to a database with only IPv4 data then the `found_entry` member will be false, but the `mmdb_error` status will still be `MMDB_SUCCESS`. ## `MMDB_lookup_sockaddr()` ```c MMDB_lookup_result_s MMDB_lookup_sockaddr( MMDB_s *const mmdb, const struct sockaddr *const sockaddr, int *const mmdb_error); ``` This function looks up an IP address that has already been resolved by `getaddrinfo()`. Other than not calling `getaddrinfo()` itself, this function is identical to the `MMDB_lookup_string()` function. ```c int mmdb_error; MMDB_lookup_result_s result = MMDB_lookup_sockaddr(mmdb, address->ai_addr, &mmdb_error); if (MMDB_SUCCESS != mmdb_error) { ... } if (result.found_entry) { ... } ``` ## Data Lookup Functions There are three functions for looking up data associated with an IP address. ```c int MMDB_get_value( MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, ...); int int MMDB_vget_value( MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, va_list va_path); int MMDB_aget_value( MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, const char *const *const path); ``` The three functions allow three slightly different calling styles, but they all do the same thing. The first parameter is an `MMDB_entry_s` value. In most cases this will come from the `MMDB_lookup_result_s` value returned by `MMDB_lookup_string()` or `MMDB_lookup_sockaddr()`. The second parameter is a reference to an `MMDB_entry_data_s` structure. This will be populated with the data that is being looked up, if any is found. If nothing is found, then the `has_data` member of this structure will be false. If `has_data` is true then you can look at the `data_type` member. The final parameter is a lookup path. The path consists of a set of strings representing either map keys (e.g, "city") or array indexes (e.g., "0", "1") to use in the lookup. This allow you to navigate a complex data structure. For example, given this example: ```js { "names": { "en": "Germany", "de": "Deutschland" }, "cities": [ "Berlin", "Frankfurt" ] } ``` We could look up the English name with this code: ```c MMDB_lookup_result_s result = MMDB_lookup_sockaddr(mmdb, address->ai_addr, &mmdb_error); MMDB_entry_data_s entry_data; int status = MMDB_get_value(&result.entry, &entry_data, "names", "en", NULL); if (MMDB_SUCCESS != status) { ... } if (entry_data.has_data) { ... } ``` If we wanted to find the first city the lookup path would be `"cities", "0"`. If you don't provide a lookup path at all, you'll get the entry which corresponds to the top level map. The lookup path must always end with `NULL`, regardless of which function you call. The `MMDB_get_value` function takes a variable number of arguments. All of the arguments after the `MMDB_entry_data_s *` structure pointer are the lookup path. The last argument must be `NULL`. The `MMDB_vget_value` function accepts a `va_list` as the lookup path. The last element retrieved by `va_arg()` must be `NULL`. Finally, the `MMDB_aget_value` accepts an array of strings as the lookup path. The last member of this array must be `NULL`. If you want to get all of the entry data at once you can call `MMDB_get_entry_data_list()` instead. For each of the three functions, the return value is a status code as defined above. ## `MMDB_get_entry_data_list()` ```c int MMDB_get_entry_data_list( MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list); ``` This function allows you to get all of the data for a complex data structure at once, rather than looking up each piece using repeated calls to `MMDB_get_value()`. ```c MMDB_lookup_result_s result = MMDB_lookup_sockaddr(mmdb, address->ai_addr, &mmdb_error); MMDB_entry_data_list_s *entry_data_list, *first; int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); if (MMDB_SUCCESS != status) { ... } // save this so we can free this data later first = entry_data_list; while (1) { MMDB_entry_data_list_s *next = entry_data_list = entry_data_list->next; if (NULL == next) { break; } switch (next->entry_data.type) { case MMDB_DATA_TYPE_MAP: { ... } case MMDB_DATA_TYPE_UTF8_STRING: { ... } ... } } MMDB_free_entry_data_list(first); ``` It's up to you to interpret the `entry_data_list` data structure. The list is linked in a depth-first traversal. Let's use this structure as an example: ```js { "names": { "en": "Germany", "de": "Deutschland" }, "cities": [ "Berlin", "Frankfurt" ] } ``` The list will consist of the following items: 1. MAP - top level map 2. UTF8_STRING - "names" key 3. MAP - map for "names" key 4. UTF8_STRING - "en" key 5. UTF8_STRING - value for "en" key 6. UTF8_STRING - "de" key 7. UTF8_STRING - value for "de" key 8. UTF8_STRING - "cities" key 9. ARRAY - value for "cities" key 10. UTF8_STRING - array[0] 11. UTF8_STRING - array[1] The return value of the function is a status code as defined above. ## `MMDB_free_entry_data_list()` ```c void MMDB_free_entry_data_list( MMDB_entry_data_list_s *const entry_data_list); ``` The `MMDB_get_entry_data_list()` and `MMDB_get_metadata_as_entry_data_list()` functions will allocate the linked list structure from the heap. Call this function to free the `MMDB_entry_data_list_s` structure. ## `MMDB_get_metadata_as_entry_data_list()` ```c int MMDB_get_metadata_as_entry_data_list( MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list); ``` This function allows you to retrieve the database metadata as a linked list of `MMDB_entry_data_list_s` structures. This can be a more convenient way to deal with the metadata than using the metadata structure directly. ```c MMDB_entry_data_list_s *entry_data_list, *first; int status = MMDB_get_metadata_as_entry_data_list(mmdb, &entry_data_list); if (MMDB_SUCCESS != status) { ... } first = entry_data_list; ... // do something with the data MMDB_free_entry_data_list(first); ``` The return value of the function is a status code as defined above. ## `MMDB_dump_entry_data_list()` ```c int MMDB_dump_entry_data_list( FILE *const stream, MMDB_entry_data_list_s *const entry_data_list, int indent); ``` This function takes a linked list of `MMDB_entry_data_list_s` structures and stringifies it to the given `stream`. The `indent` parameter is the starting indent level for the generated output. It is incremented for nested data structures (maps, array, etc.). The `stream` must be a file handle (`stdout`, etc). If your platform provides something like the GNU `open_memstream()` you can use that to capture the output as a string. The output is formatted in a JSON-ish fashion, but values are marked with their data type (except for maps and arrays which are shown with "{}" and "[]" respectively). The specific output format may change in future releases, so you should not rely on the specific formatting produced by this function. It is intended to be used to show data to users in a readable way and for debugging purposes. The return value of the function is a status code as defined above. ## `MMDB_read_node()` ```c int MMDB_read_node( MMDB_s *const mmdb, uint32_t node_number, MMDB_search_node_s *const node); ``` This reads a specific node in the search tree. The third argument is a reference to an `MMDB_search_node_s` structure that will be populated by this function. The return value is a status code. If you pass a `node_number` that is greater than the number of nodes in the database, this function will return `MMDB_INVALID_NODE_NUMBER_ERROR`, otherwise it will return `MMDB_SUCCESS`. ## `MMDB_lib_version()` ```c const char *MMDB_lib_version(void) ``` This function returns the library version as a string, something like "2.0.0". # EXAMPLE ```c #include int main(int argc, char **argv) { MMDB_s mmdb; int status = MMDB_open(fname, MMDB_MODE_MMAP, &mmdb); if (MMDB_SUCCESS != status) { fprintf(stderr, "\n Can't open %s - %s\n", fname, MMDB_strerror(status)); if (MMDB_IO_ERROR == status) { fprintf(stderr, " IO error: %s\n", strerror(errno)); } exit(1); } int gai_error, mmdb_error; MMDB_lookup_result_s result = MMDB_lookup_string(mmdb, ipstr, &gai_error, &mmdb_error); if (0 != gai_error) { fprintf(stderr, "\n Error from getaddrinfo for %s - %s\n\n", ipstr, gai_strerror(gai_error)); exit(2); } if (MMDB_SUCCESS != mmdb_error) { fprintf(stderr, "\n Got an error from libmaxminddb: %s\n\n", MMDB_strerror(mmdb_error)); exit(3); } MMDB_entry_data_list_s *entry_data_list = NULL; int exit_code = 0; if (result.found_entry) { int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); if (MMDB_SUCCESS != status) { fprintf( stderr, "Got an error looking up the entry data - %s\n", MMDB_strerror(status)); exit_code = 4; goto end; } if (NULL != entry_data_list) { MMDB_dump_entry_data_list(stdout, entry_data_list, 2); } } else { fprintf( stderr, "\n No entry for this IP address (%s) was found\n\n", ip_address); exit_code = 5; } end: MMDB_free_entry_data_list(entry_data_list); MMDB_close(&mmdb); exit(exit_code); } ``` # THREAD SAFETY This library is thread safe when compiled and linked with a thread-safe `malloc` and `free` implementation. # INSTALLATION AND SOURCE You can download the latest release of libmaxminddb [from GitHub](https://github.com/maxmind/libmaxminddb/releases). [Our GitHub repo](https://github.com/maxmind/libmaxminddb) is publicly available. Please fork it! # BUG REPORTS AND PULL REQUESTS Please report all issues to [our GitHub issue tracker](https://github.com/maxmind/libmaxminddb/issues). We welcome bug reports and pull requests. Please note that pull requests are greatly preferred over patches. # AUTHORS This library was written by Boris Zentner (bzentner@maxmind.com) and Dave Rolsky (drolsky@maxmind.com). # COPYRIGHT AND LICENSE Copyright 2013-2014 MaxMind, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. # SEE ALSO mmdblookup(1) libmaxminddb-1.0.4/doc/mmdblookup.md000066400000000000000000000045131245160621500174130ustar00rootroot00000000000000# NAME mmdblookup - a utility to look up an IP address in a MaxMind DB file # SYNOPSIS mmdblookup --file [FILE PATH] --ip [IP ADDRESS] [DATA PATH] # DESCRIPTION `mmdblookup` looks up an IP address in the specified MaxMind DB file. The record for the IP address is displayed in a JSON-like structure with type annotations. If an IP's data entry resolves to a map or array, you can provide a lookup path to only show part of that data. For example, given a JSON structure like this: ```js { "names": { "en": "Germany", "de": "Deutschland" }, "cities": [ "Berlin", "Frankfurt" ] } ``` You could look up just the English name by calling mmdblookup with a lookup path of: ```bash mmdblookup --file ... --ip ... names en ``` Or you could look up the second city in the list with: ```bash mmdblookup --file ... --ip ... cities 1 ``` Array numbering begins with zero (0). If you do not provide a path to lookup, all of the information for a given IP will be shown. # OPTIONS This application accepts the following options: -f, --file : The path to the MMDB file. Required. -i, --ip : The IP address to look up. Required. -v, --verbose : Turns on verbose output. Specifically, this causes this application to output the database metadata. --version : Print the program's version number and exit. -h, -?, --help : Show usage information. # BUG REPORTS AND PULL REQUESTS Please report all issues to [our GitHub issue tracker](https://github.com/maxmind/libmaxminddb/issues). We welcome bug reports and pull requests. Please note that pull requests are greatly preferred over patches. # AUTHORS This utility was written by Boris Zentner (bzentner@maxmind.com) and Dave Rolsky (drolsky@maxmind.com). # COPYRIGHT AND LICENSE Copyright 2013-2014 MaxMind, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. # SEE ALSO libmaxminddb(3) libmaxminddb-1.0.4/doc/release.md000066400000000000000000000014501245160621500166570ustar00rootroot00000000000000# How to Release this Library Here's what you do: ## Update the package version in configure.ac This is specified as the second argument to `AC_INIT`. This should be something like 0.5.4 or 1.0.1. ## Run `make release` to create the git tag This will create a tag based on the version in configure.ac and push it to the default remote. ## Run `make dist` to create a tarball and upload it to GitHub Go the [releases page](https://github.com/maxmind/libmaxminddb/releases) and find the tag you just pushed. Then click "Edit tag". You should change the title of the release to describe the highlights of the release. Then copy the list of changes from Changes.md into main textarea. Drag the tarball you just created to the "Attach binaries" spot on the page. Click "Update release" and you're done. libmaxminddb-1.0.4/include/000077500000000000000000000000001245160621500155735ustar00rootroot00000000000000libmaxminddb-1.0.4/include/maxminddb.h000066400000000000000000000156351245160621500177210ustar00rootroot00000000000000#ifdef __cplusplus extern "C" { #endif #ifndef MAXMINDDB_H #define MAXMINDDB_H #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200112L #endif #include #include #include #include #include #include #ifdef _WIN32 #include #include /* libmaxminddb package version from configure */ #define PACKAGE_VERSION "1.0.4" typedef ADDRESS_FAMILY sa_family_t; #if defined(_MSC_VER) /* MSVC doesn't define signed size_t, copy it from configure */ #define ssize_t int /* MSVC doesn't support restricted pointers */ #define restrict #endif #else #include #include #include #endif #define MMDB_DATA_TYPE_EXTENDED (0) #define MMDB_DATA_TYPE_POINTER (1) #define MMDB_DATA_TYPE_UTF8_STRING (2) #define MMDB_DATA_TYPE_DOUBLE (3) #define MMDB_DATA_TYPE_BYTES (4) #define MMDB_DATA_TYPE_UINT16 (5) #define MMDB_DATA_TYPE_UINT32 (6) #define MMDB_DATA_TYPE_MAP (7) #define MMDB_DATA_TYPE_INT32 (8) #define MMDB_DATA_TYPE_UINT64 (9) #define MMDB_DATA_TYPE_UINT128 (10) #define MMDB_DATA_TYPE_ARRAY (11) #define MMDB_DATA_TYPE_CONTAINER (12) #define MMDB_DATA_TYPE_END_MARKER (13) #define MMDB_DATA_TYPE_BOOLEAN (14) #define MMDB_DATA_TYPE_FLOAT (15) /* flags for open */ #define MMDB_MODE_MMAP (1) #define MMDB_MODE_MASK (7) /* error codes */ #define MMDB_SUCCESS (0) #define MMDB_FILE_OPEN_ERROR (1) #define MMDB_CORRUPT_SEARCH_TREE_ERROR (2) #define MMDB_INVALID_METADATA_ERROR (3) #define MMDB_IO_ERROR (4) #define MMDB_OUT_OF_MEMORY_ERROR (5) #define MMDB_UNKNOWN_DATABASE_FORMAT_ERROR (6) #define MMDB_INVALID_DATA_ERROR (7) #define MMDB_INVALID_LOOKUP_PATH_ERROR (8) #define MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR (9) #define MMDB_INVALID_NODE_NUMBER_ERROR (10) #define MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR (11) #if !(MMDB_UINT128_IS_BYTE_ARRAY) #if MMDB_UINT128_USING_MODE typedef unsigned int mmdb_uint128_t __attribute__ ((__mode__(TI))); #else typedef unsigned __int128 mmdb_uint128_t; #endif #endif /* This is a pointer into the data section for a given IP address lookup */ typedef struct MMDB_entry_s { struct MMDB_s *mmdb; uint32_t offset; } MMDB_entry_s; typedef struct MMDB_lookup_result_s { bool found_entry; MMDB_entry_s entry; uint16_t netmask; } MMDB_lookup_result_s; typedef struct MMDB_entry_data_s { bool has_data; union { uint32_t pointer; const char *utf8_string; double double_value; const uint8_t *bytes; uint16_t uint16; uint32_t uint32; int32_t int32; uint64_t uint64; #if MMDB_UINT128_IS_BYTE_ARRAY uint8_t uint128[16]; #else mmdb_uint128_t uint128; #endif bool boolean; float float_value; }; /* This is a 0 if a given entry cannot be found. This can only happen * when a call to MMDB_(v)get_value() asks for hash keys or array * indices that don't exist. */ uint32_t offset; /* This is the next entry in the data section, but it's really only * relevant for entries that part of a larger map or array * struct. There's no good reason for an end user to look at this * directly. */ uint32_t offset_to_next; /* This is only valid for strings, utf8_strings or binary data */ uint32_t data_size; /* This is an MMDB_DATA_TYPE_* constant */ uint32_t type; } MMDB_entry_data_s; /* This is the return type when someone asks for all the entry data in a map or array */ typedef struct MMDB_entry_data_list_s { MMDB_entry_data_s entry_data; struct MMDB_entry_data_list_s *next; } MMDB_entry_data_list_s; typedef struct MMDB_description_s { const char *language; const char *description; } MMDB_description_s; typedef struct MMDB_metadata_s { uint32_t node_count; uint16_t record_size; uint16_t ip_version; const char *database_type; struct { size_t count; const char **names; } languages; uint16_t binary_format_major_version; uint16_t binary_format_minor_version; uint64_t build_epoch; struct { size_t count; MMDB_description_s **descriptions; } description; } MMDB_metadata_s; typedef struct MMDB_ipv4_start_node_s { uint16_t netmask; uint32_t node_value; } MMDB_ipv4_start_node_s; typedef struct MMDB_s { uint32_t flags; const char *filename; ssize_t file_size; const uint8_t *file_content; const uint8_t *data_section; uint32_t data_section_size; const uint8_t *metadata_section; uint32_t metadata_section_size; uint16_t full_record_byte_size; uint16_t depth; MMDB_ipv4_start_node_s ipv4_start_node; MMDB_metadata_s metadata; } MMDB_s; typedef struct MMDB_search_node_s { uint64_t left_record; uint64_t right_record; } MMDB_search_node_s; /* *INDENT-OFF* */ /* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */ extern int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb); extern MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb, const char *const ipstr, int *const gai_error, int *const mmdb_error); extern MMDB_lookup_result_s MMDB_lookup_sockaddr( MMDB_s *const mmdb, const struct sockaddr *const sockaddr, int *const mmdb_error); extern int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number, MMDB_search_node_s *const node); extern int MMDB_get_value(MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, ...); extern int MMDB_vget_value(MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, va_list va_path); extern int MMDB_aget_value(MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, const char *const *const path); extern int MMDB_get_metadata_as_entry_data_list( MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list); extern int MMDB_get_entry_data_list( MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list); extern void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list); extern void MMDB_close(MMDB_s *const mmdb); extern const char *MMDB_lib_version(void); extern int MMDB_dump_entry_data_list(FILE *const stream, MMDB_entry_data_list_s *const entry_data_list, int indent); extern const char *MMDB_strerror(int error_code); /* --prototypes end - don't remove this comment-- */ /* *INDENT-ON* */ #endif /* MAXMINDDB_H */ #ifdef __cplusplus } #endif libmaxminddb-1.0.4/include/maxminddb_config.h.in000066400000000000000000000006411245160621500216420ustar00rootroot00000000000000#ifndef MAXMINDDB_CONFIG_H #define MAXMINDDB_CONFIG_H #ifndef MMDB_UINT128_USING_MODE /* Define as 1 if we we use unsigned int __atribute__ ((__mode__(TI))) for uint128 values */ #define MMDB_UINT128_USING_MODE 0 #endif #ifndef MMDB_UINT128_IS_BYTE_ARRAY /* Define as 1 if we don't have an unsigned __int128 type */ #undef MMDB_UINT128_IS_BYTE_ARRAY #endif #endif /* MAXMINDDB_CONFIG_H */ libmaxminddb-1.0.4/projects/000077500000000000000000000000001245160621500160015ustar00rootroot00000000000000libmaxminddb-1.0.4/projects/VS12-tests/000077500000000000000000000000001245160621500176345ustar00rootroot00000000000000libmaxminddb-1.0.4/projects/VS12-tests/bad_pointers.vcxproj000066400000000000000000000122111245160621500237170ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj bad_pointers test_bad_pointers Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/basic_lookup.vcxproj000066400000000000000000000122111245160621500237200ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11C512-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj basic_lookup test_basic_lookup Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/data_entry_list.vcxproj000066400000000000000000000122221245160621500244350ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11C882-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj data_entry_list test_data_entry_list Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/data_types.vcxproj000066400000000000000000000122031245160621500234040ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj data_types test_data_types Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/dump.vcxproj000066400000000000000000000121611245160621500222170ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj dump test_dump Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/get_value.vcxproj000066400000000000000000000122001245160621500232170ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj get_value test_get_value Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/get_value_pointer_bug.vcxproj000066400000000000000000000122441245160621500256240ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj get_value_pointer_bug test_get_value_pointer_bug Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/ipv4_start_cache.vcxproj000066400000000000000000000122251245160621500244750ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11D930-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj ipv4_start_cache test_ipv4_start_cache Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/ipv6_lookup_in_ipv4.vcxproj000066400000000000000000000122361245160621500251620ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj ipv6_lookup_in_ipv4 test_ipv6_lookup_in_ipv4 Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/libtap.vcxproj000066400000000000000000000076041245160621500225330ustar00rootroot00000000000000 Debug Win32 Release Win32 {4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA} Win32Proj libtap StaticLibrary true Unicode v120 StaticLibrary false true Unicode v120 $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) /Z7 %(AdditionalOptions) Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) Windows true true true libmaxminddb-1.0.4/projects/VS12-tests/maxminddb_test_helper.vcxproj000066400000000000000000000124301245160621500256120ustar00rootroot00000000000000 Debug Win32 Release Win32 {A8F568F6-5507-4EC2-A834-F2C0A3C635A5} Win32Proj ConsoleApplication1 test_maxminddb_test_helper StaticLibrary true v120 Unicode Application false v120 true Unicode true false NotUsing Level3 Disabled WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} true true true true false {82953bda-2960-4ada-a6d5-92e65ccb4a3d} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/metadata.vcxproj000066400000000000000000000121751245160621500230370ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj metadata test_metadata Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/no_map_get_value.vcxproj000066400000000000000000000122251245160621500245570ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj no_map_get_value test_no_map_get_value Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/read_node.vcxproj000066400000000000000000000122001245160621500231640ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj read_node test_read_node Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/shared.vcxproj000066400000000000000000000121651245160621500225240ustar00rootroot00000000000000 Debug Win32 Release Win32 {A8F568F6-5507-4EC2-A834-F2C0A3C635A5} Win32Proj ConsoleApplication1 test_maxminddb_test_helper StaticLibrary true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false NotUsing Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap /FS %(AdditionalOptions) Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {82953bda-2960-4ada-a6d5-92e65ccb4a3d} true true true true false {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} libmaxminddb-1.0.4/projects/VS12-tests/threads.vcxproj000066400000000000000000000117671245160621500227170ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11E9FC-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj threads test_threads Application true v120 Unicode Application false v120 true Unicode true false Level3 Disabled WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12-tests/version.vcxproj000066400000000000000000000121721245160621500227410ustar00rootroot00000000000000 Debug Win32 Release Win32 {8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2} Win32Proj version test_version Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/projects/VS12/000077500000000000000000000000001245160621500164745ustar00rootroot00000000000000libmaxminddb-1.0.4/projects/VS12/README.md000066400000000000000000000053671245160621500177660ustar00rootroot00000000000000# Project Notes DO NOT modify project settings for each configuration and/or platform on a per-project basis. Use property sheets to set shared configuration properties. The rule of thumb - if you set same value for the same property in more than one configuration or platform, you did it wrong. ## libmaxminddb.props This is the base property sheet for libMaxMindDB project. It contains settings that are shared between all configurations, such as compiler warning level, not using link-time code generation, etc. In order to minimize the number of property sheet files, this propery sheet also contains settings for Win32 and Debug configurations, which are overridden by the x64 and Release property sheets described below. ## libmaxminddb-release.props This property sheet contains all Release settings and is shared between Win32 and x64 release builds. It must be located higher than the base property sheet in the property Manager window for each configuration where it's used (i.e. Release|Win32 and Release|x64). ## libmaxminddb-x64.props This property sheet contains all x64 settings and is shared between all Debug and Release x64 configurations. It must be located higher than the base property sheet in the property Manager window for each configuration where it's used (i.e. Debug|x64 and Release|x64). ## Adding More Projects If you want to add more projects into this solution, follow the same logic and create their own property sheets. Do not use libmaxminddb property sheets in those projects because it will interfere with their intermediate directories. Instead, copy and rename libmaxminddb property sheets as a starting point. DO NOT add libmaxminddb.lib to the Additional Dependencies box of command line tools or any other libraries you built, for that matter. This box is only for standard Windows libraries. Instead, add libmaxminddb as a reference to all command line tool projects. Do the same for any other library projects you added to this solutionn. For external 3rd-party .lib files, create a solution folder called Libraries and add Debug, Debug64, Release, Release64 subfolders, then drag and drop all versinos of .lib to their respective folders and use Exclude From Build in each library file's property to assign them to the proper build confguration. Unused libraries will be shown with a traffic stop sign in each configuration. If you have a lot of projects, it might be easier to do this by editing .vcxproj and .vcxproj.filters in a text editor. # Tests To use the tests, you must download the `libtap` and `maxmind-db` submodules. This can be done by running `git submodule update --init --recursive` from the Git checkout. Each test source file has a separate project. Once compiled, the tests must be run from the base directory of the checkout. libmaxminddb-1.0.4/projects/VS12/libmaxminddb-release.props000066400000000000000000000016431245160621500236350ustar00rootroot00000000000000 MaxSpeed AnySuitable true Speed true libmaxminddb-1.0.4/projects/VS12/libmaxminddb-x64.props000066400000000000000000000007151245160621500226350ustar00rootroot00000000000000 $(SolutionDir)$(Platform)\$(Configuration)\obj\ MachineX64 libmaxminddb-1.0.4/projects/VS12/libmaxminddb.props000066400000000000000000000025641245160621500222220ustar00rootroot00000000000000 $(SolutionDir)$(Configuration)\obj\ ..\..\include _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) ProgramDatabase Level3 false $(OutDir)vc$(PlatformToolsetVersion).pdb Disabled Disabled false false if NOT EXIST (..\..\include\maxminddb_config.h) ( copy maxminddb_config.h ..\..\include\maxminddb_config.h ) MachineX86 false libmaxminddb-1.0.4/projects/VS12/libmaxminddb.sln000066400000000000000000000247401245160621500216530ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmaxminddb", "libmaxminddb.vcxproj", "{82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_basic_lookup", "..\VS12-tests\basic_lookup.vcxproj", "{8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_data_entry_list", "..\VS12-tests\data_entry_list.vcxproj", "{8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_data_types", "..\VS12-tests\data_types.vcxproj", "{8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_dump", "..\VS12-tests\dump.vcxproj", "{8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_get_value", "..\VS12-tests\get_value.vcxproj", "{8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_get_value_pointer_bug", "..\VS12-tests\get_value_pointer_bug.vcxproj", "{8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_ipv4_start_cache", "..\VS12-tests\ipv4_start_cache.vcxproj", "{8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_ipv6_lookup_in_ipv4", "..\VS12-tests\ipv6_lookup_in_ipv4.vcxproj", "{8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtap", "..\VS12-tests\libtap.vcxproj", "{4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_metadata", "..\VS12-tests\metadata.vcxproj", "{8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_no_map_get_value", "..\VS12-tests\no_map_get_value.vcxproj", "{8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_read_node", "..\VS12-tests\read_node.vcxproj", "{8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_maxminddb_test_helper", "..\VS12-tests\shared.vcxproj", "{A8F568F6-5507-4EC2-A834-F2C0A3C635A5}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_version", "..\VS12-tests\version.vcxproj", "{8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_bad_pointers", "..\VS12-tests\bad_pointers.vcxproj", "{8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Debug|Win32.ActiveCfg = Debug|Win32 {82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Debug|Win32.Build.0 = Debug|Win32 {82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Debug|x64.ActiveCfg = Debug|x64 {82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Debug|x64.Build.0 = Debug|x64 {82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Release|Win32.ActiveCfg = Release|Win32 {82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Release|Win32.Build.0 = Release|Win32 {82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Release|x64.ActiveCfg = Release|x64 {82953BDA-2960-4ADA-A6D5-92E65CCB4A3D}.Release|x64.Build.0 = Release|x64 {8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11C512-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11C882-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11CBD4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11CEEA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11D5E8-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11D2AA-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11D930-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11DC64-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Debug|Win32.ActiveCfg = Debug|Win32 {4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Debug|Win32.Build.0 = Debug|Win32 {4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Debug|x64.ActiveCfg = Debug|Win32 {4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Release|Win32.ActiveCfg = Release|Win32 {4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Release|Win32.Build.0 = Release|Win32 {4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA}.Release|x64.ActiveCfg = Release|Win32 {8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11DFC0-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11E33A-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11E68C-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Debug|Win32.ActiveCfg = Debug|Win32 {A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Debug|Win32.Build.0 = Debug|Win32 {A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Debug|x64.ActiveCfg = Debug|Win32 {A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Release|Win32.ActiveCfg = Release|Win32 {A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Release|Win32.Build.0 = Release|Win32 {A8F568F6-5507-4EC2-A834-F2C0A3C635A5}.Release|x64.ActiveCfg = Release|Win32 {8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11ED26-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 {8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.ActiveCfg = Debug|Win32 {8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|Win32.Build.0 = Debug|Win32 {8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Debug|x64.ActiveCfg = Debug|Win32 {8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.ActiveCfg = Release|Win32 {8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|Win32.Build.0 = Release|Win32 {8E11BAF4-7B63-11E4-AE98-6B41E8A9DDB2}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal libmaxminddb-1.0.4/projects/VS12/libmaxminddb.vcxproj000066400000000000000000000146631245160621500225550ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 {82953BDA-2960-4ADA-A6D5-92E65CCB4A3D} Win32Proj libmaxminddb StaticLibrary true v120 Unicode StaticLibrary true v120 Unicode StaticLibrary false v120 true Unicode StaticLibrary false v120 true Unicode $(ProjectName)d $(ProjectName)d WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) Windows true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) Windows true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) Windows true true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) Windows true true true libmaxminddb-1.0.4/projects/VS12/libmaxminddb.vcxproj.filters000066400000000000000000000015711245160621500242160ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd Source Files Header Files libmaxminddb-1.0.4/projects/VS12/maxminddb_config.h000066400000000000000000000006441245160621500221410ustar00rootroot00000000000000#ifndef MAXMINDDB_CONFIG_H #define MAXMINDDB_CONFIG_H #ifndef MMDB_UINT128_USING_MODE /* Define as 1 if we we use unsigned int __atribute__ ((__mode__(TI))) for uint128 values */ #define MMDB_UINT128_USING_MODE 0 #endif #ifndef MMDB_UINT128_IS_BYTE_ARRAY /* Define as 1 if we don't have an unsigned __int128 type */ #define MMDB_UINT128_IS_BYTE_ARRAY 1 #endif #endif /* MAXMINDDB_CONFIG_H */ libmaxminddb-1.0.4/projects/test.vcxproj.template000066400000000000000000000121461245160621500222130ustar00rootroot00000000000000 Debug Win32 Release Win32 {%UUID%} Win32Proj %TESTNAME% test_%TESTNAME% Application true v120 Unicode Application false v120 true Unicode true $(Configuration)\$(ProjectName)\ false $(Configuration)\$(ProjectName)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) $(SolutionDir)\..\..\include;$(SolutionDir)\..\..\t\libtap Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies) Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true {4dfc985a-83d7-4e61-85fe-c6ea6e43e3aa} {82953bda-2960-4ada-a6d5-92e65ccb4a3d} {a8f568f6-5507-4ec2-a834-f2c0a3c635a5} true true true true false libmaxminddb-1.0.4/src/000077500000000000000000000000001245160621500147375ustar00rootroot00000000000000libmaxminddb-1.0.4/src/Makefile.am000066400000000000000000000003141245160621500167710ustar00rootroot00000000000000include $(top_srcdir)/common.mk lib_LTLIBRARIES = libmaxminddb.la libmaxminddb_la_SOURCES = maxminddb.c libmaxminddb_la_LDFLAGS = -version-info 0:7:0 include_HEADERS = $(top_srcdir)/include/maxminddb.h libmaxminddb-1.0.4/src/maxminddb-compat-util.h000066400000000000000000000144351245160621500213160ustar00rootroot00000000000000#include #include /* *INDENT-OFF* */ /* The memmem, strdup, and strndup functions were all copied from the * FreeBSD source, along with the relevant copyright notice. * * It'd be nicer to simply use the functions available on the system if they * exist, but there doesn't seem to be a good way to detect them without also * defining things like _GNU_SOURCE, which we want to avoid, because then we * end up _accidentally_ using GNU features without noticing, which then * breaks on systems like OSX. * * C is fun! */ /* Applies to memmem implementation */ /*- * Copyright (c) 2005 Pascal Gloor * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ static void * mmdb_memmem(const void *l, size_t l_len, const void *s, size_t s_len) { register char *cur, *last; const char *cl = (const char *)l; const char *cs = (const char *)s; /* we need something to compare */ if (l_len == 0 || s_len == 0) return NULL; /* "s" must be smaller or equal to "l" */ if (l_len < s_len) return NULL; /* special case where s_len == 1 */ if (s_len == 1) return memchr(l, (int)*cs, l_len); /* the last position where its possible to find "s" in "l" */ last = (char *)cl + l_len - s_len; for (cur = (char *)cl; cur <= last; cur++) if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0) return cur; return NULL; } /* Applies to strnlen implementation */ /*- * Copyright (c) 2009 David Schultz * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ static size_t mmdb_strnlen(const char *s, size_t maxlen) { size_t len; for (len = 0; len < maxlen; len++, s++) { if (!*s) break; } return (len); } /* Applies to strdup and strndup implementation */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ static char * mmdb_strdup(const char *str) { size_t len; char *copy; len = strlen(str) + 1; if ((copy = malloc(len)) == NULL) return (NULL); memcpy(copy, str, len); return (copy); } static char * mmdb_strndup(const char *str, size_t n) { size_t len; char *copy; len = mmdb_strnlen(str, n); if ((copy = malloc(len + 1)) == NULL) return (NULL); memcpy(copy, str, len); copy[len] = '\0'; return (copy); } /* *INDENT-ON* */ libmaxminddb-1.0.4/src/maxminddb.c000066400000000000000000001622061245160621500170550ustar00rootroot00000000000000#if HAVE_CONFIG_H #include #endif #include "maxminddb.h" #include "maxminddb-compat-util.h" #include #include #include #include #include #include #ifdef _WIN32 #include #include #else #include #include #include #endif #define MMDB_DATA_SECTION_SEPARATOR (16) #ifdef MMDB_DEBUG #define LOCAL #define NO_PROTO #define DEBUG_FUNC #define DEBUG_MSG(msg) fprintf(stderr, msg "\n") #define DEBUG_MSGF(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__) #define DEBUG_BINARY(fmt, byte) \ do { \ char *binary = byte_to_binary(byte); \ if (NULL == binary) { \ fprintf(stderr, "Malloc failed in DEBUG_BINARY\n"); \ abort(); \ } \ fprintf(stderr, fmt "\n", binary); \ free(binary); \ } while (0) #define DEBUG_NL fprintf(stderr, "\n") #else #define LOCAL static #define NO_PROTO static #define DEBUG_MSG(...) #define DEBUG_MSGF(...) #define DEBUG_BINARY(...) #define DEBUG_NL #endif #ifdef MMDB_DEBUG DEBUG_FUNC char *byte_to_binary(uint8_t byte) { char *bits = malloc(sizeof(char) * 9); if (NULL == bits) { return bits; } for (uint8_t i = 0; i < 8; i++) { bits[i] = byte & (128 >> i) ? '1' : '0'; } bits[8] = '\0'; return bits; } DEBUG_FUNC char *type_num_to_name(uint8_t num) { switch (num) { case 0: return "extended"; case 1: return "pointer"; case 2: return "utf8_string"; case 3: return "double"; case 4: return "bytes"; case 5: return "uint16"; case 6: return "uint32"; case 7: return "map"; case 8: return "int32"; case 9: return "uint64"; case 10: return "uint128"; case 11: return "array"; case 12: return "container"; case 13: return "end_marker"; case 14: return "boolean"; case 15: return "float"; default: return "unknown type"; } } #endif typedef struct record_info_s { uint16_t record_length; uint32_t (*left_record_getter)(const uint8_t *); uint32_t (*right_record_getter)(const uint8_t *); uint8_t right_record_offset; } record_info_s; #define METADATA_MARKER "\xab\xcd\xefMaxMind.com" /* This is 128kb */ #define METADATA_BLOCK_MAX_SIZE 131072 /* *INDENT-OFF* */ /* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */ LOCAL const uint8_t *find_metadata(const uint8_t *file_content, ssize_t file_size, uint32_t *metadata_size); LOCAL int read_metadata(MMDB_s *mmdb); LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb); LOCAL uint16_t value_for_key_as_uint16(MMDB_entry_s *start, char *key); LOCAL uint32_t value_for_key_as_uint32(MMDB_entry_s *start, char *key); LOCAL uint64_t value_for_key_as_uint64(MMDB_entry_s *start, char *key); LOCAL char *value_for_key_as_string(MMDB_entry_s *start, char *key); LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, MMDB_entry_s *metadata_start); LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, MMDB_entry_s *metadata_start); LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses); LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, sa_family_t address_family, MMDB_lookup_result_s *result); LOCAL record_info_s record_info_for_database(MMDB_s *mmdb); LOCAL MMDB_ipv4_start_node_s find_ipv4_start_node(MMDB_s *mmdb); LOCAL int populate_result(MMDB_s *mmdb, uint32_t node_count, uint32_t value, uint16_t netmask, MMDB_lookup_result_s *result); LOCAL uint32_t get_left_28_bit_record(const uint8_t *record); LOCAL uint32_t get_right_28_bit_record(const uint8_t *record); LOCAL int path_length(va_list va_path); LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb, MMDB_entry_data_s *entry_data); LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb, MMDB_entry_data_s *entry_data); LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data); LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset, MMDB_entry_data_s *entry_data); LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, MMDB_entry_data_s *entry_data); LOCAL int get_ext_type(int raw_ext_type); LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, int ptr_size); LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, MMDB_entry_data_list_s *const entry_data_list); LOCAL float get_ieee754_float(const uint8_t *restrict p); LOCAL double get_ieee754_double(const uint8_t *restrict p); LOCAL uint32_t get_uint32(const uint8_t *p); LOCAL uint32_t get_uint24(const uint8_t *p); LOCAL uint32_t get_uint16(const uint8_t *p); LOCAL uint64_t get_uintX(const uint8_t *p, int length); LOCAL int32_t get_sintX(const uint8_t *p, int length); LOCAL MMDB_entry_data_list_s *new_entry_data_list(void); LOCAL void free_mmdb_struct(MMDB_s *const mmdb); LOCAL void free_languages_metadata(MMDB_s *mmdb); LOCAL void free_descriptions_metadata(MMDB_s *mmdb); LOCAL MMDB_entry_data_list_s *dump_entry_data_list( FILE *stream, MMDB_entry_data_list_s *entry_data_list, int indent, int *status); LOCAL void print_indentation(FILE *stream, int i); LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size); /* --prototypes end - don't remove this comment-- */ /* *INDENT-ON* */ #define CHECKED_DECODE_ONE(mmdb, offset, entry_data) \ do { \ int status = decode_one(mmdb, offset, entry_data); \ if (MMDB_SUCCESS != status) { \ return status; \ } \ } while (0) #define CHECKED_DECODE_ONE_FOLLOW(mmdb, offset, entry_data) \ do { \ int status = decode_one_follow(mmdb, offset, entry_data); \ if (MMDB_SUCCESS != status) { \ return status; \ } \ } while (0) #define FREE_AND_SET_NULL(p) { free((void *)(p)); (p) = NULL; } int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) { mmdb->file_content = NULL; mmdb->data_section = NULL; mmdb->metadata.database_type = NULL; mmdb->metadata.languages.count = 0; mmdb->metadata.description.count = 0; mmdb->filename = mmdb_strdup(filename); if (NULL == mmdb->filename) { free_mmdb_struct(mmdb); return MMDB_OUT_OF_MEMORY_ERROR; } ssize_t size; #ifdef _WIN32 HANDLE fd = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fd == INVALID_HANDLE_VALUE) { free_mmdb_struct(mmdb); return MMDB_FILE_OPEN_ERROR; } size = GetFileSize(fd, NULL); if (size == INVALID_FILE_SIZE) { free_mmdb_struct(mmdb); CloseHandle(fd); return MMDB_FILE_OPEN_ERROR; } #else int fd = open(filename, O_RDONLY); if (fd < 0) { free_mmdb_struct(mmdb); return MMDB_FILE_OPEN_ERROR; } struct stat s; if (fstat(fd, &s) ) { free_mmdb_struct(mmdb); close(fd); return MMDB_FILE_OPEN_ERROR; } size = s.st_size; #endif if ((flags & MMDB_MODE_MASK) == 0) { flags |= MMDB_MODE_MMAP; } mmdb->flags = flags; mmdb->file_size = size; #ifdef _WIN32 HANDLE mmh = CreateFileMappingA(fd, NULL, PAGE_READONLY, 0, size, NULL); uint8_t *file_content = (uint8_t *)MapViewOfFile(mmh, FILE_MAP_READ, 0, 0, 0); CloseHandle(fd); if (file_content == NULL) { CloseHandle(mmh); free_mmdb_struct(mmdb); return MMDB_IO_ERROR; } #else uint8_t *file_content = (uint8_t *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if (MAP_FAILED == file_content) { free_mmdb_struct(mmdb); return MMDB_IO_ERROR; } #endif uint32_t metadata_size = 0; const uint8_t *metadata = find_metadata(file_content, size, &metadata_size); if (NULL == metadata) { free_mmdb_struct(mmdb); return MMDB_INVALID_METADATA_ERROR; } mmdb->metadata_section = metadata; mmdb->metadata_section_size = metadata_size; int status = read_metadata(mmdb); if (MMDB_SUCCESS != status) { free_mmdb_struct(mmdb); return status; } if (mmdb->metadata.binary_format_major_version != 2) { free_mmdb_struct(mmdb); return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; } #ifdef _WIN32 WSADATA wsa; WSAStartup(MAKEWORD(2, 2), &wsa); #endif uint32_t search_tree_size = mmdb->metadata.node_count * mmdb->full_record_byte_size; mmdb->file_content = file_content; mmdb->data_section = file_content + search_tree_size; mmdb->data_section_size = mmdb->file_size - search_tree_size; mmdb->metadata_section = metadata; mmdb->ipv4_start_node.node_value = 0; mmdb->ipv4_start_node.netmask = 0; return MMDB_SUCCESS; } LOCAL const uint8_t *find_metadata(const uint8_t *file_content, ssize_t file_size, uint32_t *metadata_size) { ssize_t max_size = file_size > METADATA_BLOCK_MAX_SIZE ? METADATA_BLOCK_MAX_SIZE : file_size; uint8_t *search_area = (uint8_t *)(file_content + (file_size - max_size)); uint8_t *tmp = search_area; do { tmp = mmdb_memmem(search_area, max_size, METADATA_MARKER, strlen(METADATA_MARKER)); if (NULL != tmp) { max_size -= tmp - search_area; search_area = tmp; } } while (NULL != tmp && tmp != search_area); const uint8_t *metadata_start = search_area + strlen(METADATA_MARKER); *metadata_size = file_size - (search_area - file_content); return metadata_start; } LOCAL int read_metadata(MMDB_s *mmdb) { /* We need to create a fake MMDB_s struct in order to decode values from the metadata. The metadata is basically just like the data section, so we want to use the same functions we use for the data section to get metadata values. */ MMDB_s metadata_db = make_fake_metadata_db(mmdb); MMDB_entry_s metadata_start = { .mmdb = &metadata_db, .offset = 0 }; mmdb->metadata.node_count = value_for_key_as_uint32(&metadata_start, "node_count"); if (!mmdb->metadata.node_count) { DEBUG_MSG("could not find node_count value in metadata"); return MMDB_INVALID_METADATA_ERROR; } mmdb->metadata.record_size = value_for_key_as_uint16(&metadata_start, "record_size"); if (!mmdb->metadata.record_size) { DEBUG_MSG("could not find record_size value in metadata"); return MMDB_INVALID_METADATA_ERROR; } if (mmdb->metadata.record_size != 24 && mmdb->metadata.record_size != 28 && mmdb->metadata.record_size != 32) { DEBUG_MSGF("bad record size in metadata: %i", mmdb->metadata.record_size); return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; } mmdb->metadata.ip_version = value_for_key_as_uint16(&metadata_start, "ip_version"); if (!mmdb->metadata.ip_version) { DEBUG_MSG("could not find ip_version value in metadata"); return MMDB_INVALID_METADATA_ERROR; } if (!(mmdb->metadata.ip_version == 4 || mmdb->metadata.ip_version == 6)) { DEBUG_MSGF("ip_version value in metadata is not 4 or 6 - it was %i", mmdb->metadata.ip_version); return MMDB_INVALID_METADATA_ERROR; } mmdb->metadata.database_type = value_for_key_as_string(&metadata_start, "database_type"); if (NULL == mmdb->metadata.database_type) { DEBUG_MSG("could not find database_type value in metadata"); return MMDB_INVALID_METADATA_ERROR; } int status = populate_languages_metadata(mmdb, &metadata_db, &metadata_start); if (MMDB_SUCCESS != status) { DEBUG_MSG("could not populate languages from metadata"); return status; } mmdb->metadata.binary_format_major_version = value_for_key_as_uint16(&metadata_start, "binary_format_major_version"); if (!mmdb->metadata.binary_format_major_version) { DEBUG_MSG( "could not find binary_format_major_version value in metadata"); return MMDB_INVALID_METADATA_ERROR; } mmdb->metadata.binary_format_minor_version = value_for_key_as_uint16(&metadata_start, "binary_format_minor_version"); mmdb->metadata.build_epoch = value_for_key_as_uint64(&metadata_start, "build_epoch"); if (!mmdb->metadata.build_epoch) { DEBUG_MSG("could not find build_epoch value in metadata"); return MMDB_INVALID_METADATA_ERROR; } status = populate_description_metadata(mmdb, &metadata_db, &metadata_start); if (MMDB_SUCCESS != status) { DEBUG_MSG("could not populate description from metadata"); return status; } mmdb->full_record_byte_size = mmdb->metadata.record_size * 2 / 8U; mmdb->depth = mmdb->metadata.ip_version == 4 ? 32 : 128; return MMDB_SUCCESS; } LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb) { MMDB_s fake_metadata_db = { .data_section = mmdb->metadata_section, .data_section_size = mmdb->metadata_section_size }; return fake_metadata_db; } LOCAL uint16_t value_for_key_as_uint16(MMDB_entry_s *start, char *key) { MMDB_entry_data_s entry_data; const char *path[] = { key, NULL }; MMDB_aget_value(start, &entry_data, path); return entry_data.uint16; } LOCAL uint32_t value_for_key_as_uint32(MMDB_entry_s *start, char *key) { MMDB_entry_data_s entry_data; const char *path[] = { key, NULL }; MMDB_aget_value(start, &entry_data, path); return entry_data.uint32; } LOCAL uint64_t value_for_key_as_uint64(MMDB_entry_s *start, char *key) { MMDB_entry_data_s entry_data; const char *path[] = { key, NULL }; MMDB_aget_value(start, &entry_data, path); return entry_data.uint64; } LOCAL char *value_for_key_as_string(MMDB_entry_s *start, char *key) { MMDB_entry_data_s entry_data; const char *path[] = { key, NULL }; MMDB_aget_value(start, &entry_data, path); return mmdb_strndup((char *)entry_data.utf8_string, entry_data.data_size); } LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, MMDB_entry_s *metadata_start) { MMDB_entry_data_s entry_data; const char *path[] = { "languages", NULL }; MMDB_aget_value(metadata_start, &entry_data, path); if (MMDB_DATA_TYPE_ARRAY != entry_data.type) { return MMDB_INVALID_METADATA_ERROR; } MMDB_entry_s array_start = { .mmdb = metadata_db, .offset = entry_data.offset }; MMDB_entry_data_list_s *member; MMDB_get_entry_data_list(&array_start, &member); MMDB_entry_data_list_s *first_member = member; uint32_t array_size = member->entry_data.data_size; mmdb->metadata.languages.count = 0; mmdb->metadata.languages.names = malloc(array_size * sizeof(char *)); if (NULL == mmdb->metadata.languages.names) { return MMDB_OUT_OF_MEMORY_ERROR; } for (uint32_t i = 0; i < array_size; i++) { member = member->next; if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) { return MMDB_INVALID_METADATA_ERROR; } mmdb->metadata.languages.names[i] = mmdb_strndup((char *)member->entry_data.utf8_string, member->entry_data.data_size); if (NULL == mmdb->metadata.languages.names[i]) { return MMDB_OUT_OF_MEMORY_ERROR; } // We assign this as we go so that if we fail a malloc and need to // free it, the count is right. mmdb->metadata.languages.count = i + 1; } MMDB_free_entry_data_list(first_member); return MMDB_SUCCESS; } LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db, MMDB_entry_s *metadata_start) { MMDB_entry_data_s entry_data; const char *path[] = { "description", NULL }; MMDB_aget_value(metadata_start, &entry_data, path); if (MMDB_DATA_TYPE_MAP != entry_data.type) { return MMDB_INVALID_METADATA_ERROR; } MMDB_entry_s map_start = { .mmdb = metadata_db, .offset = entry_data.offset }; MMDB_entry_data_list_s *member; MMDB_get_entry_data_list(&map_start, &member); MMDB_entry_data_list_s *first_member = member; uint32_t map_size = member->entry_data.data_size; mmdb->metadata.description.count = 0; mmdb->metadata.description.descriptions = malloc(map_size * sizeof(MMDB_description_s *)); if (NULL == mmdb->metadata.description.descriptions) { return MMDB_OUT_OF_MEMORY_ERROR; } for (uint32_t i = 0; i < map_size; i++) { mmdb->metadata.description.descriptions[i] = malloc(sizeof(MMDB_description_s)); if (NULL == mmdb->metadata.description.descriptions[i]) { return MMDB_OUT_OF_MEMORY_ERROR; } mmdb->metadata.description.count = i + 1; mmdb->metadata.description.descriptions[i]->language = NULL; mmdb->metadata.description.descriptions[i]->description = NULL; member = member->next; if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) { return MMDB_INVALID_METADATA_ERROR; } mmdb->metadata.description.descriptions[i]->language = mmdb_strndup((char *)member->entry_data.utf8_string, member->entry_data.data_size); if (NULL == mmdb->metadata.description.descriptions[i]->language) { return MMDB_OUT_OF_MEMORY_ERROR; } member = member->next; if (MMDB_DATA_TYPE_UTF8_STRING != member->entry_data.type) { return MMDB_INVALID_METADATA_ERROR; } mmdb->metadata.description.descriptions[i]->description = mmdb_strndup((char *)member->entry_data.utf8_string, member->entry_data.data_size); if (NULL == mmdb->metadata.description.descriptions[i]->description) { return MMDB_OUT_OF_MEMORY_ERROR; } } MMDB_free_entry_data_list(first_member); return MMDB_SUCCESS; } MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb, const char *const ipstr, int *const gai_error, int *const mmdb_error) { MMDB_lookup_result_s result = { .found_entry = false, .netmask = 0, .entry = { .mmdb = mmdb, .offset = 0 } }; struct addrinfo *addresses = NULL; *gai_error = resolve_any_address(ipstr, &addresses); if (*gai_error) { if (NULL != addresses) { freeaddrinfo(addresses); } return result; } if (mmdb->metadata.ip_version == 4 && addresses->ai_addr->sa_family == AF_INET6) { *mmdb_error = MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR; freeaddrinfo(addresses); return result; } result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, mmdb_error); freeaddrinfo(addresses); return result; } LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses) { struct addrinfo hints = { .ai_socktype = SOCK_STREAM }; int gai_status; if (NULL != strchr(ipstr, ':')) { hints.ai_flags = AI_NUMERICHOST; #if defined AI_V4MAPPED && !defined __FreeBSD__ hints.ai_flags |= AI_V4MAPPED; #endif hints.ai_family = AF_INET6; } else { hints.ai_flags = AI_NUMERICHOST; hints.ai_family = AF_INET; } gai_status = getaddrinfo(ipstr, NULL, &hints, addresses); if (gai_status) { return gai_status; } return 0; } MMDB_lookup_result_s MMDB_lookup_sockaddr( MMDB_s *const mmdb, const struct sockaddr *const sockaddr, int *const mmdb_error) { MMDB_lookup_result_s result = { .found_entry = false, .netmask = 0, .entry = { .mmdb = mmdb, .offset = 0 } }; uint8_t mapped_address[16], *address; if (mmdb->metadata.ip_version == 4) { if (sockaddr->sa_family == AF_INET6) { return result; } address = (uint8_t *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr; } else { if (sockaddr->sa_family == AF_INET6) { address = (uint8_t *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr. s6_addr; } else { address = mapped_address; memset(address, 0, 12); memcpy(address + 12, &((struct sockaddr_in *)sockaddr)->sin_addr.s_addr, 4); } } *mmdb_error = find_address_in_search_tree(mmdb, address, sockaddr->sa_family, &result); return result; } LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address, sa_family_t address_family, MMDB_lookup_result_s *result) { record_info_s record_info = record_info_for_database(mmdb); if (0 == record_info.right_record_offset) { return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; } DEBUG_NL; DEBUG_MSG("Looking for address in search tree"); uint32_t node_count = mmdb->metadata.node_count; uint32_t value = 0; uint16_t max_depth0 = mmdb->depth - 1; uint16_t start_bit = max_depth0; if (mmdb->metadata.ip_version == 6 && address_family == AF_INET) { MMDB_ipv4_start_node_s ipv4_start_node = find_ipv4_start_node(mmdb); DEBUG_MSGF("IPv4 start node is %u (netmask %u)", ipv4_start_node.node_value, ipv4_start_node.netmask); /* We have an IPv6 database with no IPv4 data */ if (ipv4_start_node.node_value >= node_count) { return populate_result(mmdb, node_count, ipv4_start_node.node_value, ipv4_start_node.netmask, result); } value = ipv4_start_node.node_value; start_bit -= ipv4_start_node.netmask; } const uint8_t *search_tree = mmdb->file_content; const uint8_t *record_pointer; for (int current_bit = start_bit; current_bit >= 0; current_bit--) { uint8_t bit_is_true = address[(max_depth0 - current_bit) >> 3] & (1U << (~(max_depth0 - current_bit) & 7)) ? 1 : 0; DEBUG_MSGF("Looking at bit %i - bit's value is %i", current_bit, bit_is_true); DEBUG_MSGF(" current node = %u", value); record_pointer = &search_tree[value * record_info.record_length]; if (bit_is_true) { record_pointer += record_info.right_record_offset; value = record_info.right_record_getter(record_pointer); } else { value = record_info.left_record_getter(record_pointer); } /* Ideally we'd check to make sure that a record never points to a * previously seen value, but that's more complicated. For now, we can * at least check that we don't end up at the top of the tree again. */ if (0 == value) { DEBUG_MSGF(" %s record has a value of 0", bit_is_true ? "right" : "left"); return MMDB_CORRUPT_SEARCH_TREE_ERROR; } if (value >= node_count) { return populate_result(mmdb, node_count, value, current_bit, result); } else { DEBUG_MSGF(" proceeding to search tree node %i", value); } } DEBUG_MSG( "Reached the end of the address bits without leaving the search tree"); // We should not be able to reach this return. If we do, something very bad happened. return MMDB_CORRUPT_SEARCH_TREE_ERROR; } LOCAL record_info_s record_info_for_database(MMDB_s *mmdb) { record_info_s record_info = { .record_length = mmdb->full_record_byte_size, .right_record_offset = 0 }; if (record_info.record_length == 6) { record_info.left_record_getter = &get_uint24; record_info.right_record_getter = &get_uint24; record_info.right_record_offset = 3; } else if (record_info.record_length == 7) { record_info.left_record_getter = &get_left_28_bit_record; record_info.right_record_getter = &get_right_28_bit_record; record_info.right_record_offset = 3; } else if (record_info.record_length == 8) { record_info.left_record_getter = &get_uint32; record_info.right_record_getter = &get_uint32; record_info.right_record_offset = 4; } return record_info; } LOCAL MMDB_ipv4_start_node_s find_ipv4_start_node(MMDB_s *mmdb) { /* In a pathological case of a database with a single node search tree, * this check will be true even after we've found the IPv4 start node, but * that doesn't seem worth trying to fix. */ if (mmdb->ipv4_start_node.node_value != 0) { return mmdb->ipv4_start_node; } record_info_s record_info = record_info_for_database(mmdb); const uint8_t *search_tree = mmdb->file_content; uint32_t node_value = 0; const uint8_t *record_pointer; uint32_t netmask; for (netmask = 0; netmask < 96; netmask++) { record_pointer = &search_tree[node_value * record_info.record_length]; node_value = record_info.left_record_getter(record_pointer); /* This can happen if there's no IPv4 data _or_ if there is a subnet * with data that contains the entire IPv4 range (like ::/64) */ if (node_value >= mmdb->metadata.node_count) { break; } } mmdb->ipv4_start_node.node_value = node_value; mmdb->ipv4_start_node.netmask = netmask; return mmdb->ipv4_start_node; } LOCAL int populate_result(MMDB_s *mmdb, uint32_t node_count, uint32_t value, uint16_t netmask, MMDB_lookup_result_s *result) { uint32_t offset = value - node_count; DEBUG_MSGF(" data section offset is %i (record value = %i)", offset, value); if (offset > mmdb->data_section_size) { return MMDB_CORRUPT_SEARCH_TREE_ERROR; } result->netmask = mmdb->depth - netmask; result->entry.offset = offset; result->found_entry = result->entry.offset > 0 ? true : false; return MMDB_SUCCESS; } LOCAL uint32_t get_left_28_bit_record(const uint8_t *record) { return record[0] * 65536 + record[1] * 256 + record[2] + ((record[3] & 0xf0) << 20); } LOCAL uint32_t get_right_28_bit_record(const uint8_t *record) { uint32_t value = get_uint32(record); return value & 0xfffffff; } int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number, MMDB_search_node_s *const node) { record_info_s record_info = record_info_for_database(mmdb); if (0 == record_info.right_record_offset) { return MMDB_UNKNOWN_DATABASE_FORMAT_ERROR; } if (node_number > mmdb->metadata.node_count) { return MMDB_INVALID_NODE_NUMBER_ERROR; } const uint8_t *search_tree = mmdb->file_content; const uint8_t *record_pointer = &search_tree[node_number * record_info.record_length]; node->left_record = record_info.left_record_getter(record_pointer); record_pointer += record_info.right_record_offset; node->right_record = record_info.right_record_getter(record_pointer); return MMDB_SUCCESS; } int MMDB_get_value(MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, ...) { va_list path; va_start(path, entry_data); int status = MMDB_vget_value(start, entry_data, path); va_end(path); return status; } int MMDB_vget_value(MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, va_list va_path) { int length = path_length(va_path); const char *path_elem; int i = 0; const char **path = malloc((length + 1) * sizeof(const char *)); if (NULL == path) { return MMDB_OUT_OF_MEMORY_ERROR; } while (NULL != (path_elem = va_arg(va_path, char *))) { path[i] = path_elem; i++; } path[i] = NULL; int status = MMDB_aget_value(start, entry_data, path); free((char **)path); return status; } LOCAL int path_length(va_list va_path) { int i = 0; const char *ignore; va_list path_copy; va_copy(path_copy, va_path); while (NULL != (ignore = va_arg(path_copy, char *))) { i++; } va_end(path_copy); return i; } int MMDB_aget_value(MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, const char *const *const path) { MMDB_s *mmdb = start->mmdb; uint32_t offset = start->offset; memset(entry_data, 0, sizeof(MMDB_entry_data_s)); DEBUG_NL; DEBUG_MSG("looking up value by path"); CHECKED_DECODE_ONE_FOLLOW(mmdb, offset, entry_data); DEBUG_NL; DEBUG_MSGF("top level element is a %s", type_num_to_name(entry_data->type)); /* Can this happen? It'd probably represent a pathological case under * normal use, but there's nothing preventing someone from passing an * invalid MMDB_entry_s struct to this function */ if (!entry_data->has_data) { return MMDB_INVALID_LOOKUP_PATH_ERROR; } const char *path_elem; int i = 0; while (NULL != (path_elem = path[i++])) { DEBUG_NL; DEBUG_MSGF("path elem = %s", path_elem); /* XXX - it'd be good to find a quicker way to skip through these entries that doesn't involve decoding them completely. Basically we need to just use the size from the control byte to advance our pointer rather than calling decode_one(). */ if (entry_data->type == MMDB_DATA_TYPE_ARRAY) { int status = lookup_path_in_array(path_elem, mmdb, entry_data); if (MMDB_SUCCESS != status) { memset(entry_data, 0, sizeof(MMDB_entry_data_s)); return status; } } else if (entry_data->type == MMDB_DATA_TYPE_MAP) { int status = lookup_path_in_map(path_elem, mmdb, entry_data); if (MMDB_SUCCESS != status) { memset(entry_data, 0, sizeof(MMDB_entry_data_s)); return status; } } else { /* Once we make the code traverse maps & arrays without calling * decode_one() we can get rid of this. */ memset(entry_data, 0, sizeof(MMDB_entry_data_s)); return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR; } } return MMDB_SUCCESS; } LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb, MMDB_entry_data_s *entry_data) { uint32_t size = entry_data->data_size; char *first_invalid; int saved_errno = errno; errno = 0; int array_index = strtol(path_elem, &first_invalid, 10); if (array_index < 0 || ERANGE == errno) { errno = saved_errno; return MMDB_INVALID_LOOKUP_PATH_ERROR; } errno = saved_errno; if (*first_invalid || (uint32_t)array_index >= size) { return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR; } for (int i = 0; i < array_index; i++) { /* We don't want to follow a pointer here. If the next element is a * pointer we simply skip it and keep going */ CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); int status = skip_map_or_array(mmdb, entry_data); if (MMDB_SUCCESS != status) { return status; } } MMDB_entry_data_s value; CHECKED_DECODE_ONE_FOLLOW(mmdb, entry_data->offset_to_next, &value); memcpy(entry_data, &value, sizeof(MMDB_entry_data_s)); return MMDB_SUCCESS; } LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb, MMDB_entry_data_s *entry_data) { uint32_t size = entry_data->data_size; uint32_t offset = entry_data->offset_to_next; size_t path_elem_len = strlen(path_elem); while (size-- > 0) { MMDB_entry_data_s key, value; CHECKED_DECODE_ONE_FOLLOW(mmdb, offset, &key); uint32_t offset_to_value = key.offset_to_next; if (MMDB_DATA_TYPE_UTF8_STRING != key.type) { return MMDB_INVALID_DATA_ERROR; } if (key.data_size == path_elem_len && !memcmp(path_elem, key.utf8_string, path_elem_len)) { DEBUG_MSG("found key matching path elem"); CHECKED_DECODE_ONE_FOLLOW(mmdb, offset_to_value, &value); memcpy(entry_data, &value, sizeof(MMDB_entry_data_s)); return MMDB_SUCCESS; } else { /* We don't want to follow a pointer here. If the next element is * a pointer we simply skip it and keep going */ CHECKED_DECODE_ONE(mmdb, offset_to_value, &value); int status = skip_map_or_array(mmdb, &value); if (MMDB_SUCCESS != status) { return status; } offset = value.offset_to_next; } } memset(entry_data, 0, sizeof(MMDB_entry_data_s)); return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR; } LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data) { if (entry_data->type == MMDB_DATA_TYPE_MAP) { uint32_t size = entry_data->data_size; while (size-- > 0) { CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); // key CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); // value int status = skip_map_or_array(mmdb, entry_data); if (MMDB_SUCCESS != status) { return status; } } } else if (entry_data->type == MMDB_DATA_TYPE_ARRAY) { uint32_t size = entry_data->data_size; while (size-- > 0) { CHECKED_DECODE_ONE(mmdb, entry_data->offset_to_next, entry_data); // value int status = skip_map_or_array(mmdb, entry_data); if (MMDB_SUCCESS != status) { return status; } } } return MMDB_SUCCESS; } LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset, MMDB_entry_data_s *entry_data) { CHECKED_DECODE_ONE(mmdb, offset, entry_data); if (entry_data->type == MMDB_DATA_TYPE_POINTER) { /* The pointer could point to any part of the data section but the * next entry for this particular offset may be the one after the * pointer, not the one after whatever the pointer points to. This * depends on whether the pointer points to something that is a simple * value or a compound value. For a compound value, the next one is * the one after the pointer result, not the one after the pointer. */ uint32_t next = entry_data->offset_to_next; CHECKED_DECODE_ONE(mmdb, entry_data->pointer, entry_data); if (entry_data->type != MMDB_DATA_TYPE_MAP && entry_data->type != MMDB_DATA_TYPE_ARRAY) { entry_data->offset_to_next = next; } } return MMDB_SUCCESS; } #if !MMDB_UINT128_IS_BYTE_ARRAY NO_PROTO mmdb_uint128_t get_uint128(const uint8_t *p, int length) { mmdb_uint128_t value = 0; while (length-- > 0) { value <<= 8; value += *p++; } return value; } #endif LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset, MMDB_entry_data_s *entry_data) { const uint8_t *mem = mmdb->data_section; if (offset > mmdb->data_section_size) { return MMDB_INVALID_DATA_ERROR; } entry_data->offset = offset; entry_data->has_data = true; DEBUG_NL; DEBUG_MSGF("Offset: %i", offset); uint8_t ctrl = mem[offset++]; DEBUG_BINARY("Control byte: %s", ctrl); int type = (ctrl >> 5) & 7; DEBUG_MSGF("Type: %i (%s)", type, type_num_to_name(type)); if (type == MMDB_DATA_TYPE_EXTENDED) { type = get_ext_type(mem[offset++]); DEBUG_MSGF("Extended type: %i (%s)", type, type_num_to_name(type)); } entry_data->type = type; if (type == MMDB_DATA_TYPE_POINTER) { int psize = (ctrl >> 3) & 3; DEBUG_MSGF("Pointer size: %i", psize); entry_data->pointer = get_ptr_from(ctrl, &mem[offset], psize); DEBUG_MSGF("Pointer to: %i", entry_data->pointer); entry_data->data_size = psize + 1; entry_data->offset_to_next = offset + psize + 1; return MMDB_SUCCESS; } uint32_t size = ctrl & 31; switch (size) { case 29: size = 29 + mem[offset++]; break; case 30: size = 285 + get_uint16(&mem[offset]); offset += 2; break; case 31: size = 65821 + get_uint24(&mem[offset]); offset += 3; default: break; } DEBUG_MSGF("Size: %i", size); if (type == MMDB_DATA_TYPE_MAP || type == MMDB_DATA_TYPE_ARRAY) { entry_data->data_size = size; entry_data->offset_to_next = offset; return MMDB_SUCCESS; } if (type == MMDB_DATA_TYPE_BOOLEAN) { entry_data->boolean = size ? true : false; entry_data->data_size = 0; entry_data->offset_to_next = offset; DEBUG_MSGF("boolean value: %s", entry_data->boolean ? "true" : "false"); return MMDB_SUCCESS; } if (type == MMDB_DATA_TYPE_UINT16) { if (size > 2) { return MMDB_INVALID_DATA_ERROR; } entry_data->uint16 = (uint16_t)get_uintX(&mem[offset], size); DEBUG_MSGF("uint16 value: %u", entry_data->uint16); } else if (type == MMDB_DATA_TYPE_UINT32) { if (size > 4) { return MMDB_INVALID_DATA_ERROR; } entry_data->uint32 = (uint32_t)get_uintX(&mem[offset], size); DEBUG_MSGF("uint32 value: %u", entry_data->uint32); } else if (type == MMDB_DATA_TYPE_INT32) { if (size > 4) { return MMDB_INVALID_DATA_ERROR; } entry_data->int32 = get_sintX(&mem[offset], size); DEBUG_MSGF("int32 value: %i", entry_data->int32); } else if (type == MMDB_DATA_TYPE_UINT64) { if (size > 8) { return MMDB_INVALID_DATA_ERROR; } entry_data->uint64 = get_uintX(&mem[offset], size); DEBUG_MSGF("uint64 value: %" PRIu64, entry_data->uint64); } else if (type == MMDB_DATA_TYPE_UINT128) { if (size > 16) { return MMDB_INVALID_DATA_ERROR; } #if MMDB_UINT128_IS_BYTE_ARRAY memset(entry_data->uint128, 0, 16); if (size > 0) { memcpy(entry_data->uint128 + 16 - size, &mem[offset], size); } #else entry_data->uint128 = get_uint128(&mem[offset], size); #endif } else if (type == MMDB_DATA_TYPE_FLOAT) { if (size != 4) { return MMDB_INVALID_DATA_ERROR; } size = 4; entry_data->float_value = get_ieee754_float(&mem[offset]); DEBUG_MSGF("float value: %f", entry_data->float_value); } else if (type == MMDB_DATA_TYPE_DOUBLE) { if (size != 8) { return MMDB_INVALID_DATA_ERROR; } size = 8; entry_data->double_value = get_ieee754_double(&mem[offset]); DEBUG_MSGF("double value: %f", entry_data->double_value); } else if (type == MMDB_DATA_TYPE_UTF8_STRING) { entry_data->utf8_string = size == 0 ? "" : (char *)&mem[offset]; entry_data->data_size = size; #ifdef MMDB_DEBUG char *string = mmdb_strndup(entry_data->utf8_string, size > 50 ? 50 : size); if (NULL == string) { abort(); } DEBUG_MSGF("string value: %s", string); free(string); #endif } else if (type == MMDB_DATA_TYPE_BYTES) { entry_data->bytes = &mem[offset]; entry_data->data_size = size; } entry_data->offset_to_next = offset + size; return MMDB_SUCCESS; } LOCAL int get_ext_type(int raw_ext_type) { return 7 + raw_ext_type; } LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr, int ptr_size) { uint32_t new_offset; switch (ptr_size) { case 0: new_offset = (ctrl & 7) * 256 + ptr[0]; break; case 1: new_offset = 2048 + (ctrl & 7) * 65536 + ptr[0] * 256 + ptr[1]; break; case 2: new_offset = 2048 + 524288 + (ctrl & 7) * 16777216 + get_uint24(ptr); break; case 3: default: new_offset = get_uint32(ptr); break; } return MMDB_DATA_SECTION_SEPARATOR + new_offset; } int MMDB_get_metadata_as_entry_data_list( MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list) { MMDB_s metadata_db = make_fake_metadata_db(mmdb); MMDB_entry_s metadata_start = { .mmdb = &metadata_db, .offset = 0 }; return MMDB_get_entry_data_list(&metadata_start, entry_data_list); } int MMDB_get_entry_data_list( MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list) { *entry_data_list = new_entry_data_list(); if (NULL == *entry_data_list) { return MMDB_OUT_OF_MEMORY_ERROR; } return get_entry_data_list(start->mmdb, start->offset, *entry_data_list); } LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset, MMDB_entry_data_list_s *const entry_data_list) { CHECKED_DECODE_ONE(mmdb, offset, &entry_data_list->entry_data); switch (entry_data_list->entry_data.type) { case MMDB_DATA_TYPE_POINTER: { uint32_t next_offset = entry_data_list->entry_data.offset_to_next; uint32_t last_offset; while (entry_data_list->entry_data.type == MMDB_DATA_TYPE_POINTER) { CHECKED_DECODE_ONE(mmdb, last_offset = entry_data_list->entry_data.pointer, &entry_data_list->entry_data); } if (entry_data_list->entry_data.type == MMDB_DATA_TYPE_ARRAY || entry_data_list->entry_data.type == MMDB_DATA_TYPE_MAP) { int status = get_entry_data_list(mmdb, last_offset, entry_data_list); if (MMDB_SUCCESS != status) { return status; } } entry_data_list->entry_data.offset_to_next = next_offset; } break; case MMDB_DATA_TYPE_ARRAY: { uint32_t array_size = entry_data_list->entry_data.data_size; uint32_t array_offset = entry_data_list->entry_data.offset_to_next; MMDB_entry_data_list_s *previous = entry_data_list; while (array_size-- > 0) { MMDB_entry_data_list_s *entry_data_list_to = previous->next = new_entry_data_list(); if (NULL == entry_data_list_to) { return MMDB_OUT_OF_MEMORY_ERROR; } int status = get_entry_data_list(mmdb, array_offset, entry_data_list_to); if (MMDB_SUCCESS != status) { return status; } array_offset = entry_data_list_to->entry_data.offset_to_next; while (previous->next) { previous = previous->next; } } entry_data_list->entry_data.offset_to_next = array_offset; } break; case MMDB_DATA_TYPE_MAP: { uint32_t size = entry_data_list->entry_data.data_size; offset = entry_data_list->entry_data.offset_to_next; MMDB_entry_data_list_s *previous = entry_data_list; while (size-- > 0) { MMDB_entry_data_list_s *entry_data_list_to = previous->next = new_entry_data_list(); if (NULL == entry_data_list_to) { return MMDB_OUT_OF_MEMORY_ERROR; } int status = get_entry_data_list(mmdb, offset, entry_data_list_to); if (MMDB_SUCCESS != status) { return status; } while (previous->next) { previous = previous->next; } offset = entry_data_list_to->entry_data.offset_to_next; entry_data_list_to = previous->next = new_entry_data_list(); if (NULL == entry_data_list_to) { return MMDB_OUT_OF_MEMORY_ERROR; } status = get_entry_data_list(mmdb, offset, entry_data_list_to); if (MMDB_SUCCESS != status) { return status; } while (previous->next) { previous = previous->next; } offset = entry_data_list_to->entry_data.offset_to_next; } entry_data_list->entry_data.offset_to_next = offset; } break; default: break; } return MMDB_SUCCESS; } LOCAL float get_ieee754_float(const uint8_t *restrict p) { volatile float f; uint8_t *q = (void *)&f; #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ q[3] = p[0]; q[2] = p[1]; q[1] = p[2]; q[0] = p[3]; #else memcpy(q, p, 4); #endif return f; } LOCAL double get_ieee754_double(const uint8_t *restrict p) { volatile double d; uint8_t *q = (void *)&d; #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ q[7] = p[0]; q[6] = p[1]; q[5] = p[2]; q[4] = p[3]; q[3] = p[4]; q[2] = p[5]; q[1] = p[6]; q[0] = p[7]; #else memcpy(q, p, 8); #endif return d; } LOCAL uint32_t get_uint32(const uint8_t *p) { return p[0] * 16777216U + p[1] * 65536 + p[2] * 256 + p[3]; } LOCAL uint32_t get_uint24(const uint8_t *p) { return p[0] * 65536U + p[1] * 256 + p[2]; } LOCAL uint32_t get_uint16(const uint8_t *p) { return p[0] * 256U + p[1]; } LOCAL uint64_t get_uintX(const uint8_t *p, int length) { uint64_t value = 0; while (length-- > 0) { value <<= 8; value += *p++; } return value; } LOCAL int32_t get_sintX(const uint8_t *p, int length) { return (int32_t)get_uintX(p, length); } LOCAL MMDB_entry_data_list_s *new_entry_data_list(void) { /* We need calloc here in order to ensure that the ->next pointer in the * struct doesn't point to some random address. */ return calloc(1, sizeof(MMDB_entry_data_list_s)); } void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list) { if (entry_data_list == NULL) { return; } if (entry_data_list->next) { MMDB_free_entry_data_list(entry_data_list->next); } free(entry_data_list); } void MMDB_close(MMDB_s *const mmdb) { free_mmdb_struct(mmdb); } LOCAL void free_mmdb_struct(MMDB_s *const mmdb) { if (!mmdb) { return; } if (NULL != mmdb->filename) { FREE_AND_SET_NULL(mmdb->filename); } if (NULL != mmdb->file_content) { #ifdef _WIN32 UnmapViewOfFile(mmdb->file_content); /* Winsock is only initialized if open was successful so we only have * to cleanup then. */ WSACleanup(); #else munmap((void *)mmdb->file_content, mmdb->file_size); #endif } if (NULL != mmdb->metadata.database_type) { FREE_AND_SET_NULL(mmdb->metadata.database_type); } free_languages_metadata(mmdb); free_descriptions_metadata(mmdb); } LOCAL void free_languages_metadata(MMDB_s *mmdb) { if (!mmdb->metadata.languages.count) { return; } for (size_t i = 0; i < mmdb->metadata.languages.count; i++) { FREE_AND_SET_NULL(mmdb->metadata.languages.names[i]); } FREE_AND_SET_NULL(mmdb->metadata.languages.names); } LOCAL void free_descriptions_metadata(MMDB_s *mmdb) { if (!mmdb->metadata.description.count) { return; } for (size_t i = 0; i < mmdb->metadata.description.count; i++) { if (NULL != mmdb->metadata.description.descriptions[i]) { if (NULL != mmdb->metadata.description.descriptions[i]->language) { FREE_AND_SET_NULL( mmdb->metadata.description.descriptions[i]->language); } if (NULL != mmdb->metadata.description.descriptions[i]->description) { FREE_AND_SET_NULL( mmdb->metadata.description.descriptions[i]->description); } FREE_AND_SET_NULL(mmdb->metadata.description.descriptions[i]); } } FREE_AND_SET_NULL(mmdb->metadata.description.descriptions); } const char *MMDB_lib_version(void) { return PACKAGE_VERSION; } int MMDB_dump_entry_data_list(FILE *const stream, MMDB_entry_data_list_s *const entry_data_list, int indent) { int status; dump_entry_data_list(stream, entry_data_list, indent, &status); return status; } LOCAL MMDB_entry_data_list_s *dump_entry_data_list( FILE *stream, MMDB_entry_data_list_s *entry_data_list, int indent, int *status) { switch (entry_data_list->entry_data.type) { case MMDB_DATA_TYPE_MAP: { uint32_t size = entry_data_list->entry_data.data_size; print_indentation(stream, indent); fprintf(stream, "{\n"); indent += 2; for (entry_data_list = entry_data_list->next; size && entry_data_list; size--) { char *key = mmdb_strndup( (char *)entry_data_list->entry_data.utf8_string, entry_data_list->entry_data.data_size); if (NULL == key) { *status = MMDB_OUT_OF_MEMORY_ERROR; return NULL; } print_indentation(stream, indent); fprintf(stream, "\"%s\": \n", key); free(key); entry_data_list = entry_data_list->next; entry_data_list = dump_entry_data_list(stream, entry_data_list, indent + 2, status); if (MMDB_SUCCESS != *status) { return NULL; } } indent -= 2; print_indentation(stream, indent); fprintf(stream, "}\n"); } break; case MMDB_DATA_TYPE_ARRAY: { uint32_t size = entry_data_list->entry_data.data_size; print_indentation(stream, indent); fprintf(stream, "[\n"); indent += 2; for (entry_data_list = entry_data_list->next; size && entry_data_list; size--) { entry_data_list = dump_entry_data_list(stream, entry_data_list, indent, status); if (MMDB_SUCCESS != *status) { return NULL; } } indent -= 2; print_indentation(stream, indent); fprintf(stream, "]\n"); } break; case MMDB_DATA_TYPE_UTF8_STRING: { char *string = mmdb_strndup((char *)entry_data_list->entry_data.utf8_string, entry_data_list->entry_data.data_size); if (NULL == string) { *status = MMDB_OUT_OF_MEMORY_ERROR; return NULL; } print_indentation(stream, indent); fprintf(stream, "\"%s\" \n", string); free(string); entry_data_list = entry_data_list->next; } break; case MMDB_DATA_TYPE_BYTES: { char *hex_string = bytes_to_hex((uint8_t *)entry_data_list->entry_data.bytes, entry_data_list->entry_data.data_size); if (NULL == hex_string) { *status = MMDB_OUT_OF_MEMORY_ERROR; return NULL; } print_indentation(stream, indent); fprintf(stream, "%s \n", hex_string); free(hex_string); entry_data_list = entry_data_list->next; } break; case MMDB_DATA_TYPE_DOUBLE: print_indentation(stream, indent); fprintf(stream, "%f \n", entry_data_list->entry_data.double_value); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_FLOAT: print_indentation(stream, indent); fprintf(stream, "%f \n", entry_data_list->entry_data.float_value); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_UINT16: print_indentation(stream, indent); fprintf(stream, "%u \n", entry_data_list->entry_data.uint16); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_UINT32: print_indentation(stream, indent); fprintf(stream, "%u \n", entry_data_list->entry_data.uint32); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_BOOLEAN: print_indentation(stream, indent); fprintf(stream, "%s \n", entry_data_list->entry_data.boolean ? "true" : "false"); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_UINT64: print_indentation(stream, indent); fprintf(stream, "%" PRIu64 " \n", entry_data_list->entry_data.uint64); entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_UINT128: print_indentation(stream, indent); #if MMDB_UINT128_IS_BYTE_ARRAY char *hex_string = bytes_to_hex((uint8_t *)entry_data_list->entry_data.uint128, 16); fprintf(stream, "0x%s \n", hex_string); free(hex_string); #else uint64_t high = entry_data_list->entry_data.uint128 >> 64; uint64_t low = (uint64_t)entry_data_list->entry_data.uint128; fprintf(stream, "0x%016" PRIX64 "%016" PRIX64 " \n", high, low); #endif entry_data_list = entry_data_list->next; break; case MMDB_DATA_TYPE_INT32: print_indentation(stream, indent); fprintf(stream, "%d \n", entry_data_list->entry_data.int32); entry_data_list = entry_data_list->next; break; default: *status = MMDB_INVALID_DATA_ERROR; return NULL; } *status = MMDB_SUCCESS; return entry_data_list; } LOCAL void print_indentation(FILE *stream, int i) { char buffer[1024]; int size = i >= 1024 ? 1023 : i; memset(buffer, 32, size); buffer[size] = '\0'; fputs(buffer, stream); } LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size) { char *hex_string = malloc((size * 2) + 1); char *hex_pointer = hex_string; for (uint32_t i = 0; i < size; i++) { sprintf(hex_pointer + (2 * i), "%02X", bytes[i]); } return hex_string; } const char *MMDB_strerror(int error_code) { switch (error_code) { case MMDB_SUCCESS: return "Success (not an error)"; case MMDB_FILE_OPEN_ERROR: return "Error opening the specified MaxMind DB file"; case MMDB_CORRUPT_SEARCH_TREE_ERROR: return "The MaxMind DB file's search tree is corrupt"; case MMDB_INVALID_METADATA_ERROR: return "The MaxMind DB file contains invalid metadata"; case MMDB_IO_ERROR: return "An attempt to read data from the MaxMind DB file failed"; case MMDB_OUT_OF_MEMORY_ERROR: return "A memory allocation call failed"; case MMDB_UNKNOWN_DATABASE_FORMAT_ERROR: return "The MaxMind DB file is in a format this library can't handle (unknown record size or binary format version)"; case MMDB_INVALID_DATA_ERROR: return "The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"; case MMDB_INVALID_LOOKUP_PATH_ERROR: return "The lookup path contained an invalid value (like a negative integer for an array index)"; case MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR: return "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)"; case MMDB_INVALID_NODE_NUMBER_ERROR: return "The MMDB_read_node function was called with a node number that does not exist in the search tree"; case MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR: return "You attempted to look up an IPv6 address in an IPv4-only database"; default: return "Unknown error code"; } } libmaxminddb-1.0.4/t/000077500000000000000000000000001245160621500144135ustar00rootroot00000000000000libmaxminddb-1.0.4/t/Makefile.am000066400000000000000000000010351245160621500164460ustar00rootroot00000000000000include $(top_srcdir)/common.mk AM_LDFLAGS = $(top_builddir)/src/libmaxminddb.la noinst_LTLIBRARIES = libmmdbtest.la libmmdbtest_la_SOURCES = maxminddb_test_helper.c libtap/tap.c check_PROGRAMS = \ bad_pointers_t basic_lookup_t data_entry_list_t data_types_t \ dump_t get_value_t get_value_pointer_bug_t ipv4_start_cache_t \ ipv6_lookup_in_ipv4_t metadata_t no_map_get_value_t read_node_t \ threads_t version_t threads_t_CFLAGS = $(CFLAGS) -pthread TESTS = $(check_PROGRAMS) compile_c++_t.pl mmdblookup_t.pl LDADD = libmmdbtest.la libmaxminddb-1.0.4/t/bad_pointers_t.c000066400000000000000000000031121245160621500175500ustar00rootroot00000000000000#include "maxminddb_test_helper.h" void run_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-broken-pointers-24.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); { const char *ip = "1.1.1.16"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); MMDB_entry_data_s entry_data; int status = MMDB_get_value(&result.entry, &entry_data, NULL); cmp_ok( status, "==", MMDB_INVALID_DATA_ERROR, "MMDB_get_value returns MMDB_INVALID_DATA_ERROR for bad pointer in data section"); MMDB_entry_data_list_s *entry_data_list; status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); cmp_ok( status, "==", MMDB_INVALID_DATA_ERROR, "MMDB_get_entry_data_list returns MMDB_INVALID_DATA_ERROR for bad pointer in data section"); MMDB_free_entry_data_list(entry_data_list); } { const char *ip = "1.1.1.32"; int gai_error, mmdb_error; MMDB_lookup_result_s UNUSED(result) = MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error); cmp_ok( mmdb_error, "==", MMDB_CORRUPT_SEARCH_TREE_ERROR, "MMDB_lookup_string sets mmdb_error to MMDB_CORRUPT_SEARCH_TREE_ERROR when a search tree record points outside the data section"); } MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/basic_lookup_t.c000066400000000000000000000124241245160621500175570ustar00rootroot00000000000000#include "maxminddb_test_helper.h" /* These globals are gross but it's the easiest way to mix calling * for_all_modes() and for_all_record_sizes() */ static int Current_Mode; static const char *Current_Mode_Description; void test_one_result(MMDB_s *mmdb, MMDB_lookup_result_s result, const char *ip, const char *expect, const char *function, const char *filename, const char *mode_desc) { int is_ok = ok(result.found_entry, "got a result for an IP in the database - %s - %s - %s - %s", function, ip, filename, mode_desc); if (!is_ok) { return; } MMDB_entry_data_s data = data_ok(&result, MMDB_DATA_TYPE_UTF8_STRING, "result{ip}", "ip", NULL); char *string = strndup(data.utf8_string, data.data_size); char *real_expect; if (mmdb->metadata.ip_version == 4 || strncmp(expect, "::", 2) == 0) { real_expect = strndup(expect, strlen(expect)); } else { // When looking up IPv4 addresses in a mixed DB the result will be // something like "::1.2.3.4", not just "1.2.3.4". int maxlen = strlen(expect) + 3; real_expect = malloc(maxlen); snprintf(real_expect, maxlen, "::%s", expect); } is(string, real_expect, "found expected result for ip key - %s - %s - %s - %s", function, ip, filename, mode_desc); free(real_expect); free(string); } void test_one_ip(MMDB_s *mmdb, const char *ip, const char *expect, const char *filename, const char *mode_desc) { MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); test_one_result(mmdb, result, ip, expect, "MMDB_lookup_string", filename, mode_desc); result = lookup_sockaddr_ok(mmdb, ip, filename, mode_desc); test_one_result(mmdb, result, ip, expect, "MMDB_lookup_addrinfo", filename, mode_desc); } void run_ipX_tests(const char *filename, const char **missing_ips, int missing_ips_length, const char *pairs[][2], int pairs_rows) { const char *path = test_database_path(filename); int mode = Current_Mode; const char *mode_desc = Current_Mode_Description; MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); char desc_suffix[500]; snprintf(desc_suffix, 500, "%s - %s", filename, mode_desc); for (int i = 0; i < missing_ips_length; i++) { const char *ip = missing_ips[i]; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); ok( !result.found_entry, "no result entry struct returned for IP address not in the database (string lookup) - %s - %s - %s", ip, filename, mode_desc); result = lookup_sockaddr_ok(mmdb, ip, filename, mode_desc); ok( !result.found_entry, "no result entry struct returned for IP address not in the database (ipv4 lookup) - %s - %s - %s", ip, filename, mode_desc); } for (int i = 0; i < pairs_rows; i += 1) { const char *ip_to_lookup = pairs[i][0]; const char *expect = pairs[i][1]; test_one_ip(mmdb, ip_to_lookup, expect, filename, mode_desc); } MMDB_close(mmdb); free(mmdb); } void run_ipv4_tests(int UNUSED( record_size), const char *filename, const char *UNUSED( ignored)) { const char *pairs[9][2] = { { "1.1.1.1", "1.1.1.1" }, { "1.1.1.2", "1.1.1.2" }, { "1.1.1.3", "1.1.1.2" }, { "1.1.1.7", "1.1.1.4" }, { "1.1.1.9", "1.1.1.8" }, { "1.1.1.15", "1.1.1.8" }, { "1.1.1.17", "1.1.1.16" }, { "1.1.1.31", "1.1.1.16" }, { "1.1.1.32", "1.1.1.32" }, }; const char *missing[1] = { "2.3.4.5" }; run_ipX_tests(filename, missing, 1, pairs, 9); } void run_ipv6_tests(int UNUSED( record_size), const char *filename, const char *UNUSED( ignored)) { const char *pairs[9][2] = { { "::1:ffff:ffff", "::1:ffff:ffff" }, { "::2:0:0", "::2:0:0" }, { "::2:0:1a", "::2:0:0" }, { "::2:0:40", "::2:0:40" }, { "::2:0:4f", "::2:0:40" }, { "::2:0:50", "::2:0:50" }, { "::2:0:52", "::2:0:50" }, { "::2:0:58", "::2:0:58" }, { "::2:0:59", "::2:0:58" }, }; const char *missing[2] = { "2.3.4.5", "::abcd" }; run_ipX_tests(filename, missing, 2, pairs, 9); } void all_record_sizes(int mode, const char *description) { const char *ipv4_filename_fmts[] = { "MaxMind-DB-test-ipv4-%i.mmdb", "MaxMind-DB-test-mixed-%i.mmdb" }; Current_Mode = mode; Current_Mode_Description = description; for (int i = 0; i < 2; i++) { for_all_record_sizes(ipv4_filename_fmts[i], &run_ipv4_tests); } const char *ipv6_filename_fmts[] = { "MaxMind-DB-test-ipv6-%i.mmdb", "MaxMind-DB-test-mixed-%i.mmdb" }; for (int i = 0; i < 2; i++) { for_all_record_sizes(ipv6_filename_fmts[i], &run_ipv6_tests); } } int main(void) { plan(NO_PLAN); for_all_modes(&all_record_sizes); done_testing(); } libmaxminddb-1.0.4/t/compile_c++_t.pl000077500000000000000000000040721245160621500173610ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use Cwd qw( abs_path ); use FindBin qw( $Bin ); eval <<'EOF'; use Test::More 0.88; use File::Temp qw( tempdir ); use IPC::Run3 qw( run3 ); EOF if ($@) { print "1..0 # skip all tests skipped - these tests need the Test::More 0.88, File::Temp, and IPC::Run3 modules:\n"; print "$@"; exit 0; } my $test_db = "$Bin/maxmind-db/test-data/GeoIP2-City-Test.mmdb"; my $cpp_code = <<"EOF"; #include int main(int argc, char *argv[]) { const char *fname = "$test_db"; MMDB_s mmdb; return MMDB_open(fname, MMDB_MODE_MMAP, &mmdb); } EOF my $tempdir = tempdir(CLEANUP => 1 ); my $file = "$tempdir/open.cpp"; open my $fh, '>', $file or die $!; print {$fh} $cpp_code or die $!; close $fh or die $!; my $exe = "$tempdir/open"; my $include_dir = abs_path("$Bin/../include"); my $lib_dir = abs_path("$Bin/../src/.libs"); my $cxx = $ENV{CXX} || 'c++'; _test_cmd( [ $cxx, $file, "-I$include_dir", "-L$lib_dir", "-lmaxminddb", "-o$exe" ], qr/^$/, q{}, 0, 'compile C++ program which links against libmaxminddb', ); $ENV{LD_LIBRARY_PATH} = $lib_dir; _test_cmd( [$exe], qr/^$/, q{}, 0, 'compiled C++ program executes without errors' ); done_testing(); sub _test_cmd { my $cmd = shift; my $expect_stdout = shift; my $expect_stderr = shift; my $expect_status = shift; my $desc = shift; my $stdout; my $stderr; run3( $cmd, \undef, \$stdout, \$stderr, ); my $exit_status = $? >> 8; # We don't need to retest that the help output shows up for all errors if ( defined $expect_stdout ) { like( $stdout, $expect_stdout, "stdout for @{$cmd}" ); } if ( ref $expect_stderr ) { like( $stderr, $expect_stderr, "stderr for @{$cmd}" ); } else { is( $stderr, $expect_stderr, "stderr for @{$cmd}" ); } is( $exit_status, $expect_status, "exit status was $expect_status for @{$cmd}" ); } libmaxminddb-1.0.4/t/data_entry_list_t.c000066400000000000000000000320371245160621500202740ustar00rootroot00000000000000#include "maxminddb_test_helper.h" MMDB_entry_data_list_s *test_array_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *array = entry_data_list = entry_data_list->next; cmp_ok(array->entry_data.type, "==", MMDB_DATA_TYPE_ARRAY, "'array' key's value is an array"); cmp_ok(array->entry_data.data_size, "==", 3, "'array' key's value has 3 elements"); MMDB_entry_data_list_s *idx0 = entry_data_list = entry_data_list->next; cmp_ok(idx0->entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "first array entry is a UINT32"); cmp_ok(idx0->entry_data.uint32, "==", 1, "first array entry value is 1"); MMDB_entry_data_list_s *idx1 = entry_data_list = entry_data_list->next; cmp_ok(idx1->entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "second array entry is a UINT32"); cmp_ok(idx1->entry_data.uint32, "==", 2, "second array entry value is 2"); MMDB_entry_data_list_s *idx2 = entry_data_list = entry_data_list->next; cmp_ok(idx2->entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "third array entry is a UINT32"); cmp_ok(idx2->entry_data.uint32, "==", 3, "third array entry value is 3"); return entry_data_list; } MMDB_entry_data_list_s *test_boolean_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_BOOLEAN, "'boolean' key's value is a boolean"); ok(value->entry_data.boolean, "'boolean' key's value is true"); return entry_data_list; } MMDB_entry_data_list_s *test_bytes_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_BYTES, "'bytes' key's value is bytes"); uint8_t *bytes = malloc(value->entry_data.data_size); if (NULL == bytes) { BAIL_OUT("malloc failed"); } memcpy(bytes, value->entry_data.bytes, value->entry_data.data_size); uint8_t expect[] = { 0x00, 0x00, 0x00, 0x2a }; ok(memcmp(bytes, expect, 4) == 0, "got expected value for bytes key"); free((void *)bytes); return entry_data_list; } MMDB_entry_data_list_s *test_double_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_DOUBLE, "'double' key's value is a double"); compare_double(value->entry_data.double_value, 42.123456); return entry_data_list; } MMDB_entry_data_list_s *test_float_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_FLOAT, "'float' key's value is a float"); compare_float(value->entry_data.float_value, 1.1F); return entry_data_list; } MMDB_entry_data_list_s *test_int32_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_INT32, "'int32' key's value is an int32"); int32_t expect = 1 << 28; expect *= -1; cmp_ok(value->entry_data.int32, "==", expect, "got expected value for int32 key"); return entry_data_list; } MMDB_entry_data_list_s *test_arrayX_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *arrayX = entry_data_list = entry_data_list->next; cmp_ok(arrayX->entry_data.type, "==", MMDB_DATA_TYPE_ARRAY, "'map{mapX}{arrayX}' key's value is an array"); cmp_ok(arrayX->entry_data.data_size, "==", 3, "'map{mapX}{arrayX}' key's value has 3 elements"); MMDB_entry_data_list_s *idx0 = entry_data_list = entry_data_list->next; cmp_ok(idx0->entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "first array entry is a UINT32"); cmp_ok(idx0->entry_data.uint32, "==", 7, "first array entry value is 7"); MMDB_entry_data_list_s *idx1 = entry_data_list = entry_data_list->next; cmp_ok(idx1->entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "second array entry is a UINT32"); cmp_ok(idx1->entry_data.uint32, "==", 8, "second array entry value is 8"); MMDB_entry_data_list_s *idx2 = entry_data_list = entry_data_list->next; cmp_ok(idx2->entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "third array entry is a UINT32"); cmp_ok(idx2->entry_data.uint32, "==", 9, "third array entry value is 9"); return entry_data_list; } MMDB_entry_data_list_s *test_mapX_key_value_pair(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *mapX_key = entry_data_list = entry_data_list->next; cmp_ok(mapX_key->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "found a map key in 'map{mapX}'"); const char *mapX_key_name = dup_entry_string_or_bail(mapX_key->entry_data); if (strcmp(mapX_key_name, "utf8_stringX") == 0) { MMDB_entry_data_list_s *mapX_value = entry_data_list = entry_data_list->next; cmp_ok(mapX_value->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "'map{mapX}{utf8_stringX}' type is utf8_string"); const char *utf8_stringX_value = dup_entry_string_or_bail( mapX_value->entry_data); ok(strcmp(utf8_stringX_value, "hello") == 0, "map{mapX}{utf8_stringX} value is 'hello'"); free((void *)utf8_stringX_value); } else if (strcmp(mapX_key_name, "arrayX") == 0) { entry_data_list = test_arrayX_value(entry_data_list); } else { ok(0, "unknown key found in map{mapX} - %s", mapX_key_name); } free((void *)mapX_key_name); return entry_data_list; } MMDB_entry_data_list_s *test_map_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *map = entry_data_list = entry_data_list->next; cmp_ok(map->entry_data.type, "==", MMDB_DATA_TYPE_MAP, "'map' key's value is a map"); cmp_ok(map->entry_data.data_size, "==", 1, "'map' key's value has 1 key/value pair"); MMDB_entry_data_list_s *map_key_1 = entry_data_list = entry_data_list->next; cmp_ok(map_key_1->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "found a map key in 'map'"); const char *map_key_1_name = dup_entry_string_or_bail(map_key_1->entry_data); ok(strcmp(map_key_1_name, "mapX") == 0, "key name is mapX"); free((void *)map_key_1_name); MMDB_entry_data_list_s *mapX = entry_data_list = entry_data_list->next; cmp_ok(mapX->entry_data.type, "==", MMDB_DATA_TYPE_MAP, "'map{mapX}' key's value is a map"); cmp_ok(mapX->entry_data.data_size, "==", 2, "'map' key's value has 2 key/value pairs"); entry_data_list = test_mapX_key_value_pair(entry_data_list); entry_data_list = test_mapX_key_value_pair(entry_data_list); return entry_data_list; } MMDB_entry_data_list_s *test_uint128_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_UINT128, "'uint128' key's value is an uint128"); #if MMDB_UINT128_IS_BYTE_ARRAY uint8_t expect[16] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ok(memcmp(value->entry_data.uint128, expect, 16) == 0, "uint128 field is 2**120"); #else mmdb_uint128_t expect = 1; expect <<= 120; ok(value->entry_data.uint128 == expect, "uint128 field is 2**120"); #endif return entry_data_list; } MMDB_entry_data_list_s *test_uint16_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_UINT16, "'uint16' key's value is an uint16"); uint16_t expect = 100; ok(value->entry_data.uint16 == expect, "uint16 field is 100"); return entry_data_list; } MMDB_entry_data_list_s *test_uint32_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "'uint32' key's value is an uint32"); uint32_t expect = 1 << 28; ok(value->entry_data.uint32 == expect, "uint32 field is 100"); return entry_data_list; } MMDB_entry_data_list_s *test_uint64_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_UINT64, "'uint64' key's value is an uint64"); uint64_t expect = 1; expect <<= 60; ok(value->entry_data.uint64 == expect, "uint64 field is 2**60"); return entry_data_list; } MMDB_entry_data_list_s *test_utf8_string_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "'utf8_string' key's value is a string"); const char *utf8_string = dup_entry_string_or_bail(value->entry_data); // This is hex for "unicode! ☯ - ♫" as bytes char expect[19] = { 0x75, 0x6e, 0x69, 0x63, 0x6f, 0x64, 0x65, 0x21, 0x20, 0xe2, 0x98, 0xaf, 0x20, 0x2d, 0x20, 0xe2, 0x99, 0xab, 0x00 }; is(utf8_string, expect, "got expected value for utf8_string key"); free((void *)utf8_string); return entry_data_list; } void run_tests(int mode, const char *description) { const char *filename = "MaxMind-DB-test-decoder.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, description); free((void *)path); char *ip = "1.1.1.1"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, description); MMDB_entry_data_list_s *entry_data_list, *first; int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); if (MMDB_SUCCESS != status) { BAIL_OUT("MMDB_get_entry_data_list failed with %s", MMDB_strerror(status)); } else { cmp_ok(status, "==", MMDB_SUCCESS, "MMDB_get_entry_data_list succeeded"); } first = entry_data_list; cmp_ok(entry_data_list->entry_data.type, "==", MMDB_DATA_TYPE_MAP, "first entry in entry data list is a map"); cmp_ok(entry_data_list->entry_data.data_size, "==", 12, "first map in entry data list has 12 k/v pairs"); while (1) { MMDB_entry_data_list_s *key = entry_data_list = entry_data_list->next; if (!key) { break; } cmp_ok(key->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "found a map key"); const char *key_name = dup_entry_string_or_bail(key->entry_data); if (strcmp(key_name, "array") == 0) { entry_data_list = test_array_value(entry_data_list); } else if (strcmp(key_name, "boolean") == 0) { entry_data_list = test_boolean_value(entry_data_list); } else if (strcmp(key_name, "bytes") == 0) { entry_data_list = test_bytes_value(entry_data_list); } else if (strcmp(key_name, "double") == 0) { entry_data_list = test_double_value(entry_data_list); } else if (strcmp(key_name, "float") == 0) { entry_data_list = test_float_value(entry_data_list); } else if (strcmp(key_name, "int32") == 0) { entry_data_list = test_int32_value(entry_data_list); } else if (strcmp(key_name, "map") == 0) { entry_data_list = test_map_value(entry_data_list); } else if (strcmp(key_name, "uint128") == 0) { entry_data_list = test_uint128_value(entry_data_list); } else if (strcmp(key_name, "uint16") == 0) { entry_data_list = test_uint16_value(entry_data_list); } else if (strcmp(key_name, "uint32") == 0) { entry_data_list = test_uint32_value(entry_data_list); } else if (strcmp(key_name, "uint64") == 0) { entry_data_list = test_uint64_value(entry_data_list); } else if (strcmp(key_name, "utf8_string") == 0) { entry_data_list = test_utf8_string_value(entry_data_list); } else { ok(0, "unknown key found in map - %s", key_name); } free((void *)key_name); } MMDB_free_entry_data_list(first); MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/data_types_t.c000066400000000000000000000350451245160621500172460ustar00rootroot00000000000000#include "maxminddb_test_helper.h" void test_all_data_types(MMDB_lookup_result_s *result, const char *ip, const char *UNUSED(filename), const char *mode_desc) { { char description[500]; snprintf(description, 500, "utf8_string field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UTF8_STRING, description, "utf8_string", NULL); const char *string = strndup(data.utf8_string, data.data_size); // This is hex for "unicode! ☯ - ♫" as bytes char expect[19] = { 0x75, 0x6e, 0x69, 0x63, 0x6f, 0x64, 0x65, 0x21, 0x20, 0xe2, 0x98, 0xaf, 0x20, 0x2d, 0x20, 0xe2, 0x99, 0xab, 0x00 }; is(string, expect, "got expected utf8_string value"); free((char *)string); } { char description[500]; snprintf(description, 500, "double field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_DOUBLE, description, "double", NULL); compare_double(data.double_value, 42.123456); } { char description[500]; snprintf(description, 500, "float field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_FLOAT, description, "float", NULL); compare_float(data.float_value, 1.1F); } { char description[500]; snprintf(description, 500, "bytes field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_BYTES, description, "bytes", NULL); uint8_t expect[] = { 0x00, 0x00, 0x00, 0x2a }; ok(memcmp((uint8_t *)data.bytes, expect, 4) == 0, "bytes field has expected value"); } { char description[500]; snprintf(description, 500, "uint16 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UINT16, description, "uint16", NULL); uint16_t expect = 100; ok(data.uint16 == expect, "uint16 field is 100"); } { char description[500]; snprintf(description, 500, "uint32 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UINT32, description, "uint32", NULL); uint32_t expect = 1 << 28; ok(data.uint32 == expect, "uint32 field is 2**28"); } { char description[500]; snprintf(description, 500, "int32 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_INT32, description, "int32", NULL); int32_t expect = 1 << 28; expect *= -1; cmp_ok(data.int32, "==", expect, "int32 field is -(2**28)"); } { char description[500]; snprintf(description, 500, "uint64 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UINT64, description, "uint64", NULL); uint64_t expect = 1; expect <<= 60; ok(data.uint64 == expect, "uint64 field is 2**60"); } { char description[500]; snprintf(description, 500, "uint128 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UINT128, description, "uint128", NULL); #if MMDB_UINT128_IS_BYTE_ARRAY uint8_t expect[16] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ok(memcmp(data.uint128, expect, 16) == 0, "uint128 field is 2**120"); #else mmdb_uint128_t expect = 1; expect <<= 120; ok(data.uint128 == expect, "uint128 field is 2**120"); #endif } { char description[500]; snprintf(description, 500, "boolean field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_BOOLEAN, description, "boolean", NULL); cmp_ok(data.boolean, "==", true, "boolean field is true"); } { char description[500]; snprintf(description, 500, "array field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_ARRAY, description, "array", NULL); ok(data.data_size == 3, "array field has 3 elements"); snprintf(description, 500, "array[0] for %s - %s", ip, mode_desc); data = data_ok(result, MMDB_DATA_TYPE_UINT32, description, "array", "0", NULL); ok(data.uint32 == 1, "array[0] is 1"); snprintf(description, 500, "array[1] for %s - %s", ip, mode_desc); data = data_ok(result, MMDB_DATA_TYPE_UINT32, description, "array", "1", NULL); ok(data.uint32 == 2, "array[1] is 1"); snprintf(description, 500, "array[2] for %s - %s", ip, mode_desc); data = data_ok(result, MMDB_DATA_TYPE_UINT32, description, "array", "2", NULL); ok(data.uint32 == 3, "array[2] is 1"); } { char description[500]; snprintf(description, 500, "map field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_MAP, description, "map", NULL); ok(data.data_size == 1, "map field has 1 element"); snprintf(description, 500, "map{mapX} for %s - %s", ip, mode_desc); data = data_ok(result, MMDB_DATA_TYPE_MAP, description, "map", "mapX", NULL); ok(data.data_size == 2, "map{mapX} field has 2 elements"); snprintf(description, 500, "map{mapX}{utf8_stringX} for %s - %s", ip, mode_desc); data = data_ok(result, MMDB_DATA_TYPE_UTF8_STRING, description, "map", "mapX", "utf8_stringX", NULL); const char *string = strndup(data.utf8_string, data.data_size); is(string, "hello", "map{mapX}{utf8_stringX} is 'hello'"); free((char *)string); snprintf(description, 500, "map{mapX}{arrayX} for %s - %s", ip, mode_desc); data = data_ok(result, MMDB_DATA_TYPE_ARRAY, description, "map", "mapX", "arrayX", NULL); ok(data.data_size == 3, "map{mapX}{arrayX} field has 3 elements"); snprintf(description, 500, "map{mapX}{arrayX}[0] for %s - %s", ip, mode_desc); data = data_ok(result, MMDB_DATA_TYPE_UINT32, description, "map", "mapX", "arrayX", "0", NULL); ok(data.uint32 == 7, "map{mapX}{arrayX}[0] is 7"); snprintf(description, 500, "map{mapX}{arrayX}[1] for %s - %s", ip, mode_desc); data = data_ok(result, MMDB_DATA_TYPE_UINT32, description, "map", "mapX", "arrayX", "1", NULL); ok(data.uint32 == 8, "map{mapX}{arrayX}[1] is 8"); snprintf(description, 500, "map{mapX}{arrayX}[2] for %s - %s", ip, mode_desc); data = data_ok(result, MMDB_DATA_TYPE_UINT32, description, "map", "mapX", "arrayX", "2", NULL); ok(data.uint32 == 9, "map{mapX}{arrayX}[2] is 9"); } } void test_all_data_types_as_zero(MMDB_lookup_result_s *result, const char *ip, const char *UNUSED( filename), const char *mode_desc) { { char description[500]; snprintf(description, 500, "utf8_string field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UTF8_STRING, description, "utf8_string", NULL); is(data.utf8_string, "", "got expected utf8_string value (NULL)"); } { char description[500]; snprintf(description, 500, "double field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_DOUBLE, description, "double", NULL); compare_double(data.double_value, 0.0); } { char description[500]; snprintf(description, 500, "float field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_FLOAT, description, "float", NULL); compare_float(data.float_value, 0.0F); } { char description[500]; snprintf(description, 500, "bytes field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_BYTES, description, "bytes", NULL); ok(data.data_size == 0, "bytes field data_size is 0"); /* In C does it makes sense to write something like this? uint8_t expect[0] = {}; ok(memcmp(data.bytes, expect, 0) == 0, "got expected bytes value (NULL)"); */ } { char description[500]; snprintf(description, 500, "uint16 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UINT16, description, "uint16", NULL); uint16_t expect = 0; ok(data.uint16 == expect, "uint16 field is 0"); } { char description[500]; snprintf(description, 500, "uint32 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UINT32, description, "uint32", NULL); uint32_t expect = 0; ok(data.uint32 == expect, "uint32 field is 0"); } { char description[500]; snprintf(description, 500, "int32 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_INT32, description, "int32", NULL); int32_t expect = 0; expect *= -1; cmp_ok(data.int32, "==", expect, "int32 field is 0"); } { char description[500]; snprintf(description, 500, "uint64 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UINT64, description, "uint64", NULL); uint64_t expect = 0; ok(data.uint64 == expect, "uint64 field is 0"); } { char description[500]; snprintf(description, 500, "uint128 field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_UINT128, description, "uint128", NULL); #if MMDB_UINT128_IS_BYTE_ARRAY uint8_t expect[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ok(memcmp(data.uint128, expect, 16) == 0, "uint128 field is 0"); #else mmdb_uint128_t expect = 0; ok(data.uint128 == expect, "uint128 field is 0"); #endif } { char description[500]; snprintf(description, 500, "boolean field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_BOOLEAN, description, "boolean", NULL); cmp_ok(data.boolean, "==", false, "boolean field is false"); } { char description[500]; snprintf(description, 500, "array field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_ARRAY, description, "array", NULL); ok(data.data_size == 0, "array field has 0 elements"); } { char description[500]; snprintf(description, 500, "map field for %s - %s", ip, mode_desc); MMDB_entry_data_s data = data_ok(result, MMDB_DATA_TYPE_MAP, description, "map", NULL); ok(data.data_size == 0, "map field has 0 elements"); } } void run_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-decoder.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); // All of the remaining tests require an open mmdb if (NULL == mmdb) { diag("could not open %s - skipping remaining tests", path); return; } free((void *)path); { const char *ip = "not an ip"; int gai_error, mmdb_error; MMDB_lookup_result_s result = MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error); cmp_ok(gai_error, "==", EAI_NONAME, "MMDB_lookup populates getaddrinfo error properly - %s", ip); ok(!result.found_entry, "no result entry struct returned for invalid IP address '%s'", ip); } { const char *ip = "e900::"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); ok( !result.found_entry, "no result entry struct returned for IP address not in the database - %s - %s - %s", ip, filename, mode_desc); } { const char *ip = "::1.1.1.1"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); ok( result.found_entry, "got a result entry struct for IP address in the database - %s - %s - %s", ip, filename, mode_desc); cmp_ok( result.entry.offset, ">", 0, "result.entry.offset > 0 for address in the database - %s - %s - %s", ip, filename, mode_desc); test_all_data_types(&result, ip, filename, mode_desc); } { const char *ip = "::4.5.6.7"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); ok( result.found_entry, "got a result entry struct for IP address in the database - %s - %s - %s", ip, filename, mode_desc); cmp_ok( result.entry.offset, ">", 0, "result.entry.offset > 0 for address in the database - %s - %s - %s", ip, filename, mode_desc); test_all_data_types(&result, ip, filename, mode_desc); } { const char *ip = "::0.0.0.0"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); ok( result.found_entry, "got a result entry struct for IP address in the database - %s - %s - %s", ip, filename, mode_desc); cmp_ok( result.entry.offset, ">", 0, "result.entry.offset > 0 for address in the database - %s - %s - %s", ip, filename, mode_desc); test_all_data_types_as_zero(&result, ip, filename, mode_desc); } MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/dump_t.c000066400000000000000000000051761245160621500160600ustar00rootroot00000000000000#define _GNU_SOURCE #include "maxminddb_test_helper.h" #ifdef HAVE_OPEN_MEMSTREAM void run_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-decoder.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); const char *ip = "1.1.1.1"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); MMDB_entry_data_list_s *entry_data_list; int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); char *dump_output; size_t dump_size; FILE *stream = open_memstream(&dump_output, &dump_size); status = MMDB_dump_entry_data_list(stream, entry_data_list, 0); fclose(stream); MMDB_free_entry_data_list(entry_data_list); ok(MMDB_SUCCESS == status, "MMDB_dump_entry_data_list is successful - %s", mode_desc); cmp_ok(dump_size, ">", 0, "MMDB_dump produced output - %s", mode_desc); char *expect[] = { "{", " \"array\": ", " [", " 1 ", " 2 ", " 3 ", " ]", " \"boolean\": ", " true ", " \"bytes\": ", " 0000002A ", " \"double\": ", " 42.123456 ", " \"float\": ", " 1.100000 ", " \"int32\": ", " -268435456 ", " \"map\": ", " {", " \"mapX\": ", " {", " \"arrayX\": ", " [", " 7 ", " 8 ", " 9 ", " ]", " \"utf8_stringX\": ", " \"hello\" ", " }", " }", " \"uint128\": ", " 0x01000000000000000000000000000000 ", " \"uint16\": ", " 100 ", " \"uint32\": ", " 268435456 ", " \"uint64\": ", " 1152921504606846976 ", " \"utf8_string\": ", " \"unicode! ☯ - ♫\" ", "}" }; for (int i = 0; i < 42; i++) { ok(strstr(dump_output, expect[i]) != NULL, "dump output contains expected line (%s) - %s", expect[i], mode_desc); } free(dump_output); MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } #else int main(void) { plan(SKIP_ALL, "This test requires the open_memstream() function"); } #endif libmaxminddb-1.0.4/t/get_value_pointer_bug_t.c000066400000000000000000000045311245160621500214550ustar00rootroot00000000000000#include "maxminddb_test_helper.h" /* This test exercises a bug found in MMDB_get_value for certain types of * nested data structures which contain pointers. See * https://github.com/maxmind/libmaxminddb/issues/2 and * https://github.com/maxmind/libmaxminddb/issues/3. * * There is also the potential for a similar bug when looking up a value by * path in an array. This is not tested (yet) as we don't have the right test * data for it. * * These tests are somewhat fragile since they depend on a specific data * layout in the database. Ideally the test would check that this layout * exists before checking to see if the lookups are correct. */ void test_one_ip(MMDB_s *mmdb, const char *filename, const char *mode_desc, char *ip, char *country_code) { MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); MMDB_entry_data_s entry_data = data_ok(&result, MMDB_DATA_TYPE_UTF8_STRING, "country{iso_code}", "country", "iso_code", NULL); if (ok(entry_data.has_data, "found data for country{iso_code}")) { char *string = strndup(entry_data.utf8_string, entry_data.data_size); if (!string) { ok(0, "strndup() call failed"); exit(1); } if (!ok(strcmp(string, country_code) == 0, "iso_code is %s", country_code)) { diag(" value is %s", string); } free(string); } } void run_tests(int mode, const char *mode_desc) { const char *filename = "GeoIP2-City-Test.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); /* This exercises a bug where the entire top-level value is a pointer to * another part of the data section. */ test_one_ip(mmdb, filename, mode_desc, "2001:218::", "JP"); /* This exercises a bug where one subnet's data shares part of the data * with another subnet - in this case it is the "country" key (and others) * in the top level map. We are testing that the "country" key's value is * handled correctly. The value _should_ be a pointer to another map. */ test_one_ip(mmdb, filename, mode_desc, "81.2.69.160", "GB"); MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/get_value_t.c000066400000000000000000000222141245160621500170560ustar00rootroot00000000000000#include "maxminddb_test_helper.h" void test_array_0_result(int status, MMDB_entry_data_s entry_data, char *function) { cmp_ok(status, "==", MMDB_SUCCESS, "status for %s() is MMDB_SUCCESS - array[0]", function); ok(entry_data.has_data, "found a value for array[0]"); cmp_ok(entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "returned entry type is uint32 - array[0]"); cmp_ok(entry_data.uint32, "==", 1, "entry value is 1 - array[0]"); } void test_array_2_result(int status, MMDB_entry_data_s entry_data, char *function) { cmp_ok(status, "==", MMDB_SUCCESS, "status for %s() is MMDB_SUCCESS - array[2]", function); ok(entry_data.has_data, "found a value for array[2]"); cmp_ok(entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "returned entry type is uint32 - array[2]"); cmp_ok(entry_data.uint32, "==", 3, "entry value is 3 - array[2]"); } int call_vget_value(MMDB_entry_s *entry, MMDB_entry_data_s *entry_data, ...) { va_list keys; va_start(keys, entry_data); int status = MMDB_vget_value(entry, entry_data, keys); va_end(keys); return status; } void test_simple_structure(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-decoder.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); const char *ip = "1.1.1.1"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); { MMDB_entry_data_s entry_data; const char *lookup_path[] = { "array", "0", NULL }; int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path); test_array_0_result(status, entry_data, "MMDB_aget_value"); status = MMDB_get_value(&result.entry, &entry_data, "array", "0", NULL); test_array_0_result(status, entry_data, "MMDB_get_value"); status = call_vget_value(&result.entry, &entry_data, "array", "0", NULL); test_array_0_result(status, entry_data, "MMDB_vget_value"); } { MMDB_entry_data_s entry_data; const char *lookup_path[] = { "array", "2", NULL }; int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path); test_array_2_result(status, entry_data, "MMDB_aget_value"); status = MMDB_get_value(&result.entry, &entry_data, "array", "2", NULL); test_array_2_result(status, entry_data, "MMDB_get_value"); status = call_vget_value(&result.entry, &entry_data, "array", "2", NULL); test_array_2_result(status, entry_data, "MMDB_vget_value"); } { MMDB_entry_data_s entry_data; int status = MMDB_get_value(&result.entry, &entry_data, "array", "zero", NULL); cmp_ok(status, "==", MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR, "MMDB_get_value() returns error on non-integer array index"); } { MMDB_entry_data_s entry_data; int status = MMDB_get_value(&result.entry, &entry_data, "array", "-1", NULL); cmp_ok(status, "==", MMDB_INVALID_LOOKUP_PATH_ERROR, "MMDB_get_value() returns error on negative integer"); } { MMDB_entry_data_s entry_data; int status = MMDB_get_value(&result.entry, &entry_data, "array", "18446744073709551616", NULL); cmp_ok(status, "==", MMDB_INVALID_LOOKUP_PATH_ERROR, "MMDB_get_value() returns error on integer larger than LONG_MAX"); } MMDB_close(mmdb); free(mmdb); } void test_complex_map_a_result(int status, MMDB_entry_data_s entry_data, char *function) { cmp_ok(status, "==", MMDB_SUCCESS, "status for %s() is MMDB_SUCCESS - map1{map2}{array}[0]{map3}{a}", function); ok(entry_data.has_data, "found a value for map1{map2}{array}[0]{map3}{a}"); cmp_ok(entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "returned entry type is uint32 - map1{map2}{array}[0]{map3}{a}"); cmp_ok(entry_data.uint32, "==", 1, "entry value is 1 - map1{map2}{array}[0]{map3}{a}"); } void test_complex_map_c_result(int status, MMDB_entry_data_s entry_data, char *function) { cmp_ok( status, "==", MMDB_SUCCESS, "status for %s() is MMDB_SUCCESS - map1{map2}{array}[0]{map3}{c}", function); ok(entry_data.has_data, "found a value for map1{map2}{array}[0]{map3}{c}"); cmp_ok(entry_data.type, "==", MMDB_DATA_TYPE_UINT32, "returned entry type is uint32 - map1{map2}{array}[0]{map3}{c}"); cmp_ok(entry_data.uint32, "==", 3, "entry value is 3 - map1{map2}{array}[0]{map3}{c}"); } void test_no_result(int status, MMDB_entry_data_s entry_data, char *function, char *path_description) { cmp_ok(status, "==", MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR, "status for %s() is MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR - %s", function, path_description); ok(!entry_data.has_data, "did not find a value for %s", path_description); } void test_nested_structure(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-nested.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); const char *ip = "1.1.1.1"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); { MMDB_entry_data_s entry_data; const char *lookup_path[] = { "map1", "map2", "array", "0", "map3", "a", NULL }; int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path); test_complex_map_a_result(status, entry_data, "MMDB_aget_value"); status = MMDB_get_value(&result.entry, &entry_data, "map1", "map2", "array", "0", "map3", "a", NULL); test_complex_map_a_result(status, entry_data, "MMDB_get_value"); status = call_vget_value(&result.entry, &entry_data, "map1", "map2", "array", "0", "map3", "a", NULL); test_complex_map_a_result(status, entry_data, "MMDB_vget_value"); } { MMDB_entry_data_s entry_data; const char *lookup_path[] = { "map1", "map2", "array", "0", "map3", "c", NULL }; int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path); test_complex_map_c_result(status, entry_data, "MMDB_aget_value"); status = MMDB_get_value(&result.entry, &entry_data, "map1", "map2", "array", "0", "map3", "c", NULL); test_complex_map_c_result(status, entry_data, "MMDB_get_value"); status = call_vget_value(&result.entry, &entry_data, "map1", "map2", "array", "0", "map3", "c", NULL); test_complex_map_c_result(status, entry_data, "MMDB_vget_value"); } { MMDB_entry_data_s entry_data; const char *lookup_path[] = { "map1", "map42", "array", "0", "map3", "c", NULL }; int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path); test_no_result(status, entry_data, "MMDB_aget_value", "map1{map42}{array}[0]{map3}{c}"); status = MMDB_get_value(&result.entry, &entry_data, "map1", "map42", "array", "0", "map3", "c", NULL); test_no_result(status, entry_data, "MMDB_get_value", "map1{map42}{array}[0]{map3}{c}"); status = call_vget_value(&result.entry, &entry_data, "map1", "map42", "array", "0", "map3", "c", NULL); test_no_result(status, entry_data, "MMDB_vget_value", "map1{map42}{array}[0]{map3}{c}"); } { MMDB_entry_data_s entry_data; const char *lookup_path[] = { "map1", "map2", "array", "9", "map3", "c", NULL }; int status = MMDB_aget_value(&result.entry, &entry_data, lookup_path); test_no_result(status, entry_data, "MMDB_aget_value", "map1{map42}{array}[9]{map3}{c}"); status = MMDB_get_value(&result.entry, &entry_data, "map1", "map2", "array", "9", "map3", "c", NULL); test_no_result(status, entry_data, "MMDB_get_value", "map1{map42}{array}[9]{map3}{c}"); status = call_vget_value(&result.entry, &entry_data, "map1", "map2", "array", "9", "map3", "c", NULL); test_no_result(status, entry_data, "MMDB_vget_value", "map1{map42}{array}[9]{map3}{c}"); } MMDB_close(mmdb); free(mmdb); } void run_tests(int mode, const char *mode_desc) { test_simple_structure(mode, mode_desc); test_nested_structure(mode, mode_desc); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/ipv4_start_cache_t.c000066400000000000000000000017101245160621500203230ustar00rootroot00000000000000#include "maxminddb_test_helper.h" void test_one_ip(MMDB_s *mmdb, const char *ip, const char *filename, const char *mode_desc) { MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); ok( result.found_entry, "got a result for an IPv4 address included in a larger-than-IPv4 subnet - %s - %s", ip, mode_desc); data_ok(&result, MMDB_DATA_TYPE_UTF8_STRING, "string value for IP", NULL); } void run_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-no-ipv4-search-tree.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); test_one_ip(mmdb, "1.1.1.1", filename, mode_desc); test_one_ip(mmdb, "255.255.255.255", filename, mode_desc); MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/ipv6_lookup_in_ipv4_t.c000066400000000000000000000014461245160621500210140ustar00rootroot00000000000000#include "maxminddb_test_helper.h" void run_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-ipv4-28.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); const char *ip = "::abcd"; int gai_error, mmdb_error; MMDB_lookup_result_s UNUSED(result) = MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error); cmp_ok( mmdb_error, "==", MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR, "MMDB_lookup_string sets mmdb_error to MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR when we try to look up an IPv6 address in an IPv4-only database"); MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/libtap/000077500000000000000000000000001245160621500156665ustar00rootroot00000000000000libmaxminddb-1.0.4/t/maxmind-db/000077500000000000000000000000001245160621500164335ustar00rootroot00000000000000libmaxminddb-1.0.4/t/maxminddb_test_helper.c000066400000000000000000000145731245160621500211320ustar00rootroot00000000000000#if HAVE_CONFIG_H #include #endif #define _POSIX_C_SOURCE 200112L #include #include #include #include "maxminddb.h" #include "maxminddb_test_helper.h" #ifdef _WIN32 #include #else #include #include #endif #define NO_PROTO #ifndef strndup /* *INDENT-OFF* */ /* Copied from the libiberty strndup.c, which is LPGPL 2+ */ NO_PROTO char *strndup (const char *s, size_t n) { char *result; size_t len = strlen (s); if (n < len) len = n; result = (char *) malloc (len + 1); if (!result) return 0; result[len] = '\0'; return (char *) memcpy (result, s, len); } /* *INDENT-ON* */ #endif void for_all_record_sizes(const char *filename_fmt, void (*tests)(int record_size, const char *filename, const char *description)) { int sizes[] = { 24, 28, 32 }; for (int i = 0; i < 3; i++) { int size = sizes[i]; char filename[500]; snprintf(filename, 500, filename_fmt, size); char description[14]; snprintf(description, 14, "%i bit record", size); tests(size, filename, description); } } void for_all_modes(void (*tests)(int mode, const char *description)) { tests(MMDB_MODE_MMAP, "mmap mode"); } const char *test_database_path(const char *filename) { char cwd[500]; char *UNUSED(tmp) = getcwd(cwd, 500); char *test_db_dir; #ifdef _WIN32 test_db_dir = "./t/maxmind-db/test-data"; #else if (strcmp(basename(cwd), "t") == 0) { test_db_dir = "./maxmind-db/test-data"; } else { test_db_dir = "./t/maxmind-db/test-data"; } #endif char *path = malloc(500); assert(NULL != path); snprintf(path, 500, "%s/%s", test_db_dir, filename); return (const char *)path; } const char *dup_entry_string_or_bail(MMDB_entry_data_s entry_data) { const char *string = strndup(entry_data.utf8_string, entry_data.data_size); if (NULL == string) { BAIL_OUT("strndup failed"); } return string; } MMDB_s *open_ok(const char *db_file, int mode, const char *mode_desc) { if (0 != access(db_file, R_OK)) { BAIL_OUT( "could not read the specified file - %s\nIf you are in a git checkout try running 'git submodule update --init'", db_file); } MMDB_s *mmdb = (MMDB_s *)calloc(1, sizeof(MMDB_s)); if (NULL == mmdb) { BAIL_OUT("could not allocate memory for our MMDB_s struct"); } int status = MMDB_open(db_file, mode, mmdb); int is_ok = ok(MMDB_SUCCESS == status, "open %s status is success - %s", db_file, mode_desc); if (!is_ok) { diag("open status code = %d (%s)", status, MMDB_strerror(status)); free(mmdb); return NULL; } is_ok = ok(NULL != mmdb, "returned mmdb struct is not null for %s - %s", db_file, mode_desc); if (!is_ok) { free(mmdb); return NULL; } return mmdb; } MMDB_lookup_result_s lookup_string_ok(MMDB_s *mmdb, const char *ip, const char *file, const char *mode_desc) { int gai_error, mmdb_error; MMDB_lookup_result_s result = MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error); test_lookup_errors(gai_error, mmdb_error, "MMDB_lookup_string", ip, file, mode_desc); return result; } MMDB_lookup_result_s lookup_sockaddr_ok(MMDB_s *mmdb, const char *ip, const char *file, const char *mode_desc) { int ai_flags = AI_NUMERICHOST; struct addrinfo hints = { .ai_socktype = SOCK_STREAM }; struct addrinfo *addresses = NULL; if (ip[0] == ':') { hints.ai_flags = ai_flags; #if defined AI_V4MAPPED && !defined __FreeBSD__ hints.ai_flags |= AI_V4MAPPED; #endif hints.ai_family = AF_INET6; } else { hints.ai_flags = ai_flags; hints.ai_family = AF_INET; } int gai_error = getaddrinfo(ip, NULL, &hints, &addresses); int mmdb_error = 0; MMDB_lookup_result_s result = { .found_entry = false }; if (gai_error == 0) { result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error); } if (NULL != addresses) { freeaddrinfo(addresses); } test_lookup_errors(gai_error, mmdb_error, "MMDB_lookup_sockaddr", ip, file, mode_desc); return result; } void test_lookup_errors(int gai_error, int mmdb_error, const char *function, const char *ip, const char *file, const char *mode_desc) { int is_ok = ok(0 == gai_error, "no getaddrinfo error in call to %s for %s - %s - %s", function, ip, file, mode_desc); if (!is_ok) { diag("error from call to getaddrinfo for %s - %s", ip, gai_strerror(gai_error)); } is_ok = ok(0 == mmdb_error, "no MMDB error in call to %s for %s - %s - %s", function, ip, file, mode_desc); if (!is_ok) { diag("MMDB error - %s", MMDB_strerror(mmdb_error)); } } MMDB_entry_data_s data_ok(MMDB_lookup_result_s *result, uint32_t expect_type, const char *description, ...) { va_list keys; va_start(keys, description); MMDB_entry_data_s data; int status = MMDB_vget_value(&result->entry, &data, keys); va_end(keys); if (cmp_ok(status, "==", MMDB_SUCCESS, "no error from call to MMDB_vget_value - %s", description)) { if (!ok(data.type == expect_type, "got the expected data type - %s", description)) { diag(" data type value is %i but expected %i", data.type, expect_type); } } else { diag(" error from MMDB_vget_value - %s", MMDB_strerror(status)); } return data; } void compare_double(double got, double expect) { double diff = fabs(got - expect); int is_ok = ok(diff < 0.01, "double value was approximately %2.6f", expect); if (!is_ok) { diag(" got %2.6f but expected %2.6f (diff = %2.6f)", got, expect, diff); } } void compare_float(float got, float expect) { float diff = fabsf(got - expect); int is_ok = ok(diff < 0.01, "float value was approximately %2.1f", expect); if (!is_ok) { diag(" got %2.4f but expected %2.1f (diff = %2.1f)", got, expect, diff); } } libmaxminddb-1.0.4/t/maxminddb_test_helper.h000066400000000000000000000045421245160621500211320ustar00rootroot00000000000000/* Some test files may require something newer */ #ifndef _GNU_SOURCE #define _POSIX_C_SOURCE 200112L #endif #if HAVE_CONFIG_H #include #endif #include #include #include #include "maxminddb.h" #include "libtap/tap.h" #ifdef _WIN32 #include #include #define R_OK 4 #else #include #endif #if (_MSC_VER && _MSC_VER < 1900) /* _snprintf has security issues, but I don't think it is worth worrying about for the unit tests. */ #define snprintf _snprintf #endif #ifndef MMDB_TEST_HELPER_C #define MMDB_TEST_HELPER_C (1) #ifdef __GNUC__ # define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else # define UNUSED #endif #define MAX_DESCRIPTION_LENGTH 500 #ifndef strndup extern char *strndup(const char *s, size_t n); #endif /* *INDENT-OFF* */ /* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */ extern void for_all_record_sizes(const char *filename_fmt, void (*tests)(int record_size, const char *filename, const char *description)); extern void for_all_modes(void (*tests)(int mode, const char *description)); extern const char *test_database_path(const char *filename); extern const char *dup_entry_string_or_bail(MMDB_entry_data_s entry_data); extern MMDB_s *open_ok(const char *db_file, int mode, const char *mode_desc); extern MMDB_lookup_result_s lookup_string_ok(MMDB_s *mmdb, const char *ip, const char *file, const char *mode_desc); extern MMDB_lookup_result_s lookup_sockaddr_ok(MMDB_s *mmdb, const char *ip, const char *file, const char *mode_desc); extern void test_lookup_errors(int gai_error, int mmdb_error, const char *function, const char *ip, const char *file, const char *mode_desc); extern MMDB_entry_data_s data_ok(MMDB_lookup_result_s *result, uint32_t expect_type, const char *description, ...); extern void compare_double(double got, double expect); extern void compare_float(float got, float expect); /* --prototypes end - don't remove this comment-- */ /* *INDENT-ON* */ #endif libmaxminddb-1.0.4/t/metadata_t.c000066400000000000000000000211741245160621500166670ustar00rootroot00000000000000#include "maxminddb_test_helper.h" void test_metadata(MMDB_s *mmdb, const char *mode_desc) { cmp_ok(mmdb->metadata.node_count, "==", 37, "node_count is 37 - %s", mode_desc); cmp_ok(mmdb->metadata.record_size, "==", 24, "record_size is 24 - %s", mode_desc); cmp_ok(mmdb->metadata.ip_version, "==", 4, "ip_version is 4 - %s", mode_desc); is(mmdb->metadata.database_type, "Test", "database_type is Test - %s", mode_desc); // 2013-07-01T00:00:00Z uint64_t expect_epoch = 1372636800; int is_ok = ok(mmdb->metadata.build_epoch >= expect_epoch, "build_epoch > %lli", expect_epoch); if (!is_ok) { diag(" epoch is %lli", mmdb->metadata.build_epoch); } cmp_ok(mmdb->metadata.binary_format_major_version, "==", 2, "binary_format_major_version is 2 - %s", mode_desc); cmp_ok(mmdb->metadata.binary_format_minor_version, "==", 0, "binary_format_minor_version is 0 - %s", mode_desc); cmp_ok(mmdb->metadata.languages.count, "==", 2, "found 2 languages - %s", mode_desc); is(mmdb->metadata.languages.names[0], "en", "first language is en - %s", mode_desc); is(mmdb->metadata.languages.names[1], "zh", "second language is zh - %s", mode_desc); cmp_ok(mmdb->metadata.description.count, "==", 2, "found 2 descriptions - %s", mode_desc); for (uint16_t i = 0; i < mmdb->metadata.description.count; i++) { const char *language = mmdb->metadata.description.descriptions[i]->language; const char *description = mmdb->metadata.description.descriptions[i]->description; if (strncmp(language, "en", 2) == 0) { ok(1, "found en description"); is(description, "Test Database", "en description"); } else if (strncmp(language, "zh", 2) == 0) { ok(1, "found zh description"); is(description, "Test Database Chinese", "zh description"); } else { ok(0, "found unknown description in unexpected language - %s", language); } } cmp_ok(mmdb->full_record_byte_size, "==", 6, "full_record_byte_size is 6 - %s", mode_desc); } MMDB_entry_data_list_s *test_languages_value(MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *languages = entry_data_list = entry_data_list->next; cmp_ok(languages->entry_data.type, "==", MMDB_DATA_TYPE_ARRAY, "'languages' key's value is an array"); cmp_ok(languages->entry_data.data_size, "==", 2, "'languages' key's value has 2 elements"); MMDB_entry_data_list_s *idx0 = entry_data_list = entry_data_list->next; cmp_ok(idx0->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "first array entry is a UTF8_STRING"); const char *lang0 = dup_entry_string_or_bail(idx0->entry_data); is(lang0, "en", "first language is en"); free((void *)lang0); MMDB_entry_data_list_s *idx1 = entry_data_list = entry_data_list->next; cmp_ok(idx1->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "second array entry is a UTF8_STRING"); const char *lang1 = dup_entry_string_or_bail(idx1->entry_data); is(lang1, "zh", "second language is zh"); free((void *)lang1); return entry_data_list; } MMDB_entry_data_list_s *test_description_value( MMDB_entry_data_list_s *entry_data_list) { MMDB_entry_data_list_s *description = entry_data_list = entry_data_list->next; cmp_ok(description->entry_data.type, "==", MMDB_DATA_TYPE_MAP, "'description' key's value is a map"); cmp_ok(description->entry_data.data_size, "==", 2, "'description' key's value has 2 key/value pairs"); for (int i = 0; i < 2; i++) { MMDB_entry_data_list_s *key = entry_data_list = entry_data_list->next; cmp_ok(key->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "found a map key in 'map'"); const char *key_name = dup_entry_string_or_bail(key->entry_data); MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "map value is a UTF8_STRING"); const char *description = dup_entry_string_or_bail(value->entry_data); if (strcmp(key_name, "en") == 0) { is(description, "Test Database", "en description == 'Test Database'"); } else if (strcmp(key_name, "zh") == 0) { is(description, "Test Database Chinese", "zh description == 'Test Database Chinese'"); } else { ok(0, "unknown key found in description map - %s", key_name); } free((void *)key_name); free((void *)description); } return entry_data_list; } void test_metadata_as_data_entry_list(MMDB_s * mmdb, const char *mode_desc) { MMDB_entry_data_list_s *entry_data_list, *first; int status = MMDB_get_metadata_as_entry_data_list(mmdb, &entry_data_list); first = entry_data_list; cmp_ok(status, "==", MMDB_SUCCESS, "get metadata as data_entry_list - %s", mode_desc); cmp_ok(first->entry_data.data_size, "==", 9, "metadata map has 9 key/value pairs"); while (1) { MMDB_entry_data_list_s *key = entry_data_list = entry_data_list->next; if (!key) { break; } cmp_ok(key->entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "found a map key"); const char *key_name = dup_entry_string_or_bail(key->entry_data); if (strcmp(key_name, "node_count") == 0) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.uint32, "==", 37, "node_count == 37"); } else if (strcmp(key_name, "record_size") == 0) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.uint16, "==", 24, "record_size == 24"); } else if (strcmp(key_name, "ip_version") == 0) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.uint16, "==", 4, "ip_version == 4"); } else if (strcmp(key_name, "binary_format_major_version") == 0) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.uint16, "==", 2, "binary_format_major_version == 2"); } else if (strcmp(key_name, "binary_format_minor_version") == 0) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; cmp_ok(value->entry_data.uint16, "==", 0, "binary_format_minor_version == 0"); } else if (strcmp(key_name, "build_epoch") == 0) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; ok(value->entry_data.uint64 > 1373571901, "build_epoch > 1373571901"); } else if (strcmp(key_name, "database_type") == 0) { MMDB_entry_data_list_s *value = entry_data_list = entry_data_list->next; const char *type = dup_entry_string_or_bail(value->entry_data); is(type, "Test", "type == Test"); free((void *)type); } else if (strcmp(key_name, "languages") == 0) { entry_data_list = test_languages_value(entry_data_list); } else if (strcmp(key_name, "description") == 0) { entry_data_list = test_description_value(entry_data_list); } else { ok(0, "unknown key found in metadata map - %s", key_name); } free((void *)key_name); } MMDB_free_entry_data_list(first); } void run_tests(int mode, const char *mode_desc) { const char *file = "MaxMind-DB-test-ipv4-24.mmdb"; const char *path = test_database_path(file); MMDB_s *mmdb = open_ok(path, mode, mode_desc); // All of the remaining tests require an open mmdb if (NULL == mmdb) { diag("could not open %s - skipping remaining tests", path); return; } free((void *)path); test_metadata(mmdb, mode_desc); test_metadata_as_data_entry_list(mmdb, mode_desc); MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/mmdblookup_t.pl000077500000000000000000000071261245160621500174550ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use FindBin qw( $Bin ); eval <<'EOF'; use Test::More 0.88; use IPC::Run3 qw( run3 ); EOF if ($@) { print "1..0 # skip all tests skipped - these tests need the Test::More 0.88, IPC::Run3 and Test::Output modules:\n"; print "$@"; exit 0; } my $mmdblookup = "$Bin/../bin/mmdblookup"; my $test_data_dir = "$Bin/maxmind-db/test-data"; { ok( -x $mmdblookup, 'mmdblookup script is executable' ); } for my $arg (qw( -h -? --help )) { _test_stdout( [$arg], qr{mmdblookup --file.+This application accepts the following options:}s, 0, "help output from $arg" ); } _test_both( [], qr{mmdblookup --file.+This application accepts the following options:}s, qr{ERROR: You must provide a filename with --file}, 1, "help output with no CLI options" ); _test_stderr( [qw( --file foo )], qr{ERROR: You must provide an IP address with --ip}, 1, 'error when no --ip is given' ); _test_stdout( [qw( --version )], qr/mmdblookup version \d+\.\d+\.\d+/, 0, 'output for --version' ); _test_stdout( ['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', '2.125.160.216'], qr/"en"\s*:\s*"Boxford"/, 0, 'output for 2.125.160.216' ); _test_stdout( ['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', '2.125.160.216', '--verbose'], qr/Database metadata.+"en"\s*:\s*"Boxford"/s, 0, 'verbose output for 2.125.160.216' ); _test_stdout( ['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', '2.125.160.216', qw( location latitude )], qr/^\s*51\.750000 \s*$/s, 0, 'output for 2.125.160.216 with lookup path' ); _test_stderr( [ qw( --file this/path/better/not/exist.mmdb --ip 1.2.3.4 ) ], qr{Can't open this/path/better/not/exist.mmdb}s, 2, 'error for file that does not exist' ); _test_stderr( ['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', 'not-an-ip-address' ], qr{Error from call to getaddrinfo for not-an-ip-address}s, 3, 'error for bad IP address' ); _test_stderr( ['--file', "$test_data_dir/GeoIP2-City-Test.mmdb", '--ip', '10.2.3.4' ], qr{\QCould not find an entry for this IP address (10.2.3.4)}s, 6, 'error for bad PI address' ); done_testing(); sub _test_stdout { my $args = shift; my $expect_stdout = shift; my $expect_status = shift; my $desc = shift; _test_both( $args, $expect_stdout, q{}, $expect_status, $desc ); } sub _test_stderr { my $args = shift; my $expect_stderr = shift; my $expect_status = shift; my $desc = shift; _test_both( $args, undef, $expect_stderr, $expect_status, $desc ); } sub _test_both { my $args = shift; my $expect_stdout = shift; my $expect_stderr = shift; my $expect_status = shift; my $desc = shift; my $stdout; my $stderr; run3( [ $mmdblookup, @{$args} ], \undef, \$stdout, \$stderr, ); my $exit_status = $? >> 8; # We don't need to retest that the help output shows up for all errors if ( defined $expect_stdout ) { like( $stdout, $expect_stdout, "stdout for mmdblookup @{$args}" ); } if ( ref $expect_stderr ) { like( $stderr, $expect_stderr, "stderr for mmdblookup @{$args}" ); } else { is( $stderr, $expect_stderr, "stderr for mmdblookup @{$args}" ); } is( $exit_status, $expect_status, "exit status was $expect_status for mmdblookup @{$args}" ); } libmaxminddb-1.0.4/t/no_map_get_value_t.c000066400000000000000000000016361245160621500204140ustar00rootroot00000000000000#include "maxminddb_test_helper.h" void run_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-string-value-entries.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); const char *ip = "1.1.1.1"; MMDB_lookup_result_s result = lookup_string_ok(mmdb, ip, filename, mode_desc); MMDB_entry_data_s entry_data; int status = MMDB_get_value(&result.entry, &entry_data, NULL); cmp_ok(status, "==", MMDB_SUCCESS, "status for MMDB_get_value() is MMDB_SUCCESS"); ok(entry_data.has_data, "found a value when varargs list is just NULL"); cmp_ok(entry_data.type, "==", MMDB_DATA_TYPE_UTF8_STRING, "returned entry type is utf8_string"); MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/read_node_t.c000066400000000000000000000053251245160621500170270ustar00rootroot00000000000000#include "maxminddb_test_helper.h" void run_read_node_tests(MMDB_s *mmdb, const uint32_t tests[][3], int test_count, uint8_t record_size) { for (int i = 0; i < test_count; i++) { uint32_t node_number = tests[i][0]; MMDB_search_node_s node; int status = MMDB_read_node(mmdb, node_number, &node); if (MMDB_SUCCESS == status) { cmp_ok(node.left_record, "==", tests[i][1], "left record for node %i is %i - %i bit DB", node_number, tests[i][1], record_size); cmp_ok(node.right_record, "==", tests[i][2], "left record for node %i is %i - %i bit DB", node_number, tests[i][2], record_size); } else { diag("call to MMDB_read_node for node %i failed - %i bit DB", node_number, record_size); } } } void run_24_bit_record_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-mixed-24.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); const uint32_t tests[5][3] = { { 0, 1, 242 }, { 80, 81, 197 }, { 96, 97, 242 }, { 103, 242, 104 }, { 241, 96, 242 } }; run_read_node_tests(mmdb, tests, 5, 24); MMDB_close(mmdb); free(mmdb); } void run_28_bit_record_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-mixed-28.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); const uint32_t tests[5][3] = { { 0, 1, 242 }, { 80, 81, 197 }, { 96, 97, 242 }, { 103, 242, 104 }, { 241, 96, 242 } }; run_read_node_tests(mmdb, tests, 5, 28); MMDB_close(mmdb); free(mmdb); } void run_32_bit_record_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-mixed-32.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); const uint32_t tests[5][3] = { { 0, 1, 242 }, { 80, 81, 197 }, { 96, 97, 242 }, { 103, 242, 104 }, { 241, 96, 242 } }; run_read_node_tests(mmdb, tests, 5, 32); MMDB_close(mmdb); free(mmdb); } void run_tests(int mode, const char *mode_desc) { run_24_bit_record_tests(mode, mode_desc); run_28_bit_record_tests(mode, mode_desc); run_32_bit_record_tests(mode, mode_desc); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); } libmaxminddb-1.0.4/t/threads_t.c000066400000000000000000000122701245160621500165360ustar00rootroot00000000000000#include "maxminddb_test_helper.h" #include typedef struct thread_arg { int thread_id; MMDB_s *mmdb; const char *ip_to_lookup; } thread_arg_s; typedef struct test_result { const char *ip_looked_up; int lookup_string_gai_error; int lookup_string_mmdb_error; int found_entry; int get_value_status; int data_type_ok; char *data_value; } test_result_s; void test_one_ip(MMDB_s *mmdb, const char *ip, test_result_s *test_result) { test_result->ip_looked_up = ip; int gai_error = 0; int mmdb_error = 0; MMDB_lookup_result_s result = MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error); test_result->lookup_string_gai_error = gai_error; if (gai_error) { return; } test_result->lookup_string_mmdb_error = mmdb_error; if (mmdb_error) { return; } test_result->found_entry = result.found_entry; if (!result.found_entry) { return; } MMDB_entry_data_s data; int status = MMDB_get_value(&result.entry, &data, "ip", NULL); test_result->get_value_status = status; if (status) { return; } test_result->data_type_ok = data.type == MMDB_DATA_TYPE_UTF8_STRING; if (!test_result->data_type_ok) { return; } test_result->data_value = strndup(data.utf8_string, data.data_size); return; } void *run_one_thread(void *arg) { thread_arg_s *thread_arg = (thread_arg_s *)arg; MMDB_s *mmdb = thread_arg->mmdb; const char *ip = thread_arg->ip_to_lookup; test_result_s *result = malloc(sizeof(test_result_s)); test_one_ip(mmdb, ip, result); pthread_exit((void *)result); } void process_result(test_result_s *result, const char *expect, const char *mode_desc) { int is_ok; is_ok = ok(!result->lookup_string_gai_error, "no getaddrinfo error for %s - %s", result->ip_looked_up, mode_desc); if (!is_ok) { return; } is_ok = ok(!result->lookup_string_mmdb_error, "no mmdb error for %s - %s", result->ip_looked_up, mode_desc); if (!is_ok) { return; } is_ok = ok(result->found_entry, "got a result for %s in the database - %s", result->ip_looked_up, mode_desc); if (!is_ok) { return; } is_ok = ok(!result->get_value_status, "no error from MMDB_get_value for %s - %s", result->ip_looked_up, mode_desc); if (!is_ok) { return; } is_ok = ok(result->data_type_ok, "MMDB_get_value found a utf8_string at 'ip' key for %s - %s", result->ip_looked_up, mode_desc); if (!is_ok) { return; } is(result->data_value, expect, "found expected result for 'ip' key for %s - %s", result->ip_looked_up, mode_desc); } void run_ipX_tests(MMDB_s *mmdb, const char *pairs[][2], int pairs_rows, int mode, const char *mode_desc) { pthread_t threads[pairs_rows]; struct thread_arg thread_args[pairs_rows]; for (int i = 0; i < pairs_rows; i += 1) { thread_args[i].thread_id = i; thread_args[i].mmdb = mmdb; thread_args[i].ip_to_lookup = pairs[i][0]; int error = pthread_create(&threads[i], NULL, run_one_thread, &thread_args[i]); if (error) { BAIL_OUT("pthread_create failed"); } } for (int i = 0; i < pairs_rows; i += 1) { void *thread_return; int error = pthread_join(threads[i], &thread_return); if (error) { BAIL_OUT("pthread_join failed"); } test_result_s *test_result = (test_result_s *)thread_return; if (NULL != test_result) { process_result(test_result, pairs[i][1], mode_desc); if (test_result->data_type_ok) { free(test_result->data_value); } free(test_result); } } } void run_tests(int mode, const char *mode_desc) { const char *filename = "MaxMind-DB-test-mixed-32.mmdb"; const char *path = test_database_path(filename); MMDB_s *mmdb = open_ok(path, mode, mode_desc); free((void *)path); const char *pairs[18][2] = { { "1.1.1.1", "::1.1.1.1" }, { "1.1.1.2", "::1.1.1.2" }, { "1.1.1.3", "::1.1.1.2" }, { "1.1.1.7", "::1.1.1.4" }, { "1.1.1.9", "::1.1.1.8" }, { "1.1.1.15", "::1.1.1.8" }, { "1.1.1.17", "::1.1.1.16" }, { "1.1.1.31", "::1.1.1.16" }, { "1.1.1.32", "::1.1.1.32" }, { "::1:ffff:ffff", "::1:ffff:ffff" }, { "::2:0:0", "::2:0:0" }, { "::2:0:1a", "::2:0:0" }, { "::2:0:40", "::2:0:40" }, { "::2:0:4f", "::2:0:40" }, { "::2:0:50", "::2:0:50" }, { "::2:0:52", "::2:0:50" }, { "::2:0:58", "::2:0:58" }, { "::2:0:59", "::2:0:58" }, }; run_ipX_tests(mmdb, pairs, 18, mode, mode_desc); MMDB_close(mmdb); free(mmdb); } int main(void) { plan(NO_PLAN); for_all_modes(&run_tests); done_testing(); pthread_exit(NULL); } libmaxminddb-1.0.4/t/version_t.c000066400000000000000000000003761245160621500165750ustar00rootroot00000000000000#include "maxminddb_test_helper.h" int main(void) { const char *version = MMDB_lib_version(); if (ok(version != NULL, "MMDB_lib_version exists")) { is(version, PACKAGE_VERSION, "version is " PACKAGE_VERSION); } done_testing(); } pax_global_header00006660000000000000000000000064124351732500014514gustar00rootroot0000000000000052 comment=1d8d185b6289625183544a6bd9b1457f2b6011bc libmaxminddb-1.0.4/t/libtap/000077500000000000000000000000001243517325000156665ustar00rootroot00000000000000libmaxminddb-1.0.4/t/libtap/.gitignore000066400000000000000000000000621243517325000176540ustar00rootroot00000000000000/t/* !/t/*.* *.a *.lo *.o *.sw? /.deps /.dirstamp libmaxminddb-1.0.4/t/libtap/.travis.yml000066400000000000000000000003011243517325000177710ustar00rootroot00000000000000language: c compiler: - gcc - clang before_install: sudo apt-get install -y libtest-differences-perl install: make CC=$CC install script: make CC=$CC test after_script: make uninstall libmaxminddb-1.0.4/t/libtap/COPYING000066400000000000000000000432541243517325000167310ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. libmaxminddb-1.0.4/t/libtap/INSTALL000066400000000000000000000023341243517325000167210ustar00rootroot00000000000000To install libtap on a unix-like system: $ make $ make check $ make install Note that `make check` runs Perl unit-tests, which require the Test::Differences module from CPAN; if you run them, make sure to install it. To compile with gcc -ansi, run $ make ANSI=1 On Windows, the library can be created by first setting up the correct development environment variables. Usually this is done by running vcvars32.bat included in the visual studio distribution. You should also install gnu make which can be found at http://gnuwin32.sourceforge.net/packages/make.htm. And you should have perl to run the tests although this isnt absolutely necessary. Once this is done, you should be able to run the following: > make -f Makefile.win > make check Alternatively, you might want to use the visual studio project file included by Alexander Kahl (e-user). If you want to use it directly in another project, you can copy tap.c and tap.h there and it shouldn't have a problem compiling. $ ls tap.c tap.h test.c $ cat test.c #include "tap.h" int main () { plan(1); ok(50 + 5, "foo %s", "bar"); done_testing(); } $ gcc test.c tap.c $ a.out 1..1 ok 1 - foo bar libmaxminddb-1.0.4/t/libtap/Makefile000066400000000000000000000016351243517325000173330ustar00rootroot00000000000000CFLAGS = -g -Wall -I. CC = gcc TESTS = $(patsubst %.c, %, $(wildcard t/*.c)) ifdef ANSI # -D_BSD_SOURCE for MAP_ANONYMOUS CFLAGS += -ansi -D_BSD_SOURCE LDLIBS += -lbsd-compat endif %: $(CC) $(LDFLAGS) $(TARGET_ARCH) $(filter %.o %.a %.so, $^) $(LDLIBS) -o $@ %.o: $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $(filter %.c, $^) $(LDLIBS) -o $@ %.a: $(AR) rcs $@ $(filter %.o, $^) %.so: $(CC) -shared $(LDFLAGS) $(TARGET_ARCH) $(filter %.o, $^) $(LDLIBS) -o $@ all: libtap.a tests libtap.a: tap.o tap.o: tap.c tap.h tests: $(TESTS) $(TESTS): %: %.o libtap.a $(patsubst %, %.o, $(TESTS)): %.o: %.c tap.h clean: rm -rf *.o t/*.o libtap.a $(TESTS) install: libtap.a tap.h sudo cp libtap.a /usr/lib sudo cp tap.h /usr/include uninstall: sudo rm /usr/lib/libtap.a /usr/include/tap.h dist: rm libtap.zip zip -r libtap * check test: all prove .PHONY: all clean install uninstall dist check test tests libmaxminddb-1.0.4/t/libtap/Makefile.win000066400000000000000000000012431243517325000201220ustar00rootroot00000000000000CFLAGS = /Zi /Wall /wd4255 /wd4996 /wd4127 /wd4820 /wd4100 /wd4619 \ /wd4514 /wd4668 /I. CC = cl /nologo TESTS = $(patsubst %.c, %.exe, $(wildcard t/*.c)) %.exe: $(CC) $(LDFLAGS) $(filter %.obj %.lib %.dll, $^) $(LDLIBS) /Fe $@ %.o: $(CC) $(CFLAGS) $(CPPFLAGS) /c $(filter %.c, $^) $(LDLIBS) /Fo $@ %.lib: lib /nologo /out:$@ $(filter %.obj, $^) %.dll: lib /nologo /out:$@ $(filter %.obj, $^) all: tap.lib tests tap.lib: tap.obj tap.obj: tap.c tap.h tests: $(TESTS) $(TESTS): %.exe: %.obj tap.lib $(patsubst %.exe, %.obj, $(TESTS)): %.obj: %.c tap.h clean: rm -rf *.obj t/*.obj tap.lib $(TESTS) check test: all prove .PHONY: all clean check test tests libmaxminddb-1.0.4/t/libtap/README.md000066400000000000000000000154501243517325000171520ustar00rootroot00000000000000NAME ==== libtap - Write tests in C SYNOPSIS ======== #include int main () { plan(5); ok(3 == 3); is("fnord", "eek", "two different strings not that way?"); ok(3 <= 8732, "%d <= %d", 3, 8732); like("fnord", "f(yes|no)r*[a-f]$"); cmp_ok(3, ">=", 10); done_testing(); } results in: 1..5 ok 1 not ok 2 - two different strings not that way? # Failed test 'two different strings not that way?' # at t/synopsis.c line 7. # got: 'fnord' # expected: 'eek' ok 3 - 3 <= 8732 ok 4 not ok 5 # Failed test at t/synopsis.c line 10. # 3 # >= # 10 # Looks like you failed 2 tests of 5 run. DESCRIPTION =========== tap is an easy to read and easy to write way of creating tests for your software. This library creates functions that can be used to generate it for your C programs. It is mostly based on the Test::More Perl module. INSTALL ======= On **Unix** systems: $ make $ make install For more detailed installation instructions (eg, for **Windows**), see `INSTALL`. FUNCTIONS ========= - plan(tests) - plan(NO_PLAN) - plan(SKIP_ALL); - plan(SKIP_ALL, fmt, ...) Use this to start a series of tests. When you know how many tests there will be, you can put a number as a number of tests you expect to run. If you do not know how many tests there will be, you can use plan(NO_PLAN) or not call this function. When you pass it a number of tests to run, a message similar to the following will appear in the output: 1..5 If you pass it SKIP_ALL, the whole test will be skipped. - ok(test) - ok(test, fmt, ...) Specify a test. the test can be any statement returning a true or false value. You may optionally pass a format string describing the test. ok(r = reader_new("Of Mice and Men"), "create a new reader"); ok(reader_go_to_page(r, 55), "can turn the page"); ok(r->page == 55, "page turned to the right one"); Should print out: ok 1 - create a new reader ok 2 - can turn the page ok 3 - page turned to the right one On failure, a diagnostic message will be printed out. not ok 3 - page turned to the right one # Failed test 'page turned to the right one' # at reader.c line 13. - is(got, expected) - is(got, expected, fmt, ...) - isnt(got, unexpected) - isnt(got, unexpected, fmt, ...) Tests that the string you got is what you expected. with isnt, it is the reverse. is("this", "that", "this is that"); prints: not ok 1 - this is that # Failed test 'this is that' # at is.c line 6. # got: 'this' # expected: 'that' - cmp_ok(a, op, b) - cmp_ok(a, op, b, fmt, ...) Compares two ints with any binary operator that doesn't require an lvalue. This is nice to use since it provides a better error message than an equivalent ok. cmp_ok(420, ">", 666); prints: not ok 1 # Failed test at cmpok.c line 5. # 420 # > # 666 - cmp_mem(got, expected, n) - cmp_mem(got, expected, n, fmt, ...) Tests that the first n bytes of the memory you got is what you expected. NULL pointers for got and expected are handled (if either is NULL, the test fails), but you need to ensure n is not too large. char *a = "foo"; char *b = "bar"; cmp_mem(a, b, 3) prints not ok 1 # Failed test at t/cmp_mem.c line 9. # Difference starts at offset 0 # got: 0x66 # expected: 0x62 - like(got, expected) - like(got, expected, fmt, ...) - unlike(got, unexpected) - unlike(got, unexpected, fmt, ...) Tests that the string you got matches the expected extended POSIX regex. unlike is the reverse. These macros are the equivalent of a skip on Windows. like("stranger", "^s.(r).*\\1$", "matches the regex"); prints: ok 1 - matches the regex - pass() - pass(fmt, ...) - fail() - fail(fmt, ...) Speciy that a test succeeded or failed. Use these when the statement is longer than you can fit into the argument given to an ok() test. - dies_ok(code) - dies_ok(code, fmt, ...) - lives_ok(code) - lives_ok(code, fmt, ...) Tests whether the given code causes your program to exit. The code gets passed to a macro that will test it in a forked process. If the code succeeds it will be executed in the parent process. You can test things like passing a function a null pointer and make sure it doesnt dereference it and crash. dies_ok({abort();}, "abort does close your program"); dies_ok({int x = 0/0;}, "divide by zero crash"); lives_ok({pow(3.0, 5.0);}, "nothing wrong with taking 3**5"); On Windows, these macros are the equivalent of a skip. - done_testing() Summarizes the tests that occurred and exits the main function. If there was no plan, it will print out the number of tests as. 1..5 It will also print a diagnostic message about how many failures there were. # Looks like you failed 2 tests of 3 run. If all planned tests were successful, it will return 0. If any test fails, it will return the number of failed tests (including ones that were missing). If they all passed, but there were missing tests, it will return 255. - note(fmt, ...) - diag(fmt, ...) print out a message to the tap output. note prints to stdout and diag prints to stderr. Each line is preceeded by a "# " so that you know its a diagnostic message. note("This is\na note\nto describe\nsomething."); prints: # This is # a note # to describe # something ok() and these functions return ints so you can use them like: ok(1) && note("yo!"); ok(0) || diag("I have no idea what just happened"); - skip(test, n) - skip(test, n, fmt, ...) - end_skip Skip a series of n tests if test is true. You may give a reason why you are skipping them or not. The (possibly) skipped tests must occur between the skip and end_skip macros. skip(TRUE, 2); ok(1); ok(0); end_skip; prints: ok 1 # skip ok 2 # skip - todo() - todo(fmt, ...) - end_todo Specifies a series of tests that you expect to fail because they are not yet implemented. todo() ok(0); end_todo; prints: not ok 1 # TODO # Failed (TODO) test at todo.c line 7 - BAIL_OUT() - BAIL_OUT(fmt, ...) Immediately stops all testing. BAIL_OUT("Can't go no further"); prints Bail out! Can't go no further and exits with 255. libmaxminddb-1.0.4/t/libtap/libtap.vcxproj000066400000000000000000000071741243517325000205670ustar00rootroot00000000000000 Debug Win32 Release Win32 {4DFC985A-83D7-4E61-85FE-C6EA6E43E3AA} Win32Proj libtap StaticLibrary true Unicode StaticLibrary false true Unicode Level3 Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) Windows true Level3 MaxSpeed true true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) Windows true true true libmaxminddb-1.0.4/t/libtap/t/000077500000000000000000000000001243517325000161315ustar00rootroot00000000000000libmaxminddb-1.0.4/t/libtap/t/cmp_mem.c000066400000000000000000000014031243517325000177100ustar00rootroot00000000000000#include "tap.h" int main () { setvbuf(stdout, NULL, _IONBF, 0); unsigned char all_0[] = {0, 0, 0, 0}; unsigned char all_255[] = {255, 255, 255, 255}; unsigned char half[] = {0, 0, 255, 255}; unsigned char half_2[] = {0, 0, 255, 255}; plan(8); cmp_mem(half, half_2, 4, "Same array different address"); cmp_mem(all_0, all_0, 4, "Array must be equal to itself"); cmp_mem(all_0, all_255, 4, "Arrays with different contents"); cmp_mem(all_0, half, 4, "Arrays differ, but start the same"); cmp_mem(all_0, all_255, 0, "Comparing 0 bytes of different arrays"); cmp_mem(NULL, all_0, 4, "got == NULL"); cmp_mem(all_0, NULL, 4, "expected == NULL"); cmp_mem(NULL, NULL, 4, "got == expected == NULL"); done_testing(); } libmaxminddb-1.0.4/t/libtap/t/cmpok.c000066400000000000000000000005651243517325000174140ustar00rootroot00000000000000#include "tap.h" int main () { setvbuf(stdout, NULL, _IONBF, 0); plan(9); cmp_ok(420, ">", 666); cmp_ok(23, "==", 55, "the number 23 is definitely 55"); cmp_ok(23, "==", 55); cmp_ok(23, "!=", 55); cmp_ok(23, "frob", 55); cmp_ok(23, "<=", 55); cmp_ok(55, "+", -55); cmp_ok(23, "%", 5); cmp_ok(55, "%", 5); done_testing(); } libmaxminddb-1.0.4/t/libtap/t/diesok.c000066400000000000000000000006431243517325000175560ustar00rootroot00000000000000#include "tap.h" int main () { setvbuf(stdout, NULL, _IONBF, 0); plan(5); ok(1, "sanity"); dies_ok({int x = 0; x = x/x;}, "can't divide by zero"); lives_ok({int x; x = 3/7;}, "this is a perfectly fine statement"); dies_ok({abort();}, "abort kills the program"); dies_ok( {printf("stdout\n"); fprintf(stderr, "stderr\n"); abort();}, "supress output"); done_testing(); } libmaxminddb-1.0.4/t/libtap/t/is.c000066400000000000000000000015611243517325000167130ustar00rootroot00000000000000#include "tap.h" int main () { setvbuf(stdout, NULL, _IONBF, 0); plan(18); is("this", "that", "this is that"); /* bang */ is("this", "this", "this is this"); is("this", "that"); /* bang */ is("this", "this"); is(NULL, NULL, "null is null"); is(NULL, "this", "null is this"); /* bang */ is("this", NULL, "this is null"); /* bang */ is("foo\nfoo\nfoo", "bar\nbar\nbar"); /* bang */ is("foo\nfoo\nfoo", "foo\nfoo\nfoo"); isnt("this", "that", "this isnt that"); isnt("this", "this", "this isnt this"); /* bang */ isnt("this", "that"); isnt("this", "this"); /* bang */ isnt(NULL, NULL, "null isnt null"); /* bang */ isnt(NULL, "this", "null isnt this"); isnt("this", NULL, "this isnt null"); isnt("foo\nfoo\nfoo", "bar\nbar\nbar"); isnt("foo\nfoo\nfoo", "foo\nfoo\nfoo"); /* bang */ done_testing(); } libmaxminddb-1.0.4/t/libtap/t/like.c000066400000000000000000000004201243517325000172150ustar00rootroot00000000000000#include "tap.h" int main () { setvbuf(stdout, NULL, _IONBF, 0); plan(3); like("strange", "range", "strange ~~ /range/"); unlike("strange", "anger", "strange !~~ /anger/"); like("stranger", "^s.(r).*\\1$", "matches the regex"); done_testing(); } libmaxminddb-1.0.4/t/libtap/t/notediag.c000066400000000000000000000004211243517325000200640ustar00rootroot00000000000000#include "tap.h" int main () { setvbuf(stdout, NULL, _IONBF, 0); note("note no new line"); note("note new line\n"); note(""); note(NULL); diag("diag no new line"); diag("diag new line\n"); diag(""); diag(NULL); return 1; } libmaxminddb-1.0.4/t/libtap/t/simple.c000066400000000000000000000010161243517325000175640ustar00rootroot00000000000000#include "tap.h" int main () { setvbuf(stdout, NULL, _IONBF, 0); plan(24); ok(1); ok(1); ok(1); ok(0); ok(1, "foo"); ok(1, "bar"); ok(1, "baz"); ok(1, "quux"); ok(1, "thud"); ok(1, "wombat"); ok(1, "blurgle"); ok(1, "frob"); ok(0, "frobnicate"); ok(1, "eek"); ok(1, "ook"); ok(1, "frodo"); ok(1, "bilbo"); ok(1, "wubble"); ok(1, "flarp"); ok(1, "fnord"); pass(); fail(); pass("good"); fail("bad"); done_testing(); } libmaxminddb-1.0.4/t/libtap/t/skip.c000066400000000000000000000006721243517325000172500ustar00rootroot00000000000000#include "tap.h" int main () { setvbuf(stdout, NULL, _IONBF, 0); plan(8); skip(0, 3, "%s cannot fork", "windows"); ok(1, "quux"); ok(1, "thud"); ok(1, "wombat"); end_skip; skip(1, 1, "need to be on windows"); ok(0, "blurgle"); end_skip; skip(0, 3); ok(1, "quux"); ok(1, "thud"); ok(1, "wombat"); end_skip; skip(1, 1); ok(0, "blurgle"); end_skip; done_testing(); } libmaxminddb-1.0.4/t/libtap/t/synopsis.c000066400000000000000000000004421243517325000201640ustar00rootroot00000000000000#include "tap.h" int main () { setvbuf(stdout, NULL, _IONBF, 0); plan(5); ok(3 == 3); is("fnord", "eek", "two different strings not that way?"); ok(3 <= 8732, "%d <= %d", 3, 8732); like("fnord", "f(yes|no)r*[a-f]$"); cmp_ok(3, ">=", 10); done_testing(); } libmaxminddb-1.0.4/t/libtap/t/test.t000077500000000000000000000115021243517325000172770ustar00rootroot00000000000000#!/usr/bin/perl use strict; use warnings; use Test::More tests => 10; use Test::Differences; my $x = $^O eq 'MSWin32' ? ".exe" : ""; sub cmd_eq_or_diff { my ($command, $expected) = @_; my $output = `$command$x 2>&1`; eq_or_diff($output, $expected, $command); } cmd_eq_or_diff "t/cmpok", < # 666 not ok 2 - the number 23 is definitely 55 # Failed test 'the number 23 is definitely 55' # at t/cmpok.c line 7. # 23 # == # 55 not ok 3 # Failed test at t/cmpok.c line 8. # 23 # == # 55 ok 4 # unrecognized operator 'frob' not ok 5 # Failed test at t/cmpok.c line 10. # 23 # frob # 55 ok 6 not ok 7 # Failed test at t/cmpok.c line 12. # 55 # + # -55 ok 8 not ok 9 # Failed test at t/cmpok.c line 14. # 55 # % # 5 # Looks like you failed 6 tests of 9 run. END cmd_eq_or_diff "t/cmp_mem", <= # 10 # Looks like you failed 2 tests of 5 run. END cmd_eq_or_diff "t/todo", < This file is licensed under the GPLv2 or any later version */ #define _BSD_SOURCE 1 #include #include #include #include #include "tap.h" static int expected_tests = NO_PLAN; static int failed_tests; static int current_test; static char *todo_mesg; static char * vstrdupf (const char *fmt, va_list args) { char *str; int size; va_list args2; va_copy(args2, args); if (!fmt) fmt = ""; size = vsnprintf(NULL, 0, fmt, args2) + 2; str = malloc(size); if (!str) { perror("malloc error"); exit(1); } vsprintf(str, fmt, args); va_end(args2); return str; } void tap_plan (int tests, const char *fmt, ...) { expected_tests = tests; if (tests == SKIP_ALL) { char *why; va_list args; va_start(args, fmt); why = vstrdupf(fmt, args); va_end(args); printf("1..0 "); note("SKIP %s\n", why); exit(0); } if (tests != NO_PLAN) { printf("1..%d\n", tests); } } int vok_at_loc (const char *file, int line, int test, const char *fmt, va_list args) { char *name = vstrdupf(fmt, args); if (!test) printf("not "); printf("ok %d", ++current_test); if (*name) printf(" - %s", name); if (todo_mesg) { printf(" # TODO"); if (*todo_mesg) printf(" %s", todo_mesg); } printf("\n"); if (!test) { fprintf(stderr, "# Failed "); if (todo_mesg) fprintf(stderr, "(TODO) "); fprintf(stderr, "test "); if (*name) fprintf(stderr, "'%s'\n# ", name); fprintf(stderr, "at %s line %d.\n", file, line); if (!todo_mesg) failed_tests++; } free(name); return test; } int ok_at_loc (const char *file, int line, int test, const char *fmt, ...) { va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); return test; } static int mystrcmp (const char *a, const char *b) { return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b); } #define eq(a, b) (!mystrcmp(a, b)) #define ne(a, b) (mystrcmp(a, b)) int is_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...) { int test = eq(got, expected); va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" got: '%s'", got); diag(" expected: '%s'", expected); } return test; } int isnt_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...) { int test = ne(got, expected); va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" got: '%s'", got); diag(" expected: anything else"); } return test; } int cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, const char *fmt, ...) { int test = eq(op, "||") ? a || b : eq(op, "&&") ? a && b : eq(op, "|") ? a | b : eq(op, "^") ? a ^ b : eq(op, "&") ? a & b : eq(op, "==") ? a == b : eq(op, "!=") ? a != b : eq(op, "<") ? a < b : eq(op, ">") ? a > b : eq(op, "<=") ? a <= b : eq(op, ">=") ? a >= b : eq(op, "<<") ? a << b : eq(op, ">>") ? a >> b : eq(op, "+") ? a + b : eq(op, "-") ? a - b : eq(op, "*") ? a * b : eq(op, "/") ? a / b : eq(op, "%") ? a % b : diag("unrecognized operator '%s'", op); va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" %d", a); diag(" %s", op); diag(" %d", b); } return test; } static int find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) { size_t i; if (a == b) return 0; if (!a || !b) return 2; for (i = 0; i < n; i++) { if (a[i] != b[i]) { *offset = i; return 1; } } return 0; } int cmp_mem_at_loc (const char *file, int line, const void *got, const void *expected, size_t n, const char *fmt, ...) { size_t offset; int diff = find_mem_diff(got, expected, n, &offset); va_list args; va_start(args, fmt); vok_at_loc(file, line, !diff, fmt, args); va_end(args); if (diff == 1) { diag(" Difference starts at offset %d", offset); diag(" got: 0x%02x", ((unsigned char *)got)[offset]); diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]); } else if (diff == 2) { diag(" got: %s", got ? "not NULL" : "NULL"); diag(" expected: %s", expected ? "not NULL" : "NULL"); } return !diff; } static void vdiag_to_fh (FILE *fh, const char *fmt, va_list args) { char *mesg, *line; int i; if (!fmt) return; mesg = vstrdupf(fmt, args); line = mesg; for (i = 0; *line; i++) { char c = mesg[i]; if (!c || c == '\n') { mesg[i] = '\0'; fprintf(fh, "# %s\n", line); if (!c) break; mesg[i] = c; line = mesg + i + 1; } } free(mesg); return; } int diag (const char *fmt, ...) { va_list args; va_start(args, fmt); vdiag_to_fh(stderr, fmt, args); va_end(args); return 0; } int note (const char *fmt, ...) { va_list args; va_start(args, fmt); vdiag_to_fh(stdout, fmt, args); va_end(args); return 0; } int exit_status () { int retval = 0; if (expected_tests == NO_PLAN) { printf("1..%d\n", current_test); } else if (current_test != expected_tests) { diag("Looks like you planned %d test%s but ran %d.", expected_tests, expected_tests > 1 ? "s" : "", current_test); retval = 255; } if (failed_tests) { diag("Looks like you failed %d test%s of %d run.", failed_tests, failed_tests > 1 ? "s" : "", current_test); if (expected_tests == NO_PLAN) retval = failed_tests; else retval = expected_tests - current_test + failed_tests; } return retval; } int bail_out (int ignore, const char *fmt, ...) { va_list args; va_start(args, fmt); printf("Bail out! "); vprintf(fmt, args); printf("\n"); va_end(args); exit(255); return 0; } void tap_skip (int n, const char *fmt, ...) { char *why; va_list args; va_start(args, fmt); why = vstrdupf(fmt, args); va_end(args); while (n --> 0) { printf("ok %d ", ++current_test); note("skip %s\n", why); } free(why); } void tap_todo (int ignore, const char *fmt, ...) { va_list args; va_start(args, fmt); todo_mesg = vstrdupf(fmt, args); va_end(args); } void tap_end_todo () { free(todo_mesg); todo_mesg = NULL; } #ifndef _WIN32 #include #include #include #if defined __APPLE__ || defined BSD #define MAP_ANONYMOUS MAP_ANON #endif /* Create a shared memory int to keep track of whether a piece of code executed dies. to be used in the dies_ok and lives_ok macros. */ int tap_test_died (int status) { static int *test_died = NULL; int prev; if (!test_died) { test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *test_died = 0; } prev = *test_died; *test_died = status; return prev; } int like_at_loc (int for_match, const char *file, int line, const char *got, const char *expected, const char *fmt, ...) { int test; regex_t re; va_list args; int err = regcomp(&re, expected, REG_EXTENDED); if (err) { char errbuf[256]; regerror(err, &re, errbuf, sizeof errbuf); fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n", expected, errbuf, file, line); exit(255); } err = regexec(&re, got, 0, NULL, 0); regfree(&re); test = for_match ? !err : err; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { if (for_match) { diag(" '%s'", got); diag(" doesn't match: '%s'", expected); } else { diag(" '%s'", got); diag(" matches: '%s'", expected); } } return test; } #endif libmaxminddb-1.0.4/t/libtap/tap.h000066400000000000000000000115011243517325000166210ustar00rootroot00000000000000/* libtap - Write tests in C Copyright 2012 Jake Gelbman This file is licensed under the GPLv2 or any later version */ #ifndef __TAP_H__ #define __TAP_H__ #ifdef __cplusplus extern "C" { #endif #ifndef va_copy #ifdef __va_copy #define va_copy __va_copy #else #define va_copy(d, s) ((d) = (s)) #endif #endif #include #include #include int vok_at_loc (const char *file, int line, int test, const char *fmt, va_list args); int ok_at_loc (const char *file, int line, int test, const char *fmt, ...); int is_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...); int isnt_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...); int cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, const char *fmt, ...); int cmp_mem_at_loc (const char *file, int line, const void *got, const void *expected, size_t n, const char *fmt, ...); int bail_out (int ignore, const char *fmt, ...); void tap_plan (int tests, const char *fmt, ...); int diag (const char *fmt, ...); int note (const char *fmt, ...); int exit_status (void); void tap_skip (int n, const char *fmt, ...); void tap_todo (int ignore, const char *fmt, ...); void tap_end_todo (void); #define NO_PLAN -1 #define SKIP_ALL -2 #define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define cmp_mem(...) cmp_mem_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL); #define plan(...) tap_plan(__VA_ARGS__, NULL) #define done_testing() return exit_status() #define BAIL_OUT(...) bail_out(0, "" __VA_ARGS__, NULL) #define pass(...) ok(1, "" __VA_ARGS__) #define fail(...) ok(0, "" __VA_ARGS__) #define skip(test, ...) do {if (test) {tap_skip(__VA_ARGS__, NULL); break;} #define end_skip } while (0) #define todo(...) tap_todo(0, "" __VA_ARGS__, NULL) #define end_todo tap_end_todo() #define dies_ok(...) dies_ok_common(1, __VA_ARGS__) #define lives_ok(...) dies_ok_common(0, __VA_ARGS__) #ifdef _WIN32 #define like(...) tap_skip(1, "like is not implemented on Windows") #define unlike tap_skip(1, "unlike is not implemented on Windows") #define dies_ok_common(...) \ tap_skip(1, "Death detection is not supported on Windows") #else #define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) #define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) int like_at_loc (int for_match, const char *file, int line, const char *got, const char *expected, const char *fmt, ...); #include #include #include int tap_test_died (int status); #define dies_ok_common(for_death, code, ...) \ do { \ int cpid; \ int it_died; \ tap_test_died(1); \ cpid = fork(); \ switch (cpid) { \ case -1: \ perror("fork error"); \ exit(1); \ case 0: \ close(1); \ close(2); \ code \ tap_test_died(0); \ exit(0); \ } \ if (waitpid(cpid, NULL, 0) < 0) { \ perror("waitpid error"); \ exit(1); \ } \ it_died = tap_test_died(0); \ if (!it_died) \ {code} \ ok(for_death ? it_died : !it_died, "" __VA_ARGS__); \ } while (0) #endif #ifdef __cplusplus } #endif #endif pax_global_header00006660000000000000000000000064123227021630014510gustar00rootroot0000000000000052 comment=f887fec99eabf6d68746e257b894bae854fefc27 libmaxminddb-1.0.4/t/maxmind-db/000077500000000000000000000000001232270216300164275ustar00rootroot00000000000000libmaxminddb-1.0.4/t/maxmind-db/.gitignore000066400000000000000000000000071232270216300204140ustar00rootroot00000000000000/_site libmaxminddb-1.0.4/t/maxmind-db/LICENSE000066400000000000000000000004361232270216300174370ustar00rootroot00000000000000This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. libmaxminddb-1.0.4/t/maxmind-db/MaxMind-DB-spec.md000066400000000000000000000462121232270216300215260ustar00rootroot00000000000000--- layout: default title: MaxMind DB File Format Specification version: v2.0 --- # MaxMind DB File Format Specification ## Version This spec documents **version 2.0** of the MaxMind DB binary format. The version number consists of separate major and minor version numbers. It should not be considered a decimal number. In other words, version 2.10 comes after version 2.9. Code which is capable of reading a given major version of the format should not be broken by minor version changes to the format. ## Overview The binary database is split into three parts: 1. The binary search tree. Each level of the tree corresponds to a single bit in the 128 bit representation of an IPv6 address. 2. The data section. These are the values returned to the client for a specific IP address, e.g. "US", "New York", or a more complex map type made up of multiple fields. 3. Database metadata. Information about the database itself. ## Database Metadata This portion of the database is stored at the end of the file. It is documented first because understanding some of the metadata is key to understanding how the other sections work. This section can be found by looking for a binary sequence matching "\xab\xcd\xefMaxMind.com". The *last* occurrence of this string in the file marks the end of the data section and the beginning of the metadata. Since we allow for arbitrary binary data in the data section, some other piece of data could contain these values. This is why you need to find the last occurrence of this sequence. The maximum allowable size for the metadata section, including the marker that starts the metadata, is 128kb. The metadata is stored as a map data structure. This structure is described later in the spec. Changing a key's data type or removing a key would consistute a major version change for this spec. Except where otherwise specified, each key listed is required for the database to be considered valid. Adding a key constitutes a minor version change. Removing a key or changing its type constitutes a major version change. The list of known keys for the current version of the format is as follows: ### node\_count This is an unsigned 32-bit integer indicating the number of nodes in the search tree. ### record\_size This is an unsigned 16-bit integer. It indicates the number of bits in a record in the search tree. Note that each node consists of *two* records. ### ip\_version This is an unsigned 16-bit integer which is always 4 or 6. It indicates whether the database contains IPv4 or IPv6 address data. ### database\_type This is a string that indicates the structure of each data record associated with an IP address. The actual definition of these structures is left up to the database creator. Names starting with "GeoIP" are reserved for use by MaxMind (and "GeoIP" is a trademark anyway). ### languages An array of strings, each of which is a language code. A given record may contain data items that have been localized to some or all of these languages. Records should not contain localized data for languages not included in this array. This is an optional key, as this may not be relevant for all types of data. ### binary\_format\_major\_version This is an unsigned 16-bit integer indicating the major version number for the database's binary format. ### binary\_format\_minor\_version This is an unsigned 16-bit integer indicating the minor version number for the database's binary format. ### build\_epoch This is an unsigned 64-bit integer that contains the database build timestamp as a Unix epoch value. ### description This key will always point to a map. The keys of that map will be language codes, and the values will be a description in that language as a UTF-8 string. The codes may include additional information such as script or country identifiers, like "zh-TW" or "mn-Cyrl-MN". The additional identifiers will be separated by a dash character ("-"). This is key is optional. However, creators of databases are strongly encouraged to include a description in at least one language. ### Calculating the Search Tree Section Size The formula for calculating the search tree section size *in bytes* is as follows: ( ( $record_size * 2 ) / 8 ) * $number_of_nodes The end of the search tree marks the beginning of the data section. ## Binary Search Tree Section The database file starts with a binary search tree. The number of nodes in the tree is dependent on how many unique netblocks are needed for the particular database. For example, the city database needs many more small netblocks than the country database. The top most node is always located at the beginning of the search tree section's address space. Each node consists of two records, each of which is a pointer to an address in the file. The pointers can point to one of three things. First, it may point to another node in the search tree address space. These pointers are followed as part of the IP address search algorithm, described below. The pointer can also point to 0. If this is the case, it means that the IP address we are searching for is not in the database. Finally, it may point to an address in the data section. This is the data relevant to the given netblock. ### Node Layout Each node in the search tree consists of two records, each of which is a pointer. The record size varies by database, but inside a single database node records are always the same size. A record may be anywhere from 24 to 128 bits long, dependending on the number of nodes in the tree. These pointers are stored in big-endian format (most significant byte first). Here are some examples of how the records are laid out in a node for 24, 28, and 32 bit records. Larger record sizes follow this same pattern. #### 24 bits (small database), one node is 6 bytes | <------------- node --------------->| | 23 .. 0 | 23 .. 0 | #### 28 bits (medium database), one node is 7 bytes | <------------- node --------------->| | 23 .. 0 | 27..24 | 27..24 | 23 .. 0 | Note, the last 4 bits of each pointer are combined into the middle byte. #### 32 bits (large database), one node is 8 bytes | <------------- node --------------->| | 31 .. 0 | 31 .. 0 | ### Search Lookup Algorithm The first step is to convert the IP address to its big-endian binary representation. For an IPv4 address, this becomes 32 bits. For IPv6 you get 128 bits. The leftmost bit corresponds to the first node in the search tree. For each bit, a value of 0 means we choose the left record in a node, and a value of 1 means we choose the right record. The record value is always interpreted as an unsigned integer. The maximum size of the integer is dependent on the number of bits in a record (24, 28, or 32). If the record value is a number that is less than the *number of nodes* (not in bytes, but the actual node count) in the search tree (this is stored in the database metadata), then the value is a node number. In this case, we find that node in the search tree and repeat the lookup algorithm from there. If the record value is equal to the number of nodes, that means that we do not have any data for the IP address, and the search ends here. If the record value is *greater* than the number of nodes in the search tree, then it is an actual pointer value pointing into the data section. The value of the pointer is calculated from the start of the data section, *not* from the start of the file. In order to determine where in the data section we should start looking, we use the following formula: $data_section_offset = ( $record_value - $node_count ) - 16 (data section separator size) The reason that we subtract the `$node_count` is best demonstrated by an example. Let's assume we have a 24-bit tree with 1,000 nodes. Each node contains 48 bits, or 6 bytes. The size of the tree in bytes is 6,000. When a record in the tree contains a number that is <= 1,000, this is a *node number*, and we look up that node. If a record contains a value >= 1,017, we know that it is a data section value. We subtract the node count (1,000) and then subtract 16 for the data section separator, giving us the number 1. If a record contained the value 6,000, the formula would give us an offset of 5,000. In order to determine where in the file this offset really points to, we also need to know where the data section starts. This can be calculated by determining the size of the search tree in bytes and then adding an additional 16 bytes for the data section separator (see below). So the final formula to determine the offset in the file is: $offset_in_file = ( $record_value - $node_count ) + $search_tree_size_in_bytes ### IPv4 addresses in an IPv6 tree When storing IPv4 addresses in an IPv6 tree, they are stored as-is, so they occupy the first 32-bits of the address space (from 0 to 2**32 - 1). Creators of databases should decide on a strategy for handling the various mappings between IPv4 and IPv6. The strategy that MaxMind uses for its GeoIP databases is to include a pointer from the `::ffff:0:0/96` subnet to the root node of the IPv4 address space in the tree. This accounts for the [IPv4-mapped IPv6 address](http://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses). MaxMind also includes a pointer from the `2002::/16` subnet to the root node of the IPv4 address space in the tree. This accounts for the [6to4 mapping](http://en.wikipedia.org/wiki/6to4) subnet. Database creators are encouraged to document whether they are doing something similar for their databases. The Teredo subnet cannot be accounted for in the tree. Instead, code that searches the tree can offer to decode the IPv4 portion of a Teredo address and look that up. ## Data Section Separator There are 16 bytes of NULLs in between the search tree and the data section. This separator exists in order to make it possible for a verification tool to distinguish between the two sections. This separator is not considered part of the data section itself. In other words, the data section starts at `$size_of_search_tree + 16" bytes in the file. ## Output Data Section Each output data field has an associated type, and that type is encoded as a number that begins the data field. Some types are variable length. In those cases, the type indicator is also followed by a length. The data payload always comes at the end of the field. All binary data is stored in big-endian format. Note that the *interpretation* of a given data type's meaning is decided by higher-level APIs, not by the binary format itself. ### pointer - 1 A pointer to another part of the data section's address space. The pointer will point to the beginning of a field. It is illegal for a pointer to point to another pointer. Pointer values start from the beginning of the data section, *not* the beginning of the file. ### UTF-8 string - 2 A variable length byte sequence that contains valid utf8. If the length is zero then this is an empty string. ### double - 3 This is stored as an IEEE-754 double (binary64) in big-endian format. The length of a double is always 8 bytes. ### bytes - 4 A variable length byte sequence containing any sort of binary data. If the length is zero then this a zero-length byte sequence. This is not currently used but may be used in the future to embed non-text data (images, etc.). ### integer formats Integers are stored in variable length binary fields. We support 16-bit, 32-bit, 64-bit, and 128-bit unsigned integers. We also support 32-bit signed integers. A 128-bit integer can use up to 16 bytes, but may use fewer. Similarly, a 32-bit integer may use from 0-4 bytes. The number of bytes used is determined by the length specifier in the control byte. See below for details. A length of zero always indicates the number 0. When storing a signed integer, the left-most bit is the sign. A 1 is negative and a 0 is positive. The type numbers for our integer types are: * unsigned 16-bit int - 5 * unsigned 32-bit int - 6 * signed 32-bit int - 8 * unsigned 64-bit int - 9 * unsigned 128-bit int - 10 The unsigned 32-bit and 128-bit types may be used to store IPv4 and IPv6 addresses, respectively. The signed 32-bit integers are stored using the 2's complement representation. ### map - 7 A map data type contains a set of key/value pairs. Unlike other data types, the length information for maps indicates how many key/value pairs it contains, not its length in bytes. This size can be zero. See below for the algorithm used to determine the number of pairs in the hash. This algorithm is also used to determine the length of a field's payload. ### array - 11 An array type contains a set of ordered values. The length information for arrays indicates how many values it contains, not its length in bytes. This size can be zero. This type uses the same algorithm as maps for determining the length of a field's payload. ### data cache container - 12 This is a special data type that marks a container used to cache repeated data. For example, instead of repeating the string "United States" over and over in the database, we store it in the cache container and use pointers *into* this container instead. Nothing in the database will ever contain a pointer to the this field itself. Instead, various fields will point into the container. The primary reason for making this a separate data type versus simply inlining the cached data is so that a database dumper tool can skip this cache when dumping the data section. The cache contents will end up being dumped as pointers into it are followed. ### end marker - 13 The end marker marks the end of the data section. It is not strictly necessary, but including this marker allows a data section deserializer to process a stream of input, rather than having to find the end of the section before beginning the deserialization. This data type is not followed by a payload, and its size is always zero. ### boolean - 14 A true or false value. The length information for a boolean type will always be 0 or 1, indicating the value. There is no payload for this field. ### float - 15 This is stored as an IEEE-754 float (binary32) in big-endian format. The length of a float is always 4 bytes. This type is provided primarily for completeness. Because of the way floating point numbers are stored, this type can easily lose precision when serialized and then deserialized. If this is an issue for you, consider using a double instead. ### Data Field Format Each field starts with a control byte. This control byte provides information about the field's data type and payload size. The first three bits of the control byte tell you what type the field is. If these bits are all 0, then this is an "extended" type, which means that the *next* byte contains the actual type. Otherwise, the first three bytes will contain a number from 1 to 7, the actual type for the field. We've tried to assign the most commonly used types as numbers 1-7 as an optimization. With an extended type, the type number in the second byte is the number minus 7. In other words, an array (type 11) will be stored with a 0 for the type in the first byte and a 4 in the second. Here is an example of how the control byte may combine with the next byte to tell us the type: 001XXXXX pointer 010XXXXX UTF-8 string 010XXXXX unsigned 32-bit int (ASCII) 000XXXXX 00000011 unsigned 128-bit int (binary) 000XXXXX 00000100 array 000XXXXX 00000110 end marker #### Payload Size The next five bits in the control byte tell you how long the data field's payload is, except for maps and pointers. Maps and pointers use this size information a bit differently. See below. If the five bits are smaller than 29, then those bits are the payload size in bytes. For example: 01000010 UTF-8 string - 2 bytes long 01011100 UTF-8 string - 28 bytes long 11000001 unsigned 32-bit int - 1 byte long 00000011 00000011 unsigned 128-bit int - 3 bytes long If the five bits are equal to 29, 30, or 31, then use the following algorithm to calculate the payload size. If the value is 29, then the size is 29 + *the next byte after the type specifying bytes as an unsigned integer*. If the value is 30, then the size is 285 + *the next two bytes after the type specifying bytes as a single unsigned integer*. If the value is 31, then the size is 65,821 + *the next three bytes after the type specifying bytes as a single unsigned integer*. Some examples: 01011101 00110011 UTF-8 string - 80 bytes long In this case, the last five bits of the control byte equal 29. We treat the next byte as an unsigned integer. The next byte is 51, so the total size is (29 + 51) = 80. 01011110 00110011 00110011 UTF-8 string - 13,392 bytes long The last five bits of the control byte equal 30. We treat the next two bytes as a single unsigned integer. The next two bytes equal 13,107, so the total size is (285 + 13,107) = 13,392. 01011111 00110011 00110011 00110011 UTF-8 string - 3,421,264 bytes long The last five bits of the control byte equal 31. We treat the next three bytes as a single unsigned integer. The next three bytes equal 3,355,443, so the total size is (65,821 + 3,355,443) = 3,421,264. This means that the maximum payload size for a single field is 16,843,036 bytes. The binary number types always have a known size, but for consistency's sake, the control byte will always specify the correct size for these types. #### Maps Maps use the size in the control byte (and any following bytes) to indicate the number of key/value pairs in the map, not the size of the payload in bytes. This means that the maximum number of pairs for a single map is 16,843,036. Maps are laid out with each key followed by its value, followed by the next pair, etc. The keys are **always** UTF-8 strings. The values may be any data type, including maps or pointers. Once we know the number of pairs, we can look at each pair in turn to determine the size of the key and the key name, as well as the value's type and payload. #### Pointers Pointers use the last five bits in the control byte to calculate the pointer value. To calculate the pointer value, we start by subdiving the five bits into two groups. The first two bits indicate the size, and the next three bits are part of the value, so we end up with a control byte breaking down like this: 001SSVVV. The size can be 0, 1, 2, or 3. If the size is 0, the pointer is built by appending the next byte to the last three bits to produce an 11-bit value. If the size is 1, the pointer is built by appending the next two bytes to the last three bits to produce a 19-bit value + 2048. If the size is 2, the pointer is built by appending the next three bytes to the last three bits to produce a 27-bit value + 526336. Finally, if the size is 3, the pointer's value is contained in the next four bytes as a 32-bit value. In this case, the last three bits of the control byte are ignored. This means that we are limited to 4GB of address space for pointers, so the data section size for the database is limited to 4GB. ## License This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA libmaxminddb-1.0.4/t/maxmind-db/README.md000066400000000000000000000002261232270216300177060ustar00rootroot00000000000000MaxMind DB is a binary file format that stores data indexed by IP address subnets (IPv4 or IPv6). This repository contains the spec for that format. libmaxminddb-1.0.4/t/maxmind-db/bin/000077500000000000000000000000001232270216300171775ustar00rootroot00000000000000libmaxminddb-1.0.4/t/maxmind-db/bin/regen-github-pages000077500000000000000000000016531232270216300226070ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use autodie qw( :all ); use Cwd qw( abs_path ); use FindBin qw( $Bin ); use File::Slurp qw( read_file ); use Markdent::Simple::Fragment 0.22; my $repo = abs_path("$Bin/.."); my $markdown = read_file("$repo/MaxMind-DB-spec.md"); my $mds = Markdent::Simple::Fragment->new(); my $spec_html = $mds->markdown_to_html( dialects => 'GitHub', markdown => $markdown, ); my ($title) = $markdown =~ /^\#\s+(.+)\n/; my $index_html = <<"EOF"; $title
$spec_html
EOF system qw( git co gh-pages ); open my $fh, '>', "$repo/index.html"; print {$fh} $index_html; close $fh; libmaxminddb-1.0.4/t/maxmind-db/source-data/000077500000000000000000000000001232270216300206365ustar00rootroot00000000000000libmaxminddb-1.0.4/t/maxmind-db/source-data/GeoIP2-City-Test.json000066400000000000000000005252221232270216300244110ustar00rootroot00000000000000["2001:218::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:220::/32",{"country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841},"location":{"longitude":"127.5","latitude":"37","time_zone":"Asia/Seoul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841}}] ["2001:230::/32",{"country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841},"location":{"longitude":"127.5","latitude":"37","time_zone":"Asia/Seoul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841}}] ["2001:238::/32",{"country":{"iso_code":"TW","names":{"pt-BR":"Taiwan","es":"Taiwán","ru":"Тайвань","en":"Taiwan","zh-CN":"台湾","fr":"Taïwan","de":"Taiwan","ja":"台湾"},"geoname_id":1668284},"location":{"longitude":"121","latitude":"24","time_zone":"Asia/Taipei"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TW","names":{"pt-BR":"Taiwan","es":"Taiwán","ru":"Тайвань","en":"Taiwan","zh-CN":"台湾","fr":"Taïwan","de":"Taiwan","ja":"台湾"},"geoname_id":1668284}}] ["2001:240::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:250::/31",{"country":{"iso_code":"CN","names":{"pt-BR":"China","es":"República Popular China","ru":"Китай","en":"People's Republic of China","zh-CN":"中国","fr":"Chine","de":"China","ja":"中国"},"geoname_id":1814991},"location":{"longitude":"105","latitude":"35"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"CN","names":{"pt-BR":"China","es":"República Popular China","ru":"Китай","en":"People's Republic of China","zh-CN":"中国","fr":"Chine","de":"China","ja":"中国"},"geoname_id":1814991}}] ["2001:252::/32",{"country":{"iso_code":"CN","names":{"pt-BR":"China","es":"República Popular China","ru":"Китай","en":"People's Republic of China","zh-CN":"中国","fr":"Chine","de":"China","ja":"中国"},"geoname_id":1814991},"location":{"longitude":"105","latitude":"35"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"CN","names":{"pt-BR":"China","es":"República Popular China","ru":"Китай","en":"People's Republic of China","zh-CN":"中国","fr":"Chine","de":"China","ja":"中国"},"geoname_id":1814991}}] ["2001:254::/32",{"country":{"iso_code":"CN","names":{"pt-BR":"China","es":"República Popular China","ru":"Китай","en":"People's Republic of China","zh-CN":"中国","fr":"Chine","de":"China","ja":"中国"},"geoname_id":1814991},"location":{"longitude":"105","latitude":"35"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"CN","names":{"pt-BR":"China","es":"República Popular China","ru":"Китай","en":"People's Republic of China","zh-CN":"中国","fr":"Chine","de":"China","ja":"中国"},"geoname_id":1814991}}] ["2001:256::/32",{"country":{"iso_code":"CN","names":{"pt-BR":"China","es":"República Popular China","ru":"Китай","en":"People's Republic of China","zh-CN":"中国","fr":"Chine","de":"China","ja":"中国"},"geoname_id":1814991},"location":{"longitude":"105","latitude":"35"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"CN","names":{"pt-BR":"China","es":"República Popular China","ru":"Китай","en":"People's Republic of China","zh-CN":"中国","fr":"Chine","de":"China","ja":"中国"},"geoname_id":1814991}}] ["2001:258::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:260::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:268::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:270::/32",{"country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841},"location":{"longitude":"127.5","latitude":"37","time_zone":"Asia/Seoul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841}}] ["2001:278::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:280::/32",{"country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841},"location":{"longitude":"127.5","latitude":"37","time_zone":"Asia/Seoul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841}}] ["2001:288::/32",{"country":{"iso_code":"TW","names":{"pt-BR":"Taiwan","es":"Taiwán","ru":"Тайвань","en":"Taiwan","zh-CN":"台湾","fr":"Taïwan","de":"Taiwan","ja":"台湾"},"geoname_id":1668284},"location":{"longitude":"121","latitude":"24","time_zone":"Asia/Taipei"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TW","names":{"pt-BR":"Taiwan","es":"Taiwán","ru":"Тайвань","en":"Taiwan","zh-CN":"台湾","fr":"Taïwan","de":"Taiwan","ja":"台湾"},"geoname_id":1668284}}] ["2001:290::/32",{"country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841},"location":{"longitude":"127.5","latitude":"37","time_zone":"Asia/Seoul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841}}] ["2001:298::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:2a0::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:2a8::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:2b0::/32",{"country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841},"location":{"longitude":"127.5","latitude":"37","time_zone":"Asia/Seoul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841}}] ["2001:2b8::/32",{"country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841},"location":{"longitude":"127.5","latitude":"37","time_zone":"Asia/Seoul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841}}] ["2001:2c0::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:2c8::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:2d8::/32",{"country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841},"location":{"longitude":"127.5","latitude":"37","time_zone":"Asia/Seoul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"KR","names":{"pt-BR":"Coréia, República da","es":"Corea, República de","ru":"Южная Корея","en":"South Korea","zh-CN":"韩国","fr":"Corée du Sud","de":"Republik Korea","ja":"大韓民国"},"geoname_id":1835841}}] ["2001:2e0::/32",{"country":{"iso_code":"HK","names":{"pt-BR":"Hong Kong","es":"Hong Kong","ru":"Гонконг","en":"Hong Kong","zh-CN":"香港","fr":"Hong Kong","de":"Hongkong","ja":"香港"},"geoname_id":1819730},"location":{"longitude":"114.16667","latitude":"22.25","time_zone":"Asia/Hong_Kong"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"HK","names":{"pt-BR":"Hong Kong","es":"Hong Kong","ru":"Гонконг","en":"Hong Kong","zh-CN":"香港","fr":"Hong Kong","de":"Hongkong","ja":"香港"},"geoname_id":1819730}}] ["2001:2e8::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:2f0::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2001:2f8::/32",{"country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060},"location":{"longitude":"139.75309","latitude":"35.68536","time_zone":"Asia/Tokyo"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JP","names":{"pt-BR":"Japão","es":"Japón","ru":"Япония","en":"Japan","zh-CN":"日本","fr":"Japon","de":"Japan","ja":"日本"},"geoname_id":1861060}}] ["2a02:cf40::/29",{"country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096},"location":{"longitude":"10","latitude":"62","time_zone":"Europe/Oslo"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096}}] ["2a02:cf80::/29",{"country":{"iso_code":"IL","names":{"pt-BR":"Israel","es":"Israel","ru":"Израиль","en":"Israel","zh-CN":"以色列","fr":"Israël","de":"Israel","ja":"イスラエル国"},"geoname_id":294640},"location":{"longitude":"34.75","latitude":"31.5","time_zone":"Asia/Jerusalem"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IL","names":{"pt-BR":"Israel","es":"Israel","ru":"Израиль","en":"Israel","zh-CN":"以色列","fr":"Israël","de":"Israel","ja":"イスラエル国"},"geoname_id":294640}}] ["2a02:cfc0::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:d000::/29",{"country":{"iso_code":"CH","names":{"pt-BR":"Suíça","es":"Suiza","ru":"Швейцария","en":"Switzerland","zh-CN":"瑞士","fr":"Suisse","de":"Schweiz","ja":"スイス連邦"},"geoname_id":2658434},"location":{"longitude":"8.01427","latitude":"47.00016","time_zone":"Europe/Zurich"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"CH","names":{"pt-BR":"Suíça","es":"Suiza","ru":"Швейцария","en":"Switzerland","zh-CN":"瑞士","fr":"Suisse","de":"Schweiz","ja":"スイス連邦"},"geoname_id":2658434}}] ["2a02:d040::/29",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"location":{"longitude":"15","latitude":"62","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886}}] ["2a02:d080::/29",{"country":{"iso_code":"BH","names":{"pt-BR":"Bahrain","es":"Bahréin","ru":"Бахрейн","en":"Bahrain","zh-CN":"巴林","fr":"Bahreïn","de":"Bahrain","ja":"バーレーン"},"geoname_id":290291},"location":{"longitude":"50.5","latitude":"26","time_zone":"Asia/Bahrain"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"BH","names":{"pt-BR":"Bahrain","es":"Bahréin","ru":"Бахрейн","en":"Bahrain","zh-CN":"巴林","fr":"Bahreïn","de":"Bahrain","ja":"バーレーン"},"geoname_id":290291}}] ["2a02:d0c0::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:d100::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:d140::/29",{"country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096},"location":{"longitude":"10","latitude":"62","time_zone":"Europe/Oslo"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096}}] ["2a02:d180::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:d1c0::/29",{"country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395},"location":{"longitude":"12.83333","latitude":"42.83333","time_zone":"Europe/Rome"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395}}] ["2a02:d200::/29",{"country":{"iso_code":"FI","names":{"pt-BR":"Finlândia","es":"Finlandia","ru":"Финляндия","en":"Finland","zh-CN":"芬兰","fr":"Finlande","de":"Finnland","ja":"フィンランド共和国"},"geoname_id":660013},"location":{"longitude":"26","latitude":"64","time_zone":"Europe/Helsinki"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FI","names":{"pt-BR":"Finlândia","es":"Finlandia","ru":"Финляндия","en":"Finland","zh-CN":"芬兰","fr":"Finlande","de":"Finnland","ja":"フィンランド共和国"},"geoname_id":660013}}] ["2a02:d240::/29",{"country":{"iso_code":"BY","names":{"pt-BR":"Bielo-Rússia","es":"Bielorrusia","ru":"Беларусь","en":"Belarus","zh-CN":"白俄罗斯","fr":"Biélorussie","de":"Weißrussland","ja":"ベラルーシ共和国"},"geoname_id":630336},"location":{"longitude":"28","latitude":"53","time_zone":"Europe/Minsk"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"BY","names":{"pt-BR":"Bielo-Rússia","es":"Bielorrusia","ru":"Беларусь","en":"Belarus","zh-CN":"白俄罗斯","fr":"Biélorussie","de":"Weißrussland","ja":"ベラルーシ共和国"},"geoname_id":630336}}] ["2a02:d280::/29",{"country":{"iso_code":"CZ","names":{"pt-BR":"República Checa","es":"República Checa","ru":"Чешская Республика","en":"Czech Republic","zh-CN":"捷克共和国","fr":"Tchéquie","de":"Tschechische Republik","ja":"チェコ共和国"},"geoname_id":3077311},"location":{"longitude":"15","latitude":"49.75","time_zone":"Europe/Prague"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"CZ","names":{"pt-BR":"República Checa","es":"República Checa","ru":"Чешская Республика","en":"Czech Republic","zh-CN":"捷克共和国","fr":"Tchéquie","de":"Tschechische Republik","ja":"チェコ共和国"},"geoname_id":3077311}}] ["2a02:d2c0::/29",{"country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758},"location":{"longitude":"53","latitude":"32","time_zone":"Asia/Tehran"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758}}] ["2a02:d300::/29",{"country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791},"location":{"longitude":"32","latitude":"49"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791}}] ["2a02:d340::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:d380::/29",{"country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758},"location":{"longitude":"53","latitude":"32","time_zone":"Asia/Tehran"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758}}] ["2a02:d3c0::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:d400::/29",{"country":{"iso_code":"HU","names":{"pt-BR":"Hungria","es":"Hungría","ru":"Венгрия","en":"Hungary","zh-CN":"匈牙利","fr":"Hongrie","de":"Ungarn","ja":"ハンガリー共和国"},"geoname_id":719819},"location":{"longitude":"20","latitude":"47","time_zone":"Europe/Budapest"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"HU","names":{"pt-BR":"Hungria","es":"Hungría","ru":"Венгрия","en":"Hungary","zh-CN":"匈牙利","fr":"Hongrie","de":"Ungarn","ja":"ハンガリー共和国"},"geoname_id":719819}}] ["2a02:d440::/29",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"location":{"longitude":"15","latitude":"62","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886}}] ["2a02:d480::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:d4c0::/30",{"country":{"iso_code":"FI","names":{"pt-BR":"Finlândia","es":"Finlandia","ru":"Финляндия","en":"Finland","zh-CN":"芬兰","fr":"Finlande","de":"Finnland","ja":"フィンランド共和国"},"geoname_id":660013},"location":{"longitude":"26","latitude":"64","time_zone":"Europe/Helsinki"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FI","names":{"pt-BR":"Finlândia","es":"Finlandia","ru":"Финляндия","en":"Finland","zh-CN":"芬兰","fr":"Finlande","de":"Finnland","ja":"フィンランド共和国"},"geoname_id":660013}}] ["2a02:d4e0::/30",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:d500::/29",{"location":{"longitude":"9.14062","latitude":"48.69096","time_zone":"Europe/Vaduz"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"}}] ["2a02:d540::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:d580::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:d5c0::/29",{"country":{"iso_code":"ES","names":{"pt-BR":"Espanha","es":"España","ru":"Испания","en":"Spain","zh-CN":"西班牙","fr":"Espagne","de":"Spanien","ja":"スペイン"},"geoname_id":2510769},"location":{"longitude":"-4","latitude":"40"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"ES","names":{"pt-BR":"Espanha","es":"España","ru":"Испания","en":"Spain","zh-CN":"西班牙","fr":"Espagne","de":"Spanien","ja":"スペイン"},"geoname_id":2510769}}] ["2a02:d600::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:d640::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:d680::/30",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:d6a0::/30",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:d6c0::/29",{"country":{"iso_code":"BG","names":{"pt-BR":"Bulgária","es":"Bulgaria","ru":"Болгария","en":"Bulgaria","zh-CN":"保加利亚","fr":"Bulgarie","de":"Bulgarien","ja":"ブルガリア共和国"},"geoname_id":732800},"location":{"longitude":"25","latitude":"43","time_zone":"Europe/Sofia"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"BG","names":{"pt-BR":"Bulgária","es":"Bulgaria","ru":"Болгария","en":"Bulgaria","zh-CN":"保加利亚","fr":"Bulgarie","de":"Bulgarien","ja":"ブルガリア共和国"},"geoname_id":732800}}] ["2a02:d700::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:d740::/29",{"country":{"iso_code":"CH","names":{"pt-BR":"Suíça","es":"Suiza","ru":"Швейцария","en":"Switzerland","zh-CN":"瑞士","fr":"Suisse","de":"Schweiz","ja":"スイス連邦"},"geoname_id":2658434},"location":{"longitude":"8.01427","latitude":"47.00016","time_zone":"Europe/Zurich"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"CH","names":{"pt-BR":"Suíça","es":"Suiza","ru":"Швейцария","en":"Switzerland","zh-CN":"瑞士","fr":"Suisse","de":"Schweiz","ja":"スイス連邦"},"geoname_id":2658434}}] ["2a02:d780::/29",{"country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758},"location":{"longitude":"53","latitude":"32","time_zone":"Asia/Tehran"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758}}] ["2a02:d7c0::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:d800::/29",{"country":{"iso_code":"RO","names":{"pt-BR":"Romênia","es":"Rumanía","ru":"Румыния","en":"Romania","zh-CN":"罗马尼亚","fr":"Roumanie","de":"Rumänien","ja":"ルーマニア"},"geoname_id":798549},"location":{"longitude":"25","latitude":"46","time_zone":"Europe/Bucharest"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RO","names":{"pt-BR":"Romênia","es":"Rumanía","ru":"Румыния","en":"Romania","zh-CN":"罗马尼亚","fr":"Roumanie","de":"Rumänien","ja":"ルーマニア"},"geoname_id":798549}}] ["2a02:d840::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:d880::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:d8c0::/29",{"country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096},"location":{"longitude":"10","latitude":"62","time_zone":"Europe/Oslo"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096}}] ["2a02:d900::/29",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"location":{"longitude":"15","latitude":"62","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886}}] ["2a02:d940::/29",{"country":{"iso_code":"BE","names":{"pt-BR":"Bélgica","es":"Bélgica","ru":"Бельгия","en":"Belgium","zh-CN":"比利时","fr":"Belgique","de":"Belgien","ja":"ベルギー王国"},"geoname_id":2802361},"location":{"longitude":"4","latitude":"50.83333","time_zone":"Europe/Brussels"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"BE","names":{"pt-BR":"Bélgica","es":"Bélgica","ru":"Бельгия","en":"Belgium","zh-CN":"比利时","fr":"Belgique","de":"Belgien","ja":"ベルギー王国"},"geoname_id":2802361}}] ["2a02:d980::/29",{"country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795},"location":{"longitude":"34.91155","latitude":"39.05901","time_zone":"Europe/Istanbul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795}}] ["2a02:d9c0::/29",{"country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795},"location":{"longitude":"34.91155","latitude":"39.05901","time_zone":"Europe/Istanbul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795}}] ["2a02:da00::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:da40::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:da80::/29",{"country":{"iso_code":"AT","names":{"pt-BR":"Áustria","es":"Austria","ru":"Австрия","en":"Austria","zh-CN":"奥地利","fr":"Autriche","de":"Österreich","ja":"オーストリア共和国"},"geoname_id":2782113},"location":{"longitude":"13.33333","latitude":"47.33333","time_zone":"Europe/Vienna"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"AT","names":{"pt-BR":"Áustria","es":"Austria","ru":"Австрия","en":"Austria","zh-CN":"奥地利","fr":"Autriche","de":"Österreich","ja":"オーストリア共和国"},"geoname_id":2782113}}] ["2a02:dac0::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:db00::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:db40::/29",{"country":{"iso_code":"RO","names":{"pt-BR":"Romênia","es":"Rumanía","ru":"Румыния","en":"Romania","zh-CN":"罗马尼亚","fr":"Roumanie","de":"Rumänien","ja":"ルーマニア"},"geoname_id":798549},"location":{"longitude":"25","latitude":"46","time_zone":"Europe/Bucharest"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RO","names":{"pt-BR":"Romênia","es":"Rumanía","ru":"Румыния","en":"Romania","zh-CN":"罗马尼亚","fr":"Roumanie","de":"Rumänien","ja":"ルーマニア"},"geoname_id":798549}}] ["2a02:db80::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:dbc0::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:dc00::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:dc40::/29",{"country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795},"location":{"longitude":"34.91155","latitude":"39.05901","time_zone":"Europe/Istanbul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795}}] ["2a02:dc80::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:dcc0::/29",{"country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791},"location":{"longitude":"32","latitude":"49"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791}}] ["2a02:dd00::/29",{"country":{"iso_code":"AL","names":{"pt-BR":"Albânia","es":"Albania","ru":"Албания","en":"Albania","zh-CN":"阿尔巴尼亚","fr":"Albanie","de":"Albanien","ja":"アルバニア共和国"},"geoname_id":783754},"location":{"longitude":"20","latitude":"41","time_zone":"Europe/Tirane"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"AL","names":{"pt-BR":"Albânia","es":"Albania","ru":"Албания","en":"Albania","zh-CN":"阿尔巴尼亚","fr":"Albanie","de":"Albanien","ja":"アルバニア共和国"},"geoname_id":783754}}] ["2a02:dd40::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:dd80::/29",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"location":{"longitude":"15","latitude":"62","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886}}] ["2a02:ddc0::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:de00::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:de40::/29",{"country":{"iso_code":"IL","names":{"pt-BR":"Israel","es":"Israel","ru":"Израиль","en":"Israel","zh-CN":"以色列","fr":"Israël","de":"Israel","ja":"イスラエル国"},"geoname_id":294640},"location":{"longitude":"34.75","latitude":"31.5","time_zone":"Asia/Jerusalem"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IL","names":{"pt-BR":"Israel","es":"Israel","ru":"Израиль","en":"Israel","zh-CN":"以色列","fr":"Israël","de":"Israel","ja":"イスラエル国"},"geoname_id":294640}}] ["2a02:de80::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:dec0::/29",{"country":{"iso_code":"LB","names":{"pt-BR":"Líbano","es":"Líbano","ru":"Ливан","en":"Lebanon","zh-CN":"黎巴嫩","fr":"Liban","de":"Libanon","ja":"レバノン共和国"},"geoname_id":272103},"location":{"longitude":"35.83333","latitude":"33.83333","time_zone":"Asia/Beirut"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"LB","names":{"pt-BR":"Líbano","es":"Líbano","ru":"Ливан","en":"Lebanon","zh-CN":"黎巴嫩","fr":"Liban","de":"Libanon","ja":"レバノン共和国"},"geoname_id":272103}}] ["2a02:df00::/29",{"country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758},"location":{"longitude":"53","latitude":"32","time_zone":"Asia/Tehran"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758}}] ["2a02:df40::/29",{"country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795},"location":{"longitude":"34.91155","latitude":"39.05901","time_zone":"Europe/Istanbul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795}}] ["2a02:df80::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:dfc0::/29",{"country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758},"location":{"longitude":"53","latitude":"32","time_zone":"Asia/Tehran"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758}}] ["2a02:e000::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:e040::/29",{"country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405},"location":{"longitude":"5.75","latitude":"52.5","time_zone":"Europe/Amsterdam"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405}}] ["2a02:e080::/29",{"country":{"iso_code":"KW","names":{"pt-BR":"Kuwait","es":"Kuwait","ru":"Кувейт","en":"Kuwait","zh-CN":"科威特","fr":"Koweït","de":"Kuwait","ja":"クウェート"},"geoname_id":285570},"location":{"longitude":"47.75","latitude":"29.5","time_zone":"Asia/Kuwait"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"KW","names":{"pt-BR":"Kuwait","es":"Kuwait","ru":"Кувейт","en":"Kuwait","zh-CN":"科威特","fr":"Koweït","de":"Kuwait","ja":"クウェート"},"geoname_id":285570}}] ["2a02:e0c0::/29",{"country":{"iso_code":"CH","names":{"pt-BR":"Suíça","es":"Suiza","ru":"Швейцария","en":"Switzerland","zh-CN":"瑞士","fr":"Suisse","de":"Schweiz","ja":"スイス連邦"},"geoname_id":2658434},"location":{"longitude":"8.01427","latitude":"47.00016","time_zone":"Europe/Zurich"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"CH","names":{"pt-BR":"Suíça","es":"Suiza","ru":"Швейцария","en":"Switzerland","zh-CN":"瑞士","fr":"Suisse","de":"Schweiz","ja":"スイス連邦"},"geoname_id":2658434}}] ["2a02:e100::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:e140::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:e180::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:e1c0::/29",{"country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405},"location":{"longitude":"5.75","latitude":"52.5","time_zone":"Europe/Amsterdam"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405}}] ["2a02:e200::/30",{"country":{"iso_code":"AT","names":{"pt-BR":"Áustria","es":"Austria","ru":"Австрия","en":"Austria","zh-CN":"奥地利","fr":"Autriche","de":"Österreich","ja":"オーストリア共和国"},"geoname_id":2782113},"location":{"longitude":"13.33333","latitude":"47.33333","time_zone":"Europe/Vienna"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"AT","names":{"pt-BR":"Áustria","es":"Austria","ru":"Австрия","en":"Austria","zh-CN":"奥地利","fr":"Autriche","de":"Österreich","ja":"オーストリア共和国"},"geoname_id":2782113}}] ["2a02:e220::/30",{"country":{"iso_code":"SA","names":{"pt-BR":"Arábia Saudita","es":"Arabia Saudita","ru":"Саудовская Аравия","en":"Saudi Arabia","zh-CN":"沙特阿拉伯","fr":"Arabie saoudite","de":"Saudi-Arabien","ja":"サウジアラビア王国"},"geoname_id":102358},"location":{"longitude":"45","latitude":"25","time_zone":"Asia/Riyadh"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"SA","names":{"pt-BR":"Arábia Saudita","es":"Arabia Saudita","ru":"Саудовская Аравия","en":"Saudi Arabia","zh-CN":"沙特阿拉伯","fr":"Arabie saoudite","de":"Saudi-Arabien","ja":"サウジアラビア王国"},"geoname_id":102358}}] ["2a02:e240::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:e280::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:e2c0::/29",{"country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395},"location":{"longitude":"12.83333","latitude":"42.83333","time_zone":"Europe/Rome"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395}}] ["2a02:e300::/29",{"country":{"iso_code":"BY","names":{"pt-BR":"Bielo-Rússia","es":"Bielorrusia","ru":"Беларусь","en":"Belarus","zh-CN":"白俄罗斯","fr":"Biélorussie","de":"Weißrussland","ja":"ベラルーシ共和国"},"geoname_id":630336},"location":{"longitude":"28","latitude":"53","time_zone":"Europe/Minsk"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"BY","names":{"pt-BR":"Bielo-Rússia","es":"Bielorrusia","ru":"Беларусь","en":"Belarus","zh-CN":"白俄罗斯","fr":"Biélorussie","de":"Weißrussland","ja":"ベラルーシ共和国"},"geoname_id":630336}}] ["2a02:e340::/29",{"country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096},"location":{"longitude":"10","latitude":"62","time_zone":"Europe/Oslo"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096}}] ["2a02:e380::/29",{"country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395},"location":{"longitude":"12.83333","latitude":"42.83333","time_zone":"Europe/Rome"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395}}] ["2a02:e3c0::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:e400::/29",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"location":{"longitude":"15","latitude":"62","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886}}] ["2a02:e440::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:e480::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:e4c0::/29",{"country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405},"location":{"longitude":"5.75","latitude":"52.5","time_zone":"Europe/Amsterdam"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405}}] ["2a02:e500::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:e540::/29",{"country":{"iso_code":"RS","names":{"pt-BR":"Sérvia","es":"Serbia","ru":"Сербия","en":"Serbia","zh-CN":"塞尔维亚","fr":"Serbie","de":"Serbien","ja":"セルビア"},"geoname_id":6290252},"location":{"longitude":"20.45998","latitude":"44.81892","time_zone":"Europe/Belgrade"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RS","names":{"pt-BR":"Sérvia","es":"Serbia","ru":"Сербия","en":"Serbia","zh-CN":"塞尔维亚","fr":"Serbie","de":"Serbien","ja":"セルビア"},"geoname_id":6290252}}] ["2a02:e580::/29",{"country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096},"location":{"longitude":"10","latitude":"62","time_zone":"Europe/Oslo"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096}}] ["2a02:e5c0::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:e600::/30",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:e620::/30",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:e640::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:e680::/29",{"country":{"iso_code":"JO","names":{"pt-BR":"Jordânia","es":"Jordania","ru":"Иордания","en":"Hashemite Kingdom of Jordan","zh-CN":"约旦","fr":"Jordanie","de":"Jordanien","ja":"ヨルダン・ハシミテ王国"},"geoname_id":248816},"location":{"longitude":"36","latitude":"31","time_zone":"Asia/Amman"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JO","names":{"pt-BR":"Jordânia","es":"Jordania","ru":"Иордания","en":"Hashemite Kingdom of Jordan","zh-CN":"约旦","fr":"Jordanie","de":"Jordanien","ja":"ヨルダン・ハシミテ王国"},"geoname_id":248816}}] ["2a02:e6c0::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:e700::/29",{"country":{"iso_code":"LY","names":{"pt-BR":"Líbia Árabe Jamahiriya","es":"Libia, República Árabe","ru":"Ливия","en":"Libya","zh-CN":"阿拉伯利比亚民众国","fr":"Libye","de":"Libysch-Arabische Dschamahirija","ja":"社会主義人民リビア・アラブ国"},"geoname_id":2215636},"location":{"longitude":"17","latitude":"28","time_zone":"Africa/Tripoli"},"continent":{"names":{"pt-BR":"África","es":"África","ru":"Африка","en":"Africa","zh-CN":"非洲","fr":"Afrique","de":"Afrika","ja":"アフリカ"},"geoname_id":6255146,"code":"AF"},"registered_country":{"iso_code":"LY","names":{"pt-BR":"Líbia Árabe Jamahiriya","es":"Libia, República Árabe","ru":"Ливия","en":"Libya","zh-CN":"阿拉伯利比亚民众国","fr":"Libye","de":"Libysch-Arabische Dschamahirija","ja":"社会主義人民リビア・アラブ国"},"geoname_id":2215636}}] ["2a02:e740::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:e780::/29",{"country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795},"location":{"longitude":"34.91155","latitude":"39.05901","time_zone":"Europe/Istanbul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795}}] ["2a02:e7c0::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:e800::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:e840::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:e880::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:e900::/29",{"country":{"iso_code":"IE","names":{"pt-BR":"Irlanda","es":"República de Irlanda","ru":"Ирландия","en":"Ireland","zh-CN":"爱尔兰","fr":"Irlande","de":"Irland","ja":"アイルランド"},"geoname_id":2963597},"location":{"longitude":"-8","latitude":"53","time_zone":"Europe/Dublin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"IE","names":{"pt-BR":"Irlanda","es":"República de Irlanda","ru":"Ирландия","en":"Ireland","zh-CN":"爱尔兰","fr":"Irlande","de":"Irland","ja":"アイルランド"},"geoname_id":2963597}}] ["2a02:e940::/29",{"country":{"iso_code":"RO","names":{"pt-BR":"Romênia","es":"Rumanía","ru":"Румыния","en":"Romania","zh-CN":"罗马尼亚","fr":"Roumanie","de":"Rumänien","ja":"ルーマニア"},"geoname_id":798549},"location":{"longitude":"25","latitude":"46","time_zone":"Europe/Bucharest"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RO","names":{"pt-BR":"Romênia","es":"Rumanía","ru":"Румыния","en":"Romania","zh-CN":"罗马尼亚","fr":"Roumanie","de":"Rumänien","ja":"ルーマニア"},"geoname_id":798549}}] ["2a02:e980::/29",{"country":{"iso_code":"IL","names":{"pt-BR":"Israel","es":"Israel","ru":"Израиль","en":"Israel","zh-CN":"以色列","fr":"Israël","de":"Israel","ja":"イスラエル国"},"geoname_id":294640},"location":{"longitude":"34.75","latitude":"31.5","time_zone":"Asia/Jerusalem"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IL","names":{"pt-BR":"Israel","es":"Israel","ru":"Израиль","en":"Israel","zh-CN":"以色列","fr":"Israël","de":"Israel","ja":"イスラエル国"},"geoname_id":294640}}] ["2a02:e9c0::/29",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"location":{"longitude":"15","latitude":"62","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886}}] ["2a02:ea00::/29",{"country":{"iso_code":"CH","names":{"pt-BR":"Suíça","es":"Suiza","ru":"Швейцария","en":"Switzerland","zh-CN":"瑞士","fr":"Suisse","de":"Schweiz","ja":"スイス連邦"},"geoname_id":2658434},"location":{"longitude":"8.01427","latitude":"47.00016","time_zone":"Europe/Zurich"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"CH","names":{"pt-BR":"Suíça","es":"Suiza","ru":"Швейцария","en":"Switzerland","zh-CN":"瑞士","fr":"Suisse","de":"Schweiz","ja":"スイス連邦"},"geoname_id":2658434}}] ["2a02:ea40::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:ea80::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:eac0::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:eb00::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:eb40::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:eb80::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:ebc0::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:ec00::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:ec40::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:ec80::/29",{"location":{"longitude":"9.14062","latitude":"48.69096","time_zone":"Europe/Vaduz"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"}}] ["2a02:ecc0::/29",{"country":{"iso_code":"AZ","names":{"pt-BR":"Azerbaijão","es":"Azerbaiyán","ru":"Азербайджан","en":"Azerbaijan","zh-CN":"阿塞拜疆","fr":"Azerbaïdjan","de":"Aserbaidschan","ja":"アゼルバイジャン共和国"},"geoname_id":587116},"location":{"longitude":"47.5","latitude":"40.5","time_zone":"Asia/Baku"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"AZ","names":{"pt-BR":"Azerbaijão","es":"Azerbaiyán","ru":"Азербайджан","en":"Azerbaijan","zh-CN":"阿塞拜疆","fr":"Azerbaïdjan","de":"Aserbaidschan","ja":"アゼルバイジャン共和国"},"geoname_id":587116}}] ["2a02:ed00::/29",{"country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096},"location":{"longitude":"10","latitude":"62","time_zone":"Europe/Oslo"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096}}] ["2a02:ed40::/29",{"country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795},"location":{"longitude":"34.91155","latitude":"39.05901","time_zone":"Europe/Istanbul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795}}] ["2a02:ed80::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:edc0::/29",{"country":{"iso_code":"SA","names":{"pt-BR":"Arábia Saudita","es":"Arabia Saudita","ru":"Саудовская Аравия","en":"Saudi Arabia","zh-CN":"沙特阿拉伯","fr":"Arabie saoudite","de":"Saudi-Arabien","ja":"サウジアラビア王国"},"geoname_id":102358},"location":{"longitude":"45","latitude":"25","time_zone":"Asia/Riyadh"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"SA","names":{"pt-BR":"Arábia Saudita","es":"Arabia Saudita","ru":"Саудовская Аравия","en":"Saudi Arabia","zh-CN":"沙特阿拉伯","fr":"Arabie saoudite","de":"Saudi-Arabien","ja":"サウジアラビア王国"},"geoname_id":102358}}] ["2a02:ee00::/29",{"country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791},"location":{"longitude":"32","latitude":"49"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791}}] ["2a02:ee40::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:ee80::/29",{"country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405},"location":{"longitude":"5.75","latitude":"52.5","time_zone":"Europe/Amsterdam"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405}}] ["2a02:eec0::/29",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"location":{"longitude":"15","latitude":"62","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886}}] ["2a02:ef00::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:ef40::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:ef80::/29",{"country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795},"location":{"longitude":"34.91155","latitude":"39.05901","time_zone":"Europe/Istanbul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795}}] ["2a02:efc0::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:f000::/29",{"country":{"iso_code":"CZ","names":{"pt-BR":"República Checa","es":"República Checa","ru":"Чешская Республика","en":"Czech Republic","zh-CN":"捷克共和国","fr":"Tchéquie","de":"Tschechische Republik","ja":"チェコ共和国"},"geoname_id":3077311},"location":{"longitude":"15","latitude":"49.75","time_zone":"Europe/Prague"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"CZ","names":{"pt-BR":"República Checa","es":"República Checa","ru":"Чешская Республика","en":"Czech Republic","zh-CN":"捷克共和国","fr":"Tchéquie","de":"Tschechische Republik","ja":"チェコ共和国"},"geoname_id":3077311}}] ["2a02:f040::/29",{"country":{"iso_code":"BH","names":{"pt-BR":"Bahrain","es":"Bahréin","ru":"Бахрейн","en":"Bahrain","zh-CN":"巴林","fr":"Bahreïn","de":"Bahrain","ja":"バーレーン"},"geoname_id":290291},"location":{"longitude":"50.5","latitude":"26","time_zone":"Asia/Bahrain"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"BH","names":{"pt-BR":"Bahrain","es":"Bahréin","ru":"Бахрейн","en":"Bahrain","zh-CN":"巴林","fr":"Bahreïn","de":"Bahrain","ja":"バーレーン"},"geoname_id":290291}}] ["2a02:f080::/30",{"country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791},"location":{"longitude":"32","latitude":"49"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791}}] ["2a02:f0a0::/30",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:f0c0::/29",{"country":{"iso_code":"JO","names":{"pt-BR":"Jordânia","es":"Jordania","ru":"Иордания","en":"Hashemite Kingdom of Jordan","zh-CN":"约旦","fr":"Jordanie","de":"Jordanien","ja":"ヨルダン・ハシミテ王国"},"geoname_id":248816},"location":{"longitude":"36","latitude":"31","time_zone":"Asia/Amman"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"JO","names":{"pt-BR":"Jordânia","es":"Jordania","ru":"Иордания","en":"Hashemite Kingdom of Jordan","zh-CN":"约旦","fr":"Jordanie","de":"Jordanien","ja":"ヨルダン・ハシミテ王国"},"geoname_id":248816}}] ["2a02:f100::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:f140::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:f180::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:f1c0::/29",{"country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791},"location":{"longitude":"32","latitude":"49"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"UA","names":{"pt-BR":"Ucrânia","es":"Ucrania","ru":"Украина","en":"Ukraine","zh-CN":"乌克兰","fr":"Ukraine","de":"Ukraine","ja":"ウクライナ共和国"},"geoname_id":690791}}] ["2a02:f200::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:f240::/29",{"country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758},"location":{"longitude":"53","latitude":"32","time_zone":"Asia/Tehran"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758}}] ["2a02:f280::/29",{"country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382},"location":{"longitude":"2","latitude":"46","time_zone":"Europe/Paris"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["2a02:f2c0::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:f300::/29",{"country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096},"location":{"longitude":"10","latitude":"62","time_zone":"Europe/Oslo"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096}}] ["2a02:f340::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:f380::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:f3c0::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:f400::/29",{"country":{"iso_code":"AE","names":{"pt-BR":"Emirados Árabes Unidos","es":"Emiratos Árabes Unidos","ru":"Объединенные Арабские Эмираты","en":"United Arab Emirates","zh-CN":"阿拉伯联合酋长国","fr":"Émirats Arabes Unis","de":"Vereinigte Arabische Emirate","ja":"アラブ首長国連邦"},"geoname_id":290557},"location":{"longitude":"54","latitude":"24","time_zone":"Asia/Dubai"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"AE","names":{"pt-BR":"Emirados Árabes Unidos","es":"Emiratos Árabes Unidos","ru":"Объединенные Арабские Эмираты","en":"United Arab Emirates","zh-CN":"阿拉伯联合酋长国","fr":"Émirats Arabes Unis","de":"Vereinigte Arabische Emirate","ja":"アラブ首長国連邦"},"geoname_id":290557}}] ["2a02:f440::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:f480::/29",{"country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096},"location":{"longitude":"10","latitude":"62","time_zone":"Europe/Oslo"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096}}] ["2a02:f4c0::/29",{"country":{"iso_code":"ES","names":{"pt-BR":"Espanha","es":"España","ru":"Испания","en":"Spain","zh-CN":"西班牙","fr":"Espagne","de":"Spanien","ja":"スペイン"},"geoname_id":2510769},"location":{"longitude":"-4","latitude":"40"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"ES","names":{"pt-BR":"Espanha","es":"España","ru":"Испания","en":"Spain","zh-CN":"西班牙","fr":"Espagne","de":"Spanien","ja":"スペイン"},"geoname_id":2510769}}] ["2a02:f500::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:f540::/30",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:f560::/30",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:f580::/29",{"country":{"iso_code":"AM","names":{"pt-BR":"Armênia","es":"Armenia","ru":"Армения","en":"Armenia","zh-CN":"亚美尼亚","fr":"Arménie","de":"Armenien","ja":"アルメニア共和国"},"geoname_id":174982},"location":{"longitude":"45","latitude":"40","time_zone":"Asia/Yerevan"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"AM","names":{"pt-BR":"Armênia","es":"Armenia","ru":"Армения","en":"Armenia","zh-CN":"亚美尼亚","fr":"Arménie","de":"Armenien","ja":"アルメニア共和国"},"geoname_id":174982}}] ["2a02:f5c0::/29",{"country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405},"location":{"longitude":"5.75","latitude":"52.5","time_zone":"Europe/Amsterdam"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405}}] ["2a02:f600::/29",{"country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405},"location":{"longitude":"5.75","latitude":"52.5","time_zone":"Europe/Amsterdam"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405}}] ["2a02:f640::/29",{"country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405},"location":{"longitude":"5.75","latitude":"52.5","time_zone":"Europe/Amsterdam"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405}}] ["2a02:f680::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:f6c0::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:f700::/29",{"country":{"iso_code":"LB","names":{"pt-BR":"Líbano","es":"Líbano","ru":"Ливан","en":"Lebanon","zh-CN":"黎巴嫩","fr":"Liban","de":"Libanon","ja":"レバノン共和国"},"geoname_id":272103},"location":{"longitude":"35.83333","latitude":"33.83333","time_zone":"Asia/Beirut"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"LB","names":{"pt-BR":"Líbano","es":"Líbano","ru":"Ливан","en":"Lebanon","zh-CN":"黎巴嫩","fr":"Liban","de":"Libanon","ja":"レバノン共和国"},"geoname_id":272103}}] ["2a02:f740::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:f780::/29",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"location":{"longitude":"15","latitude":"62","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886}}] ["2a02:f7c0::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:f800::/29",{"country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370},"location":{"longitude":"100","latitude":"60"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"RU","names":{"pt-BR":"Rússia","es":"Rusia","ru":"Россия","en":"Russia","zh-CN":"俄罗斯","fr":"Russie","de":"Russland","ja":"ロシア"},"geoname_id":2017370}}] ["2a02:f840::/29",{"country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405},"location":{"longitude":"5.75","latitude":"52.5","time_zone":"Europe/Amsterdam"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405}}] ["2a02:f880::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:f8c0::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:f900::/29",{"country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758},"location":{"longitude":"53","latitude":"32","time_zone":"Asia/Tehran"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"IR","names":{"pt-BR":"República Islâmica do Irã","es":"Irán (República Islámica)","ru":"Иран","en":"Iran","zh-CN":"伊朗伊斯兰共和国","fr":"Iran (République islamique de)","de":"Iran (Islamische Republik)","ja":"イラン・イスラム共和国"},"geoname_id":130758}}] ["2a02:f940::/29",{"country":{"iso_code":"HU","names":{"pt-BR":"Hungria","es":"Hungría","ru":"Венгрия","en":"Hungary","zh-CN":"匈牙利","fr":"Hongrie","de":"Ungarn","ja":"ハンガリー共和国"},"geoname_id":719819},"location":{"longitude":"20","latitude":"47","time_zone":"Europe/Budapest"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"HU","names":{"pt-BR":"Hungria","es":"Hungría","ru":"Венгрия","en":"Hungary","zh-CN":"匈牙利","fr":"Hongrie","de":"Ungarn","ja":"ハンガリー共和国"},"geoname_id":719819}}] ["2a02:f980::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:f9c0::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:fa00::/29",{"country":{"iso_code":"SA","names":{"pt-BR":"Arábia Saudita","es":"Arabia Saudita","ru":"Саудовская Аравия","en":"Saudi Arabia","zh-CN":"沙特阿拉伯","fr":"Arabie saoudite","de":"Saudi-Arabien","ja":"サウジアラビア王国"},"geoname_id":102358},"location":{"longitude":"45","latitude":"25","time_zone":"Asia/Riyadh"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"SA","names":{"pt-BR":"Arábia Saudita","es":"Arabia Saudita","ru":"Саудовская Аравия","en":"Saudi Arabia","zh-CN":"沙特阿拉伯","fr":"Arabie saoudite","de":"Saudi-Arabien","ja":"サウジアラビア王国"},"geoname_id":102358}}] ["2a02:fa40::/29",{"country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795},"location":{"longitude":"34.91155","latitude":"39.05901","time_zone":"Europe/Istanbul"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"registered_country":{"iso_code":"TR","names":{"pt-BR":"Turquia","es":"Turquía","ru":"Турция","en":"Turkey","zh-CN":"土耳其","fr":"Turquie","de":"Türkei","ja":"トルコ共和国"},"geoname_id":298795}}] ["2a02:fa80::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:fac0::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:fb00::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:fb40::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:fb80::/29",{"country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395},"location":{"longitude":"12.83333","latitude":"42.83333","time_zone":"Europe/Rome"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395}}] ["2a02:fbc0::/29",{"country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544},"location":{"longitude":"20","latitude":"52","time_zone":"Europe/Warsaw"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"PL","names":{"pt-BR":"Polônia","es":"Polonia","ru":"Польша","en":"Poland","zh-CN":"波兰","fr":"Pologne","de":"Polen","ja":"ポーランド共和国"},"geoname_id":798544}}] ["2a02:fc00::/29",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"location":{"longitude":"15","latitude":"62","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886}}] ["2a02:fc40::/29",{"country":{"iso_code":"DK","names":{"pt-BR":"Dinamarca","es":"Dinamarca","ru":"Дания","en":"Denmark","zh-CN":"丹麦","fr":"Danemark","de":"Dänemark","ja":"デンマーク王国"},"geoname_id":2623032},"location":{"longitude":"10","latitude":"56","time_zone":"Europe/Copenhagen"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DK","names":{"pt-BR":"Dinamarca","es":"Dinamarca","ru":"Дания","en":"Denmark","zh-CN":"丹麦","fr":"Danemark","de":"Dänemark","ja":"デンマーク王国"},"geoname_id":2623032}}] ["2a02:fc80::/29",{"country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096},"location":{"longitude":"10","latitude":"62","time_zone":"Europe/Oslo"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NO","names":{"pt-BR":"Noruega","es":"Noruega","ru":"Норвегия","en":"Norway","zh-CN":"挪威","fr":"Norvège","de":"Norwegen","ja":"ノルウェー王国"},"geoname_id":3144096}}] ["2a02:fcc0::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:fd00::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:fd40::/29",{"country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395},"location":{"longitude":"12.83333","latitude":"42.83333","time_zone":"Europe/Rome"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395}}] ["2a02:fd80::/29",{"country":{"iso_code":"DK","names":{"pt-BR":"Dinamarca","es":"Dinamarca","ru":"Дания","en":"Denmark","zh-CN":"丹麦","fr":"Danemark","de":"Dänemark","ja":"デンマーク王国"},"geoname_id":2623032},"location":{"longitude":"10","latitude":"56","time_zone":"Europe/Copenhagen"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DK","names":{"pt-BR":"Dinamarca","es":"Dinamarca","ru":"Дания","en":"Denmark","zh-CN":"丹麦","fr":"Danemark","de":"Dänemark","ja":"デンマーク王国"},"geoname_id":2623032}}] ["2a02:fdc0::/29",{"country":{"iso_code":"AT","names":{"pt-BR":"Áustria","es":"Austria","ru":"Австрия","en":"Austria","zh-CN":"奥地利","fr":"Autriche","de":"Österreich","ja":"オーストリア共和国"},"geoname_id":2782113},"location":{"longitude":"13.33333","latitude":"47.33333","time_zone":"Europe/Vienna"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"AT","names":{"pt-BR":"Áustria","es":"Austria","ru":"Австрия","en":"Austria","zh-CN":"奥地利","fr":"Autriche","de":"Österreich","ja":"オーストリア共和国"},"geoname_id":2782113}}] ["2a02:fe00::/29",{"country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405},"location":{"longitude":"5.75","latitude":"52.5","time_zone":"Europe/Amsterdam"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"NL","names":{"pt-BR":"Países Baixos","es":"Holanda","ru":"Нидерланды","en":"Netherlands","zh-CN":"荷兰","fr":"Pays-Bas","de":"Niederlande","ja":"オランダ王国"},"geoname_id":2750405}}] ["2a02:fe40::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:fe80::/29",{"country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395},"location":{"longitude":"12.83333","latitude":"42.83333","time_zone":"Europe/Rome"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395}}] ["2a02:fec0::/29",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"location":{"longitude":"-2.69531","latitude":"54.75844","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["2a02:ff00::/29",{"country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395},"location":{"longitude":"12.83333","latitude":"42.83333","time_zone":"Europe/Rome"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"IT","names":{"pt-BR":"Itália","es":"Italia","ru":"Италия","en":"Italy","zh-CN":"意大利","fr":"Italie","de":"Italien","ja":"イタリア共和国"},"geoname_id":3175395}}] ["2a02:ff40::/29",{"country":{"iso_code":"IM","names":{"pt-BR":"Ilha de Man","es":"Isla de Man","ru":"Мэн, о-в","en":"Isle of Man","zh-CN":"曼岛","fr":"Île de Man","de":"Insel Man","ja":"マン島"},"geoname_id":3042225},"location":{"longitude":"-4.5","latitude":"54.25","time_zone":"Europe/Isle_of_Man"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"IM","names":{"pt-BR":"Ilha de Man","es":"Isla de Man","ru":"Мэн, о-в","en":"Isle of Man","zh-CN":"曼岛","fr":"Île de Man","de":"Insel Man","ja":"マン島"},"geoname_id":3042225}}] ["2a02:ff80::/29",{"country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044},"location":{"longitude":"10.5","latitude":"51.5","time_zone":"Europe/Berlin"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["2a02:ffc0::/29",{"country":{"iso_code":"GI","names":{"en":"Gibraltar","pt-BR":"Gibraltar","fr":"Gibraltar","de":"Gibraltar","ja":"ジブラルタル","es":"Gibraltar","ru":"Гибралтар"},"geoname_id":2411586},"location":{"longitude":"-5.35","latitude":"36.13333","time_zone":"Europe/Gibraltar"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"GI","names":{"en":"Gibraltar","pt-BR":"Gibraltar","fr":"Gibraltar","de":"Gibraltar","ja":"ジブラルタル","es":"Gibraltar","ru":"Гибралтар"},"geoname_id":2411586}}] ["::2.125.160.216/125",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"city":{"names":{"en":"Boxford"},"geoname_id":"2655045"},"subdivisions":[{"iso_code":"ENG","names":{"en":"England","pt-BR":"Inglaterra","fr":"Angleterre","es":"Inglaterra"},"geoname_id":6269131},{"iso_code":"WBK","names":{"en":"West Berkshire","zh-CN":"西伯克郡","ru":"Западный Беркшир"},"geoname_id":3333217}],"location":{"longitude":"-1.2500","latitude":"51.7500","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"postal":{"code":"OX1"},"registered_country":{"iso_code":"FR","names":{"pt-BR":"França","es":"Francia","ru":"Франция","en":"France","zh-CN":"法国","fr":"France","de":"Frankreich","ja":"フランス共和国"},"geoname_id":3017382}}] ["::81.2.69.142/127",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"city":{"names":{"en":"London","pt-BR":"Londres","fr":"Londres","de":"London","ja":"ロンドン","es":"Londres","ru":"Лондон"},"geoname_id":"2643743"},"subdivisions":[{"iso_code":"ENG","names":{"en":"England","pt-BR":"Inglaterra","fr":"Angleterre","es":"Inglaterra"},"geoname_id":6269131}],"location":{"longitude":"-0.0931","latitude":"51.5142","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"US","names":{"pt-BR":"Estados Unidos","es":"Estados Unidos","ru":"США","en":"United States","zh-CN":"美国","fr":"États-Unis","de":"USA","ja":"アメリカ合衆国"},"geoname_id":6252001}}] ["::81.2.69.144/124",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"city":{"names":{"en":"London","pt-BR":"Londres","fr":"Londres","de":"London","ja":"ロンドン","es":"Londres","ru":"Лондон"},"geoname_id":"2643743"},"subdivisions":[{"iso_code":"ENG","names":{"en":"England","pt-BR":"Inglaterra","fr":"Angleterre","es":"Inglaterra"},"geoname_id":6269131}],"location":{"longitude":"-0.0931","latitude":"51.5142","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"US","names":{"pt-BR":"Estados Unidos","es":"Estados Unidos","ru":"США","en":"United States","zh-CN":"美国","fr":"États-Unis","de":"USA","ja":"アメリカ合衆国"},"geoname_id":6252001}}] ["::81.2.69.160/123",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"city":{"names":{"en":"London","pt-BR":"Londres","fr":"Londres","de":"London","ja":"ロンドン","es":"Londres","ru":"Лондон"},"geoname_id":"2643743"},"subdivisions":[{"iso_code":"ENG","names":{"en":"England","pt-BR":"Inglaterra","fr":"Angleterre","es":"Inglaterra"},"geoname_id":6269131}],"location":{"longitude":"-0.0931","latitude":"51.5142","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"US","names":{"pt-BR":"Estados Unidos","es":"Estados Unidos","ru":"США","en":"United States","zh-CN":"美国","fr":"États-Unis","de":"USA","ja":"アメリカ合衆国"},"geoname_id":6252001}}] ["::81.2.69.192/124",{"country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167},"city":{"names":{"en":"London","pt-BR":"Londres","fr":"Londres","de":"London","ja":"ロンドン","es":"Londres","ru":"Лондон"},"geoname_id":"2643743"},"subdivisions":[{"iso_code":"ENG","names":{"en":"England","pt-BR":"Inglaterra","fr":"Angleterre","es":"Inglaterra"},"geoname_id":6269131}],"location":{"longitude":"-0.0931","latitude":"51.5142","time_zone":"Europe/London"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"US","names":{"pt-BR":"Estados Unidos","es":"Estados Unidos","ru":"США","en":"United States","zh-CN":"美国","fr":"États-Unis","de":"USA","ja":"アメリカ合衆国"},"geoname_id":6252001}}] ["::216.160.83.56/125",{"country":{"iso_code":"US","names":{"pt-BR":"Estados Unidos","es":"Estados Unidos","ru":"США","en":"United States","zh-CN":"美国","fr":"États-Unis","de":"USA","ja":"アメリカ合衆国"},"geoname_id":6252001},"city":{"names":{"en":"Milton","ru":"Мильтон"},"geoname_id":"5803556"},"subdivisions":[{"iso_code":"WA","names":{"zh-CN":"华盛顿州","en":"Washington","fr":"État de Washington","ja":"ワシントン州","es":"Washington","ru":"Вашингтон"},"geoname_id":5815135}],"location":{"longitude":"-122.3149","latitude":"47.2513","time_zone":"America/Los_Angeles","metro_code":"819"},"continent":{"names":{"pt-BR":"América do Norte","es":"América del Norte","ru":"Северная Америка","en":"North America","zh-CN":"北美洲","fr":"Amérique du Nord","de":"Nordamerika","ja":"北アメリカ"},"geoname_id":6255149,"code":"NA"},"postal":{"code":"98354"},"registered_country":{"iso_code":"GB","names":{"pt-BR":"Reino Unido","es":"Reino Unido","ru":"Великобритания","en":"United Kingdom","zh-CN":"英国","fr":"Royaume-Uni","de":"Vereinigtes Königreich","ja":"イギリス"},"geoname_id":2635167}}] ["::89.160.20.112/124",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"city":{"names":{"zh-CN":"林雪平","en":"Linköping","fr":"Linköping","de":"Linköping","ja":"リンシェーピング"},"geoname_id":"2694762"},"subdivisions":[{"iso_code":"E","names":{"en":"Östergötland County","fr":"Comté d'Östergötland"},"geoname_id":2685867}],"location":{"longitude":"15.6167","latitude":"58.4167","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["::89.160.20.128/121",{"country":{"iso_code":"SE","names":{"pt-BR":"Suécia","es":"Suecia","ru":"Швеция","en":"Sweden","zh-CN":"瑞典","fr":"Suède","de":"Schweden","ja":"スウェーデン王国"},"geoname_id":2661886},"city":{"names":{"zh-CN":"林雪平","en":"Linköping","fr":"Linköping","de":"Linköping","ja":"リンシェーピング"},"geoname_id":"2694762"},"subdivisions":[{"iso_code":"E","names":{"en":"Östergötland County","fr":"Comté d'Östergötland"},"geoname_id":2685867}],"location":{"longitude":"15.6167","latitude":"58.4167","time_zone":"Europe/Stockholm"},"continent":{"names":{"pt-BR":"Europa","es":"Europa","ru":"Европа","en":"Europe","zh-CN":"欧洲","fr":"Europe","de":"Europa","ja":"ヨーロッパ"},"geoname_id":6255148,"code":"EU"},"registered_country":{"iso_code":"DE","names":{"pt-BR":"Alemanha","es":"Alemania","ru":"Германия","en":"Germany","zh-CN":"德国","fr":"Allemagne","de":"Deutschland","ja":"ドイツ連邦共和国"},"geoname_id":2921044}}] ["::67.43.156.0/120",{"country":{"iso_code":"BT","names":{"pt-BR":"Butão","es":"Bután","ru":"Бутан","en":"Bhutan","zh-CN":"不丹","fr":"Bhutan","de":"Bhutan","ja":"ブータン王国"},"geoname_id":1252634},"location":{"longitude":"90.5000","latitude":"27.5000","time_zone":"Asia/Thimphu"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"traits":{"is_anonymous_proxy":1},"registered_country":{"iso_code":"RO","names":{"pt-BR":"Romênia","es":"Rumanía","ru":"Румыния","en":"Romania","zh-CN":"罗马尼亚","fr":"Roumanie","de":"Rumänien","ja":"ルーマニア"},"geoname_id":798549}}] ["::202.196.224.0/116",{"country":{"iso_code":"PH","names":{"pt-BR":"Filipinas","es":"Filipinas","ru":"Филиппины","en":"Philippines","zh-CN":"菲律宾","fr":"Philippines","de":"Philippinen","ja":"フィリピン共和国"},"geoname_id":1694008},"location":{"longitude":"122","latitude":"13","time_zone":"Asia/Manila"},"continent":{"names":{"pt-BR":"Ásia","es":"Asia","ru":"Азия","en":"Asia","zh-CN":"亚洲","fr":"Asie","de":"Asien","ja":"アジア"},"geoname_id":6255147,"code":"AS"},"postal":{"code":"34021"},"represented_country":{"iso_code":"US","names":{"pt-BR":"Estados Unidos","es":"Estados Unidos","ru":"США","en":"United States","zh-CN":"美国","fr":"États-Unis","de":"USA","ja":"アメリカ合衆国"},"type":"military","geoname_id":6252001},"registered_country":{"iso_code":"PH","names":{"pt-BR":"Filipinas","es":"Filipinas","ru":"Филиппины","en":"Philippines","zh-CN":"菲律宾","fr":"Philippines","de":"Philippinen","ja":"フィリピン共和国"},"geoname_id":1694008}}] libmaxminddb-1.0.4/t/maxmind-db/test-data/000077500000000000000000000000001232270216300203155ustar00rootroot00000000000000libmaxminddb-1.0.4/t/maxmind-db/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb000066400000000000000000000436561232270216300277200ustar00rootroot00000000000000      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ab}cdefghijklmnopqrstuvwxyz{|~        `     ` !S"4#($%&'N)-*+,.1/0235D6:789N;A<>*=*?@**BCNELFIGHNJKNMPNOQRNTsUdV]WZXY[\^a_`bcNelfighNjkNmpnoqrtu|vywxNz{N}~NNN`O7Yw O2` [g[ Y2 2     (2%" !#$2&')0*-+,2./1423[568w9X:I;B<?=>-@A CFDE GHOJQKNLMYOPZRUSTVWYhZa[^\]2_`becdfg ipjmkl2no-qtrs uv xyz{~|}  gfY   [[? q!22`O` Y2     !O 0)& #!"$% '(*-+,"./ 182534#R6729<:;=>@|A]BNCJDGEF2HI KLM OVPSQR$TU-WZXY[\Y^m_f`cabdegjhiklnuorpq stvywx z{}~ %iO2!g Y   Cwg"2g2[ O2$ &<    O  ! 'j"#%4&-'*()+,.1/0 23 5<6978:;=@>?YABDEdFUGNHKIJ LMORPQ2STV]WZXY[[\ ^a_`bcetfmgjhi!klnqop2rsu|vywx2z{}~`Y(O2`(``(2)eDcityJgeoname_id(EEnamesBenGBoxfordIcontinentDcodeBEU _r, BdeFEuropaBenFEuropeBes GBfr QBjaOヨーロッパEpt-BR GBruLЕвропаEzh-CNF欧洲Gcountry (5Hiso_codeBGB BdeWVereinigtes KönigreichBenNUnited KingdomBesKReino UnidoBfrKRoyaume-UniBjaLイギリス u Bru\Великобритания F英国HlocationHlatitudeg51.7500Ilongitudeg-1.2500Itime_zoneMEurope/LondonFpostal 3COX1Rregistered_country . BFR BdeJFrankreichBenFFranceBesGFranciaBfr!BjaUフランス共和国 uGFrançaBruNФранция F法国Lsubdivisions _ CENG BenGEnglandBesJInglaterraBfrJAngleterre u"H 2a CWBK BenNWest BerkshireBru]Западный Беркшир L西伯克郡 ( 3BAS _r+ BdeEAsienBenDAsiaBes"BfrDAsieBjaIアジア uEÁsiaBruHАзия F亚洲  BBT BdeFBhutanBen#(BesFButánBfr#(BjaRブータン王国 uFButãoBruJБутан F不丹!@!Jg27.5000![g90.5000!mLAsia/Thimphu!  /U BRO BdeIRumänienBenGRomaniaBesHRumaníaBfrHRoumanieBjaOルーマニア uHRomêniaBruNРумыния L罗马尼亚FtraitsRis_anonymous_proxy  (W BdeFLondonBen$LBesGLondresBfr$[BjaLロンドン u$[BruLЛондон ( 2 !@!Jg51.5142![g-0.0931!m!w! _e BUS BdeCUSABenMUnited StatesBesNEstados UnidosBfrKÉtats-UnisBjaUアメリカ合衆国 u$BruFСША F美国""*  )j BdeJLinköpingBen%?Bfr%?BjaXリンシェーピング I林雪平 ( 2 ( BSE BdeHSchwedenBenFSwedenBesFSueciaBfrFSuèdeBjaXスウェーデン王国 uGSuéciaBruLШвеция F瑞典!@!Jg58.4167![g15.6167!mPEurope/Stockholm! ,T BDE BdeKDeutschlandBenGGermanyBesHAlemaniaBfrIAllemagneBjaXドイツ連邦共和国 uHAlemanhaBruPГермания F德国" ( AE BenUÖstergötland CountyBfrWComté d'Östergötland (" 8 BPH BdeKPhilippinenBenKPhilippinesBesIFilipinasBfr'BjaXフィリピン共和国 u')BruRФилиппины I菲律宾!@!Jb13![c122!mKAsia/Manila! 3E34021!&Srepresented_country _e BUS $DtypeHmilitary  X$ BenFMiltonBruNМильтон ( 3BNA _r- BdeKNordamerikaBenMNorth AmericaBesRAmérica del NorteBfrQAmérique du NordBjaO北アメリカ uQAmérica do NorteBru]Северная Америка I北美洲 $!@!Jg47.2513![i-122.3149Jmetro_code3!mSAmerica/Los_Angeles! 3E98354! " X_ BWA BenJWashingtonBes(BfrSÉtat de WashingtonBjaRワシントン州BruRВашингтон L华盛顿州 (" e BJP BdeEJapanBen(BesFJapónBfrEJaponBjaF日本 uFJapãoBruLЯпония (!@!Jh35.68536![i139.75309!mJAsia/Tokyo!( (" A BKR BdeNRepublik KoreaBenKSouth KoreaBesTCorea, República deBfrMCorée du SudBjaL大韓民国 uVCoréia, República daBruUЮжная Корея F韩国!@!Jb37![e127.5!mJAsia/Seoul!( (" t BTW BdeFTaiwanBen(BesGTaiwánBfrGTaïwanBjaF台湾 u(BruNТайвань (!@!Jb24![c121!mKAsia/Taipei!( ("  BCN BdeEChinaBenZPeople's Republic of ChinaBesXRepública Popular ChinaBfrEChineBjaF中国 u(qBruJКитай (!@!Jb35![c105!(_ (" R BHK BdeHHongkongBenIHong KongBes(Bfr(BjaF香港 u(BruNГонконг (-!@!Je22.25![i114.16667!mNAsia/Hong_Kong!( ( 2 / BNO BdeHNorwegenBenFNorwayBesGNoruegaBfrHNorvègeBjaUノルウェー王国 u(BruPНорвегия F挪威!@!Jb62![b10!mKEurope/Oslo!( (" ~ BIL BdeFIsraelBen(4Bes(4BfrGIsraëlBjaRイスラエル国 u(4BruNИзраиль I以色列!@!Jd31.5![e34.75!mNAsia/Jerusalem!(" ( 2 !!@!Jb46![a2!mLEurope/Paris!! ( 2 ( BCH BdeGSchweizBenKSwitzerlandBesESuizaBfrFSuisseBjaOスイス連邦 uGSuíçaBruRШвейцария F瑞士!@!Jh47.00016![g8.01427!mMEurope/Zurich!( ( 2 %!@!Jb62![b15!m&!% (" m BBH BdeGBahrainBen(BesHBahréinBfrHBahreïnBjaOバーレーン u(BruNБахрейн F巴林!@!Jb26![d50.5!mLAsia/Bahrain!( ( 2 Z BRU BdeHRusslandBenFRussiaBesERusiaBfrFRussieBjaIロシア uGRússiaBruLРоссия I俄罗斯!@!Jb60![c100!(A ( 2  /P BPL BdeEPolenBenFPolandBesGPoloniaBfrGPologneBjaXポーランド共和国 uHPolôniaBruLПольша F波兰!@!Jb52![b20!mMEurope/Warsaw!( ( 2 &&!@!Jd51.5![d10.5!mMEurope/Berlin!&& ( 2 0s BIT BdeGItalienBenEItalyBesFItaliaBfrFItalieBjaUイタリア共和国 uGItáliaBruLИталия I意大利!@!Jh42.83333![h12.83333!mKEurope/Rome!( ( 2  - BFI BdeHFinnlandBenGFinlandBesIFinlandiaBfrHFinlandeBja[フィンランド共和国 uJFinlândiaBruRФинляндия F芬兰!@!Jb64![b26!mOEurope/Helsinki!( > ( 2  @ BBY BdeMWeißrusslandBenGBelarusBesKBielorrusiaBfrLBiélorussieBjaXベラルーシ共和国 uMBielo-RússiaBruPБеларусь L白俄罗斯!@!Jb53![b28!mLEurope/Minsk!( ( 2 . BCZ BdeUTschechische RepublikBenNCzech RepublicBesPRepública ChecaBfrITchéquieBjaRチェコ共和国 u( Bru]Чешская Республика O捷克共和国!@!Je49.75![b15!mMEurope/Prague!( ("  BIR BdeZIran (Islamische Republik)BenDIranBes\Irán (República Islámica)Bfr]Iran (République islamique de)Bja]イラン・イスラム共和国 u\República Islâmica do IrãBruHИран X伊朗伊斯兰共和国!@!Jb32![b53!mKAsia/Tehran!( ( 2  g BUA BdeGUkraineBen( BesGUcraniaBfr( BjaXウクライナ共和国 uHUcrâniaBruNУкраина I乌克兰!@!Jb49![b32!( ( 2 !@!Jh54.75844![h-2.69531!m!w! ( 2  BHU BdeFUngarnBenGHungaryBesHHungríaBfrGHongrieBjaXハンガリー共和国 uGHungriaBruNВенгрия I匈牙利!@!Jb47![b20!mOEurope/Budapest!( U ( 2!@!Jh48.69096![g9.14062!mLEurope/Vaduz ( 2 &O BES BdeGSpanienBenESpainBesGEspañaBfrGEspagneBjaLスペイン uGEspanhaBruNИспания I西班牙!@!Jb40![b-4!(+ ( 2  . BBG BdeIBulgarienBenHBulgariaBes(BfrHBulgarieBjaXブルガリア共和国 uIBulgáriaBruPБолгария L保加利亚!@!Jb43![b25!mLEurope/Sofia!( ( 2 #!@!Jb46![b25!mPEurope/Bucharest!# ( 2 *¹ BBE BdeGBelgienBenGBelgiumBesHBélgicaBfrHBelgiqueBjaRベルギー王国 u(BruNБельгия I比利时!@!Jh50.83333![a4!mOEurope/Brussels!( (" + BTR BdeGTürkeiBenFTurkeyBesHTurquíaBfrGTurquieBjaRトルコ共和国 uGTurquiaBruLТурция I土耳其!@!Jh39.05901![h34.91155!mOEurope/Istanbul!(5 ( 2 *s BAT BdeKÖsterreichBenGAustriaBes(BfrHAutricheBja[オーストリア共和国 uHÁustriaBruNАвстрия I奥地利!@!Jh47.33333![h13.33333!mMEurope/Vienna!( ( 2  BAL BdeHAlbanienBenGAlbaniaBes(BfrGAlbanieBjaXアルバニア共和国 uHAlbâniaBruNАлбания O阿尔巴尼亚!@!Jb41![b20!mMEurope/Tirane!( (" & BLB BdeGLibanonBenGLebanonBesGLíbanoBfrELibanBjaUレバノン共和国 u(nBruJЛиван I黎巴嫩!@!Jh33.83333![h35.83333!mKAsia/Beirut!(F ( 2 ) BNL BdeKNiederlandeBenKNetherlandsBesGHolandaBfrHPays-BasBjaRオランダ王国 uNPaíses BaixosBruTНидерланды F荷兰!@!Jd52.5![d5.75!mPEurope/Amsterdam!( (" [ BKW BdeFKuwaitBen(Bes(BfrGKoweïtBjaOクウェート u(BruLКувейт I科威特!@!Jd29.5![e47.75!mKAsia/Kuwait!( ("  BSA BdeMSaudi-ArabienBenLSaudi ArabiaBesNArabia SauditaBfrOArabie saouditeBja[サウジアラビア王国 uOArábia SauditaBru]Саудовская Аравия O沙特阿拉伯!@!Jb25![b45!mKAsia/Riyadh!(6 ( 2 _L BRS BdeGSerbienBenFSerbiaBes(8BfrFSerbieBjaLセルビア uGSérviaBruLСербия L塞尔维亚!@!Jh44.81892![h20.45998!mOEurope/Belgrade!( ("  BJO BdeIJordanienBen[Hashemite Kingdom of JordanBesHJordaniaBfrHJordanieBja]ヨルダン・ハシミテ王国 uIJordâniaBruPИордания F约旦!@!Jb31![b36!mJAsia/Amman!( ( 3BAF _r* BdeFAfrikaBenFAfricaBesGÁfricaBfrGAfriqueBjaLアフリカ u(BruLАфрика F非洲 ! BLY Bde]Libysch-Arabische DschamahirijaBenELibyaBesXLibia, República ÁrabeBfrELibyeBja] 社会主義人民リビア・アラブ国 uXLíbia Árabe JamahiriyaBruJЛивия [阿拉伯利比亚民众国!@!Jb28![b17!mNAfrica/Tripoli!( ( 2 -8 BIE BdeFIrlandBenGIrelandBesURepública de IrlandaBfrGIrlandeBjaRアイルランド uGIrlandaBruPИрландия I爱尔兰!@!Jb53![b-8!mMEurope/Dublin!( (" l BAZ BdeMAserbaidschanBenJAzerbaijanBesKAzerbaiyánBfrLAzerbaïdjanBja]アゼルバイジャン共和国 uKAzerbaijãoBruVАзербайджан L阿塞拜疆!@!Jd40.5![d47.5!mIAsia/Baku!( (" n BAE Bde\Vereinigte Arabische EmirateBenTUnited Arab EmiratesBesWEmiratos Árabes UnidosBfrTÉmirats Arabes UnisBjaXアラブ首長国連邦 uWEmirados Árabes UnidosBru]Объединенные Арабские Эмираты X阿拉伯联合酋长国!@!Jb24![b54!mJAsia/Dubai!(q ("  BAM BdeHArmenienBenGArmeniaBes(BfrHArménieBjaXアルメニア共和国 uHArmêniaBruNАрмения L亚美尼亚!@!Jb40![b45!mLAsia/Yerevan!( ( 2 (8 BDK BdeIDänemarkBenGDenmarkBesIDinamarcaBfrHDanemarkBjaUデンマーク王国 u(qBruJДания F丹麦!@!Jb56![b10!mQEurope/Copenhagen!(G ( 2 .k BIM BdeIInsel ManBenKIsle of ManBesKIsla de ManBfrKÎle de ManBjaIマン島 uKIlha de ManBruMМэн, о-в F曼岛!@!Je54.25![d-4.5!mREurope/Isle_of_Man!( ( 2 $B BGI BdeIGibraltarBen(Bes(Bfr(BjaRジブラルタル u(BruRГибралтар!@!Jh36.13333![e-5.35!mPEurope/Gibraltar!(MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeKGeoIP2 CityKdescriptionBen]6GeoIP2 City Test Broken Double Format Database (a small sample of real GeoIP2 data)BzhO小型数据库Jip_versionIlanguagesBenBzhJnode_countKrecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/GeoIP2-City-Test.mmdb000066400000000000000000000444241232270216300240360ustar00rootroot00000000000000      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ab}cdefghijklmnopqrstuvwxyz{|~        `     ` !S"4#($%&'a)-*+,.1/0235D6:789a;A<>P=P?@PPBCaELFIGHaJKaMPNOQRaTsUdV]WZXY[\^a_`bcaelfighajkampnoqrtu|vywxaz{a}~aaa`,7vS      (%" !#$&'[)0*-+,./1423568w9X:I;B<?=>@AvCFDEvGHJQKNLMOPMRUSTVWYhZa[^\]_`becdfgvipjmklnoqtrsvuvvxyz{~|}vv`vv,v ? ! "S   v   #v0)& #!"$%v'(*-+,#./v182534$679<:;=>@|A]BNCJDGEFHIvKLMvOVPSQR%TUWZXY,[\^m_f`cabdegjhiklnuorpqvstvywxvz{}~v&"v vvvC #v$ '    vv! ("# %4&-'*() +, .1/0v23v5<6978 :;=@>?ABDEdFUGNHKIJvLM ORPQSTV]WZXY[\^a_`bcetfmgjhi"klnqoprsu|vywxz{}~)w)w *%*DcityJgeoname_id(EEnamesBenGBoxfordIcontinentDcodeBEU _r, BdeFEuropaBenFEuropeBes GBfr QBjaOヨーロッパEpt-BR GBruLЕвропаEzh-CNF欧洲Gcountry (5Hiso_codeBGB BdeWVereinigtes KönigreichBenNUnited KingdomBesKReino UnidoBfrKRoyaume-UniBjaLイギリス u Bru\Великобритания F英国HlocationHlatitudeh@IIlongitudehItime_zoneMEurope/LondonFpostal 3COX1Rregistered_country . BFR BdeJFrankreichBenFFranceBesGFranciaBfr!BjaUフランス共和国 uGFrançaBruNФранция F法国Lsubdivisions _ CENG BenGEnglandBesJInglaterraBfrJAngleterre u"J 2a CWBK BenNWest BerkshireBru]Западный Беркшир L西伯克郡 ( 3BAS _r+ BdeEAsienBenDAsiaBes"BfrDAsieBjaIアジア uEÁsiaBruHАзия F亚洲  BBT BdeFBhutanBen#*BesFButánBfr#*BjaRブータン王国 uFButãoBruJБутан F不丹!@!Jh@;!\h@V!oLAsia/Thimphu!  /U BRO BdeIRumänienBenGRomaniaBesHRumaníaBfrHRoumanieBjaOルーマニア uHRomêniaBruNРумыния L罗马尼亚FtraitsRis_anonymous_proxy  (W BdeFLondonBen$PBesGLondresBfr$_BjaLロンドン u$_BruLЛондон ( 2 !@!Jh@IN;6!\hfA!o!y! _e BUS BdeCUSABenMUnited StatesBesNEstados UnidosBfrKÉtats-UnisBjaUアメリカ合衆国 u$BruFСША F美国"",  )j BdeJLinköpingBen%EBfr%EBjaXリンシェーピング I林雪平 ( 2 ( BSE BdeHSchwedenBenFSwedenBesFSueciaBfrFSuèdeBjaXスウェーデン王国 uGSuéciaBruLШвеция F瑞典!@!Jh@M5Vl!!\h@/;6!oPEurope/Stockholm! ,T BDE BdeKDeutschlandBenGGermanyBesHAlemaniaBfrIAllemagneBjaXドイツ連邦共和国 uHAlemanhaBruPГермания F德国" ( AE BenUÖstergötland CountyBfrWComté d'Östergötland (" 8 BPH BdeKPhilippinenBenKPhilippinesBesIFilipinasBfr'"BjaXフィリピン共和国 u'1BruRФилиппины I菲律宾!@!Jh@*!\h@^!oKAsia/Manila! 3E34021!'Srepresented_country _e BUS $DtypeHmilitary  X$ BenFMiltonBruNМильтон ( 3BNA _r- BdeKNordamerikaBenMNorth AmericaBesRAmérica del NorteBfrQAmérique du NordBjaO北アメリカ uQAmérica do NorteBru]Северная Америка I北美洲 $!@!Jh@G*0!\h^'RT`Jmetro_code3!oSAmerica/Los_Angeles! 3E98354! " X_ BWA BenJWashingtonBes(,BfrSÉtat de WashingtonBjaRワシントン州BruRВашингтон L华盛顿州 (" e BJP BdeEJapanBen(BesFJapónBfrEJaponBjaF日本 uFJapãoBruLЯпония (!@!Jh@A׹`H!\h@axP3:!oJAsia/Tokyo!( (" A BKR BdeNRepublik KoreaBenKSouth KoreaBesTCorea, República deBfrMCorée du SudBjaL大韓民国 uVCoréia, República daBruUЮжная Корея F韩国!@!Jh@B!\h@_!oJAsia/Seoul!(! (" t BTW BdeFTaiwanBen( BesGTaiwánBfrGTaïwanBjaF台湾 u( BruNТайвань (/!@!Jh@8!\h@^@!oKAsia/Taipei!( ("  BCN BdeEChinaBenZPeople's Republic of ChinaBesXRepública Popular ChinaBfrEChineBjaF中国 u(BruJКитай (!@!Jh@A!\h@Z@!( (" R BHK BdeHHongkongBenIHong KongBes(EBfr(EBjaF香港 u(EBruNГонконг (^!@!Jh@6@!\h@\[!oNAsia/Hong_Kong!(' ( 2 / BNO BdeHNorwegenBenFNorwayBesGNoruegaBfrHNorvègeBjaUノルウェー王国 u(BruPНорвегия F挪威!@!Jh@O!\h@$!oKEurope/Oslo!( (" ~ BIL BdeFIsraelBen(sBes(sBfrGIsraëlBjaRイスラエル国 u(sBruNИзраиль I以色列!@!Jh@?!\h@A`!oNAsia/Jerusalem!(a ( 2 !!@!Jh@G!\h@!oLEurope/Paris!! ( 2 ( BCH BdeGSchweizBenKSwitzerlandBesESuizaBfrFSuisseBjaOスイス連邦 uGSuíçaBruRШвейцария F瑞士!@!Jh@G>-b9!\h@ Ne!oMEurope/Zurich!(5 ( 2 %!@!Jh@O!\h@.!o&!% (" m BBH BdeGBahrainBen(BesHBahréinBfrHBahreïnBjaOバーレーン u(BruNБахрейн F巴林!@!Jh@:!\h@I@!oLAsia/Bahrain!( ( 2 Z BRU BdeHRusslandBenFRussiaBesERusiaBfrFRussieBjaIロシア uGRússiaBruLРоссия I俄罗斯!@!Jh@N!\h@Y!( ( 2  /P BPL BdeEPolenBenFPolandBesGPoloniaBfrGPologneBjaXポーランド共和国 uHPolôniaBruLПольша F波兰!@!Jh@J!\h@4!oMEurope/Warsaw!(; ( 2 &.!@!Jh@I!\h@%!oMEurope/Berlin!&. ( 2 0s BIT BdeGItalienBenEItalyBesFItaliaBfrFItalieBjaUイタリア共和国 uGItáliaBruLИталия I意大利!@!Jh@EjcI!\h@):э&!oKEurope/Rome!(  ( 2  - BFI BdeHFinnlandBenGFinlandBesIFinlandiaBfrHFinlandeBja[フィンランド共和国 uJFinlândiaBruRФинляндия F芬兰!@!Jh@P!\h@:!oOEurope/Helsinki!( ( 2  @ BBY BdeMWeißrusslandBenGBelarusBesKBielorrusiaBfrLBiélorussieBjaXベラルーシ共和国 uMBielo-RússiaBruPБеларусь L白俄罗斯!@!Jh@J!\h@<!oLEurope/Minsk!( ( 2 . BCZ BdeUTschechische RepublikBenNCzech RepublicBesPRepública ChecaBfrITchéquieBjaRチェコ共和国 u( Bru]Чешская Республика O捷克共和国!@!Jh@H!\h@.!oMEurope/Prague!( U ("  BIR BdeZIran (Islamische Republik)BenDIranBes\Irán (República Islámica)Bfr]Iran (République islamique de)Bja]イラン・イスラム共和国 u\República Islâmica do IrãBruHИран X伊朗伊斯兰共和国!@!Jh@@!\h@J!oKAsia/Tehran!( : ( 2  g BUA BdeGUkraineBen( dBesGUcraniaBfr( dBjaXウクライナ共和国 uHUcrâniaBruNУкраина I乌克兰!@!Jh@H!\h@@!( R ( 2 !@!Jh@Ka7!\htr!o!y! ( 2  BHU BdeFUngarnBenGHungaryBesHHungríaBfrGHongrieBjaXハンガリー共和国 uGHungriaBruNВенгрия I匈牙利!@!Jh@G!\h@4!oOEurope/Budapest!( ( 2!@!Jh@HXq`l !\h@"GX:S!oLEurope/Vaduz ( 2 &O BES BdeGSpanienBenESpainBesGEspañaBfrGEspagneBjaLスペイン uGEspanhaBruNИспания I西班牙!@!Jh@D!\h!( ( 2  . BBG BdeIBulgarienBenHBulgariaBes(BfrHBulgarieBjaXブルガリア共和国 uIBulgáriaBruPБолгария L保加利亚!@!Jh@E!\h@9!oLEurope/Sofia!( ( 2 #!@!Jh@G!\h@9!oPEurope/Bucharest!# ( 2 *¹ BBE BdeGBelgienBenGBelgiumBesHBélgicaBfrHBelgiqueBjaRベルギー王国 u(BruNБельгия I比利时!@!Jh@IjcI!\h@!oOEurope/Brussels!( (" + BTR BdeGTürkeiBenFTurkeyBesHTurquíaBfrGTurquieBjaRトルコ共和国 uGTurquiaBruLТурция I土耳其!@!Jh@C!\h@AtU!oOEurope/Istanbul!(/ ( 2 *s BAT BdeKÖsterreichBenGAustriaBes(BfrHAutricheBja[オーストリア共和国 uHÁustriaBruNАвстрия I奥地利!@!Jh@GcI!\h@*:э&!oMEurope/Vienna!( ( 2  BAL BdeHAlbanienBenGAlbaniaBes(BfrGAlbanieBjaXアルバニア共和国 uHAlbâniaBruNАлбания O阿尔巴尼亚!@!Jh@D!\h@4!oMEurope/Tirane!( (" & BLB BdeGLibanonBenGLebanonBesGLíbanoBfrELibanBjaUレバノン共和国 u(tBruJЛиван I黎巴嫩!@!Jh@@ꪎcI!\h@AꪎcI!oKAsia/Beirut!(L ( 2 ) BNL BdeKNiederlandeBenKNetherlandsBesGHolandaBfrHPays-BasBjaRオランダ王国 uNPaíses BaixosBruTНидерланды F荷兰!@!Jh@J@!\h@!oPEurope/Amsterdam!( (" [ BKW BdeFKuwaitBen(Bes(BfrGKoweïtBjaOクウェート u(BruLКувейт I科威特!@!Jh@=!\h@G!oKAsia/Kuwait!( ("  BSA BdeMSaudi-ArabienBenLSaudi ArabiaBesNArabia SauditaBfrOArabie saouditeBja[サウジアラビア王国 uOArábia SauditaBru]Саудовская Аравия O沙特阿拉伯!@!Jh@9!\h@F!oKAsia/Riyadh!(K ( 2 _L BRS BdeGSerbienBenFSerbiaBes(YBfrFSerbieBjaLセルビア uGSérviaBruLСербия L塞尔维亚!@!Jh@Fh^)!\h@4u?h!oOEurope/Belgrade!(< ("  BJO BdeIJordanienBen[Hashemite Kingdom of JordanBesHJordaniaBfrHJordanieBja]ヨルダン・ハシミテ王国 uIJordâniaBruPИордания F约旦!@!Jh@?!\h@B!oJAsia/Amman!( ( 3BAF _r* BdeFAfrikaBenFAfricaBesGÁfricaBfrGAfriqueBjaLアフリカ u(BruLАфрика F非洲 ! BLY Bde]Libysch-Arabische DschamahirijaBenELibyaBesXLibia, República ÁrabeBfrELibyeBja] 社会主義人民リビア・アラブ国 uXLíbia Árabe JamahiriyaBruJЛивия [阿拉伯利比亚民众国!@!Jh@<!\h@1!oNAfrica/Tripoli!( ( 2 -8 BIE BdeFIrlandBenGIrelandBesURepública de IrlandaBfrGIrlandeBjaRアイルランド uGIrlandaBruPИрландия I爱尔兰!@!Jh@J!\h !oMEurope/Dublin!(& (" l BAZ BdeMAserbaidschanBenJAzerbaijanBesKAzerbaiyánBfrLAzerbaïdjanBja]アゼルバイジャン共和国 uKAzerbaijãoBruVАзербайджан L阿塞拜疆!@!Jh@D@!\h@G!oIAsia/Baku!( (" n BAE Bde\Vereinigte Arabische EmirateBenTUnited Arab EmiratesBesWEmiratos Árabes UnidosBfrTÉmirats Arabes UnisBjaXアラブ首長国連邦 uWEmirados Árabes UnidosBru]Объединенные Арабские Эмираты X阿拉伯联合酋长国!@!Jh@8!\h@K!oJAsia/Dubai!( ("  BAM BdeHArmenienBenGArmeniaBes(BfrHArménieBjaXアルメニア共和国 uHArmêniaBruNАрмения L亚美尼亚!@!Jh@D!\h@F!oLAsia/Yerevan!( ( 2 (8 BDK BdeIDänemarkBenGDenmarkBesIDinamarcaBfrHDanemarkBjaUデンマーク王国 u(BruJДания F丹麦!@!Jh@L!\h@$!oQEurope/Copenhagen!( ( 2 .k BIM BdeIInsel ManBenKIsle of ManBesKIsla de ManBfrKÎle de ManBjaIマン島 uKIlha de ManBruMМэн, о-в F曼岛!@!Jh@K !\h!oREurope/Isle_of_Man!(Z ( 2 $B BGI BdeIGibraltarBen($Bes($Bfr($BjaRジブラルタル u($BruRГибралтар!@!Jh@Bɰ!\hffffff!oPEurope/Gibraltar!(MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeKGeoIP2 CityKdescriptionBen]!GeoIP2 City Test Database (a small sample of real GeoIP2 data)BzhO小型数据库Jip_versionIlanguagesBenBzhJnode_countKrecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb000066400000000000000000000011521232270216300264670ustar00rootroot00000000000000@@@@@@@@ @ @ @ @ @@@@@@@@@@@@@@@@@@@ @!@"@#@$@%@&@'@(@)@*@+@,@-@.@/@0@1@2@3@4@5@6@7@8@9@:@;@<@=@>@?@P@F::0/64MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_type]MaxMind DB No IPv4 Search TreeKdescriptionBen \Jip_versionIlanguagesBenJnode_count@Krecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-string-value-entries.mmdb000066400000000000000000000011031232270216300270560ustar00rootroot00000000000000%%%%%%%% % % % % %%%%%%%%%%%%%% 5ALW%b!%"%#%$%m%K1.1.1.16/28J1.1.1.8/29J1.1.1.4/30J1.1.1.2/31J1.1.1.1/32K1.1.1.32/32MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_type]MaxMind DB String Value EntriesKdescriptionBen] MaxMind DB String Value Entries (no maps or arrays as values)Jip_versionIlanguagesBenJnode_count%Krecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb000066400000000000000000000010171232270216300273140ustar00rootroot00000000000000%%%%%%%% % % % % %%%%%%%%%%%%%% 59EQ%]!%"%#%$% %0:@BipG1.1.1.8BipG1.1.1.4BipG1.1.1.2BipG1.1.1.1BipH1.1.1.32MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_count%Krecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb000066400000000000000000000055651232270216300253710ustar00rootroot00000000000000L.      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`      !"#$%&'()*+,-/0123456789:K;<=>?@ABCDEFGHIJ``MNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~EarrayGbooleanEbytesFdoublehEfloatEint32CmapGuint128Fuint16Fuint32Fuint64Kutf8_string@   * h@Eg?[ *? 6CmapDmapXFarrayX Lutf8_stringXEhello C Md U ] fRunicode! ☯ - ♫MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeWMaxMind DB Decoder TestKdescriptionBen])MaxMind DB Decoder Test database - contains every MaxMind DB data typeJip_versionIlanguagesBenJnode_countKrecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-ipv4-24.mmdb000066400000000000000000000010301232270216300250500ustar00rootroot00000000000000%%%%%%%% % % % % %%%%%%%%%%%%%% 5BNZ%f!%"%#%$%r%BipH1.1.1.16BipG1.1.1.8BipG1.1.1.4BipG1.1.1.2BipG1.1.1.1BipH1.1.1.32MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_count%Krecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-ipv4-28.mmdb000066400000000000000000000010751232270216300250650ustar00rootroot00000000000000%%%%%%%% % % % % %%%%%%%%%%%%%% 5BNZ%f!%"%#%$%r%BipH1.1.1.16BipG1.1.1.8BipG1.1.1.4BipG1.1.1.2BipG1.1.1.1BipH1.1.1.32MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_count%Krecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-ipv4-32.mmdb000066400000000000000000000011421232270216300250530ustar00rootroot00000000000000%%%%%%%% % % % % %%%%%%%%%%%%%% 5BNZ%f!%"%#%$%r%BipH1.1.1.16BipG1.1.1.8BipG1.1.1.4BipG1.1.1.2BipG1.1.1.1BipH1.1.1.32MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_count%Krecord_size libmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-ipv6-24.mmdb000066400000000000000000000023651232270216300250660ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~BipM::1:ffff:ffffBipG::2:0:0BipH::2:0:40BipH::2:0:50BipH::2:0:58MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_countKrecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-ipv6-28.mmdb000066400000000000000000000026251232270216300250710ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~BipM::1:ffff:ffffBipG::2:0:0BipH::2:0:40BipH::2:0:50BipH::2:0:58MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_countKrecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-ipv6-32.mmdb000066400000000000000000000030651232270216300250630ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~BipM::1:ffff:ffffBipG::2:0:0BipH::2:0:40BipH::2:0:50BipH::2:0:58MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_countKrecord_size libmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-mixed-24.mmdb000066400000000000000000000034671232270216300253140ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~-;IXjv```BipJ::1.1.1.16BipI::1.1.1.8BipI::1.1.1.4BipI::1.1.1.2BipI::1.1.1.1BipJ::1.1.1.32BipM::1:ffff:ffffBipG::2:0:0BipH::2:0:40BipH::2:0:50BipH::2:0:58MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_countKrecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-mixed-28.mmdb000066400000000000000000000040511232270216300253060ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~-;IXjv```BipJ::1.1.1.16BipI::1.1.1.8BipI::1.1.1.4BipI::1.1.1.2BipI::1.1.1.1BipJ::1.1.1.32BipM::1:ffff:ffffBipG::2:0:0BipH::2:0:40BipH::2:0:50BipH::2:0:58MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_countKrecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-mixed-32.mmdb000066400000000000000000000044331232270216300253050ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~-;IXjv```BipJ::1.1.1.16BipI::1.1.1.8BipI::1.1.1.4BipI::1.1.1.2BipI::1.1.1.1BipJ::1.1.1.32BipM::1:ffff:ffffBipG::2:0:0BipH::2:0:40BipH::2:0:50BipH::2:0:58MaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_typeDTestKdescriptionBenMTest DatabaseBzhUTest Database ChineseJip_versionIlanguagesBenBzhJnode_countKrecord_size libmaxminddb-1.0.4/t/maxmind-db/test-data/MaxMind-DB-test-nested.mmdb000066400000000000000000000050361232270216300252370ustar00rootroot000000000000004sssss s s s s sssssssssssssssssss s!s"s#s$s%s&s's(s)s*s+s,s-s.s/s0s1s2s3s4s5s6s7s8s9s:s;s<s=s>s?s@sAsBsCsDsEsFsGsHsIsJsKsLsMsNsOsPsQRsSsTsUsVsWsXsYsZs[s\s]s^s_s`sasbscsdsesfgxshisjskslsmsnsosspqsrssstsusvswssyzs{s|s}s~sssssssssssssssssssssssssssssssssssssssssssss`ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss ss  s ss ssssssssssssssssss s!s"3s#$s%s&s's(s)s*s+s,s-s.s/s0s1s2s`s`s5ss67ss89ss:s;s<s=>s?ss@sABssCDsEsFsGsHsIsJsKsLsMsNsOsPsQsRsSsTsUsVsWsXsYsZs[s\s]s^s_s`sasbscsdsesfsgshsisjskslsmsnsospsqsrssDmap1Dmap2EarrayDmap3AaAbAcMaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochSKMdatabase_type]MaxMind DB Nested Data StructuresKdescriptionBen]@MaxMind DB Nested Data Structures Test database - contains deeply nested map/array structuresJip_versionIlanguagesBenJnode_countsKrecord_sizelibmaxminddb-1.0.4/t/maxmind-db/test-data/README.md000066400000000000000000000007671232270216300216060ustar00rootroot00000000000000The write-test-dbs script will create a small set of test databases with a variety of data and record sizes (24, 28, & 32 bit). These test databases are useful for testing code that reads MaxMind DB files. There is also a `maps-with-pointers.raw` file. This contains the raw output of the MaxMind::DB::Writer::Serializer module, when given a series of maps which share some keys and values. It is used to test that decoder code can handle pointers to map keys and values, as well as to the whole map. libmaxminddb-1.0.4/t/maxmind-db/test-data/maps-with-pointers.raw000066400000000000000000000000731232270216300246020ustar00rootroot00000000000000Hlong_keyKlong_value1 Klong_value2Ilong_key2 &  2libmaxminddb-1.0.4/t/maxmind-db/test-data/write-test-data000077500000000000000000000312021232270216300232570ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use autodie; use utf8; use Carp qw( croak ); use Cwd qw( abs_path ); use File::Basename qw( dirname ); use JSON::XS; use Math::Int128 qw( uint128 ); use MaxMind::DB::Writer::Serializer 0.050000; use MaxMind::DB::Writer::Tree 0.050000; use Net::Works::Network; use Test::MaxMind::DB::Common::Util qw( standard_test_metadata ); my $Dir = dirname( abs_path($0) ); sub main { my @sizes = ( 24, 28, 32 ); my @ipv4_range = ( '1.1.1.1', '1.1.1.32' ); my @ipv4_subnets = Net::Works::Network->range_as_subnets(@ipv4_range); for my $record_size (@sizes) { write_test_db( $record_size, \@ipv4_subnets, { ip_version => 4 }, 'ipv4', ); } write_broken_pointers_test_db( 24, \@ipv4_subnets, { ip_version => 4 }, 'broken-pointers', ); my @ipv6_subnets = Net::Works::Network->range_as_subnets( '::1:ffff:ffff', '::2:0000:0059' ); for my $record_size (@sizes) { write_test_db( $record_size, \@ipv6_subnets, { ip_version => 6 }, 'ipv6', ); write_test_db( $record_size, [ @ipv6_subnets, Net::Works::Network->range_as_subnets( @ipv4_range, 6 ), ], { ip_version => 6 }, 'mixed', ); } write_decoder_test_db(); write_deeply_nested_structures_db(); write_geoip2_city_db(); write_broken_geoip2_city_db(); write_no_ipv4_tree_db(); write_no_map_db(\@ipv4_subnets); write_test_serialization_data(); } sub write_broken_pointers_test_db { no warnings 'redefine'; my $orig_store_data = MaxMind::DB::Writer::Serializer->can('store_data'); # This breaks the value of the record for the 1.1.1.32 network, causing it # to point outside the database. local *MaxMind::DB::Writer::Serializer::store_data = sub { my $data_pointer = shift->$orig_store_data(@_); my $value = $_[1]; if ( ref($value) eq 'HASH' && exists $value->{ip} && $value->{ip} eq '1.1.1.32' ) { $data_pointer += 100_000; } return $data_pointer; }; # The next hack will poison the data section for the 1.1.16/28 subnet # value. It's value will be a pointer that resolves to an offset outside # the database. my $key_to_poison = 'evbclUZX3mjlqxDihL+JNr+276s'; my $orig_position_for_data = MaxMind::DB::Writer::Serializer->can('_position_for_data'); local *MaxMind::DB::Writer::Serializer::_position_for_data = sub { my $key = $_[1]; if ( $key eq $key_to_poison ) { return 1_000_000; } else { return shift->$orig_position_for_data(@_); } }; write_test_db(@_); } sub write_test_db { my $record_size = shift; my $subnets = shift; my $metadata = shift; my $ip_version_name = shift; my $writer = MaxMind::DB::Writer::Tree->new( ip_version => $subnets->[0]->version(), record_size => $record_size, alias_ipv6_to_ipv4 => ( $subnets->[0]->version() == 6 ? 1 : 0 ), map_key_type_callback => sub { 'utf8_string' }, standard_test_metadata(), %{$metadata}, ); for my $subnet ( @{$subnets} ) { $writer->insert_network( $subnet, { ip => $subnet->first()->as_string() } ); } my $filename = sprintf( "$Dir/MaxMind-DB-test-%s-%i.mmdb", $ip_version_name, $record_size, ); open my $fh, '>', $filename; $writer->write_tree($fh); close $fh; return ( $writer, $filename ); } { # We will store this once for each subnet so we will also be testing # pointers, since the serializer will generate a pointer to this # structure. my %all_types = ( utf8_string => 'unicode! ☯ - ♫', double => 42.123456, bytes => pack( 'N', 42 ), uint16 => 100, uint32 => 2**28, int32 => -1 * ( 2**28 ), uint64 => uint128(1) << 60, uint128 => uint128(1) << 120, array => [ 1, 2, 3, ], map => { mapX => { utf8_stringX => 'hello', arrayX => [ 7, 8, 9 ], }, }, boolean => 1, float => 1.1, ); my %all_types_0 = ( utf8_string => q{}, double => 0, bytes => q{}, uint16 => 0, uint32 => 0, int32 => 0, uint64 => uint128(0), uint128 => uint128(0), array => [], map => {}, boolean => 0, float => 0, ); sub write_decoder_test_db { my $writer = MaxMind::DB::Writer::Tree->new( ip_version => 6, record_size => 24, database_type => 'MaxMind DB Decoder Test', languages => ['en'], description => { en => 'MaxMind DB Decoder Test database - contains every MaxMind DB data type', }, alias_ipv6_to_ipv4 => 1, map_key_type_callback => sub { my $key = $_[0]; $key =~ s/X$//; return $key eq 'array' ? [ 'array', 'uint32' ] : $key; } ); my @subnets = map { Net::Works::Network->new_from_string( string => $_ ) } qw( ::1.1.1.0/120 ::2.2.0.0/112 ::3.0.0.0/104 ::4.5.6.7/128 abcd::/64 1000::1234:0000/112 ); for my $subnet (@subnets) { $writer->insert_network( $subnet, \%all_types, ); } $writer->insert_network( Net::Works::Network->new_from_string( string => '::0.0.0.0/128' ), \%all_types_0, ); open my $fh, '>', "$Dir/MaxMind-DB-test-decoder.mmdb"; $writer->write_tree($fh); close $fh; return; } } { my %nested = ( map1 => { map2 => { array => [ { map3 => { a => 1, b => 2, c => 3 }, }, ], }, }, ); sub write_deeply_nested_structures_db { my $writer = MaxMind::DB::Writer::Tree->new( ip_version => 6, record_size => 24, ip_version => 6, database_type => 'MaxMind DB Nested Data Structures', languages => ['en'], description => { en => 'MaxMind DB Nested Data Structures Test database - contains deeply nested map/array structures', }, alias_ipv6_to_ipv4 => 1, map_key_type_callback => sub { my $key = shift; return $key =~ /^map/ ? 'map' : $key eq 'array' ? [ 'array', 'map' ] : 'uint32'; } ); my @subnets = map { Net::Works::Network->new_from_string( string => $_ ) } qw( ::1.1.1.0/120 ::2.2.0.0/112 ::3.0.0.0/104 ::4.5.6.7/128 abcd::/64 1000::1234:0000/112 ); for my $subnet (@subnets) { $writer->insert_network( $subnet, \%nested, ); } open my $fh, '>', "$Dir/MaxMind-DB-test-nested.mmdb"; $writer->write_tree($fh); close $fh; return; } } sub write_geoip2_city_db { _write_geoip2_city_db('Test'); } sub write_broken_geoip2_city_db { no warnings 'redefine'; # This is how we _used_ to encode doubles. Storing them this way with the # current reader tools can lead to weird errors. This broken database is a # good way to test the robustness of reader code in the face of broken # databases. local *MaxMind::DB::Writer::Serializer::_encode_double = sub { my $self = shift; my $value = shift; $self->_simple_encode( double => $value ); }; _write_geoip2_city_db('Test Broken Double Format'); } { my %type_map = ( cellular => 'uint16', city => 'map', continent => 'map', country => 'map', geoname_id => 'uint32', is_anonymous_proxy => 'boolean', is_satellite_provider => 'boolean', latitude => 'double', location => 'map', longitude => 'double', metro_code => 'uint16', names => 'map', postal => 'map', registered_country => 'map', represented_country => 'map', subdivisions => [ 'array', 'map' ], traits => 'map', ); my $type_cb = sub { $type_map{ $_[0] } // 'utf8_string' }; sub _write_geoip2_city_db { my $description = shift; my $writer = MaxMind::DB::Writer::Tree->new( ip_version => 6, record_size => 28, ip_version => 6, database_type => 'GeoIP2 City', languages => [ 'en', 'zh' ], description => { en => "GeoIP2 City $description Database (a small sample of real GeoIP2 data)", zh => '小型数据库', }, alias_ipv6_to_ipv4 => 1, map_key_type_callback => $type_cb, ); my $json = JSON::XS->new()->utf8(); open my $source_fh, '<', "$Dir/../source-data/GeoIP2-City-Test.json"; while (<$source_fh>) { my ( $network, $record ) = @{ $json->decode($_) }; $writer->insert_network( Net::Works::Network->new_from_string( string => $network ), $record ); } close $source_fh; my $suffix = $description =~ s/ /-/gr; open my $output_fh, '>', "$Dir/GeoIP2-City-$suffix.mmdb"; $writer->write_tree($output_fh); close $output_fh; return; } } sub write_no_ipv4_tree_db { my $subnets = shift; my $writer = MaxMind::DB::Writer::Tree->new( ip_version => 6, record_size => 24, ip_version => 6, database_type => 'MaxMind DB No IPv4 Search Tree', languages => ['en'], description => { en => 'MaxMind DB No IPv4 Search Tree', }, root_data_type => 'utf8_string', ); my $subnet = Net::Works::Network->new_from_string( string => '::/64' ); $writer->insert_network( $subnet, $subnet->as_string() ); open my $output_fh, '>', "$Dir/MaxMind-DB-no-ipv4-search-tree.mmdb"; $writer->write_tree($output_fh); close $output_fh; return; } # The point of this database is to provide something where we can test looking # up a single value. In other words, each IP address points to a non-compound # value, a string rather than a map or array. sub write_no_map_db { my $subnets = shift; my $writer = MaxMind::DB::Writer::Tree->new( ip_version => 4, record_size => 24, database_type => 'MaxMind DB String Value Entries', languages => ['en'], description => { en => 'MaxMind DB String Value Entries (no maps or arrays as values)', }, root_data_type => 'utf8_string', ); for my $subnet (@{$subnets}) { $writer->insert_network( $subnet, $subnet->as_string() ); } open my $output_fh, '>', "$Dir/MaxMind-DB-string-value-entries.mmdb"; $writer->write_tree($output_fh); close $output_fh; return; } sub write_test_serialization_data { my $serializer = MaxMind::DB::Writer::Serializer->new( map_key_type_callback => sub { 'utf8_string' } ); $serializer->store_data( map => { long_key => 'long_value1' } ); $serializer->store_data( map => { long_key => 'long_value2' } ); $serializer->store_data( map => { long_key2 => 'long_value1' } ); $serializer->store_data( map => { long_key2 => 'long_value2' } ); $serializer->store_data( map => { long_key => 'long_value1' } ); $serializer->store_data( map => { long_key2 => 'long_value2' } ); open my $fh, '>', 'maps-with-pointers.raw'; print {$fh} ${ $serializer->buffer() } or die "Cannot write to maps-with-pointers.raw: $!"; close $fh; return; } main();