Add maxmind to redbean

This commit is contained in:
Justine Tunney 2022-03-18 03:17:08 -07:00
parent af645fcbec
commit c371db6663
11 changed files with 2457 additions and 2 deletions

View file

@ -138,6 +138,7 @@ include third_party/third_party.mk
include libc/testlib/testlib.mk include libc/testlib/testlib.mk
include tool/viz/lib/vizlib.mk include tool/viz/lib/vizlib.mk
include third_party/linenoise/linenoise.mk include third_party/linenoise/linenoise.mk
include third_party/maxmind/maxmind.mk
include third_party/lua/lua.mk include third_party/lua/lua.mk
include third_party/make/make.mk include third_party/make/make.mk
include third_party/argon2/argon2.mk include third_party/argon2/argon2.mk

13
third_party/maxmind/README.cosmo vendored Normal file
View file

@ -0,0 +1,13 @@
ORIGIN
git@github.com:maxmind/libmaxminddb.git
commit d918412fe7d514108d01e346a832d51e5ccf83c0
Author: Will Storey <wstorey@maxmind.com>
Date: Thu Apr 29 11:53:54 2021 -0700
Merge pull request #265 from maxmind/greg/release
1.6.0
LOCAL CHANGES
- Added MMDB_lookup()
- Remove Berkeleyisms from API design w.r.t. IPs.

257
third_party/maxmind/getmetroname.c vendored Normal file
View file

