diff options
Diffstat (limited to '')
-rw-r--r-- | apps/geoiplookup.c | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/apps/geoiplookup.c b/apps/geoiplookup.c new file mode 100644 index 0000000..1c412ea --- /dev/null +++ b/apps/geoiplookup.c @@ -0,0 +1,375 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */ +/* geoiplookup.c + * + * Copyright (C) 2016 MaxMind, Inc. + * + * 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 + */ + +#include "GeoIP.h" +#include "GeoIPCity.h" +#include "GeoIP_internal.h" + +#if defined(_WIN32) +#ifndef uint32_t +typedef unsigned int uint32_t; +#endif +#endif + +void geoiplookup(GeoIP *gi, char *hostname, int i); + +void usage(void) { + fprintf(stderr, + "Usage: geoiplookup [-h] [-?] [-d custom_dir] [-f " + "custom_file] [-v] [-i] [-l] <ipaddress|hostname>\n"); +} + +/* extra info used in _say_range_ip */ +int info_flag = 0; + +int main(int argc, char *argv[]) { + char *hostname = NULL; + char *db_info; + GeoIP *gi; + int i; + char *custom_directory = NULL; + char *custom_file = NULL; + int version_flag = 0; + int charset = GEOIP_CHARSET_UTF8; + + if (argc < 2) { + usage(); + exit(1); + } + i = 1; + while (i < argc) { + if (strcmp(argv[i], "-v") == 0) { + version_flag = 1; + } else if (strcmp(argv[i], "-l") == 0) { + charset = GEOIP_CHARSET_ISO_8859_1; + } else if (strcmp(argv[i], "-i") == 0) { + info_flag = 1; + } else if ((strcmp(argv[i], "-?") == 0) || + (strcmp(argv[i], "-h") == 0)) { + usage(); + exit(0); + } else if (strcmp(argv[i], "-f") == 0) { + if ((i + 1) < argc) { + i++; + custom_file = argv[i]; + } + } else if (strcmp(argv[i], "-d") == 0) { + if ((i + 1) < argc) { + i++; + custom_directory = argv[i]; + } + } else { + hostname = argv[i]; + } + i++; + } + if (hostname == NULL) { + usage(); + exit(1); + } + + if (custom_directory != NULL) { + GeoIP_setup_custom_directory(custom_directory); + } + _GeoIP_setup_dbfilename(); + + if (custom_file != NULL) { + gi = GeoIP_open(custom_file, GEOIP_STANDARD | GEOIP_SILENCE); + + if (NULL == gi) { + printf("%s not available, skipping...\n", custom_file); + } else { + gi->charset = charset; + i = GeoIP_database_edition(gi); + if (version_flag == 1) { + db_info = GeoIP_database_info(gi); + printf("%s: %s\n", + GeoIPDBDescription[i], + db_info == NULL ? "" : db_info); + free(db_info); + } else { + geoiplookup(gi, hostname, i); + } + } + GeoIP_delete(gi); + } else { + /* iterate through different database types */ + for (i = 0; i < NUM_DB_TYPES; ++i) { + if (GeoIP_db_avail(i)) { + gi = GeoIP_open_type(i, GEOIP_STANDARD | GEOIP_SILENCE); + if (NULL == gi) { + /* Ignore these errors. It's possible + * to use the same database name for + * different databases. + */ + ; + } else { + gi->charset = charset; + if (version_flag == 1) { + db_info = GeoIP_database_info(gi); + printf("%s: %s\n", + GeoIPDBDescription[i], + db_info == NULL ? "" : db_info); + free(db_info); + } else { + geoiplookup(gi, hostname, i); + } + } + GeoIP_delete(gi); + } + } + } + return 0; +} + +static const char *_mk_NA(const char *p) { return p ? p : "N/A"; } + +static unsigned long __addr_to_num(const char *addr) { + unsigned int c, octet, t; + unsigned long ipnum; + int i = 3; + + octet = ipnum = 0; + while ((c = *addr++)) { + if (c == '.') { + if (octet > 255) { + return 0; + } + ipnum <<= 8; + ipnum += octet; + i--; + octet = 0; + } else { + t = octet; + octet <<= 3; + octet += t; + octet += t; + c -= '0'; + if (c > 9) { + return 0; + } + octet += c; + } + } + if ((octet > 255) || (i != 0)) { + return 0; + } + ipnum <<= 8; + return ipnum + octet; +} + +/* ptr must be a memory area with at least 16 bytes */ +static char *__num_to_addr_r(unsigned long ipnum, char *ptr) { + char *cur_str; + int octet[4]; + int num_chars_written, i; + + cur_str = ptr; + + for (i = 0; i < 4; i++) { + octet[3 - i] = ipnum % 256; + ipnum >>= 8; + } + + for (i = 0; i < 4; i++) { + num_chars_written = sprintf(cur_str, "%d", octet[i]); + cur_str += num_chars_written; + + if (i < 3) { + cur_str[0] = '.'; + cur_str++; + } + } + + return ptr; +} + +void _say_range_by_ip(GeoIP *gi, uint32_t ipnum) { + unsigned long last_nm, mask, low, hi; + char ipaddr[16]; + char tmp[16]; + char **range; + + if (info_flag == 0) { + return; /* noop unless extra information is requested */ + } + range = GeoIP_range_by_ip(gi, __num_to_addr_r(ipnum, ipaddr)); + if (range == NULL) { + return; + } + + printf(" ipaddr: %s\n", ipaddr); + + printf(" range_by_ip: %s - %s\n", range[0], range[1]); + last_nm = GeoIP_last_netmask(gi); + mask = 0xffffffff << (32 - last_nm); + low = ipnum & mask; + hi = low + (0xffffffff & ~mask); + printf(" network: %s - %s ::%ld\n", + __num_to_addr_r(low, ipaddr), + __num_to_addr_r(hi, tmp), + last_nm); + printf(" ipnum: %u\n", ipnum); + printf(" range_by_num: %lu - %lu\n", + __addr_to_num(range[0]), + __addr_to_num(range[1])); + printf(" network num: %lu - %lu ::%lu\n", low, hi, last_nm); + + GeoIP_range_by_ip_delete(range); +} + +void geoiplookup(GeoIP *gi, char *hostname, int i) { + const char *country_code; + const char *country_name; + const char *domain_name; + const char *asnum_name; + int netspeed; + int country_id; + GeoIPRegion *region; + GeoIPRecord *gir; + const char *org; + uint32_t ipnum; + + ipnum = _GeoIP_lookupaddress(hostname); + if (ipnum == 0) { + printf("%s: can't resolve hostname ( %s )\n", + GeoIPDBDescription[i], + hostname); + } else { + if (GEOIP_DOMAIN_EDITION == i) { + domain_name = GeoIP_name_by_ipnum(gi, ipnum); + if (domain_name == NULL) { + printf("%s: IP Address not found\n", GeoIPDBDescription[i]); + } else { + printf("%s: %s\n", GeoIPDBDescription[i], domain_name); + _say_range_by_ip(gi, ipnum); + free((void *)domain_name); + } + } else if (GEOIP_LOCATIONA_EDITION == i || + GEOIP_ACCURACYRADIUS_EDITION == i || + GEOIP_ASNUM_EDITION == i || GEOIP_USERTYPE_EDITION == i || + GEOIP_REGISTRAR_EDITION == i || + GEOIP_NETSPEED_EDITION_REV1 == i || + GEOIP_COUNTRYCONF_EDITION == i || + GEOIP_CITYCONF_EDITION == i || + GEOIP_REGIONCONF_EDITION == i || + GEOIP_POSTALCONF_EDITION == i) { + asnum_name = GeoIP_name_by_ipnum(gi, ipnum); + if (asnum_name == NULL) { + printf("%s: IP Address not found\n", GeoIPDBDescription[i]); + } else { + printf("%s: %s\n", GeoIPDBDescription[i], asnum_name); + _say_range_by_ip(gi, ipnum); + free((void *)asnum_name); + } + } else if (GEOIP_COUNTRY_EDITION == i) { + country_id = GeoIP_id_by_ipnum(gi, ipnum); + if (country_id < 0 || country_id >= (int)GeoIP_num_countries()) { + printf("%s: Invalid database\n", GeoIPDBDescription[i]); + return; + } + country_code = GeoIP_country_code[country_id]; + country_name = GeoIP_country_name[country_id]; + if (country_id == 0) { + printf("%s: IP Address not found\n", GeoIPDBDescription[i]); + } else { + printf("%s: %s, %s\n", + GeoIPDBDescription[i], + country_code, + country_name); + _say_range_by_ip(gi, ipnum); + } + } else if (GEOIP_REGION_EDITION_REV0 == i || + GEOIP_REGION_EDITION_REV1 == i) { + region = GeoIP_region_by_ipnum(gi, ipnum); + if (NULL == region || region->country_code[0] == '\0') { + printf("%s: IP Address not found\n", GeoIPDBDescription[i]); + } else { + printf("%s: %s, %s\n", + GeoIPDBDescription[i], + region->country_code, + region->region); + _say_range_by_ip(gi, ipnum); + } + if (region) { + GeoIPRegion_delete(region); + } + } else if (GEOIP_CITY_EDITION_REV0 == i) { + gir = GeoIP_record_by_ipnum(gi, ipnum); + if (NULL == gir) { + printf("%s: IP Address not found\n", GeoIPDBDescription[i]); + } else { + printf("%s: %s, %s, %s, %s, %s, %f, %f\n", + GeoIPDBDescription[i], + gir->country_code, + _mk_NA(gir->region), + _mk_NA(GeoIP_region_name_by_code(gir->country_code, + gir->region)), + _mk_NA(gir->city), + _mk_NA(gir->postal_code), + gir->latitude, + gir->longitude); + _say_range_by_ip(gi, ipnum); + GeoIPRecord_delete(gir); + } + } else if (GEOIP_CITY_EDITION_REV1 == i) { + gir = GeoIP_record_by_ipnum(gi, ipnum); + if (NULL == gir) { + printf("%s: IP Address not found\n", GeoIPDBDescription[i]); + } else { + printf("%s: %s, %s, %s, %s, %s, %f, %f, %d, %d\n", + GeoIPDBDescription[i], + gir->country_code, + _mk_NA(gir->region), + _mk_NA(GeoIP_region_name_by_code(gir->country_code, + gir->region)), + _mk_NA(gir->city), + _mk_NA(gir->postal_code), + gir->latitude, + gir->longitude, + gir->metro_code, + gir->area_code); + _say_range_by_ip(gi, ipnum); + GeoIPRecord_delete(gir); + } + } else if (GEOIP_ORG_EDITION == i || GEOIP_ISP_EDITION == i) { + org = GeoIP_org_by_ipnum(gi, ipnum); + if (org == NULL) { + printf("%s: IP Address not found\n", GeoIPDBDescription[i]); + } else { + printf("%s: %s\n", GeoIPDBDescription[i], org); + _say_range_by_ip(gi, ipnum); + free((void *)org); + } + } else if (GEOIP_NETSPEED_EDITION == i) { + netspeed = GeoIP_id_by_ipnum(gi, ipnum); + if (netspeed == GEOIP_UNKNOWN_SPEED) { + printf("%s: Unknown\n", GeoIPDBDescription[i]); + } else if (netspeed == GEOIP_DIALUP_SPEED) { + printf("%s: Dialup\n", GeoIPDBDescription[i]); + } else if (netspeed == GEOIP_CABLEDSL_SPEED) { + printf("%s: Cable/DSL\n", GeoIPDBDescription[i]); + } else if (netspeed == GEOIP_CORPORATE_SPEED) { + printf("%s: Corporate\n", GeoIPDBDescription[i]); + } + _say_range_by_ip(gi, ipnum); + } + } +} |