|
|
|
|
/*
|
|
|
|
|
*
|
|
|
|
|
* IP-address/hostname to country converter.
|
|
|
|
|
*
|
|
|
|
|
* Problem; you want to know where IP a.b.c.d is located.
|
|
|
|
|
*
|
|
|
|
|
* Use ares_gethostbyname ("d.c.b.a.zz.countries.nerd.dk")
|
|
|
|
|
* and get the CNAME (host->h_name). Result will be:
|
|
|
|
|
* CNAME = zz<CC>.countries.nerd.dk with address 127.0.x.y (ver 1) or
|
|
|
|
|
* CNAME = <a.b.c.d>.zz.countries.nerd.dk with address 127.0.x.y (ver 2)
|
|
|
|
|
*
|
|
|
|
|
* The 2 letter country code is in <CC> and the ISO-3166 country
|
|
|
|
|
* number is in x.y (number = x*256 + y). Version 2 of the protocol is missing
|
|
|
|
|
* the <CC> number.
|
|
|
|
|
*
|
|
|
|
|
* Ref: http://countries.nerd.dk/more.html
|
|
|
|
|
*
|
|
|
|
|
* Written by G. Vanem <gvanem@broadpark.no> 2006, 2007
|
|
|
|
|
*
|
|
|
|
|
* NB! This program may not be big-endian aware.
|
|
|
|
|
*
|
|
|
|
|
* Permission to use, copy, modify, and distribute this
|
|
|
|
|
* software and its documentation for any purpose and without
|
|
|
|
|
* fee is hereby granted, provided that the above copyright
|
|
|
|
|
* notice appear in all copies and that both that copyright
|
|
|
|
|
* notice and this permission notice appear in supporting
|
|
|
|
|
* documentation, and that the name of M.I.T. not be used in
|
|
|
|
|
* advertising or publicity pertaining to distribution of the
|
|
|
|
|
* software without specific, written prior permission.
|
|
|
|
|
* M.I.T. makes no representations about the suitability of
|
|
|
|
|
* this software for any purpose. It is provided "as is"
|
|
|
|
|
* without express or implied warranty.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "ares_setup.h"
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
|
#include <strings.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(WIN32) && !defined(WATT32)
|
|
|
|
|
#include <winsock.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <netdb.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "ares.h"
|
|
|
|
|
#include "ares_getopt.h"
|
|
|
|
|
#include "inet_net_pton.h"
|
|
|
|
|
#include "inet_ntop.h"
|
|
|
|
|
|
|
|
|
|
#ifndef HAVE_STRDUP
|
|
|
|
|
# include "ares_strdup.h"
|
|
|
|
|
# define strdup(ptr) ares_strdup(ptr)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef HAVE_STRCASECMP
|
|
|
|
|
# include "ares_strcasecmp.h"
|
|
|
|
|
# define strcasecmp(p1,p2) ares_strcasecmp(p1,p2)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef HAVE_STRNCASECMP
|
|
|
|
|
# include "ares_strcasecmp.h"
|
|
|
|
|
# define strncasecmp(p1,p2,n) ares_strncasecmp(p1,p2,n)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef INADDR_NONE
|
|
|
|
|
#define INADDR_NONE 0xffffffff
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static const char *usage = "acountry [-vh?] {host|addr} ...\n";
|
|
|
|
|
static const char nerd_fmt[] = "%u.%u.%u.%u.zz.countries.nerd.dk";
|
|
|
|
|
static const char *nerd_ver1 = nerd_fmt + 14;
|
|
|
|
|
static const char *nerd_ver2 = nerd_fmt + 11;
|
|
|
|
|
static int verbose = 0;
|
|
|
|
|
|
|
|
|
|
#define TRACE(fmt) do { \
|
|
|
|
|
if (verbose > 0) \
|
|
|
|
|
printf fmt ; \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
static void wait_ares(ares_channel channel);
|
|
|
|
|
static void callback(void *arg, int status, int timeouts, struct hostent *host);
|
|
|
|
|
static void callback2(void *arg, int status, int timeouts, struct hostent *host);
|
|
|
|
|
static void find_country_from_cname(const char *cname, struct in_addr addr);
|
|
|
|
|
|
|
|
|
|
static void Abort(const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
|
vfprintf(stderr, fmt, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
ares_channel channel;
|
|
|
|
|
int ch, status;
|
|
|
|
|
|
|
|
|
|
#if defined(WIN32) && !defined(WATT32)
|
|
|
|
|
WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
|
|
|
|
|
WSADATA wsaData;
|
|
|
|
|
WSAStartup(wVersionRequested, &wsaData);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
status = ares_library_init(ARES_LIB_INIT_ALL);
|
|
|
|
|
if (status != ARES_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "ares_library_init: %s\n", ares_strerror(status));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ((ch = ares_getopt(argc, argv, "dvh?")) != -1)
|
|
|
|
|
switch (ch)
|
|
|
|
|
{
|
|
|
|
|
case 'd':
|
|
|
|
|
#ifdef WATT32
|
|
|
|
|
dbug_init();
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
case 'v':
|
|
|
|
|
verbose++;
|
|
|
|
|
break;
|
|
|
|
|
case 'h':
|
|
|
|
|
case '?':
|
|
|
|
|
default:
|
|
|
|
|
Abort(usage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argc -= optind;
|
|
|
|
|
argv += optind;
|
|
|
|
|
if (argc < 1)
|
|
|
|
|
Abort(usage);
|
|
|
|
|
|
|
|
|
|
status = ares_init(&channel);
|
|
|
|
|
if (status != ARES_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "ares_init: %s\n", ares_strerror(status));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initiate the queries, one per command-line argument. */
|
|
|
|
|
for ( ; *argv; argv++)
|
|
|
|
|
{
|
|
|
|
|
struct in_addr addr;
|
|
|
|
|
char buf[100];
|
|
|
|
|
|
|
|
|
|
/* If this fails, assume '*argv' is a host-name that
|
|
|
|
|
* must be resolved first
|
|
|
|
|
*/
|
|
|
|
|
if (ares_inet_pton(AF_INET, *argv, &addr) != 1)
|
|
|
|
|
{
|
|
|
|
|
ares_gethostbyname(channel, *argv, AF_INET, callback2, &addr);
|
|
|
|
|
wait_ares(channel);
|
|
|
|
|
if (addr.s_addr == INADDR_NONE)
|
|
|
|
|
{
|
|
|
|
|
printf("Failed to lookup %s\n", *argv);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sprintf(buf, nerd_fmt,
|
|
|
|
|
(unsigned int)(addr.s_addr >> 24),
|
|
|
|
|
(unsigned int)((addr.s_addr >> 16) & 255),
|
|
|
|
|
(unsigned int)((addr.s_addr >> 8) & 255),
|
|
|
|
|
(unsigned int)(addr.s_addr & 255));
|
|
|
|
|
TRACE(("Looking up %s...", buf));
|
|
|
|
|
fflush(stdout);
|
|
|
|
|
ares_gethostbyname(channel, buf, AF_INET, callback, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wait_ares(channel);
|
|
|
|
|
ares_destroy(channel);
|
|
|
|
|
|
|
|
|
|
ares_library_cleanup();
|
|
|
|
|
|
|
|
|
|
#if defined(WIN32) && !defined(WATT32)
|
|
|
|
|
WSACleanup();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Wait for the queries to complete.
|
|
|
|
|
*/
|
|
|
|
|
static void wait_ares(ares_channel channel)
|
|
|
|
|
{
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
struct timeval *tvp, tv;
|
|
|
|
|
fd_set read_fds, write_fds;
|
|
|
|
|
int nfds;
|
|
|
|
|
|
|
|
|
|
FD_ZERO(&read_fds);
|
|
|
|
|
FD_ZERO(&write_fds);
|
|
|
|
|
nfds = ares_fds(channel, &read_fds, &write_fds);
|
|
|
|
|
if (nfds == 0)
|
|
|
|
|
break;
|
|
|
|
|
tvp = ares_timeout(channel, NULL, &tv);
|
|
|
|
|
select(nfds, &read_fds, &write_fds, NULL, tvp);
|
|
|
|
|
ares_process(channel, &read_fds, &write_fds);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is the callback used when we have the IP-address of interest.
|
|
|
|
|
* Extract the CNAME and figure out the country-code from it.
|
|
|
|
|
*/
|
|
|
|
|
static void callback(void *arg, int status, int timeouts, struct hostent *host)
|
|
|
|
|
{
|
|
|
|
|
const char *name = (const char*)arg;
|
|
|
|
|
const char *cname;
|
|
|
|
|
char buf[20];
|
|
|
|
|
|
|
|
|
|
(void)timeouts;
|
|
|
|
|
|
|
|
|
|
if (!host || status != ARES_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
printf("Failed to lookup %s: %s\n", name, ares_strerror(status));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TRACE(("\nFound address %s, name %s\n",
|
|
|
|
|
ares_inet_ntop(AF_INET,(const char*)host->h_addr,buf,sizeof(buf)),
|
|
|
|
|
host->h_name));
|
|
|
|
|
|
|
|
|
|
cname = host->h_name; /* CNAME gets put here */
|
|
|
|
|
if (!cname)
|
|
|
|
|
printf("Failed to get CNAME for %s\n", name);
|
|
|
|
|
else
|
|
|
|
|
find_country_from_cname(cname, *(struct in_addr*)host->h_addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is the callback used to obtain the IP-address of the host of interest.
|
|
|
|
|
*/
|
|
|
|
|
static void callback2(void *arg, int status, int timeouts, struct hostent *host)
|
|
|
|
|
{
|
|
|
|
|
struct in_addr *addr = (struct in_addr*) arg;
|
|
|
|
|
|
|
|
|
|
(void)timeouts;
|
|
|
|
|
if (!host || status != ARES_SUCCESS)
|
|
|
|
|
memset(addr, INADDR_NONE, sizeof(*addr));
|
|
|
|
|
else
|
|
|
|
|
memcpy(addr, host->h_addr, sizeof(*addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct search_list {
|
|
|
|
|
int country_number; /* ISO-3166 country number */
|
|
|
|
|
char short_name[3]; /* A2 short country code */
|
|
|
|
|
const char *long_name; /* normal country name */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct search_list *list_lookup(int number, const struct search_list *list, int num)
|
|
|
|
|
{
|
|
|
|
|
while (num > 0 && list->long_name)
|
|
|
|
|
{
|
|
|
|
|
if (list->country_number == number)
|
|
|
|
|
return (list);
|
|
|
|
|
num--;
|
|
|
|
|
list++;
|
|
|
|
|
}
|
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Ref: ftp://ftp.ripe.net/iso3166-countrycodes.txt
|
|
|
|
|
*/
|
|
|
|
|
static const struct search_list country_list[] = {
|
|
|
|
|
{ 4, "af", "Afghanistan" },
|
|
|
|
|
{ 248, "ax", "<EFBFBD>land Island" },
|
|
|
|
|
{ 8, "al", "Albania" },
|
|
|
|
|
{ 12, "dz", "Algeria" },
|
|
|
|
|
{ 16, "as", "American Samoa" },
|
|
|
|
|
{ 20, "ad", "Andorra" },
|
|
|
|
|
{ 24, "ao", "Angola" },
|
|
|
|
|
{ 660, "ai", "Anguilla" },
|
|
|
|
|
{ 10, "aq", "Antarctica" },
|
|
|
|
|
{ 28, "ag", "Antigua & Barbuda" },
|
|
|
|
|
{ 32, "ar", "Argentina" },
|
|
|
|
|
{ 51, "am", "Armenia" },
|
|
|
|
|
{ 533, "aw", "Aruba" },
|
|
|
|
|
{ 36, "au", "Australia" },
|
|
|
|
|
{ 40, "at", "Austria" },
|
|
|
|
|
{ 31, "az", "Azerbaijan" },
|
|
|
|
|
{ 44, "bs", "Bahamas" },
|
|
|
|
|
{ 48, "bh", "Bahrain" },
|
|
|
|
|
{ 50, "bd", "Bangladesh" },
|
|
|
|
|
{ 52, "bb", "Barbados" },
|
|
|
|
|
{ 112, "by", "Belarus" },
|
|
|
|
|
{ 56, "be", "Belgium" },
|
|
|
|
|
{ 84, "bz", "Belize" },
|
|
|
|
|
{ 204, "bj", "Benin" },
|
|
|
|
|
{ 60, "bm", "Bermuda" },
|
|
|
|
|
{ 64, "bt", "Bhutan" },
|
|
|
|
|
{ 68, "bo", "Bolivia" },
|
|
|
|
|
{ 70, "ba", "Bosnia & Herzegowina" },
|
|
|
|
|
{ 72, "bw", "Botswana" },
|
|
|
|
|
{ 74, "bv", "Bouvet Island" },
|
|
|
|
|
{ 76, "br", "Brazil" },
|
|
|
|
|
{ 86, "io", "British Indian Ocean Territory" },
|
|
|
|
|
{ 96, "bn", "Brunei Darussalam" },
|
|
|
|
|
{ 100, "bg", "Bulgaria" },
|
|
|
|
|
{ 854, "bf", "Burkina Faso" },
|
|
|
|
|
{ 108, "bi", "Burundi" },
|
|
|
|
|
{ 116, "kh", "Cambodia" },
|
|
|
|
|
{ 120, "cm", "Cameroon" },
|
|
|
|
|
{ 124, "ca", "Canada" },
|
|
|
|
|
{ 132, "cv", "Cape Verde" },
|
|
|
|
|
{ 136, "ky", "Cayman Islands" },
|
|
|
|
|
{ 140, "cf", "Central African Republic" },
|
|
|
|
|
{ 148, "td", "Chad" },
|
|
|
|
|
{ 152, "cl", "Chile" },
|
|
|
|
|
{ 156, "cn", "China" },
|
|
|
|
|
{ 162, "cx", "Christmas Island" },
|
|
|
|
|
{ 166, "cc", "Cocos Islands" },
|
|
|
|
|
{ 170, "co", "Colombia" },
|
|
|
|
|
{ 174, "km", "Comoros" },
|
|
|
|
|
{ 178, "cg", "Congo" },
|
|
|
|
|
{ 180, "cd", "Congo" },
|
|
|
|
|
{ 184, "ck", "Cook Islands" },
|
|
|
|
|
{ 188, "cr", "Costa Rica" },
|
|
|
|
|
{ 384, "ci", "Cote d'Ivoire" },
|
|
|
|
|
{ 191, "hr", "Croatia" },
|
|
|
|
|
{ 192, "cu", "Cuba" },
|
|
|
|
|
{ 196, "cy", "Cyprus" },
|
|
|
|
|
{ 203, "cz", "Czech Republic" },
|
|
|
|
|
{ 208, "dk", "Denmark" },
|
|
|
|
|
{ 262, "dj", "Djibouti" },
|
|
|
|
|
{ 212, "dm", "Dominica" },
|
|
|
|
|
{ 214, "do", "Dominican Republic" },
|
|
|
|
|
{ 218, "ec", "Ecuador" },
|
|
|
|
|
{ 818, "eg", "Egypt" },
|
|
|
|
|
{ 222, "sv", "El Salvador" },
|
|
|
|
|
{ 226, "gq", "Equatorial Guinea" },
|
|
|
|
|
{ 232, "er", "Eritrea" },
|
|
|
|
|
{ 233, "ee", "Estonia" },
|
|
|
|
|
{ 231, "et", "Ethiopia" },
|
|
|
|
|
{ 238, "fk", "Falkland Islands" },
|
|
|
|
|
{ 234, "fo", "Faroe Islands" },
|
|
|
|
|
{ 242, "fj", "Fiji" },
|
|
|
|
|
{ 246, "fi", "Finland" },
|
|
|
|
|
{ 250, "fr", "France" },
|
|
|
|
|
{ 249, "fx", "France, Metropolitan" },
|
|
|
|
|
{ 254, "gf", "French Guiana" },
|
|
|
|
|
{ 258, "pf", "French Polynesia" },
|
|
|
|
|
{ 260, "tf", "French Southern Territories" },
|
|
|
|
|
{ 266, "ga", "Gabon" },
|
|
|
|
|
{ 270, "gm", "Gambia" },
|
|
|
|
|
{ 268, "ge", "Georgia" },
|
|
|
|
|
{ 276, "de", "Germany" },
|
|
|
|
|
{ 288, "gh", "Ghana" },
|
|
|
|
|
{ 292, "gi", "Gibraltar" },
|
|
|
|
|
{ 300, "gr", "Greece" },
|
|
|
|
|
{ 304, "gl", "Greenland" },
|
|
|
|
|
{ 308, "gd", "Grenada" },
|
|
|
|
|
{ 312, "gp", "Guadeloupe" },
|
|
|
|
|
{ 316, "gu", "Guam" },
|
|
|
|
|
{ 320, "gt", "Guatemala" },
|
|
|
|
|
{ 324, "gn", "Guinea" },
|
|
|
|
|
{ 624, "gw", "Guinea-Bissau" },
|
|
|
|
|
{ 328, "gy", "Guyana" },
|
|
|
|
|
{ 332, "ht", "Haiti" },
|
|
|
|
|
{ 334, "hm", "Heard & Mc Donald Islands" },
|
|
|
|
|
{ 336, "va", "Vatican City" },
|
|
|
|
|
{ 340, "hn", "Honduras" },
|
|
|
|
|
{ 344, "hk", "Hong kong" },
|
|
|
|
|
{ 348, "hu", "Hungary" },
|
|
|
|
|
{ 352, "is", "Iceland" },
|
|
|
|
|
{ 356, "in", "India" },
|
|
|
|
|
{ 360, "id", "Indonesia" },
|
|
|
|
|
{ 364, "ir", "Iran" },
|
|
|
|
|
{ 368, "iq", "Iraq" },
|
|
|
|
|
{ 372, "ie", "Ireland" },
|
|
|
|
|
{ 376, "il", "Israel" },
|
|
|
|
|
{ 380, "it", "Italy" },
|
|
|
|
|
{ 388, "jm", "Jamaica" },
|
|
|
|
|
{ 392, "jp", "Japan" },
|
|
|
|
|
{ 400, "jo", "Jordan" },
|
|
|
|
|
{ 398, "kz", "Kazakhstan" },
|
|
|
|
|
{ 404, "ke", "Kenya" },
|
|
|
|
|
{ 296, "ki", "Kiribati" },
|
|
|
|
|
{ 408, "kp", "Korea (north)" },
|
|
|
|
|
{ 410, "kr", "Korea (south)" },
|
|
|
|
|
{ 414, "kw", "Kuwait" },
|
|
|
|
|
{ 417, "kg", "Kyrgyzstan" },
|
|
|
|
|
{ 418, "la", "Laos" },
|
|
|
|
|
{ 428, "lv", "Latvia" },
|
|
|
|
|
{ 422, "lb", "Lebanon" },
|
|
|
|
|
{ 426, "ls", "Lesotho" },
|
|
|
|
|
{ 430, "lr", "Liberia" },
|
|
|
|
|
{ 434, "ly", "Libya" },
|
|
|
|
|
{ 438, "li", "Liechtenstein" },
|
|
|
|
|
{ 440, "lt", "Lithuania" },
|
|
|
|
|
{ 442, "lu", "Luxembourg" },
|
|
|
|
|
{ 446, "mo", "Macao" },
|
|
|
|
|
{ 807, "mk", "Macedonia" },
|
|
|
|
|
{ 450, "mg", "Madagascar" },
|
|
|
|
|
{ 454, "mw", "Malawi" },
|
|
|
|
|
{ 458, "my", "Malaysia" },
|
|
|
|
|
{ 462, "mv", "Maldives" },
|
|
|
|
|
{ 466, "ml", "Mali" },
|
|
|
|
|
{ 470, "mt", "Malta" },
|
|
|
|
|
{ 584, "mh", "Marshall Islands" },
|
|
|
|
|
{ 474, "mq", "Martinique" },
|
|
|
|
|
{ 478, "mr", "Mauritania" },
|
|
|
|
|
{ 480, "mu", "Mauritius" },
|
|
|
|
|
{ 175, "yt", "Mayotte" },
|
|
|
|
|
{ 484, "mx", "Mexico" },
|
|
|
|
|
{ 583, "fm", "Micronesia" },
|
|
|
|
|
{ 498, "md", "Moldova" },
|
|
|
|
|
{ 492, "mc", "Monaco" },
|
|
|
|
|
{ 496, "mn", "Mongolia" },
|
|
|
|
|
{ 500, "ms", "Montserrat" },
|
|
|
|
|
{ 504, "ma", "Morocco" },
|
|
|
|
|
{ 508, "mz", "Mozambique" },
|
|
|
|
|
{ 104, "mm", "Myanmar" },
|
|
|
|
|
{ 516, "na", "Namibia" },
|
|
|
|
|
{ 520, "nr", "Nauru" },
|
|
|
|
|
{ 524, "np", "Nepal" },
|
|
|
|
|
{ 528, "nl", "Netherlands" },
|
|
|
|
|
{ 530, "an", "Netherlands Antilles" },
|
|
|
|
|
{ 540, "nc", "New Caledonia" },
|
|
|
|
|
{ 554, "nz", "New Zealand" },
|
|
|
|
|
{ 558, "ni", "Nicaragua" },
|
|
|
|
|
{ 562, "ne", "Niger" },
|
|
|
|
|
{ 566, "ng", "Nigeria" },
|
|
|
|
|
{ 570, "nu", "Niue" },
|
|
|
|
|
{ 574, "nf", "Norfolk Island" },
|
|
|
|
|
{ 580, "mp", "Northern Mariana Islands" },
|
|
|
|
|
{ 578, "no", "Norway" },
|
|
|
|
|
{ 512, "om", "Oman" },
|
|
|
|
|
{ 586, "pk", "Pakistan" },
|
|
|
|
|
{ 585, "pw", "Palau" },
|
|
|
|
|
{ 275, "ps", "Palestinian Territory" },
|
|
|
|
|
{ 591, "pa", "Panama" },
|
|
|
|
|
{ 598, "pg", "Papua New Guinea" },
|
|
|
|
|
{ 600, "py", "Paraguay" },
|
|
|
|
|
{ 604, "pe", "Peru" },
|
|
|
|
|
{ 608, "ph", "Philippines" },
|
|
|
|
|
{ 612, "pn", "Pitcairn" },
|
|
|
|
|
{ 616, "pl", "Poland" },
|
|
|
|
|
{ 620, "pt", "Portugal" },
|
|
|
|
|
{ 630, "pr", "Puerto Rico" },
|
|
|
|
|
{ 634, "qa", "Qatar" },
|
|
|
|
|
{ 638, "re", "Reunion" },
|
|
|
|
|
{ 642, "ro", "Romania" },
|
|
|
|
|
{ 643, "ru", "Russia" },
|
|
|
|
|
{ 646, "rw", "Rwanda" },
|
|
|
|
|
{ 659, "kn", "Saint Kitts & Nevis" },
|
|
|
|
|
{ 662, "lc", "Saint Lucia" },
|
|
|
|
|
{ 670, "vc", "Saint Vincent" },
|
|
|
|
|
{ 882, "ws", "Samoa" },
|
|
|
|
|
{ 674, "sm", "San Marino" },
|
|
|
|
|
{ 678, "st", "Sao Tome & Principe" },
|
|
|
|
|
{ 682, "sa", "Saudi Arabia" },
|
|
|
|
|
{ 686, "sn", "Senegal" },
|
|
|
|
|
{ 891, "cs", "Serbia and Montenegro" },
|
|
|
|
|
{ 690, "sc", "Seychelles" },
|
|
|
|
|
{ 694, "sl", "Sierra Leone" },
|
|
|
|
|
{ 702, "sg", "Singapore" },
|
|
|
|
|
{ 703, "sk", "Slovakia" },
|
|
|
|
|
{ 705, "si", "Slovenia" },
|
|
|
|
|
{ 90, "sb", "Solomon Islands" },
|
|
|
|
|
{ 706, "so", "Somalia" },
|
|
|
|
|
{ 710, "za", "South Africa" },
|
|
|
|
|
{ 239, "gs", "South Georgia" },
|
|
|
|
|
{ 724, "es", "Spain" },
|
|
|
|
|
{ 144, "lk", "Sri Lanka" },
|
|
|
|
|
{ 654, "sh", "St. Helena" },
|
|
|
|
|
{ 666, "pm", "St. Pierre & Miquelon" },
|
|
|
|
|
{ 736, "sd", "Sudan" },
|
|
|
|
|
{ 740, "sr", "Suriname" },
|
|
|
|
|
{ 744, "sj", "Svalbard & Jan Mayen Islands" },
|
|
|
|
|
{ 748, "sz", "Swaziland" },
|
|
|
|
|
{ 752, "se", "Sweden" },
|
|
|
|
|
{ 756, "ch", "Switzerland" },
|
|
|
|
|
{ 760, "sy", "Syrian Arab Republic" },
|
|
|
|
|
{ 626, "tl", "Timor-Leste" },
|
|
|
|
|
{ 158, "tw", "Taiwan" },
|
|
|
|
|
{ 762, "tj", "Tajikistan" },
|
|
|
|
|
{ 834, "tz", "Tanzania" },
|
|
|
|
|
{ 764, "th", "Thailand" },
|
|
|
|
|
{ 768, "tg", "Togo" },
|
|
|
|
|
{ 772, "tk", "Tokelau" },
|
|
|
|
|
{ 776, "to", "Tonga" },
|
|
|
|
|
{ 780, "tt", "Trinidad & Tobago" },
|
|
|
|
|
{ 788, "tn", "Tunisia" },
|
|
|
|
|
{ 792, "tr", "Turkey" },
|
|
|
|
|
{ 795, "tm", "Turkmenistan" },
|
|
|
|
|
{ 796, "tc", "Turks & Caicos Islands" },
|
|
|
|
|
{ 798, "tv", "Tuvalu" },
|
|
|
|
|
{ 800, "ug", "Uganda" },
|
|
|
|
|
{ 804, "ua", "Ukraine" },
|
|
|
|
|
{ 784, "ae", "United Arab Emirates" },
|
|
|
|
|
{ 826, "gb", "United Kingdom" },
|
|
|
|
|
{ 840, "us", "United States" },
|
|
|
|
|
{ 581, "um", "United States Minor Outlying Islands" },
|
|
|
|
|
{ 858, "uy", "Uruguay" },
|
|
|
|
|
{ 860, "uz", "Uzbekistan" },
|
|
|
|
|
{ 548, "vu", "Vanuatu" },
|
|
|
|
|
{ 862, "ve", "Venezuela" },
|
|
|
|
|
{ 704, "vn", "Vietnam" },
|
|
|
|
|
{ 92, "vg", "Virgin Islands (British)" },
|
|
|
|
|
{ 850, "vi", "Virgin Islands (US)" },
|
|
|
|
|
{ 876, "wf", "Wallis & Futuna Islands" },
|
|
|
|
|
{ 732, "eh", "Western Sahara" },
|
|
|
|
|
{ 887, "ye", "Yemen" },
|
|
|
|
|
{ 894, "zm", "Zambia" },
|
|
|
|
|
{ 716, "zw", "Zimbabwe" }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check if start of 'str' is simply an IPv4 address.
|
|
|
|
|
*/
|
|
|
|
|
#define BYTE_OK(x) ((x) >= 0 && (x) <= 255)
|
|
|
|
|
|
|
|
|
|
static int is_addr(char *str, char **end)
|
|
|
|
|
{
|
|
|
|
|
int a0, a1, a2, a3, num, rc = 0, length = 0;
|
|
|
|
|
|
|
|
|
|
num = sscanf(str,"%3d.%3d.%3d.%3d%n",&a0,&a1,&a2,&a3,&length);
|
|
|
|
|
if( (num == 4) &&
|
|
|
|
|
BYTE_OK(a0) && BYTE_OK(a1) && BYTE_OK(a2) && BYTE_OK(a3) &&
|
|
|
|
|
length >= (3+4))
|
|
|
|
|
{
|
|
|
|
|
rc = 1;
|
|
|
|
|
*end = str + length;
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Find the country-code and name from the CNAME. E.g.:
|
|
|
|
|
* version 1: CNAME = zzno.countries.nerd.dk with address 127.0.2.66
|
|
|
|
|
* yields ccode_A" = "no" and cnumber 578 (2.66).
|
|
|
|
|
* version 2: CNAME = <a.b.c.d>.zz.countries.nerd.dk with address 127.0.2.66
|
|
|
|
|
* yields cnumber 578 (2.66). ccode_A is "";
|
|
|
|
|
*/
|
|
|
|
|
static void find_country_from_cname(const char *cname, struct in_addr addr)
|
|
|
|
|
{
|
|
|
|
|
const struct search_list *country;
|
|
|
|
|
char ccode_A2[3], *ccopy, *dot_4;
|
|
|
|
|
int cnumber, z0, z1, ver_1, ver_2;
|
|
|
|
|
unsigned long ip;
|
|
|
|
|
|
|
|
|
|
ip = ntohl(addr.s_addr);
|
|
|
|
|
z0 = TOLOWER(cname[0]);
|
|
|
|
|
z1 = TOLOWER(cname[1]);
|
|
|
|
|
ccopy = strdup(cname);
|
|
|
|
|
dot_4 = NULL;
|
|
|
|
|
|
|
|
|
|
ver_1 = (z0 == 'z' && z1 == 'z' && !strcasecmp(cname+4,nerd_ver1));
|
|
|
|
|
ver_2 = (is_addr(ccopy,&dot_4) && !strcasecmp(dot_4,nerd_ver2));
|
|
|
|
|
|
|
|
|
|
if (ver_1)
|
|
|
|
|
{
|
|
|
|
|
const char *dot = strchr(cname, '.');
|
|
|
|
|
if ((z0 != 'z' && z1 != 'z') || dot != cname+4)
|
|
|
|
|
{
|
|
|
|
|
printf("Unexpected CNAME %s (ver_1)\n", cname);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (ver_2)
|
|
|
|
|
{
|
|
|
|
|
z0 = TOLOWER(dot_4[1]);
|
|
|
|
|
z1 = TOLOWER(dot_4[2]);
|
|
|
|
|
if (z0 != 'z' && z1 != 'z')
|
|
|
|
|
{
|
|
|
|
|
printf("Unexpected CNAME %s (ver_2)\n", cname);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("Unexpected CNAME %s (ver?)\n", cname);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ver_1)
|
|
|
|
|
{
|
|
|
|
|
ccode_A2[0] = (char)TOLOWER(cname[2]);
|
|
|
|
|
ccode_A2[1] = (char)TOLOWER(cname[3]);
|
|
|
|
|
ccode_A2[2] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ccode_A2[0] = '\0';
|
|
|
|
|
|
|
|
|
|
cnumber = ip & 0xFFFF;
|
|
|
|
|
|
|
|
|
|
TRACE(("Found country-code `%s', number %d\n",
|
|
|
|
|
ver_1 ? ccode_A2 : "<n/a>", cnumber));
|
|
|
|
|
|
|
|
|
|
country = list_lookup(cnumber, country_list,
|
|
|
|
|
sizeof(country_list) / sizeof(country_list[0]));
|
|
|
|
|
if (!country)
|
|
|
|
|
printf("Name for country-number %d not found.\n", cnumber);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (ver_1)
|
|
|
|
|
{
|
|
|
|
|
if ((country->short_name[0] != ccode_A2[0]) ||
|
|
|
|
|
(country->short_name[1] != ccode_A2[1]) ||
|
|
|
|
|
(country->short_name[2] != ccode_A2[2]))
|
|
|
|
|
printf("short-name mismatch; %s vs %s\n",
|
|
|
|
|
country->short_name, ccode_A2);
|
|
|
|
|
}
|
|
|
|
|
printf("%s (%s), number %d.\n",
|
|
|
|
|
country->long_name, country->short_name, cnumber);
|
|
|
|
|
}
|
|
|
|
|
free(ccopy);
|
|
|
|
|
}
|
|
|
|
|
|