@ -0,0 +1,257 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
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.
*/
#include "libc/macros.internal.h"
#include "third_party/maxmind/maxminddb.h"
const struct thatispacked MetroName {
short code;
const char *name;
} kMetroNames[] = {
{500, "Portland-Auburn ME"},
{501, "New York NY"},
{502, "Binghamton NY"},
{503, "Macon GA"},
{504, "Philadelphia PA"},
{505, "Detroit MI"},
{506, "Boston MA-Manchester NH"},
{507, "Savannah GA"},
{508, "Pittsburgh PA"},
{509, "Ft. Wayne IN"},
{510, "Cleveland-Akron (Canton) OH"},
{511, "Washington DC (Hagerstown MD)"},
{512, "Baltimore MD"},
{513, "Flint-Saginaw-Bay City MI"},
{514, "Buffalo NY"},
{515, "Cincinnati OH"},
{516, "Erie PA"},
{517, "Charlotte NC"},
{518, "Greensboro-High Point-Winston Salem NC"},
{519, "Charleston SC"},
{520, "Augusta GA"},
{521, "Providence RI-New Bedford MA"},
{522, "Columbus GA"},
{523, "Burlington VT-Plattsburgh NY"},
{524, "Atlanta GA"},
{525, "Albany GA"},
{526, "Utica NY"},
{527, "Indianapolis IN"},
{528, "Miami-Ft. Lauderdale FL"},
{529, "Louisville KY"},
{530, "Tallahassee FL-Thomasville GA"},
{531, "Tri-Cities TN-VA"},
{532, "Albany-Schenectady-Troy NY"},
{533, "Hartford & New Haven CT"},
{534, "Orlando-Daytona Beach-Melbourne FL"},
{535, "Columbus OH"},
{536, "Youngstown OH"},
{537, "Bangor ME"},
{538, "Rochester NY"},
{539, "Tampa-St. Petersburg (Sarasota) FL"},
{540, "Traverse City-Cadillac MI"},
{541, "Lexington KY"},
{542, "Dayton OH"},
{543, "Springfield-Holyoke MA"},
{544, "Norfolk-Portsmouth-Newport News VA"},
{545, "Greenville-New Bern-Washington NC"},
{546, "Columbia SC"},
{547, "Toledo OH"},
{548, "West Palm Beach-Ft. Pierce FL"},
{549, "Watertown NY"},
{550, "Wilmington NC"},
{551, "Lansing MI"},
{552, "Presque Isle ME"},
{553, "Marquette MI"},
{554, "Wheeling WV-Steubenville OH"},
{555, "Syracuse NY"},
{556, "Richmond-Petersburg VA"},
{557, "Knoxville TN"},
{558, "Lima OH"},
{559, "Bluefield-Beckley-Oak Hill WV"},
{560, "Raleigh-Durham (Fayetteville) NC"},
{561, "Jacksonville FL"},
{563, "Grand Rapids-Kalamazoo-Battle Creek MI"},
{564, "Charleston-Huntington WV"},
{565, "Elmira NY"},
{566, "Harrisburg-Lancaster-Lebanon-York PA"},
{567, "Greenville-Spartanburg SC-Asheville NC-Anderson SC"},
{569, "Harrisonburg VA"},
{570, "Florence-Myrtle Beach SC"},
{571, "Ft. Myers-Naples FL"},
{573, "Roanoke-Lynchburg VA"},
{574, "Johnstown-Altoona PA"},
{575, "Chattanooga TN"},
{576, "Salisbury MD"},
{577, "Wilkes Barre-Scranton PA"},
{581, "Terre Haute IN"},
{582, "Lafayette IN"},
{583, "Alpena MI"},
{584, "Charlottesville VA"},
{588, "South Bend-Elkhart IN"},
{592, "Gainesville FL"},
{596, "Zanesville OH"},
{597, "Parkersburg WV"},
{598, "Clarksburg-Weston WV"},
{600, "Corpus Christi TX"},
{602, "Chicago IL"},
{603, "Joplin MO-Pittsburg KS"},
{604, "Columbia-Jefferson City MO"},
{605, "Topeka KS"},
{606, "Dothan AL"},
{609, "St. Louis MO"},
{610, "Rockford IL"},
{611, "Rochester MN-Mason City IA-Austin MN"},
{612, "Shreveport LA"},
{613, "Minneapolis-St. Paul MN"},
{616, "Kansas City MO"},
{617, "Milwaukee WI"},
{618, "Houston TX"},
{619, "Springfield MO"},
{622, "New Orleans LA"},
{623, "Dallas-Ft. Worth TX"},
{624, "Sioux City IA"},
{625, "Waco-Temple-Bryan TX"},
{626, "Victoria TX"},
{627, "Wichita Falls TX & Lawton OK"},
{628, "Monroe LA-El Dorado AR"},
{630, "Birmingham AL"},
{631, "Ottumwa IA-Kirksville MO"},
{632, "Paducah KY-Cape Girardeau MO-Harrisburg-Mount Vernon IL"},
{633, "Odessa-Midland TX"},
{634, "Amarillo TX"},
{635, "Austin TX"},
{636, "Harlingen-Weslaco-Brownsville-McAllen TX"},
{637, "Cedar Rapids-Waterloo-Iowa City & Dubuque IA"},
{638, "St. Joseph MO"},
{639, "Jackson TN"},
{640, "Memphis TN"},
{641, "San Antonio TX"},
{642, "Lafayette LA"},
{643, "Lake Charles LA"},
{644, "Alexandria LA"},
{647, "Greenwood-Greenville MS"},
{648, "Champaign & Springfield-Decatur,IL"},
{649, "Evansville IN"},
{650, "Oklahoma City OK"},
{651, "Lubbock TX"},
{652, "Omaha NE"},
{656, "Panama City FL"},
{657, "Sherman TX-Ada OK"},
{658, "Green Bay-Appleton WI"},
{659, "Nashville TN"},
{661, "San Angelo TX"},
{662, "Abilene-Sweetwater TX"},
{669, "Madison WI"},
{670, "Ft. Smith-Fayetteville-Springdale-Rogers AR"},
{671, "Tulsa OK"},
{673, "Columbus-Tupelo-West Point MS"},
{675, "Peoria-Bloomington IL"},
{676, "Duluth MN-Superior WI"},
{678, "Wichita-Hutchinson KS"},
{679, "Des Moines-Ames IA"},
{682, "Davenport IA-Rock Island-Moline IL"},
{686, "Mobile AL-Pensacola (Ft. Walton Beach) FL"},
{687, "Minot-Bismarck-Dickinson(Williston) ND"},
{691, "Huntsville-Decatur (Florence) AL"},
{692, "Beaumont-Port Arthur TX"},
{693, "Little Rock-Pine Bluff AR"},
{698, "Montgomery (Selma) AL"},
{702, "La Crosse-Eau Claire WI"},
{705, "Wausau-Rhinelander WI"},
{709, "Tyler-Longview(Lufkin & Nacogdoches) TX"},
{710, "Hattiesburg-Laurel MS"},
{711, "Meridian MS"},
{716, "Baton Rouge LA"},
{717, "Quincy IL-Hannibal MO-Keokuk IA"},
{718, "Jackson MS"},
{722, "Lincoln & Hastings-Kearney NE"},
{724, "Fargo-Valley City ND"},
{725, "Sioux Falls(Mitchell) SD"},
{734, "Jonesboro AR"},
{736, "Bowling Green KY"},
{737, "Mankato MN"},
{740, "North Platte NE"},
{743, "Anchorage AK"},
{744, "Honolulu HI"},
{745, "Fairbanks AK"},
{746, "Biloxi-Gulfport MS"},
{747, "Juneau AK"},
{749, "Laredo TX"},
{751, "Denver CO"},
{752, "Colorado Springs-Pueblo CO"},
{753, "Phoenix AZ"},
{754, "Butte-Bozeman MT"},
{755, "Great Falls MT"},
{756, "Billings MT"},
{757, "Boise ID"},
{758, "Idaho Falls-Pocatello ID"},
{759, "Cheyenne WY-Scottsbluff NE"},
{760, "Twin Falls ID"},
{762, "Missoula MT"},
{764, "Rapid City SD"},
{765, "El Paso TX"},
{766, "Helena MT"},
{767, "Casper-Riverton WY"},
{770, "Salt Lake City UT"},
{771, "Yuma AZ-El Centro CA"},
{773, "Grand Junction-Montrose CO"},
{789, "Tucson (Sierra Vista) AZ"},
{790, "Albuquerque-Santa Fe NM"},
{798, "Glendive MT"},
{800, "Bakersfield CA"},
{801, "Eugene OR"},
{802, "Eureka CA"},
{803, "Los Angeles CA"},
{804, "Palm Springs CA"},
{807, "San Francisco-Oakland-San Jose CA"},
{810, "Yakima-Pasco-Richland-Kennewick WA"},
{811, "Reno NV"},
{813, "Medford-Klamath Falls OR"},
{819, "Seattle-Tacoma WA"},
{820, "Portland OR"},
{821, "Bend OR"},
{825, "San Diego CA"},
{828, "Monterey-Salinas CA"},
{839, "Las Vegas NV"},
{855, "Santa Barbara-Santa Maria-San Luis Obispo CA"},
{862, "Sacramento-Stockton-Modesto CA"},
{866, "Fresno-Visalia CA"},
{868, "Chico-Redding CA"},
{881, "Spokane WA"},
};
/**
* Returns U.S. Metropolitan Area name.
* @see Google Adwords c. 2010
*/
const char *GetMetroName(int code) {
int m, l, r;
l = 0;
r = ARRAYLEN(kMetroNames) - 1;
while (l <= r) {
m = (l + r) >> 1;
if (kMetroNames[m].code < code) {
l = m + 1;
} else if (kMetroNames[m].code > code) {
r = m - 1;
} else {
return kMetroNames[m].name;
}
}
return 0;
}

