pax_global_header00006660000000000000000000000064131046351330014511gustar00rootroot0000000000000052 comment=06548fd6dac30d4ba0ea5489c3cffe8c20b526c0 lua-geoip-0.2/000077500000000000000000000000001310463513300132345ustar00rootroot00000000000000lua-geoip-0.2/.gitignore000066400000000000000000000001031310463513300152160ustar00rootroot00000000000000*~ .*~ \#*\# .\#*\# .DS_Store .project .settings *.o *.so *.dat lua-geoip-0.2/AUTHORS000066400000000000000000000005621310463513300143070ustar00rootroot00000000000000lua-geoip bindings authors: --------------------------- Alexander Gladysh Vladimir Dronnikov Contributors: ------------- Lorenzo Pistone Mike Trinkala Vadim A. Misbakh-Soloviov Marcin Deranek Frédéric VANNIÈRE lua-geoip-0.2/BSDmakefile000066400000000000000000000016621310463513300152720ustar00rootroot00000000000000LUA_IMPL ?= lua5.1 DESTDIR ?= / CFLAGS ?= -O2 -fPIC -DPIC PKG_CONFIG ?= pkg-config CC ?= gcc INSTALL ?= install LUA_CMOD_DIR ?= $(shell $(PKG_CONFIG) $(LUA_IMPL) --variable INSTALL_CMOD) CF += $(CFLAGS) -Werror -pedantic -std=c99 -Isrc LF += $(LDFLAGS) -shared -lGeoIP all: prepare geoip.so geoip/country.so geoip/city.so prepare: @mkdir -p geoip geoip.so: src/database.o src/lua-geoip.o $(CC) $(LF) $^ -o $@ geoip/country.so: src/database.o src/country.o $(CC) $(LF) $^ -o $@ geoip/city.so: src/database.o src/city.o $(CC) $(LF) $^ -o $@ .c.o: $(CC) $(CF) -c $^ -o $@ clean: @rm -f geoip.so geoip/country.so geoip/city.so @rm -f src/*.o @rm -rf geoip install: all $(INSTALL) -d $(DESTDIR/)$(LUA_CMOD_DIR)/geoip $(INSTALL) geoip/* $(DESTDIR)/$(LUA_CMOD_DIR)/geoip $(INSTALL) geoip.so $(DESTDIR)/$(LUA_CMOD_DIR) uninstall: @rm -f $(LUA_CMOD_DIR)/geoip.so @rm -rf $(LUA_CMOD_DIR)/geoip .SUFFIXES: .c .o .so lua-geoip-0.2/COPYRIGHT000066400000000000000000000032441310463513300145320ustar00rootroot00000000000000lua-geoip bindings license -------------------------- lua-geoip bindings module code is licensed under the terms of the MIT license reproduced below. This means that lua-geoip is free software and can be used for both academic and commercial purposes at absolutely no cost. Note that MaxMind GeoIP library (not included) is licensed under LGPL 2.1, and MaxMind GeoIP data (also not included) is licensed under a custom "database" license. =============================================================================== Copyright (C) 2011-2017 lua-geoip bindings authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =============================================================================== (end of COPYRIGHT) lua-geoip-0.2/GNUmakefile000066400000000000000000000016671310463513300153200ustar00rootroot00000000000000LUA_IMPL ?= lua5.1 DESTDIR ?= / PKG_CONFIG ?= pkg-config CC ?= gcc CFLAGS ?= -O2 -fPIC -DPIC $(shell $(PKG_CONFIG) $(LUA_IMPL) --cflags) INSTALL ?= install LUA_CMOD_DIR ?= $(shell $(PKG_CONFIG) $(LUA_IMPL) --variable INSTALL_CMOD) CF += $(CFLAGS) -Werror -pedantic -std=c99 -Isrc LF += $(LDFLAGS) -shared -lGeoIP all: prepare geoip.so geoip/country.so geoip/city.so prepare: @mkdir -p geoip geoip.so: src/database.o src/lua-geoip.o geoip/country.so: src/database.o src/country.o geoip/city.so: src/database.o src/city.o .c.o: $(CC) $(CF) -c $^ -o $@ %.so: $(CC) $(LF) $^ -o $@ clean: @rm -f geoip.so geoip/country.so geoip/city.so @rm -f src/*.o @rm -rf geoip install: all $(INSTALL) -d $(DESTDIR)/$(LUA_CMOD_DIR)/geoip $(INSTALL) geoip/* $(DESTDIR)/$(LUA_CMOD_DIR)/geoip $(INSTALL) geoip.so $(DESTDIR)/$(LUA_CMOD_DIR) uninstall: @rm -f $(LUA_CMOD_DIR)/geoip.so @rm -rf $(LUA_CMOD_DIR)/geoip .SUFFIXES: .c .o .so lua-geoip-0.2/HISTORY000066400000000000000000000011371310463513300143220ustar00rootroot00000000000000Version 0.2 (2017-05-10) ======================== * IPv6 Lookup support for country * Lua5.2/5.3 compatibility * Remove the stderr capture and use the GEOIP_SILENCE flag instead * added makefiles Version 0.1.2 (2012-03-10) ========================== * GEOIP_MEMORY_CACHE is now a default option when opening a DB. * Fixed some compiler warnings. * Improved tests. Version 0.1.1 (2011-03-09) ========================== * Made code more compatible with C89. * Charset parameter no longer ignored in `city.open()` and `country.open()`. Version 0.1 (2011-03-07) ======================== Initial release. lua-geoip-0.2/README.md000066400000000000000000000024651310463513300145220ustar00rootroot00000000000000lua-geoip — bindings for MaxMind GeoIP library ============================================== See the copyright information in the file named `COPYRIGHT`. ## API * `require 'geoip'` ### Enums #### DB types * `geoip.COUNTRY` * `geoip.COUNTRY_V6` * `geoip.REGION_REV0` * `geoip.REGION_REV1` * `geoip.REGION` = `geoip.REGION_REV1` * `geoip.CITY_REV0` * `geoip.CITY_REV1` * `geoip.CITY` = `geoip.CITY_REV1` * `geoip.ORG` * `geoip.ISP` * `geoip.PROXY` * `geoip.ASNUM` * `geoip.NETSPEED` * `geoip.DOMAIN` #### Open flags * `geoip.STANDARD` * `geoip.MEMORY_CACHE` * `geoip.CHECK_CACHE` * `geoip.INDEX_CACHE` * `geoip.MMAP_CACHE` #### Charsets * `geoip.ISO_8859_1` * `geoip.UTF8` TODO: Document further. Meanwhile, see tests. ## Where to get stuff? ### On Debian / Ubuntu Using PPA: MaxMind provides a PPA for recent version of Ubuntu. To add the PPA to your APT sources, run: $ sudo add-apt-repository ppa:maxmind/ppa $ sudo apt-get update Then install the packages by running: $ sudo apt-get install geoip-database # GeoLite Country only $ sudo apt-get install libgeoip-dev ### Raw $ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz $ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz ### C library http://www.maxmind.com/app/c lua-geoip-0.2/TODO000066400000000000000000000007721310463513300137320ustar00rootroot00000000000000TODO: ----- -- Document current API. -- Fix file headers. -- Run splint all over it, and fix errors. -- Generalize copy-pasted DB handling code -- Support GEOIP_COUNTRY_EDITION_V6 somehow (separate db type?) -- consider removing db type constants from binding -- Support regions. -- Bind whole API. -- Capture not only stderr, but stdin as well, libgeoip spams there as well. -- Write better tests. -- Open by DB type leaks 18KB+ (that's how libgeoip written). -- Add a luajit.ffi binding lua-geoip-0.2/make.sh000077500000000000000000000010031310463513300145020ustar00rootroot00000000000000#! /bin/bash set -e echo "----> Going pedantic all over the source" echo "--> c89..." gcc -O2 -fPIC -I/usr/include/lua5.1 -c src/*.c -Isrc/ -Wall --pedantic -Werror --std=c89 -fms-extensions echo "--> c99..." gcc -O2 -fPIC -I/usr/include/lua5.1 -c src/*.c -Isrc/ -Wall --pedantic -Werror --std=c99 -fms-extensions echo "--> c++98..." gcc -xc++ -O2 -fPIC -I/usr/include/lua5.1 -c src/*.c -Isrc/ -Wall --pedantic -Werror --std=c++98 echo "----> Making rock" sudo luarocks make rockspec/lua-geoip-scm-1.rockspec lua-geoip-0.2/rockspec/000077500000000000000000000000001310463513300150455ustar00rootroot00000000000000lua-geoip-0.2/rockspec/lua-geoip-0.1-1.rockspec000066400000000000000000000021271310463513300211160ustar00rootroot00000000000000package = "lua-geoip" version = "0.1-1" source = { url = "git://github.com/agladysh/lua-geoip.git", branch = "v0.1" } external_dependencies = { GEOIP = { header = "GeoIP.h", } } description = { summary = "Bindings for MaxMind's GeoIP library", homepage = "http://github.com/agladysh/lua-geoip", license = "MIT/X11", maintainer = "Alexander Gladysh " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { geoip = { sources = { "src/lua-geoip.c", "src/database.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.country"] = { sources = { "src/database.c", "src/country.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.city"] = { sources = { "src/database.c", "src/city.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } } } } lua-geoip-0.2/rockspec/lua-geoip-0.1.1-1.rockspec000066400000000000000000000021331310463513300212520ustar00rootroot00000000000000package = "lua-geoip" version = "0.1.1-1" source = { url = "git://github.com/agladysh/lua-geoip.git", branch = "v0.1.1" } external_dependencies = { GEOIP = { header = "GeoIP.h", } } description = { summary = "Bindings for MaxMind's GeoIP library", homepage = "http://github.com/agladysh/lua-geoip", license = "MIT/X11", maintainer = "Alexander Gladysh " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { geoip = { sources = { "src/lua-geoip.c", "src/database.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.country"] = { sources = { "src/database.c", "src/country.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.city"] = { sources = { "src/database.c", "src/city.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } } } } lua-geoip-0.2/rockspec/lua-geoip-0.1.2-1.rockspec000066400000000000000000000021331310463513300212530ustar00rootroot00000000000000package = "lua-geoip" version = "0.1.2-1" source = { url = "git://github.com/agladysh/lua-geoip.git", branch = "v0.1.2" } external_dependencies = { GEOIP = { header = "GeoIP.h", } } description = { summary = "Bindings for MaxMind's GeoIP library", homepage = "http://github.com/agladysh/lua-geoip", license = "MIT/X11", maintainer = "Alexander Gladysh " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { geoip = { sources = { "src/lua-geoip.c", "src/database.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.country"] = { sources = { "src/database.c", "src/country.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.city"] = { sources = { "src/database.c", "src/city.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } } } } lua-geoip-0.2/rockspec/lua-geoip-0.2-1.rockspec000066400000000000000000000021271310463513300211170ustar00rootroot00000000000000package = "lua-geoip" version = "0.2-1" source = { url = "git://github.com/agladysh/lua-geoip.git", branch = "v0.2" } external_dependencies = { GEOIP = { header = "GeoIP.h", } } description = { summary = "Bindings for MaxMind's GeoIP library", homepage = "http://github.com/agladysh/lua-geoip", license = "MIT/X11", maintainer = "Alexander Gladysh " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { geoip = { sources = { "src/lua-geoip.c", "src/database.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.country"] = { sources = { "src/database.c", "src/country.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.city"] = { sources = { "src/database.c", "src/city.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } } } } lua-geoip-0.2/rockspec/lua-geoip-scm-1.rockspec000066400000000000000000000021311310463513300213750ustar00rootroot00000000000000package = "lua-geoip" version = "scm-1" source = { url = "git://github.com/agladysh/lua-geoip.git", branch = "master" } external_dependencies = { GEOIP = { header = "GeoIP.h", } } description = { summary = "Bindings for MaxMind's GeoIP library", homepage = "http://github.com/agladysh/lua-geoip", license = "MIT/X11", maintainer = "Alexander Gladysh " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { geoip = { sources = { "src/lua-geoip.c", "src/database.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.country"] = { sources = { "src/database.c", "src/country.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } }, ["geoip.city"] = { sources = { "src/database.c", "src/city.c" }, incdirs = { "src/" }, libraries = { "GeoIP" } } } } lua-geoip-0.2/src/000077500000000000000000000000001310463513300140235ustar00rootroot00000000000000lua-geoip-0.2/src/city.c000066400000000000000000000157271310463513300151530ustar00rootroot00000000000000/* * city.c: Bindings for MaxMind's GeoIP library * See copyright information in file COPYRIGHT. */ #include #include "lua-geoip.h" #include "database.h" #define LUAGEOIP_CITY_VERSION "lua-geoip.city 0.2" #define LUAGEOIP_CITY_COPYRIGHT "Copyright (C) 2011-2017, lua-geoip authors" #define LUAGEOIP_CITY_DESCRIPTION \ "Bindings for MaxMind's GeoIP library (city database)" static GeoIP * check_city_db(lua_State * L, int idx) { int type = 0; luageoip_DB * pDB = (luageoip_DB *)luaL_checkudata(L, idx, LUAGEOIP_CITY_MT); if (pDB == NULL) { lua_pushstring(L, "lua-geoip error: city db is null"); return NULL; } if (pDB->pGeoIP == NULL) { lua_pushstring(L, "lua-geoip error: attempted to use closed city db"); return NULL; } type = GeoIP_database_edition(pDB->pGeoIP); if ( type != GEOIP_CITY_EDITION_REV0 && type != GEOIP_CITY_EDITION_REV1 ) { lua_pushstring(L, "lua-geoip error: object is not a city db"); return NULL; } return pDB->pGeoIP; } /* TODO: Generalize copy-paste with country code */ static int push_city_info( lua_State * L, int first_arg_idx, GeoIPRecord * pRecord ) { static const int NUM_OPTS = 13; static const char * const opts[] = { /* order is important! */ /* 0 */ "country_code", /* 1 */ "country_code3", /* 2 */ "country_name", /* 3 */ "region", /* 4 */ "city", /* 5 */ "postal_code", /* 6 */ "latitude", /* 7 */ "longitude", /* 8 */ "metro_code", /* 9 */ "dma_code", /* 10 */ "area_code", /* 11 */ "charset", /* 12 */ "continent_code", NULL }; int nargs = lua_gettop(L) - first_arg_idx + 1; int need_all = (nargs == 0); int i = 0; if (pRecord == NULL) { lua_pushnil(L); lua_pushliteral(L, "not found"); return 2; } if (need_all) { nargs = NUM_OPTS; lua_newtable(L); } for (i = 0; i < nargs; ++i) { int idx = (need_all) ? i : luaL_checkoption(L, first_arg_idx + i, NULL, opts) ; /* TODO: Ugly */ switch (idx) { case 0: /* "country_code" */ lua_pushstring(L, pRecord->country_code); break; case 1: /* "country_code3" */ lua_pushstring(L, pRecord->country_code3); break; case 2: /* "country_name" */ lua_pushstring(L, pRecord->country_name); break; case 3: /* "region" */ lua_pushstring(L, pRecord->region); break; case 4: /* "city" */ lua_pushstring(L, pRecord->city); break; case 5: /* "postal_code" */ lua_pushstring(L, pRecord->postal_code); break; case 6: /* "latitude" */ lua_pushnumber(L, pRecord->latitude); break; case 7: /* "longitude" */ lua_pushnumber(L, pRecord->longitude); break; case 8: /* "metro_code" */ lua_pushinteger(L, pRecord->metro_code); break; case 9: /* "dma_code" */ lua_pushinteger(L, pRecord->dma_code); break; case 10: /* "area_code" */ lua_pushinteger(L, pRecord->area_code); break; case 11: /* "charset" */ lua_pushinteger(L, pRecord->charset); break; case 12: /* "continent_code" */ lua_pushstring(L, pRecord->continent_code); break; default: /* Hint: Did you synchronize switch cases with opts array? */ return luaL_error(L, "lua-geoip error: bad implementation"); } if (need_all) { lua_setfield(L, -2, opts[i]); } } GeoIPRecord_delete(pRecord); return (need_all) ? 1 : nargs; } /* TODO: Remove copy-paste below! */ static int lcity_query_by_name(lua_State * L) { GeoIP * pGeoIP = check_city_db(L, 1); const char * name = luaL_checkstring(L, 2); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } return push_city_info( L, 3, GeoIP_record_by_name(pGeoIP, name) ); } static int lcity_query_by_addr(lua_State * L) { GeoIP * pGeoIP = check_city_db(L, 1); const char * addr = luaL_checkstring(L, 2); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } return push_city_info( L, 3, GeoIP_record_by_addr(pGeoIP, addr) ); } static int lcity_query_by_ipnum(lua_State * L) { GeoIP * pGeoIP = check_city_db(L, 1); lua_Integer ipnum = luaL_checkinteger(L, 2); /* Hoping that value would fit */ if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } return push_city_info( L, 3, GeoIP_record_by_ipnum(pGeoIP, ipnum) ); } static int lcity_charset(lua_State * L) { GeoIP * pGeoIP = check_city_db(L, 1); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } lua_pushinteger(L, GeoIP_charset(pGeoIP)); return 1; } static int lcity_set_charset(lua_State * L) { GeoIP * pGeoIP = check_city_db(L, 1); int charset = luaL_checkint(L, 2); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } GeoIP_set_charset(pGeoIP, charset); return 0; } static int lcity_close(lua_State * L) { luageoip_DB * pDB = (luageoip_DB *)luaL_checkudata(L, 1, LUAGEOIP_CITY_MT); if (pDB && pDB->pGeoIP != NULL) { GeoIP_delete(pDB->pGeoIP); pDB->pGeoIP = NULL; } return 0; } #define lcity_gc lcity_close static int lcity_tostring(lua_State * L) { GeoIP * pGeoIP = check_city_db(L, 1); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } lua_pushstring(L, GeoIP_database_info(pGeoIP)); return 1; } static const luaL_Reg M[] = { { "query_by_name", lcity_query_by_name }, { "query_by_addr", lcity_query_by_addr }, { "query_by_ipnum", lcity_query_by_ipnum }, { "charset", lcity_charset }, { "set_charset", lcity_set_charset }, { "close", lcity_close }, { "__gc", lcity_gc }, { "__tostring", lcity_tostring }, { NULL, NULL } }; static int lcity_open(lua_State * L) { static const int allowed_types[] = { GEOIP_CITY_EDITION_REV0, GEOIP_CITY_EDITION_REV1 }; return luageoip_common_open_db( L, M, GEOIP_CITY_EDITION_REV1, GEOIP_MEMORY_CACHE | GEOIP_SILENCE, LUAGEOIP_CITY_MT, 0, /* all flags allowed */ 2, allowed_types ); } /* Lua module API */ static const struct luaL_Reg R[] = { { "open", lcity_open }, { NULL, NULL } }; #ifdef __cplusplus extern "C" { #endif LUALIB_API int luaopen_geoip_city(lua_State * L) { /* * Register module */ #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 luaL_register(L, "geoip.city", R); #else lua_newtable(L); luaL_setfuncs(L, R, 0); #endif /* * Register module information */ lua_pushliteral(L, LUAGEOIP_CITY_VERSION); lua_setfield(L, -2, "_VERSION"); lua_pushliteral(L, LUAGEOIP_CITY_COPYRIGHT); lua_setfield(L, -2, "_COPYRIGHT"); lua_pushliteral(L, LUAGEOIP_CITY_DESCRIPTION); lua_setfield(L, -2, "_DESCRIPTION"); return 1; } #ifdef __cplusplus } #endif lua-geoip-0.2/src/country.c000066400000000000000000000143721310463513300157010ustar00rootroot00000000000000/* * country.c: Bindings for MaxMind's GeoIP library * See copyright information in file COPYRIGHT. */ #include "lua-geoip.h" #include "database.h" #define LUAGEOIP_COUNTRY_VERSION "lua-geoip.country 0.2" #define LUAGEOIP_COUNTRY_COPYRIGHT \ "Copyright (C) 2011-2017, lua-geoip authors" #define LUAGEOIP_COUNTRY_DESCRIPTION \ "Bindings for MaxMind's GeoIP library (country database)" static GeoIP * check_country_db(lua_State * L, int idx) { int type = 0; luageoip_DB * pDB = (luageoip_DB *)luaL_checkudata( L, idx, LUAGEOIP_COUNTRY_MT ); if (pDB == NULL) { lua_pushstring(L, "lua-geoip error: country db is null"); return NULL; } if (pDB->pGeoIP == NULL) { lua_pushstring(L, "lua-geoip error: attempted to use closed country db"); return NULL; } type = GeoIP_database_edition(pDB->pGeoIP); if ( type != GEOIP_COUNTRY_EDITION && type != GEOIP_COUNTRY_EDITION_V6 ) { lua_pushstring(L, "lua-geoip error: object is not a country db"); return NULL; } return pDB->pGeoIP; } /* TODO: Handle when id 0? */ static int push_country_info(lua_State * L, int first_arg_idx, int id) { static const int NUM_OPTS = 5; static const char * const opts[] = { /* order is important! */ /* 0 */ "id", /* 1 */ "code", /* 2 */ "code3", /* 3 */ "continent", /* 4 */ "name", NULL }; int nargs = lua_gettop(L) - first_arg_idx + 1; int need_all = (nargs == 0); int i = 0; if (need_all) { nargs = NUM_OPTS; lua_newtable(L); } for (i = 0; i < nargs; ++i) { int idx = (need_all) ? i : luaL_checkoption(L, first_arg_idx + i, NULL, opts) ; /* TODO: Ugly */ switch (idx) { case 0: /* id */ lua_pushinteger(L, id); break; case 1: /* code */ lua_pushstring(L, GeoIP_code_by_id(id)); break; case 2: /* code3 */ lua_pushstring(L, GeoIP_code3_by_id(id)); break; case 3: /* continent */ lua_pushstring(L, GeoIP_continent_by_id(id)); break; case 4: /* name */ lua_pushstring(L, GeoIP_name_by_id(id)); break; default: /* Hint: Did you synchronize switch cases with opts array? */ return luaL_error(L, "lua-geoip error: bad implementation"); } if (need_all) { lua_setfield(L, -2, opts[i]); } } return (need_all) ? 1 : nargs; } /* TODO: Remove copy-paste below! */ static int lcountry_query_by_name(lua_State * L) { GeoIP * pGeoIP = check_country_db(L, 1); const char * name = luaL_checkstring(L, 2); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } return push_country_info( L, 3, GeoIP_id_by_name(pGeoIP, name) ); } static int lcountry_query_by_addr(lua_State * L) { GeoIP * pGeoIP = check_country_db(L, 1); const char * addr = luaL_checkstring(L, 2); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } return push_country_info( L, 3, GeoIP_id_by_addr(pGeoIP, addr) ); } static int lcountry_query_by_addr6(lua_State * L) { GeoIP * pGeoIP = check_country_db(L, 1); const char * addr = luaL_checkstring(L, 2); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } return push_country_info( L, 3, GeoIP_id_by_addr_v6(pGeoIP, addr) ); } static int lcountry_query_by_ipnum(lua_State * L) { GeoIP * pGeoIP = check_country_db(L, 1); lua_Integer ipnum = luaL_checkinteger(L, 2); /* Hoping that value would fit */ if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } return push_country_info( L, 3, GeoIP_id_by_ipnum(pGeoIP, ipnum) ); } static int lcountry_charset(lua_State * L) { GeoIP * pGeoIP = check_country_db(L, 1); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } lua_pushinteger(L, GeoIP_charset(pGeoIP)); return 1; } static int lcountry_set_charset(lua_State * L) { GeoIP * pGeoIP = check_country_db(L, 1); int charset = luaL_checkint(L, 2); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } GeoIP_set_charset(pGeoIP, charset); return 0; } static int lcountry_close(lua_State * L) { luageoip_DB * pDB = (luageoip_DB *)luaL_checkudata(L, 1, LUAGEOIP_COUNTRY_MT); if (pDB && pDB->pGeoIP != NULL) { GeoIP_delete(pDB->pGeoIP); pDB->pGeoIP = NULL; } return 0; } #define lcountry_gc lcountry_close static int lcountry_tostring(lua_State * L) { GeoIP * pGeoIP = check_country_db(L, 1); if (pGeoIP == NULL) { return lua_error(L); /* Error message already on stack */ } lua_pushstring(L, GeoIP_database_info(pGeoIP)); return 1; } static const luaL_Reg M[] = { { "query_by_name", lcountry_query_by_name }, { "query_by_addr", lcountry_query_by_addr }, { "query_by_ipnum", lcountry_query_by_ipnum }, { "query_by_addr6", lcountry_query_by_addr6 }, { "charset", lcountry_charset }, { "set_charset", lcountry_set_charset }, { "close", lcountry_close }, { "__gc", lcountry_gc }, { "__tostring", lcountry_tostring }, { NULL, NULL } }; static int lcountry_open(lua_State * L) { static const int allowed_types[] = { GEOIP_COUNTRY_EDITION, GEOIP_COUNTRY_EDITION_V6 }; return luageoip_common_open_db( L, M, GEOIP_COUNTRY_EDITION, GEOIP_MEMORY_CACHE | GEOIP_SILENCE, LUAGEOIP_COUNTRY_MT, GEOIP_INDEX_CACHE, /* not allowed */ 2, allowed_types ); } /* Lua module API */ static const struct luaL_Reg R[] = { { "open", lcountry_open }, { NULL, NULL } }; #ifdef __cplusplus extern "C" { #endif LUALIB_API int luaopen_geoip_country(lua_State * L) { /* * Register module */ #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 luaL_register(L, "geoip.country", R); #else lua_newtable(L); luaL_setfuncs(L, R, 0); #endif /* * Register module information */ lua_pushliteral(L, LUAGEOIP_COUNTRY_VERSION); lua_setfield(L, -2, "_VERSION"); lua_pushliteral(L, LUAGEOIP_COUNTRY_COPYRIGHT); lua_setfield(L, -2, "_COPYRIGHT"); lua_pushliteral(L, LUAGEOIP_COUNTRY_DESCRIPTION); lua_setfield(L, -2, "_DESCRIPTION"); return 1; } #ifdef __cplusplus } #endif lua-geoip-0.2/src/database.c000066400000000000000000000042551310463513300157410ustar00rootroot00000000000000#include #include #include "lua-geoip.h" #include "database.h" int luageoip_common_open_db( lua_State * L, const luaL_Reg * M, int default_type, int default_flags, const char * mt_name, unsigned int bad_flags, size_t num_allowed_types, const int * allowed_types ) { /* First argument is checked later */ int flags = luaL_optint(L, 2, default_flags); int charset = luaL_optint(L, 3, GEOIP_CHARSET_UTF8); GeoIP * pGeoIP = NULL; luageoip_DB * pResult = NULL; int error_reported = 0; if (bad_flags && (flags & bad_flags) == bad_flags) { /* TODO: Or is it concrete DB file problem? */ return luaL_error( L, "%s error: can't open db with these flags", mt_name ); } if (lua_isnoneornil(L, 1)) { pGeoIP = GeoIP_open_type(default_type, flags); } else { const char * filename = luaL_checkstring(L, 1); pGeoIP = GeoIP_open(filename, flags); } if (pGeoIP) { int type = GeoIP_database_edition(pGeoIP); int found = 0; size_t i = 0; for (i = 0; i < num_allowed_types; ++i) { if (type == allowed_types[i]) { found = 1; break; } } if (!found) { lua_pushnil(L); lua_pushfstring( L, "%s error: unexpected db type in that file (%s)", mt_name, GeoIP_database_info(pGeoIP) ); error_reported = 1; GeoIP_delete(pGeoIP); pGeoIP = NULL; } } if (pGeoIP == NULL) { if (!error_reported) { lua_pushnil(L); lua_pushfstring( L, "%s error: failed to open database file", mt_name ); error_reported = 1; } return 2; /* nil and error message already on stack */ } GeoIP_set_charset(pGeoIP, charset); pResult = (luageoip_DB *)lua_newuserdata(L, sizeof(luageoip_DB)); pResult->pGeoIP = pGeoIP; if (luaL_newmetatable(L, mt_name)) { #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 luaL_register(L, NULL, M); #else luaL_setfuncs(L, M, 0); #endif lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); } lua_setmetatable(L, -2); return 1; } lua-geoip-0.2/src/database.h000066400000000000000000000010411310463513300157340ustar00rootroot00000000000000/* * database.h: Bindings for MaxMind's GeoIP library * See copyright information in file COPYRIGHT. */ #ifndef LUAGEOIP_DATABASE_H_ #define LUAGEOIP_DATABASE_H_ #define LUAGEOIP_COUNTRY_MT "lua-geoip.db.country" #define LUAGEOIP_CITY_MT "lua-geoip.db.city" int luageoip_common_open_db( lua_State * L, const luaL_Reg * M, int default_type, int default_flags, const char * mt_name, unsigned int bad_flags, size_t num_allowed_types, const int * allowed_types ); #endif /* LUAGEOIP_DATABASE_H_ */ lua-geoip-0.2/src/lua-geoip.c000066400000000000000000000076201310463513300160560ustar00rootroot00000000000000/* * lua-geoip.c: Bindings for MaxMind's GeoIP library * See copyright information in file COPYRIGHT. */ #define LUAGEOIP_VERSION "lua-geoip 0.2" #define LUAGEOIP_COPYRIGHT "Copyright (C) 2011-2017, lua-geoip authors" #define LUAGEOIP_DESCRIPTION "Bindings for MaxMind's GeoIP library" #include "lua-geoip.h" typedef struct luageoip_Enum { const char * name; const int value; } luageoip_Enum; static const struct luageoip_Enum Options[] = { { "STANDARD", GEOIP_STANDARD }, { "MEMORY_CACHE", GEOIP_MEMORY_CACHE }, { "CHECK_CACHE", GEOIP_CHECK_CACHE }, { "INDEX_CACHE", GEOIP_INDEX_CACHE }, { "MMAP_CACHE", GEOIP_MMAP_CACHE }, { NULL, 0 } }; static const struct luageoip_Enum DBTypes[] = { { "COUNTRY", GEOIP_COUNTRY_EDITION }, /* Note that this is not an alias */ { "COUNTRY_V6",GEOIP_COUNTRY_EDITION_V6 }, { "REGION_REV0", GEOIP_REGION_EDITION_REV0 }, { "REGION_REV1", GEOIP_REGION_EDITION_REV1 }, { "REGION", GEOIP_REGION_EDITION_REV1 }, /* Alias */ { "CITY_REV0", GEOIP_CITY_EDITION_REV0 }, { "CITY_REV1", GEOIP_CITY_EDITION_REV1 }, { "CITY", GEOIP_CITY_EDITION_REV1 }, /* Alias */ { "ORG", GEOIP_ORG_EDITION }, { "ISP", GEOIP_ISP_EDITION }, { "PROXY", GEOIP_PROXY_EDITION }, { "ASNUM", GEOIP_ASNUM_EDITION }, { "NETSPEED", GEOIP_NETSPEED_EDITION }, { "DOMAIN", GEOIP_DOMAIN_EDITION }, { NULL, 0 } }; static const struct luageoip_Enum Charsets[] = { { "ISO_8859_1", GEOIP_CHARSET_ISO_8859_1 }, { "UTF8", GEOIP_CHARSET_UTF8 }, { NULL, 0 } }; static void reg_enum(lua_State * L, const luageoip_Enum * e) { for ( ; e->name; ++e) { lua_pushinteger(L, e->value); lua_setfield(L, -2, e->name); } } static int lcode_by_id(lua_State * L) { int id = luaL_checkint(L, 1); lua_pushstring(L, GeoIP_code_by_id(id)); return 1; } static int lcode3_by_id(lua_State * L) { int id = luaL_checkint(L, 1); lua_pushstring(L, GeoIP_code3_by_id(id)); return 1; } static int lname_by_id(lua_State * L) { int id = luaL_checkint(L, 1); lua_pushstring(L, GeoIP_name_by_id(id)); return 1; } static int lcontinent_by_id(lua_State * L) { int id = luaL_checkint(L, 1); lua_pushstring(L, GeoIP_continent_by_id(id)); return 1; } static int lid_by_code(lua_State * L) { const char * country = luaL_checkstring(L, 1); lua_pushinteger(L, GeoIP_id_by_code(country)); return 1; } static int lregion_name_by_code(lua_State * L) { const char * country_code = luaL_checkstring(L, 1); const char * region_code = luaL_checkstring(L, 2); lua_pushstring(L, GeoIP_region_name_by_code(country_code, region_code)); return 1; } static int ltime_zone_by_country_and_region(lua_State * L) { const char * country_code = luaL_checkstring(L, 1); const char * region_code = luaL_checkstring(L, 2); lua_pushstring( L, GeoIP_time_zone_by_country_and_region(country_code, region_code) ); return 1; } /* Lua module API */ static const struct luaL_Reg R[] = { { "code_by_id", lcode_by_id }, { "code3_by_id", lcode3_by_id }, { "name_by_id", lname_by_id }, { "continent_by_id", lcontinent_by_id }, { "id_by_code", lid_by_code }, { "region_name_by_code", lregion_name_by_code }, { "time_zone_by_country_and_region", ltime_zone_by_country_and_region }, { NULL, NULL } }; #ifdef __cplusplus extern "C" { #endif LUALIB_API int luaopen_geoip(lua_State * L) { /* * Register module */ #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 luaL_register(L, "geoip", R); #else lua_newtable(L); luaL_setfuncs(L, R, 0); #endif /* * Register module information */ lua_pushliteral(L, LUAGEOIP_VERSION); lua_setfield(L, -2, "_VERSION"); lua_pushliteral(L, LUAGEOIP_COPYRIGHT); lua_setfield(L, -2, "_COPYRIGHT"); lua_pushliteral(L, LUAGEOIP_DESCRIPTION); lua_setfield(L, -2, "_DESCRIPTION"); /* * Register enums */ reg_enum(L, Options); reg_enum(L, DBTypes); reg_enum(L, Charsets); return 1; } #ifdef __cplusplus } #endif lua-geoip-0.2/src/lua-geoip.h000066400000000000000000000011301310463513300160510ustar00rootroot00000000000000/* * lua-geoip.h: Bindings for MaxMind's GeoIP library * See copyright information in file COPYRIGHT. */ #ifndef LUAGEOIP_LUA_GEOIP_H_ #define LUAGEOIP_LUA_GEOIP_H_ #if defined (__cplusplus) extern "C" { #endif #include #include #ifndef luaL_checkint #define luaL_checkint(L,n) luaL_checkinteger(L,n) #endif #ifndef luaL_optint #define luaL_optint(L,n,s) luaL_optinteger(L,n,s) #endif #if defined (__cplusplus) } #endif #include #include typedef struct luageoip_DB { GeoIP * pGeoIP; } luageoip_DB; #endif /* LUAGEOIP_LUA_GEOIP_H */ lua-geoip-0.2/test/000077500000000000000000000000001310463513300142135ustar00rootroot00000000000000lua-geoip-0.2/test/test.lua000066400000000000000000000166211310463513300157030ustar00rootroot00000000000000-- TODO: Scrap these hacks and write a proper test suite. pcall(require, 'luarocks.require') local socket = require 'socket' local geoip = require 'geoip' local geoip_country = require 'geoip.country' local geoip_city = require 'geoip.city' local geoip_country_filename = select(1, ...) or "./GeoIP.dat" local geoip_city_filename = select(2, ...) or "./GeoLiteCity.dat" local geoip_country6_filename = select(3, ...) or "./GeoIPv6.dat" print("TESTING lua-geoip") print("") print("VERSION: ", assert(geoip._VERSION)) print("DESCRIPTION: ", assert(geoip._DESCRIPTION)) print("COPYRIGHT: ", assert(geoip._COPYRIGHT)) print("") print("VERSION: ", assert(geoip_country._VERSION)) print("DESCRIPTION: ", assert(geoip_country._DESCRIPTION)) print("COPYRIGHT: ", assert(geoip_country._COPYRIGHT)) print("") print("VERSION: ", assert(geoip_city._VERSION)) print("DESCRIPTION: ", assert(geoip_city._DESCRIPTION)) print("COPYRIGHT: ", assert(geoip_city._COPYRIGHT)) print("") -- Check that required files exist -- See README on info on how to get them assert(io.open(geoip_country_filename, "r")):close() assert(io.open(geoip_city_filename, "r")):close() assert(io.open(geoip_country6_filename, "r")):close() do local id = assert(geoip.id_by_code('RU')) assert(geoip.code_by_id(id) == 'RU') assert(geoip.code3_by_id(id) == 'RUS') assert(geoip.name_by_id(id) == 'Russian Federation') -- Depends on libgeoip version o_O assert(geoip.continent_by_id(id) == 'EU' or geoip.continent_by_id(id) == 'AS') assert(geoip.region_name_by_code('RU', '77') == "Tver'") -- WTF? MSK? assert(geoip.time_zone_by_country_and_region('RU', '77') == 'Europe/Moscow') end do assert(geoip_country.open("./BADFILENAME") == nil) assert(pcall(geoip_country.open, nil, geoip.INDEX_CACHE) == false) --assert(geoip_country.open(nil, 2 ^ 10) == nil) -- TODO: This should fail --assert(geoip_country.open(nil, nil, -1) == nil) -- TODO: This should fail assert(geoip_country.open(geoip_city_filename) == nil) end do assert(geoip_city.open("./BADFILENAME") == nil) --assert(geoip_city.open(nil, 2 ^ 10) == nil) -- TODO: This should fail --assert(geoip_city.open(nil, nil, -1) == nil) -- TODO: This should fail assert(geoip_city.open(geoip_country_filename) == nil) end do local flags = { geoip.STANDARD; geoip.MEMORY_CACHE; geoip.CHECK_CACHE; geoip.INDEX_CACHE; geoip.MMAP_CACHE; } for _, flag in ipairs(flags) do if flag ~= geoip.INDEX_CACHE then assert(geoip_country.open(nil, flag)):close() assert(geoip_country.open(geoip_country_filename, flag)):close() end assert(geoip_city.open(geoip_city_filename, flag)):close() end end do local geodb = assert( geoip_country.open(geoip_country_filename) ) geodb:close() geodb:close() end do local geodb = assert( geoip_city.open(geoip_city_filename) ) geodb:close() geodb:close() end do local check_country = function(db, method, arg) local id = assert(db[method](db, arg, "id")) assert(type(id) == "number") local expected = { id = id; code = assert(geoip.code_by_id(id)); code3 = assert(geoip.code3_by_id(id)); name = assert(geoip.name_by_id(id)); continent = assert(geoip.continent_by_id(id)); } local all = assert(db[method](db, arg)) local keys = { } for k, v in pairs(expected) do assert(all[k] == expected[k]) assert(db[method](db, arg, k) == expected[k]) keys[#keys + 1] = k end local r = { db[method](db, arg, unpack(keys)) } assert(#r == #keys) for i = 1, #keys do assert(r[i] == expected[keys[i]]) end end local apack = function(...) return select("#", ...), { ... } end local check_city = function(db, method, arg) local keys = { "country_code"; "country_code3"; "country_name"; "region"; "city"; "postal_code"; "latitude"; "longitude"; "metro_code"; "dma_code"; "area_code"; "charset"; "continent_code"; } local all = assert(db[method](db, arg)) local nret, r = apack(db[method](db, arg, unpack(keys))) assert(nret == #keys) for i = 1, #keys do assert(r[i] == all[keys[i]]) assert(r[i] == db[method](db, arg, keys[i])) end end local geodb_country = assert(geoip_country.open(geoip_country_filename)) local geodb_city = assert(geoip_city.open(geoip_city_filename)) local checkers = { [geodb_country] = check_country; [geodb_city] = check_city; } for _, geodb in ipairs { geodb_country, geodb_city } do local checker = checkers[geodb] checker(geodb, "query_by_name", "google-public-dns-a.google.com") checker(geodb, "query_by_addr", "8.8.8.8") checker(geodb, "query_by_ipnum", 134744072) -- 8.8.8.8 end geodb_country:close() geodb_city:close() end -- Country IPv6 Edition do local geodb_country6 = assert(geoip_country.open(geoip_country6_filename, geoip.MEMORY_CACHE, geoip.COUNTRY_V6)) res = geodb_country6:query_by_addr6("2a01:e0c:1::1") assert(res.code == "FR") res = geodb_country6:query_by_addr6("2a03:2880:f127:83:face:b00c:0:25de") assert(res.code == "IE") geodb_country6:close() end -- TODO: Test two different DBs open in parallel work properly local profiles = { { name = "country"; module = geoip_country; file = geoip_country_filename; field = "id"; }; { name = "city"; module = geoip_city; file = geoip_city_filename; field = "country_code"; }; } for i = 1, #profiles do local p = profiles[i] local geodb = assert(p.module.open(p.file)) do print(p.name, "profiling ipnum queries") local num_queries = 1e5 local cases = { } for i = 1, num_queries do cases[i] = math.random(0x7FFFFFFF) end local time_start = socket.gettime() for i = 1, num_queries do if i % 1e4 == 0 then print("#", i, "of", num_queries) end local result, err = geodb:query_by_ipnum(cases[i], p.field) if not result and err ~= "not found" then error(err) end end print( p.name, num_queries / (socket.gettime() - time_start), "ipnum queries per second" ) print() end do print(p.name, "profiling addr queries") -- slow due to dns resolution local num_queries = 1e5 local cases = { } for i = 1, num_queries do cases[i] = ('%d.%d.%d.%d'):format( math.random(255), math.random(255), math.random(255), math.random(255) ) end local time_start = socket.gettime() for i = 1, num_queries do if i % 1e4 == 0 then print("#", i, "of", num_queries) end local result, err = geodb:query_by_name(cases[i], p.field) if not result and err ~= "not found" then error(err) end end print( p.name, num_queries / (socket.gettime() - time_start), "addr queries per second" ) print() end do print(p.name, "profiling name queries") local num_queries = 500 -- slow due to dns resolution local time_start = socket.gettime() for i = 1, num_queries do if i % 50 == 0 then print("#", i, "of", num_queries) end assert(geodb:query_by_name("ya.ru", p.field)) end print( p.name, num_queries / (socket.gettime() - time_start), "name queries per second" ) print() end geodb:close() end print("") print("OK")