mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-06-12 15:34:47 +02:00
174 lines
7.2 KiB
C
174 lines
7.2 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
|
|
#ifndef _WIN32_WINNT
|
|
#define _WIN32_WINNT 0x0601
|
|
#endif
|
|
#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 */
|