58
third_party/maxmind/maxmind.mk vendored Normal file
View file

@ -0,0 +1,58 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += THIRD_PARTY_MAXMIND
THIRD_PARTY_MAXMIND_ARTIFACTS += THIRD_PARTY_MAXMIND_A
THIRD_PARTY_MAXMIND = $(THIRD_PARTY_MAXMIND_A_DEPS) $(THIRD_PARTY_MAXMIND_A)
THIRD_PARTY_MAXMIND_A = o/$(MODE)/third_party/maxmind/maxmind.a
THIRD_PARTY_MAXMIND_A_FILES := $(wildcard third_party/maxmind/*)
THIRD_PARTY_MAXMIND_A_HDRS = $(filter %.h,$(THIRD_PARTY_MAXMIND_A_FILES))
THIRD_PARTY_MAXMIND_A_SRCS = $(filter %.c,$(THIRD_PARTY_MAXMIND_A_FILES))
THIRD_PARTY_MAXMIND_A_OBJS = \
$(THIRD_PARTY_MAXMIND_A_SRCS:%.c=o/$(MODE)/%.o)
THIRD_PARTY_MAXMIND_A_CHECKS = \
$(THIRD_PARTY_MAXMIND_A).pkg \
$(THIRD_PARTY_MAXMIND_A_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_MAXMIND_A_DIRECTDEPS = \
LIBC_CALLS \
LIBC_FMT \
LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_UNICODE
THIRD_PARTY_MAXMIND_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_MAXMIND_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_MAXMIND_A): \
third_party/maxmind/ \
$(THIRD_PARTY_MAXMIND_A).pkg \
$(THIRD_PARTY_MAXMIND_A_OBJS)
$(THIRD_PARTY_MAXMIND_A).pkg: \
$(THIRD_PARTY_MAXMIND_A_OBJS) \
$(foreach x,$(THIRD_PARTY_MAXMIND_A_DIRECTDEPS),$($(x)_A).pkg)
$(THIRD_PARTY_MAXMIND_A_OBJS): \
OVERRIDE_CFLAGS += \
-fdata-sections \
-ffunction-sections
THIRD_PARTY_MAXMIND_LIBS = $(foreach x,$(THIRD_PARTY_MAXMIND_ARTIFACTS),$($(x)))
THIRD_PARTY_MAXMIND_SRCS = $(foreach x,$(THIRD_PARTY_MAXMIND_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_MAXMIND_HDRS = $(foreach x,$(THIRD_PARTY_MAXMIND_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_MAXMIND_CHECKS = $(foreach x,$(THIRD_PARTY_MAXMIND_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_MAXMIND_OBJS = $(foreach x,$(THIRD_PARTY_MAXMIND_ARTIFACTS),$($(x)_OBJS))
.PHONY: o/$(MODE)/third_party/maxmind
o/$(MODE)/third_party/maxmind: \
$(THIRD_PARTY_MAXMIND_CHECKS)

1617
third_party/maxmind/maxminddb.c vendored Normal file

File diff suppressed because it is too large Load diff

182
third_party/maxmind/maxminddb.h vendored Normal file
View file

@ -0,0 +1,182 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_MAXMIND_MAXMINDDB_H_
#define COSMOPOLITAN_THIRD_PARTY_MAXMIND_MAXMINDDB_H_
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#define MMDB_MODE_MMAP 1
#define MMDB_MODE_MASK 7
#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
#define MMDB_RECORD_TYPE_SEARCH_NODE 0
#define MMDB_RECORD_TYPE_EMPTY 1
#define MMDB_RECORD_TYPE_DATA 2
#define MMDB_RECORD_TYPE_INVALID 3
#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 !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/* This is a pointer into the data section for a given IP address lookup */
typedef struct MMDB_entry_s {
const 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;
uint128_t uint128;
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;
void *pool;
} MMDB_entry_data_list_s;
typedef struct MMDB_description_s {
const char *language;
const char *description;
} MMDB_description_s;
/* WARNING: do not add new fields to this struct without bumping the SONAME.
* The struct is allocated by the users of this library and increasing the
* size will cause existing users to allocate too little space when the shared
* library is upgraded */
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;
/* See above warning before adding fields */
} MMDB_metadata_s;
/* WARNING: do not add new fields to this struct without bumping the SONAME.
* The struct is allocated by the users of this library and increasing the
* size will cause existing users to allocate too little space when the shared
* library is upgraded */
typedef struct MMDB_ipv4_start_node_s {
uint16_t netmask;
uint32_t node_value;
/* See above warning before adding fields */
} MMDB_ipv4_start_node_s;
/* WARNING: do not add new fields to this struct without bumping the SONAME.
* The struct is allocated by the users of this library and increasing the
* size will cause existing users to allocate too little space when the shared
* library is upgraded */
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;
/* See above warning before adding fields */
} MMDB_s;
typedef struct MMDB_search_node_s {
uint64_t left_record;
uint64_t right_record;
uint8_t left_record_type;
uint8_t right_record_type;
MMDB_entry_s left_record_entry;
MMDB_entry_s right_record_entry;
} MMDB_search_node_s;
void MMDB_close(MMDB_s *);
int MMDB_open(const char *, uint32_t, MMDB_s *);
MMDB_lookup_result_s MMDB_lookup(const MMDB_s *, uint32_t, int *);
int MMDB_read_node(const MMDB_s *, uint32_t, MMDB_search_node_s *);
int MMDB_get_value(MMDB_entry_s *, MMDB_entry_data_s *, ...);
int MMDB_vget_value(MMDB_entry_s *, MMDB_entry_data_s *, va_list);
int MMDB_aget_value(MMDB_entry_s *, MMDB_entry_data_s *, const char *const *);
int MMDB_get_metadata_as_entry_data_list(const MMDB_s *,
MMDB_entry_data_list_s **);
int MMDB_get_entry_data_list(MMDB_entry_s *, MMDB_entry_data_list_s **);
void MMDB_free_entry_data_list(MMDB_entry_data_list_s *);
int MMDB_dump_entry_data_list(FILE *, MMDB_entry_data_list_s *, int);
const char *MMDB_lib_version(void);
const char *MMDB_strerror(int);
const char *GetMetroName(int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_MAXMIND_MAXMINDDB_H_ */

View file

@ -14,8 +14,9 @@ o/$(MODE)/third_party: \
o/$(MODE)/third_party/linenoise \ o/$(MODE)/third_party/linenoise \
o/$(MODE)/third_party/lua \ o/$(MODE)/third_party/lua \
o/$(MODE)/third_party/lz4cli \ o/$(MODE)/third_party/lz4cli \
o/$(MODE)/third_party/mbedtls \
o/$(MODE)/third_party/make \ o/$(MODE)/third_party/make \
o/$(MODE)/third_party/maxmind \
o/$(MODE)/third_party/mbedtls \
o/$(MODE)/third_party/musl \ o/$(MODE)/third_party/musl \
o/$(MODE)/third_party/python \ o/$(MODE)/third_party/python \
o/$(MODE)/third_party/quickjs \ o/$(MODE)/third_party/quickjs \

View file

@ -1146,6 +1146,26 @@ RE MODULE
end of the line. This flag may only be used with re.search and end of the line. This flag may only be used with re.search and
regex_t*:search. regex_t*:search.
MAXMIND MODULE
This module may be used to get city/country/asn/etc from IPs, e.g.
-- .init.lua
maxmind = require "maxmind"
asndb = maxmind.open('/usr/local/share/maxmind/GeoLite2-ASN.mmdb')
-- request handler
as = asndb:lookup(GetRemoteAddr())
if as then
asnum = as:get("autonomous_system_number")
asorg = as:get("autonomous_system_organization")
Write(EscapeHtml(asnum))
Write(' ')
Write(EscapeHtml(asorg))
end
For further details, please see tool/net/lmaxmind.c
CONSTANTS CONSTANTS
kLogDebug kLogDebug

301
tool/net/lmaxmind.c Normal file
View file

@ -0,0 +1,301 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
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.
*/
#include "libc/x/x.h"
#include "third_party/lua/lauxlib.h"
#include "third_party/lua/lua.h"
#include "third_party/lua/luaconf.h"
#include "third_party/maxmind/maxminddb.h"
struct MaxmindDb {
int refs;
MMDB_s mmdb;
};
struct MaxmindResult {
uint32_t ip;
struct MaxmindDb *db;
MMDB_lookup_result_s mmlr;
};
static const char *GetMmdbError(int err) {
switch (err) {
case MMDB_FILE_OPEN_ERROR:
return "FILE_OPEN_ERROR";
case MMDB_CORRUPT_SEARCH_TREE_ERROR:
return "CORRUPT_SEARCH_TREE_ERROR";
case MMDB_INVALID_METADATA_ERROR:
return "INVALID_METADATA_ERROR";
case MMDB_IO_ERROR:
return "IO_ERROR";
case MMDB_OUT_OF_MEMORY_ERROR:
return "OUT_OF_MEMORY_ERROR";
case MMDB_UNKNOWN_DATABASE_FORMAT_ERROR:
return "UNKNOWN_DATABASE_FORMAT_ERROR";
case MMDB_INVALID_DATA_ERROR:
return "INVALID_DATA_ERROR";
case MMDB_INVALID_LOOKUP_PATH_ERROR:
return "INVALID_LOOKUP_PATH_ERROR";
case MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR:
return "LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR";
case MMDB_INVALID_NODE_NUMBER_ERROR:
return "INVALID_NODE_NUMBER_ERROR";
case MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR:
return "IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR";
default:
return "UNKNOWN";
}
};
static int LuaMaxmindOpen(lua_State *L) {
int err;
const char *p;
struct MaxmindDb **udb, *db;
p = luaL_checklstring(L, 1, 0);
db = xmalloc(sizeof(struct MaxmindDb));
if ((err = MMDB_open(p, 0, &db->mmdb)) != MMDB_SUCCESS) {
free(db);
luaL_error(L, "MMDB_open(%s) → MMDB_%s", p, GetMmdbError(err));
unreachable;
}
db->refs = 1;
udb = lua_newuserdatauv(L, sizeof(db), 1);
luaL_setmetatable(L, "MaxmindDb*");
*udb = db;
return 1;
}
static wontreturn void LuaThrowMaxmindIpError(lua_State *L,
const char *function_name,
uint32_t ip, int err) {
luaL_error(L, "%s(%d.%d.%d.%d) → MMDB_%s", function_name,
(ip & 0xff000000) >> 030, (ip & 0x00ff0000) >> 020,
(ip & 0x0000ff00) >> 010, (ip & 0x000000ff) >> 000,
GetMmdbError(err));
unreachable;
}
static int LuaMaxmindDbLookup(lua_State *L) {
int err;
lua_Integer ip;
struct MaxmindDb **udb, *db;
struct MaxmindResult **ur, *r;
udb = luaL_checkudata(L, 1, "MaxmindDb*");
ip = luaL_checkinteger(L, 2);
if (ip < 0 || ip > 0xffffffff) {
lua_pushnil(L);
return 1;
}
db = *udb;
r = xmalloc(sizeof(struct MaxmindResult));
r->mmlr = MMDB_lookup(&db->mmdb, ip, &err);
if (err) {
free(r);
LuaThrowMaxmindIpError(L, "MMDB_lookup", ip, err);
}
if (!r->mmlr.found_entry) {
free(r);
lua_pushnil(L);
return 1;
}
r->ip = ip;
r->db = db;
r->db->refs++;
ur = lua_newuserdatauv(L, sizeof(r), 1);
luaL_setmetatable(L, "MaxmindResult*");
*ur = r;
return 1;
}
static int LuaMaxmindResultNetmask(lua_State *L) {
struct MaxmindResult **ur;
ur = luaL_checkudata(L, 1, "MaxmindResult*");
lua_pushinteger(L, (*ur)->mmlr.netmask - (128 - 32));
return 1;
}
static MMDB_entry_data_list_s *LuaMaxmindDump(lua_State *L,
MMDB_entry_data_list_s *dl) {
size_t i, n;
char ibuf[64];
switch (dl->entry_data.type) {
case MMDB_DATA_TYPE_UTF8_STRING:
lua_pushlstring(L, dl->entry_data.utf8_string, dl->entry_data.data_size);
return dl->next;
case MMDB_DATA_TYPE_BYTES:
lua_pushlstring(L, (void *)dl->entry_data.bytes,
dl->entry_data.data_size);
return dl->next;
case MMDB_DATA_TYPE_INT32:
lua_pushinteger(L, dl->entry_data.int32);
return dl->next;
case MMDB_DATA_TYPE_UINT16:
lua_pushinteger(L, dl->entry_data.uint16);
return dl->next;
case MMDB_DATA_TYPE_UINT32:
lua_pushinteger(L, dl->entry_data.uint32);
return dl->next;
case MMDB_DATA_TYPE_BOOLEAN:
lua_pushboolean(L, dl->entry_data.boolean);
return dl->next;
case MMDB_DATA_TYPE_UINT64:
lua_pushinteger(L, dl->entry_data.uint64);
return dl->next;
case MMDB_DATA_TYPE_UINT128:
sprintf(ibuf, "%#jx", dl->entry_data.uint128);
lua_pushstring(L, ibuf);
return dl->next;
case MMDB_DATA_TYPE_DOUBLE:
lua_pushnumber(L, dl->entry_data.double_value);
return dl->next;
case MMDB_DATA_TYPE_FLOAT:
lua_pushnumber(L, dl->entry_data.float_value);
return dl->next;
case MMDB_DATA_TYPE_ARRAY:
lua_newtable(L);
n = dl->entry_data.data_size;
for (dl = dl->next, i = 0; dl && i < n; ++i) {
dl = LuaMaxmindDump(L, dl);
lua_seti(L, -2, i + 1);
}
return dl;
case MMDB_DATA_TYPE_MAP:
lua_newtable(L);
n = dl->entry_data.data_size;
for (dl = dl->next; dl && n; n--) {
dl = LuaMaxmindDump(L, dl);
dl = LuaMaxmindDump(L, dl);
lua_settable(L, -3);
}
return dl;
default:
lua_pushnil(L);
return dl->next;
}
}
static int LuaMaxmindResultGet(lua_State *L) {
int i, n, err;
const char **path;
MMDB_entry_s entry, *ep;
MMDB_entry_data_s edata;
struct MaxmindResult **ur;
MMDB_entry_data_list_s *dl;
n = lua_gettop(L) - 1;
ur = luaL_checkudata(L, 1, "MaxmindResult*");
if (n <= 0) {
ep = &(*ur)->mmlr.entry;
} else {
path = xcalloc(n + 1, sizeof(const char *));
for (i = 0; i < n; ++i) path[i] = lua_tostring(L, 2 + i);
err = MMDB_aget_value(&(*ur)->mmlr.entry, &edata, path);
free(path);
if (err) LuaThrowMaxmindIpError(L, "getpath", (*ur)->ip, err);
if (!edata.offset) {
lua_pushnil(L);
return 1;
}
entry.mmdb = (*ur)->mmlr.entry.mmdb;
entry.offset = edata.offset;
ep = &entry;
}
err = MMDB_get_entry_data_list(ep, &dl);
if (err) LuaThrowMaxmindIpError(L, "getlist", (*ur)->ip, err);
LuaMaxmindDump(L, dl);
MMDB_free_entry_data_list(dl);
return 1;
}
static void FreeMaxmindDb(struct MaxmindDb *db) {
if (!--db->refs) {
MMDB_close(&db->mmdb);
free(db);
}
}
static int LuaMaxmindDbGc(lua_State *L) {
struct MaxmindDb **udb;
udb = luaL_checkudata(L, 1, "MaxmindDb*");
if (*udb) {
FreeMaxmindDb(*udb);
*udb = 0;
}
return 0;
}
static int LuaMaxmindResultGc(lua_State *L) {
struct MaxmindResult **ur;
ur = luaL_checkudata(L, 1, "MaxmindResult*");
if (*ur) {
FreeMaxmindDb((*ur)->db);
free(*ur);
*ur = 0;
}
return 0;
}
static const luaL_Reg kLuaMaxmind[] = {
{"open", LuaMaxmindOpen}, //
{0}, //
};
static const luaL_Reg kLuaMaxmindDbMeth[] = {
{"lookup", LuaMaxmindDbLookup}, //
{0}, //
};
static const luaL_Reg kLuaMaxmindDbMeta[] = {
{"__gc", LuaMaxmindDbGc}, //
{0}, //
};
static const luaL_Reg kLuaMaxmindResultMeth[] = {
{"get", LuaMaxmindResultGet}, //
{"netmask", LuaMaxmindResultNetmask}, //
{0}, //
};
static const luaL_Reg kLuaMaxmindResultMeta[] = {
{"__gc", LuaMaxmindResultGc}, //
{0}, //
};
static void LuaMaxmindDb(lua_State *L) {
luaL_newmetatable(L, "MaxmindDb*");
luaL_setfuncs(L, kLuaMaxmindDbMeta, 0);
luaL_newlibtable(L, kLuaMaxmindDbMeth);
luaL_setfuncs(L, kLuaMaxmindDbMeth, 0);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
}
static void LuaMaxmindResult(lua_State *L) {
luaL_newmetatable(L, "MaxmindResult*");
luaL_setfuncs(L, kLuaMaxmindResultMeta, 0);
luaL_newlibtable(L, kLuaMaxmindResultMeth);
luaL_setfuncs(L, kLuaMaxmindResultMeth, 0);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
}
int LuaMaxmind(lua_State *L) {
luaL_newlib(L, kLuaMaxmind);
LuaMaxmindResult(L);
LuaMaxmindDb(L);
return 1;
}

View file

@ -58,6 +58,7 @@ TOOL_NET_DIRECTDEPS = \
THIRD_PARTY_LUA \ THIRD_PARTY_LUA \
THIRD_PARTY_MBEDTLS \ THIRD_PARTY_MBEDTLS \
THIRD_PARTY_REGEX \ THIRD_PARTY_REGEX \
THIRD_PARTY_MAXMIND \
THIRD_PARTY_SQLITE3 \ THIRD_PARTY_SQLITE3 \
THIRD_PARTY_ZLIB \ THIRD_PARTY_ZLIB \
THIRD_PARTY_ARGON2 \ THIRD_PARTY_ARGON2 \
@ -85,6 +86,7 @@ o/$(MODE)/tool/net/%.com.dbg: \
o/$(MODE)/tool/net/redbean.com.dbg: \ o/$(MODE)/tool/net/redbean.com.dbg: \
$(TOOL_NET_DEPS) \ $(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean.o \ o/$(MODE)/tool/net/redbean.o \
o/$(MODE)/tool/net/lmaxmind.o \
o/$(MODE)/tool/net/lsqlite3.o \ o/$(MODE)/tool/net/lsqlite3.o \
o/$(MODE)/tool/net/largon2.o \ o/$(MODE)/tool/net/largon2.o \
o/$(MODE)/tool/net/net.pkg \ o/$(MODE)/tool/net/net.pkg \
@ -144,6 +146,7 @@ o/$(MODE)/tool/net/demo/virtualbean.html.zip.o: \
o/$(MODE)/tool/net/redbean-demo.com.dbg: \ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
$(TOOL_NET_DEPS) \ $(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean.o \ o/$(MODE)/tool/net/redbean.o \
o/$(MODE)/tool/net/lmaxmind.o \
o/$(MODE)/tool/net/lsqlite3.o \ o/$(MODE)/tool/net/lsqlite3.o \
o/$(MODE)/tool/net/largon2.o \ o/$(MODE)/tool/net/largon2.o \
o/$(MODE)/tool/net/net.pkg \ o/$(MODE)/tool/net/net.pkg \
@ -225,6 +228,7 @@ o/$(MODE)/tool/net/redbean-unsecure.com: \
o/$(MODE)/tool/net/redbean-unsecure.com.dbg: \ o/$(MODE)/tool/net/redbean-unsecure.com.dbg: \
$(TOOL_NET_DEPS) \ $(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean-unsecure.o \ o/$(MODE)/tool/net/redbean-unsecure.o \
o/$(MODE)/tool/net/lmaxmind.o \
o/$(MODE)/tool/net/lsqlite3.o \ o/$(MODE)/tool/net/lsqlite3.o \
o/$(MODE)/tool/net/net.pkg \ o/$(MODE)/tool/net/net.pkg \
$(CRT) \ $(CRT) \
@ -254,7 +258,6 @@ o/$(MODE)/tool/net/redbean-original.com: \
o/$(MODE)/tool/net/redbean-original.com.dbg: \ o/$(MODE)/tool/net/redbean-original.com.dbg: \
$(TOOL_NET_DEPS) \ $(TOOL_NET_DEPS) \
o/$(MODE)/tool/net/redbean-original.o \ o/$(MODE)/tool/net/redbean-original.o \
o/$(MODE)/tool/net/lsqlite3.o \
o/$(MODE)/tool/net/net.pkg \ o/$(MODE)/tool/net/net.pkg \
$(CRT) \ $(CRT) \
$(APE) $(APE)

View file

@ -5811,6 +5811,7 @@ static const luaL_Reg kLuaFuncs[] = {
}; };
extern int luaopen_lsqlite3(lua_State *); extern int luaopen_lsqlite3(lua_State *);
extern int LuaMaxmind(lua_State *);
#ifndef UNSECURE #ifndef UNSECURE
extern int luaopen_argon2(lua_State *); extern int luaopen_argon2(lua_State *);
@ -5818,6 +5819,7 @@ extern int luaopen_argon2(lua_State *);
static const luaL_Reg kLuaLibs[] = { static const luaL_Reg kLuaLibs[] = {
{"re", LuaRe}, // {"re", LuaRe}, //
{"maxmind", LuaMaxmind}, //
{"lsqlite3", luaopen_lsqlite3}, // {"lsqlite3", luaopen_lsqlite3}, //
#ifndef UNSECURE #ifndef UNSECURE
{"argon2", luaopen_argon2}, // {"argon2", luaopen_argon2}, //