/* * ip2country_v6 - MaxMind GeoIP dlfunc for Exim * https://mta.org.ua/exim-4.94-conf/dlfunc/ip2country_v6/ip2country_v6.c * * Copyright (C) 2018-2020 Victor Ustugov * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Based on source code from https://github.com/snabb/exim-geoipv6-dlfunc * by Janne Snabb */ /* Headers for inet_pton(3): */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif /* MaxMind GeoIP C API header: */ #include "GeoIP.h" //#define DLFUNC_IMPL /* Exim4 dlfunc API header: */ //#include "local_scan.h" //#include "macros.h" #include "exim.h" //# define string_copy(s) string_copy_function(s) //# define string_copyn(s, n) string_copyn_function((s), (n)) //# define string_copy_taint(s, t) string_copy_taint_function((s), (t)) extern uschar * string_copy_function(const uschar *); extern uschar * string_copyn_function(const uschar *, int n); extern uschar * string_copy_taint_function(const uschar *, BOOL tainted); /***************************************************************************** * Configuration settings: *****************************************************************************/ /* GeoIP database edition selection: */ #define EDITION_V4 GEOIP_COUNTRY_EDITION #define EDITION_V6 GEOIP_COUNTRY_EDITION_V6 /* default code returned when country is unknown: */ #define COUNTRY_CODE_UNKNOWN US"--" /* default code returned on lookup failures due to missing database: */ #define COUNTRY_CODE_LOOKUP_FAILED US"--" //------------------------------------------------------------------------- int ip2country_v6(uschar **yield, int argc, uschar *argv[]) { GeoIP *gi; const char *res; union { struct in_addr buf4; struct in6_addr buf6; } buf; if (argc != 1) { *yield = string_copy(US"Invalid number of arguments"); return ERROR; } if (inet_pton(AF_INET, (char *) argv[0], &buf) == 1) { /* IPv4 address: */ gi = GeoIP_open_type(EDITION_V4, GEOIP_STANDARD); if (gi == NULL) { log_write(0, LOG_MAIN, "ip2country_v6: Failed to open IPv4 GeoIP database"); *yield = string_copy(COUNTRY_CODE_LOOKUP_FAILED); return OK; } res = GeoIP_country_code_by_addr(gi, (char *) argv[0]); } else if (inet_pton(AF_INET6, (char *) argv[0], &buf) == 1) { /* IPv6 address: */ gi = GeoIP_open_type(EDITION_V6, GEOIP_STANDARD); if (gi == NULL) { log_write(0, LOG_MAIN, "ip2country_v6: Failed to open IPv6 GeoIP database"); *yield = string_copy(COUNTRY_CODE_LOOKUP_FAILED); return OK; } res = GeoIP_country_code_by_addr_v6(gi, (char *) argv[0]); } else { /* Unrecognized address format: */ *yield = string_copy(US"Unrecognized address format"); return FAIL; } GeoIP_delete(gi); if (res == NULL) *yield = string_copy(COUNTRY_CODE_UNKNOWN); else *yield = string_copy(US res); return OK; } int ip2continent_v6(uschar **yield, int argc, uschar *argv[]) { GeoIP *gi; const char *res; union { struct in_addr buf4; struct in6_addr buf6; } buf; const char *country; if (argc != 1) { *yield = string_copy(US"Invalid number of arguments"); return ERROR; } if (inet_pton(AF_INET, (char *) argv[0], &buf) == 1) { /* IPv4 address: */ gi = GeoIP_open_type(EDITION_V4, GEOIP_STANDARD); if (gi == NULL) { log_write(0, LOG_MAIN, "ip2country_v6: Failed to open IPv4 GeoIP database"); *yield = string_copy(COUNTRY_CODE_LOOKUP_FAILED); return OK; } country = GeoIP_country_code_by_addr(gi, (char *) argv[0]); if (country == NULL) { *yield = string_copy(COUNTRY_CODE_UNKNOWN); return OK; } res = GeoIP_continent_by_id(GeoIP_id_by_code(country)); } else if (inet_pton(AF_INET6, (char *) argv[0], &buf) == 1) { /* IPv6 address: */ gi = GeoIP_open_type(EDITION_V6, GEOIP_STANDARD); if (gi == NULL) { log_write(0, LOG_MAIN, "ip2country_v6: Failed to open IPv6 GeoIP database"); *yield = string_copy(COUNTRY_CODE_LOOKUP_FAILED); return OK; } country = GeoIP_country_code_by_addr_v6(gi, (char *) argv[0]); if (country == NULL) { *yield = string_copy(COUNTRY_CODE_UNKNOWN); return OK; } res = GeoIP_continent_by_id(GeoIP_id_by_code(country)); } else { /* Unrecognized address format: */ *yield = string_copy(US"Unrecognized address format"); return FAIL; } GeoIP_delete(gi); if (res == NULL) *yield = string_copy(COUNTRY_CODE_UNKNOWN); else *yield = string_copy(US res); return OK; } /***************************************************************************** * eof *****************************************************************************/