|
Packit |
71e9d6 |
/*
|
|
Packit |
71e9d6 |
* Copyright (c) 2015 Red Hat, Inc. All rights reserved.
|
|
Packit |
71e9d6 |
*
|
|
Packit |
71e9d6 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
71e9d6 |
* it under the terms of the GNU General Public License, version 2,
|
|
Packit |
71e9d6 |
* as published by the Free Software Foundation.
|
|
Packit |
71e9d6 |
*
|
|
Packit |
71e9d6 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
71e9d6 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
71e9d6 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
71e9d6 |
* GNU General Public License for more details.
|
|
Packit |
71e9d6 |
*
|
|
Packit |
71e9d6 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
71e9d6 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
71e9d6 |
*
|
|
Packit |
71e9d6 |
* Authors:
|
|
Packit |
71e9d6 |
* Nikos Mavrogiannopoulos <nmav@redhat.com>
|
|
Packit |
71e9d6 |
*/
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
#define _GNU_SOURCE /* asprintf */
|
|
Packit |
71e9d6 |
#include <ctype.h>
|
|
Packit |
71e9d6 |
#include <stdio.h>
|
|
Packit |
71e9d6 |
#include <stdlib.h>
|
|
Packit |
71e9d6 |
#include <string.h>
|
|
Packit |
71e9d6 |
#include <sys/socket.h>
|
|
Packit |
71e9d6 |
#include <sys/types.h>
|
|
Packit |
71e9d6 |
#include <netinet/in.h>
|
|
Packit |
71e9d6 |
#include <arpa/inet.h>
|
|
Packit |
71e9d6 |
#include <stdarg.h>
|
|
Packit |
71e9d6 |
#include "ipcalc.h"
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
#ifdef USE_GEOIP
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
# include <GeoIP.h>
|
|
Packit |
71e9d6 |
# include <GeoIPCity.h>
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
#define GEOIP_SILENCE 16 /* fix libgeoip < 1.6.3 */
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
# ifdef USE_RUNTIME_LINKING
|
|
Packit |
71e9d6 |
# include <dlfcn.h>
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
typedef void (*_GeoIP_setup_dbfilename_func)(void);
|
|
Packit |
71e9d6 |
typedef GeoIP * (*GeoIP_open_type_func)(int type, int flags);
|
|
Packit |
71e9d6 |
typedef const char * (*GeoIP_country_name_by_id_func)(GeoIP * gi, int id);
|
|
Packit |
71e9d6 |
typedef void (*GeoIP_delete_func)(GeoIP * gi);
|
|
Packit |
71e9d6 |
typedef GeoIPRecord * (*GeoIP_record_by_ipnum_func)(GeoIP * gi, unsigned long ipnum);
|
|
Packit |
71e9d6 |
typedef int (*GeoIP_id_by_ipnum_func)(GeoIP * gi, unsigned long ipnum);
|
|
Packit |
71e9d6 |
typedef int (*GeoIP_id_by_ipnum_v6_func)(GeoIP * gi, geoipv6_t ipnum);
|
|
Packit |
71e9d6 |
typedef GeoIPRecord *(*GeoIP_record_by_ipnum_v6_func)(GeoIP * gi, geoipv6_t ipnum);
|
|
Packit |
71e9d6 |
typedef const char *(*GeoIP_code_by_id_func)(int id);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
static _GeoIP_setup_dbfilename_func p_GeoIP_setup_dbfilename;
|
|
Packit |
71e9d6 |
static GeoIP_open_type_func pGeoIP_open_type;
|
|
Packit |
71e9d6 |
static GeoIP_country_name_by_id_func pGeoIP_country_name_by_id;
|
|
Packit |
71e9d6 |
static GeoIP_code_by_id_func pGeoIP_code_by_id;
|
|
Packit |
71e9d6 |
static GeoIP_delete_func pGeoIP_delete;
|
|
Packit |
71e9d6 |
static GeoIP_record_by_ipnum_func pGeoIP_record_by_ipnum;
|
|
Packit |
71e9d6 |
static GeoIP_id_by_ipnum_func pGeoIP_id_by_ipnum;
|
|
Packit |
71e9d6 |
static GeoIP_id_by_ipnum_v6_func pGeoIP_id_by_ipnum_v6;
|
|
Packit |
71e9d6 |
static GeoIP_record_by_ipnum_v6_func pGeoIP_record_by_ipnum_v6;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
#define LIBNAME LIBPATH"/libGeoIP.so.1"
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
int geo_setup(void)
|
|
Packit |
71e9d6 |
{
|
|
Packit |
71e9d6 |
static void *ld = NULL;
|
|
Packit |
71e9d6 |
static int ret = 0;
|
|
Packit |
71e9d6 |
static char err[256] = {0};
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (ld != NULL || ret != 0) {
|
|
Packit |
71e9d6 |
if (!beSilent && err[0] != 0) {
|
|
Packit |
71e9d6 |
fprintf(stderr, "%s", err);
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
return ret;
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
ld = dlopen(LIBNAME, RTLD_LAZY);
|
|
Packit |
71e9d6 |
if (ld == NULL) {
|
|
Packit |
71e9d6 |
snprintf(err, sizeof(err), "ipcalc: could not open %s\n", LIBNAME);
|
|
Packit |
71e9d6 |
ret = -1;
|
|
Packit |
71e9d6 |
goto exit;
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
p_GeoIP_setup_dbfilename = dlsym(ld, "_GeoIP_setup_dbfilename");
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
pGeoIP_open_type = dlsym(ld, "GeoIP_open_type");
|
|
Packit |
71e9d6 |
pGeoIP_country_name_by_id = dlsym(ld, "GeoIP_country_name_by_id");
|
|
Packit |
71e9d6 |
pGeoIP_delete = dlsym(ld, "GeoIP_delete");
|
|
Packit |
71e9d6 |
pGeoIP_record_by_ipnum = dlsym(ld, "GeoIP_record_by_ipnum");
|
|
Packit |
71e9d6 |
pGeoIP_id_by_ipnum = dlsym(ld, "GeoIP_id_by_ipnum");
|
|
Packit |
71e9d6 |
pGeoIP_id_by_ipnum_v6 = dlsym(ld, "GeoIP_id_by_ipnum_v6");
|
|
Packit |
71e9d6 |
pGeoIP_record_by_ipnum_v6 = dlsym(ld, "GeoIP_record_by_ipnum_v6");
|
|
Packit |
71e9d6 |
pGeoIP_code_by_id = dlsym(ld, "GeoIP_code_by_id");
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (pGeoIP_open_type == NULL || pGeoIP_country_name_by_id == NULL ||
|
|
Packit |
71e9d6 |
pGeoIP_delete == NULL || pGeoIP_record_by_ipnum == NULL ||
|
|
Packit |
71e9d6 |
pGeoIP_id_by_ipnum == NULL || pGeoIP_id_by_ipnum_v6 == NULL ||
|
|
Packit |
71e9d6 |
pGeoIP_record_by_ipnum_v6 == NULL) {
|
|
Packit |
71e9d6 |
snprintf(err, sizeof(err), "ipcalc: could not find symbols in libGeoIP\n");
|
|
Packit |
71e9d6 |
ret = -1;
|
|
Packit |
71e9d6 |
goto exit;
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
ret = 0;
|
|
Packit |
71e9d6 |
exit:
|
|
Packit |
71e9d6 |
return ret;
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
# else
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
extern void _GeoIP_setup_dbfilename(void);
|
|
Packit |
71e9d6 |
# define p_GeoIP_setup_dbfilename _GeoIP_setup_dbfilename
|
|
Packit |
71e9d6 |
# define pGeoIP_open_type GeoIP_open_type
|
|
Packit |
71e9d6 |
# define pGeoIP_country_name_by_id GeoIP_country_name_by_id
|
|
Packit |
71e9d6 |
# define pGeoIP_delete GeoIP_delete
|
|
Packit |
71e9d6 |
# define pGeoIP_record_by_ipnum GeoIP_record_by_ipnum
|
|
Packit |
71e9d6 |
# define pGeoIP_id_by_ipnum GeoIP_id_by_ipnum
|
|
Packit |
71e9d6 |
# define pGeoIP_id_by_ipnum_v6 GeoIP_id_by_ipnum_v6
|
|
Packit |
71e9d6 |
# define pGeoIP_record_by_ipnum_v6 GeoIP_record_by_ipnum_v6
|
|
Packit |
71e9d6 |
# define pGeoIP_code_by_id GeoIP_code_by_id
|
|
Packit |
71e9d6 |
# endif
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
static void geo_ipv4_lookup(struct in_addr ip, char **country, char **ccode, char **city, char **coord)
|
|
Packit |
71e9d6 |
{
|
|
Packit |
71e9d6 |
GeoIP *gi;
|
|
Packit |
71e9d6 |
GeoIPRecord *gir;
|
|
Packit |
71e9d6 |
int country_id;
|
|
Packit |
71e9d6 |
const char *p;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (geo_setup() != 0)
|
|
Packit |
71e9d6 |
return;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
ip.s_addr = ntohl(ip.s_addr);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
p_GeoIP_setup_dbfilename();
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
gi = pGeoIP_open_type(GEOIP_COUNTRY_EDITION, GEOIP_STANDARD | GEOIP_SILENCE);
|
|
Packit |
71e9d6 |
if (gi != NULL) {
|
|
Packit |
71e9d6 |
gi->charset = GEOIP_CHARSET_UTF8;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
country_id = pGeoIP_id_by_ipnum(gi, ip.s_addr);
|
|
Packit |
71e9d6 |
if (country_id < 0) {
|
|
Packit |
71e9d6 |
return;
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
p = pGeoIP_country_name_by_id(gi, country_id);
|
|
Packit |
71e9d6 |
if (p)
|
|
Packit |
71e9d6 |
*country = safe_strdup(p);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
p = pGeoIP_code_by_id(country_id);
|
|
Packit |
71e9d6 |
if (p)
|
|
Packit |
71e9d6 |
*ccode = safe_strdup(p);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
pGeoIP_delete(gi);
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
gi = pGeoIP_open_type(GEOIP_CITY_EDITION_REV1, GEOIP_STANDARD | GEOIP_SILENCE);
|
|
Packit |
71e9d6 |
if (gi != NULL) {
|
|
Packit |
71e9d6 |
gi->charset = GEOIP_CHARSET_UTF8;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
gir = pGeoIP_record_by_ipnum(gi, ip.s_addr);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (gir && gir->city)
|
|
Packit |
71e9d6 |
*city = safe_strdup(gir->city);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (gir && gir->longitude != 0 && gir->longitude != 0)
|
|
Packit |
71e9d6 |
safe_asprintf(coord, "%f,%f", gir->latitude, gir->longitude);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
pGeoIP_delete(gi);
|
|
Packit |
71e9d6 |
} else {
|
|
Packit |
71e9d6 |
gi = pGeoIP_open_type(GEOIP_CITY_EDITION_REV0, GEOIP_STANDARD | GEOIP_SILENCE);
|
|
Packit |
71e9d6 |
if (gi != NULL) {
|
|
Packit |
71e9d6 |
gi->charset = GEOIP_CHARSET_UTF8;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
gir = pGeoIP_record_by_ipnum(gi, ip.s_addr);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (gir && gir->city)
|
|
Packit |
71e9d6 |
*city = safe_strdup(gir->city);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (gir && gir->longitude != 0 && gir->longitude != 0)
|
|
Packit |
71e9d6 |
safe_asprintf(coord, "%f,%f", gir->latitude, gir->longitude);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
pGeoIP_delete(gi);
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
return;
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
static void geo_ipv6_lookup(struct in6_addr *ip, char **country, char **ccode, char **city, char **coord)
|
|
Packit |
71e9d6 |
{
|
|
Packit |
71e9d6 |
GeoIP *gi;
|
|
Packit |
71e9d6 |
GeoIPRecord *gir;
|
|
Packit |
71e9d6 |
int country_id;
|
|
Packit |
71e9d6 |
const char *p;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (geo_setup() != 0)
|
|
Packit |
71e9d6 |
return;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
p_GeoIP_setup_dbfilename();
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
gi = pGeoIP_open_type(GEOIP_COUNTRY_EDITION_V6, GEOIP_STANDARD | GEOIP_SILENCE);
|
|
Packit |
71e9d6 |
if (gi != NULL) {
|
|
Packit |
71e9d6 |
gi->charset = GEOIP_CHARSET_UTF8;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
country_id = pGeoIP_id_by_ipnum_v6(gi, (geoipv6_t)*ip);
|
|
Packit |
71e9d6 |
if (country_id < 0) {
|
|
Packit |
71e9d6 |
return;
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
p = pGeoIP_country_name_by_id(gi, country_id);
|
|
Packit |
71e9d6 |
if (p)
|
|
Packit |
71e9d6 |
*country = safe_strdup(p);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
p = pGeoIP_code_by_id(country_id);
|
|
Packit |
71e9d6 |
if (p)
|
|
Packit |
71e9d6 |
*ccode = safe_strdup(p);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
pGeoIP_delete(gi);
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
gi = pGeoIP_open_type(GEOIP_CITY_EDITION_REV1_V6, GEOIP_STANDARD | GEOIP_SILENCE);
|
|
Packit |
71e9d6 |
if (gi != NULL) {
|
|
Packit |
71e9d6 |
gi->charset = GEOIP_CHARSET_UTF8;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
gir = pGeoIP_record_by_ipnum_v6(gi, (geoipv6_t)*ip);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (gir && gir->city)
|
|
Packit |
71e9d6 |
*city = safe_strdup(gir->city);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (gir && gir->longitude != 0 && gir->longitude != 0)
|
|
Packit |
71e9d6 |
safe_asprintf(coord, "%f,%f", gir->latitude, gir->longitude);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
pGeoIP_delete(gi);
|
|
Packit |
71e9d6 |
} else {
|
|
Packit |
71e9d6 |
gi = pGeoIP_open_type(GEOIP_CITY_EDITION_REV0_V6, GEOIP_STANDARD | GEOIP_SILENCE);
|
|
Packit |
71e9d6 |
if (gi != NULL) {
|
|
Packit |
71e9d6 |
gi->charset = GEOIP_CHARSET_UTF8;
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
gir = pGeoIP_record_by_ipnum_v6(gi, (geoipv6_t)*ip);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (gir && gir->city)
|
|
Packit |
71e9d6 |
*city = safe_strdup(gir->city);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
if (gir && gir->longitude != 0 && gir->longitude != 0)
|
|
Packit |
71e9d6 |
safe_asprintf(coord, "%f,%f", gir->latitude, gir->longitude);
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
pGeoIP_delete(gi);
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
return;
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
void geo_ip_lookup(const char *ip, char **country, char **ccode, char **city, char **coord)
|
|
Packit |
71e9d6 |
{
|
|
Packit |
71e9d6 |
struct in_addr ipv4;
|
|
Packit |
71e9d6 |
struct in6_addr ipv6;
|
|
Packit |
71e9d6 |
if (inet_pton(AF_INET, ip, &ipv4) == 1) {
|
|
Packit |
71e9d6 |
geo_ipv4_lookup(ipv4, country, ccode, city, coord);
|
|
Packit |
71e9d6 |
} else if (inet_pton(AF_INET6, ip, &ipv6) == 1) {
|
|
Packit |
71e9d6 |
geo_ipv6_lookup(&ipv6, country, ccode, city, coord);
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
return;
|
|
Packit |
71e9d6 |
}
|
|
Packit |
71e9d6 |
|
|
Packit |
71e9d6 |
#endif
|