mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-06-12 19:14:46 +02:00
172ace9750
This is mainly due to licensing. The libmaxminddb library uses the Apache license, which meant if we would compile it in by default it would effectively transform our "GPLv2 or later" to "GPLv3 or later". Our implementation is ISC licensed, so we can include and enable it by default and keep things at "GPLv2 or later". This is also why we used geoip_classic in the first place as default and compiled in, and not the mmdb variant. The mmdb.c is based on the specification, using the Go implementation as a reference during development (ISC licensed), initially implemented with the help of Claude Opus 4.6. After that substantial changes were made to make it match UnrealIRCd's style and to make things less error prone: C style changes, allocation and zero termination of strings in the library, auto-NULL in variadic functions so the caller cannot forget NULL there (similar to our unreal_log/do_unreal_log), using enums as the return type instead of int (similar to curl), adding doxygen docs, etc. This also means the old mmdb library dependency has been dropped, including from configure/autoconf. At the moment we still use the geoip classic library by default, including those DB files. The idea is we will switch over sometime later after this current new MMDB stuff has received more testing. This also makes us more flexible, since .mmdb files have become the de-facto standard for pretty much all geoip vendors.
171 lines
7.1 KiB
C
171 lines
7.1 KiB
C
/*
|
|
* mmdb.h - Minimal MMDB (MaxMind DB) reader library
|
|
*
|
|
* Written from the MaxMind DB file format specification
|
|
* (https://maxmind.github.io/MaxMind-DB/).
|
|
*
|
|
* This C implementation was written by the UnrealIRCd team,
|
|
* using the Go MMDB reader oschwald/maxminddb-golang by
|
|
* Gregory J. Oschwald as a reference during development.
|
|
*
|
|
* Copyright (c) 2015 Gregory J. Oschwald (Go implementation)
|
|
* Copyright (c) 2026 UnrealIRCd team
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for
|
|
* any purpose with or without fee is hereby granted, provided that
|
|
* the above copyright notice and this permission notice appear in
|
|
* all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
|
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
|
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifndef MMDB_H
|
|
#define MMDB_H
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#else
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#endif
|
|
|
|
/** Status/error codes returned by mmdb functions */
|
|
typedef enum {
|
|
MMDB_OK = 0, /**< Success */
|
|
MMDB_ERR_OPEN, /**< Could not open or mmap the file */
|
|
MMDB_ERR_INVALID_DB, /**< Not a valid MMDB file */
|
|
MMDB_ERR_CORRUPT, /**< Search tree or data section corruption */
|
|
MMDB_ERR_NODATA, /**< IP found but requested path doesn't exist */
|
|
MMDB_ERR_TYPE, /**< Type mismatch (asked for string, got uint, etc) */
|
|
MMDB_ERR_IPV6_IN_V4, /**< Tried to look up an IPv6 address in an IPv4-only db */
|
|
MMDB_ERR_BADARG, /**< Invalid argument (e.g. unparseable IP address) */
|
|
} MMDB_Status;
|
|
|
|
/** Database metadata */
|
|
typedef struct {
|
|
uint32_t node_count; /**< Number of nodes in the search tree */
|
|
uint16_t record_size; /**< Size of each record in bits */
|
|
uint16_t ip_version; /**< IP version the database covers (4 or 6) */
|
|
uint64_t build_epoch; /**< Unix timestamp when the database was built */
|
|
char database_type[128]; /**< Database type string (e.g. "GeoLite2-Country") */
|
|
} MMDB_Metadata;
|
|
|
|
/** Database handle */
|
|
typedef struct {
|
|
uint8_t *data; /**< mmap'd (or malloc'd) file contents */
|
|
size_t data_size; /**< Total file size */
|
|
size_t data_section_offset; /**< Offset where data section starts */
|
|
size_t data_section_size; /**< Size of data section */
|
|
MMDB_Metadata metadata; /**< Parsed database metadata */
|
|
uint32_t ipv4_start_node; /**< Cached start node for IPv4 lookups in IPv6 dbs */
|
|
int ipv4_start_bit_depth; /**< Bit depth at ipv4_start_node */
|
|
int is_mmap; /**< 1 if data was mmap'd, 0 if malloc'd */
|
|
} MMDB_DB;
|
|
|
|
/** Lookup result */
|
|
typedef struct {
|
|
MMDB_DB *db; /**< Database this result belongs to */
|
|
size_t offset; /**< Offset into data section, or 0 if not found */
|
|
int has_data; /**< 1 if IP was found and has data */
|
|
} MMDB_Result;
|
|
|
|
/** Open an MMDB database file.
|
|
* Uses mmap where available, falls back to malloc+read.
|
|
* @param db Database handle to initialize
|
|
* @param filename Path to the .mmdb file
|
|
* @returns MMDB_OK on success, or an error code
|
|
*/
|
|
MMDB_Status mmdb_open(MMDB_DB *db, const char *filename);
|
|
|
|
/** Close the database and release resources.
|
|
* Safe to call on an already-closed or zero-initialized handle.
|
|
* @param db Database handle to close
|
|
*/
|
|
void mmdb_close(MMDB_DB *db);
|
|
|
|
/** Look up an IP address given as a string (IPv4 or IPv6).
|
|
* On success, check result->has_data to see if the IP was
|
|
* actually found in the database.
|
|
* @param db Database handle
|
|
* @param ip_str IP address string (e.g. "1.2.3.4" or "2001:db8::1")
|
|
* @param result Lookup result (output)
|
|
* @returns MMDB_OK on success, or an error code
|
|
*/
|
|
MMDB_Status mmdb_lookup(MMDB_DB *db, const char *ip_str, MMDB_Result *result);
|
|
|
|
/** Look up an IP address given as a sockaddr.
|
|
* Supports sockaddr_in (IPv4) and sockaddr_in6 (IPv6).
|
|
* @param db Database handle
|
|
* @param sa Socket address to look up
|
|
* @param result Lookup result (output)
|
|
* @returns MMDB_OK on success, or an error code
|
|
*/
|
|
MMDB_Status mmdb_lookup_sockaddr(MMDB_DB *db, const struct sockaddr *sa,
|
|
MMDB_Result *result);
|
|
|
|
/** Retrieve a string value from a lookup result by path.
|
|
* Returns a malloc'd, null-terminated copy. Caller must free().
|
|
* On error, *out is set to NULL.
|
|
* @param result Lookup result from mmdb_lookup()
|
|
* @param out Receives a malloc'd null-terminated string (output)
|
|
* @param ... Path of map keys (NULL sentinel is added automatically)
|
|
* @returns MMDB_OK on success, or an error code
|
|
* @note Example: mmdb_get_str(&result, &val, "country", "iso_code");
|
|
*/
|
|
MMDB_Status mmdb_do_get_str(MMDB_Result *result, char **out, ...);
|
|
#define mmdb_get_str(result, out, ...) mmdb_do_get_str(result, out, __VA_ARGS__, NULL)
|
|
|
|
/** Retrieve a uint32 value from a lookup result by path.
|
|
* Also accepts uint16 values (promoted to uint32).
|
|
* On error, *out is set to 0.
|
|
* @param result Lookup result from mmdb_lookup()
|
|
* @param out Receives the uint32 value (output)
|
|
* @param ... Path of map keys (NULL sentinel is added automatically)
|
|
* @returns MMDB_OK on success, or an error code
|
|
* @note Example: mmdb_get_uint32(&result, &asn, "autonomous_system_number");
|
|
*/
|
|
MMDB_Status mmdb_do_get_uint32(MMDB_Result *result, uint32_t *out, ...);
|
|
#define mmdb_get_uint32(result, out, ...) mmdb_do_get_uint32(result, out, __VA_ARGS__, NULL)
|
|
|
|
/** Retrieve a boolean value from a lookup result by path.
|
|
* On error, *out is set to 0.
|
|
* @param result Lookup result from mmdb_lookup()
|
|
* @param out Receives the boolean value (0 or 1) (output)
|
|
* @param ... Path of map keys (NULL sentinel is added automatically)
|
|
* @returns MMDB_OK on success, or an error code
|
|
* @note Example: mmdb_get_bool(&result, &is_vpn, "is_anonymous_vpn");
|
|
*/
|
|
MMDB_Status mmdb_do_get_bool(MMDB_Result *result, int *out, ...);
|
|
#define mmdb_get_bool(result, out, ...) mmdb_do_get_bool(result, out, __VA_ARGS__, NULL)
|
|
|
|
/** Retrieve a double (float64) value from a lookup result by path.
|
|
* Also accepts float32 values (promoted to double).
|
|
* On error, *out is set to 0.
|
|
* @param result Lookup result from mmdb_lookup()
|
|
* @param out Receives the double value (output)
|
|
* @param ... Path of map keys (NULL sentinel is added automatically)
|
|
* @returns MMDB_OK on success, or an error code
|
|
* @note Example: mmdb_get_double(&result, &lat, "location", "latitude");
|
|
*/
|
|
MMDB_Status mmdb_do_get_double(MMDB_Result *result, double *out, ...);
|
|
#define mmdb_get_double(result, out, ...) mmdb_do_get_double(result, out, __VA_ARGS__, NULL)
|
|
|
|
/** Return a human-readable error string for a status code.
|
|
* @param err Status code to describe
|
|
* @returns Static string describing the error (never NULL)
|
|
*/
|
|
const char *mmdb_strerror(MMDB_Status err);
|
|
|
|
#endif /* MMDB_H */
|