acountry.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. /*
  2. * $Id$
  3. *
  4. * IP-address/hostname to country converter.
  5. *
  6. * Problem; you want to know where IP a.b.c.d is located.
  7. *
  8. * Use ares_gethostbyname ("d.c.b.a.zz.countries.nerd.dk")
  9. * and get the CNAME (host->h_name). Result will be:
  10. * CNAME = zz<CC>.countries.nerd.dk with address 127.0.x.y (ver 1) or
  11. * CNAME = <a.b.c.d>.zz.countries.nerd.dk with address 127.0.x.y (ver 2)
  12. *
  13. * The 2 letter country code in <CC> and the ISO-3166 country
  14. * number in x.y (number = x*256 + y). Version 2 of the protocol is missing
  15. * the <CC> number.
  16. *
  17. * Ref: http://countries.nerd.dk/more.html
  18. *
  19. * Written by G. Vanem <gvanem@broadpark.no> 2006, 2007
  20. *
  21. * NB! This program may not be big-endian aware.
  22. *
  23. * Permission to use, copy, modify, and distribute this
  24. * software and its documentation for any purpose and without
  25. * fee is hereby granted, provided that the above copyright
  26. * notice appear in all copies and that both that copyright
  27. * notice and this permission notice appear in supporting
  28. * documentation, and that the name of M.I.T. not be used in
  29. * advertising or publicity pertaining to distribution of the
  30. * software without specific, written prior permission.
  31. * M.I.T. makes no representations about the suitability of
  32. * this software for any purpose. It is provided "as is"
  33. * without express or implied warranty.
  34. */
  35. #include "setup.h"
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <stdarg.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #ifdef HAVE_UNISTD_H
  42. #include <unistd.h>
  43. #endif
  44. #ifdef HAVE_STRINGS_H
  45. #include <strings.h>
  46. #endif
  47. #if defined(WIN32) && !defined(WATT32)
  48. #include <winsock.h>
  49. #else
  50. #include <sys/socket.h>
  51. #include <arpa/inet.h>
  52. #include <netinet/in.h>
  53. #include <netdb.h>
  54. #endif
  55. #include "ares.h"
  56. #include "ares_getopt.h"
  57. #include "inet_net_pton.h"
  58. #include "inet_ntop.h"
  59. #ifndef HAVE_STRDUP
  60. # include "ares_strdup.h"
  61. # define strdup(ptr) ares_strdup(ptr)
  62. #endif
  63. #ifndef HAVE_STRCASECMP
  64. # include "ares_strcasecmp.h"
  65. # define strcasecmp(p1,p2) ares_strcasecmp(p1,p2)
  66. #endif
  67. #ifndef HAVE_STRNCASECMP
  68. # include "ares_strcasecmp.h"
  69. # define strncasecmp(p1,p2,n) ares_strncasecmp(p1,p2,n)
  70. #endif
  71. #ifndef INADDR_NONE
  72. #define INADDR_NONE 0xffffffff
  73. #endif
  74. static const char *usage = "acountry [-vh?] {host|addr} ...\n";
  75. static const char nerd_fmt[] = "%u.%u.%u.%u.zz.countries.nerd.dk";
  76. static const char *nerd_ver1 = nerd_fmt + 14;
  77. static const char *nerd_ver2 = nerd_fmt + 11;
  78. static int verbose = 0;
  79. #define TRACE(fmt) do { \
  80. if (verbose > 0) \
  81. printf fmt ; \
  82. } while (0)
  83. static void wait_ares(ares_channel channel);
  84. static void callback(void *arg, int status, int timeouts, struct hostent *host);
  85. static void callback2(void *arg, int status, int timeouts, struct hostent *host);
  86. static void find_country_from_cname(const char *cname, struct in_addr addr);
  87. static void Abort(const char *fmt, ...)
  88. {
  89. va_list args;
  90. va_start(args, fmt);
  91. vfprintf(stderr, fmt, args);
  92. va_end(args);
  93. exit(1);
  94. }
  95. int main(int argc, char **argv)
  96. {
  97. ares_channel channel;
  98. int ch, status;
  99. #if defined(WIN32) && !defined(WATT32)
  100. WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
  101. WSADATA wsaData;
  102. WSAStartup(wVersionRequested, &wsaData);
  103. #endif
  104. while ((ch = ares_getopt(argc, argv, "dvh?")) != -1)
  105. switch (ch)
  106. {
  107. case 'd':
  108. #ifdef WATT32
  109. dbug_init();
  110. #endif
  111. break;
  112. case 'v':
  113. verbose++;
  114. break;
  115. case 'h':
  116. case '?':
  117. default:
  118. Abort(usage);
  119. }
  120. argc -= optind;
  121. argv += optind;
  122. if (argc < 1)
  123. Abort(usage);
  124. status = ares_init(&channel);
  125. if (status != ARES_SUCCESS)
  126. {
  127. fprintf(stderr, "ares_init: %s\n", ares_strerror(status));
  128. return 1;
  129. }
  130. /* Initiate the queries, one per command-line argument. */
  131. for ( ; *argv; argv++)
  132. {
  133. struct in_addr addr;
  134. char buf[100];
  135. /* If this fails, assume '*argv' is a host-name that
  136. * must be resolved first
  137. */
  138. if (ares_inet_pton(AF_INET, *argv, &addr) != 1)
  139. {
  140. ares_gethostbyname(channel, *argv, AF_INET, callback2, &addr);
  141. wait_ares(channel);
  142. if (addr.s_addr == INADDR_NONE)
  143. {
  144. printf("Failed to lookup %s\n", *argv);
  145. continue;
  146. }
  147. }
  148. sprintf(buf, nerd_fmt,
  149. (unsigned int)(addr.s_addr >> 24),
  150. (unsigned int)((addr.s_addr >> 16) & 255),
  151. (unsigned int)((addr.s_addr >> 8) & 255),
  152. (unsigned int)(addr.s_addr & 255));
  153. TRACE(("Looking up %s...", buf));
  154. fflush(stdout);
  155. ares_gethostbyname(channel, buf, AF_INET, callback, buf);
  156. }
  157. wait_ares(channel);
  158. ares_destroy(channel);
  159. #if defined(WIN32) && !defined(WATT32)
  160. WSACleanup();
  161. #endif
  162. return 0;
  163. }
  164. /*
  165. * Wait for the queries to complete.
  166. */
  167. static void wait_ares(ares_channel channel)
  168. {
  169. while (1)
  170. {
  171. struct timeval *tvp, tv;
  172. fd_set read_fds, write_fds;
  173. int nfds;
  174. FD_ZERO(&read_fds);
  175. FD_ZERO(&write_fds);
  176. nfds = ares_fds(channel, &read_fds, &write_fds);
  177. if (nfds == 0)
  178. break;
  179. tvp = ares_timeout(channel, NULL, &tv);
  180. select(nfds, &read_fds, &write_fds, NULL, tvp);
  181. ares_process(channel, &read_fds, &write_fds);
  182. }
  183. }
  184. /*
  185. * This is the callback used when we have the IP-address of interest.
  186. * Extract the CNAME and figure out the country-code from it.
  187. */
  188. static void callback(void *arg, int status, int timeouts, struct hostent *host)
  189. {
  190. const char *name = (const char*)arg;
  191. const char *cname;
  192. char buf[20];
  193. (void)timeouts;
  194. if (!host || status != ARES_SUCCESS)
  195. {
  196. printf("Failed to lookup %s: %s\n", name, ares_strerror(status));
  197. return;
  198. }
  199. TRACE(("\nFound address %s, name %s\n",
  200. ares_inet_ntop(AF_INET,(const char*)host->h_addr,buf,sizeof(buf)),
  201. host->h_name));
  202. cname = host->h_name; /* CNAME gets put here */
  203. if (!cname)
  204. printf("Failed to get CNAME for %s\n", name);
  205. else
  206. find_country_from_cname(cname, *(struct in_addr*)host->h_addr);
  207. }
  208. /*
  209. * This is the callback used to obtain the IP-address of the host of interest.
  210. */
  211. static void callback2(void *arg, int status, int timeouts, struct hostent *host)
  212. {
  213. struct in_addr *addr = (struct in_addr*) arg;
  214. (void)timeouts;
  215. if (!host || status != ARES_SUCCESS)
  216. memset(addr, INADDR_NONE, sizeof(*addr));
  217. else
  218. memcpy(addr, host->h_addr, sizeof(*addr));
  219. }
  220. struct search_list {
  221. int country_number; /* ISO-3166 country number */
  222. char short_name[3]; /* A2 short country code */
  223. const char *long_name; /* normal country name */
  224. };
  225. static const struct search_list *list_lookup(int number, const struct search_list *list, int num)
  226. {
  227. while (num > 0 && list->long_name)
  228. {
  229. if (list->country_number == number)
  230. return (list);
  231. num--;
  232. list++;
  233. }
  234. return (NULL);
  235. }
  236. /*
  237. * Ref: ftp://ftp.ripe.net/iso3166-countrycodes.txt
  238. */
  239. static const struct search_list country_list[] = {
  240. { 4, "af", "Afghanistan" },
  241. { 248, "ax", "Åland Island" },
  242. { 8, "al", "Albania" },
  243. { 12, "dz", "Algeria" },
  244. { 16, "as", "American Samoa" },
  245. { 20, "ad", "Andorra" },
  246. { 24, "ao", "Angola" },
  247. { 660, "ai", "Anguilla" },
  248. { 10, "aq", "Antarctica" },
  249. { 28, "ag", "Antigua & Barbuda" },
  250. { 32, "ar", "Argentina" },
  251. { 51, "am", "Armenia" },
  252. { 533, "aw", "Aruba" },
  253. { 36, "au", "Australia" },
  254. { 40, "at", "Austria" },
  255. { 31, "az", "Azerbaijan" },
  256. { 44, "bs", "Bahamas" },
  257. { 48, "bh", "Bahrain" },
  258. { 50, "bd", "Bangladesh" },
  259. { 52, "bb", "Barbados" },
  260. { 112, "by", "Belarus" },
  261. { 56, "be", "Belgium" },
  262. { 84, "bz", "Belize" },
  263. { 204, "bj", "Benin" },
  264. { 60, "bm", "Bermuda" },
  265. { 64, "bt", "Bhutan" },
  266. { 68, "bo", "Bolivia" },
  267. { 70, "ba", "Bosnia & Herzegowina" },
  268. { 72, "bw", "Botswana" },
  269. { 74, "bv", "Bouvet Island" },
  270. { 76, "br", "Brazil" },
  271. { 86, "io", "British Indian Ocean Territory" },
  272. { 96, "bn", "Brunei Darussalam" },
  273. { 100, "bg", "Bulgaria" },
  274. { 854, "bf", "Burkina Faso" },
  275. { 108, "bi", "Burundi" },
  276. { 116, "kh", "Cambodia" },
  277. { 120, "cm", "Cameroon" },
  278. { 124, "ca", "Canada" },
  279. { 132, "cv", "Cape Verde" },
  280. { 136, "ky", "Cayman Islands" },
  281. { 140, "cf", "Central African Republic" },
  282. { 148, "td", "Chad" },
  283. { 152, "cl", "Chile" },
  284. { 156, "cn", "China" },
  285. { 162, "cx", "Christmas Island" },
  286. { 166, "cc", "Cocos Islands" },
  287. { 170, "co", "Colombia" },
  288. { 174, "km", "Comoros" },
  289. { 178, "cg", "Congo" },
  290. { 180, "cd", "Congo" },
  291. { 184, "ck", "Cook Islands" },
  292. { 188, "cr", "Costa Rica" },
  293. { 384, "ci", "Cote d'Ivoire" },
  294. { 191, "hr", "Croatia" },
  295. { 192, "cu", "Cuba" },
  296. { 196, "cy", "Cyprus" },
  297. { 203, "cz", "Czech Republic" },
  298. { 208, "dk", "Denmark" },
  299. { 262, "dj", "Djibouti" },
  300. { 212, "dm", "Dominica" },
  301. { 214, "do", "Dominican Republic" },
  302. { 218, "ec", "Ecuador" },
  303. { 818, "eg", "Egypt" },
  304. { 222, "sv", "El Salvador" },
  305. { 226, "gq", "Equatorial Guinea" },
  306. { 232, "er", "Eritrea" },
  307. { 233, "ee", "Estonia" },
  308. { 231, "et", "Ethiopia" },
  309. { 238, "fk", "Falkland Islands" },
  310. { 234, "fo", "Faroe Islands" },
  311. { 242, "fj", "Fiji" },
  312. { 246, "fi", "Finland" },
  313. { 250, "fr", "France" },
  314. { 249, "fx", "France, Metropolitan" },
  315. { 254, "gf", "French Guiana" },
  316. { 258, "pf", "French Polynesia" },
  317. { 260, "tf", "French Southern Territories" },
  318. { 266, "ga", "Gabon" },
  319. { 270, "gm", "Gambia" },
  320. { 268, "ge", "Georgia" },
  321. { 276, "de", "Germany" },
  322. { 288, "gh", "Ghana" },
  323. { 292, "gi", "Gibraltar" },
  324. { 300, "gr", "Greece" },
  325. { 304, "gl", "Greenland" },
  326. { 308, "gd", "Grenada" },
  327. { 312, "gp", "Guadeloupe" },
  328. { 316, "gu", "Guam" },
  329. { 320, "gt", "Guatemala" },
  330. { 324, "gn", "Guinea" },
  331. { 624, "gw", "Guinea-Bissau" },
  332. { 328, "gy", "Guyana" },
  333. { 332, "ht", "Haiti" },
  334. { 334, "hm", "Heard & Mc Donald Islands" },
  335. { 336, "va", "Vatican City" },
  336. { 340, "hn", "Honduras" },
  337. { 344, "hk", "Hong kong" },
  338. { 348, "hu", "Hungary" },
  339. { 352, "is", "Iceland" },
  340. { 356, "in", "India" },
  341. { 360, "id", "Indonesia" },
  342. { 364, "ir", "Iran" },
  343. { 368, "iq", "Iraq" },
  344. { 372, "ie", "Ireland" },
  345. { 376, "il", "Israel" },
  346. { 380, "it", "Italy" },
  347. { 388, "jm", "Jamaica" },
  348. { 392, "jp", "Japan" },
  349. { 400, "jo", "Jordan" },
  350. { 398, "kz", "Kazakhstan" },
  351. { 404, "ke", "Kenya" },
  352. { 296, "ki", "Kiribati" },
  353. { 408, "kp", "Korea (north)" },
  354. { 410, "kr", "Korea (south)" },
  355. { 414, "kw", "Kuwait" },
  356. { 417, "kg", "Kyrgyzstan" },
  357. { 418, "la", "Laos" },
  358. { 428, "lv", "Latvia" },
  359. { 422, "lb", "Lebanon" },
  360. { 426, "ls", "Lesotho" },
  361. { 430, "lr", "Liberia" },
  362. { 434, "ly", "Libya" },
  363. { 438, "li", "Liechtenstein" },
  364. { 440, "lt", "Lithuania" },
  365. { 442, "lu", "Luxembourg" },
  366. { 446, "mo", "Macao" },
  367. { 807, "mk", "Macedonia" },
  368. { 450, "mg", "Madagascar" },
  369. { 454, "mw", "Malawi" },
  370. { 458, "my", "Malaysia" },
  371. { 462, "mv", "Maldives" },
  372. { 466, "ml", "Mali" },
  373. { 470, "mt", "Malta" },
  374. { 584, "mh", "Marshall Islands" },
  375. { 474, "mq", "Martinique" },
  376. { 478, "mr", "Mauritania" },
  377. { 480, "mu", "Mauritius" },
  378. { 175, "yt", "Mayotte" },
  379. { 484, "mx", "Mexico" },
  380. { 583, "fm", "Micronesia" },
  381. { 498, "md", "Moldova" },
  382. { 492, "mc", "Monaco" },
  383. { 496, "mn", "Mongolia" },
  384. { 500, "ms", "Montserrat" },
  385. { 504, "ma", "Morocco" },
  386. { 508, "mz", "Mozambique" },
  387. { 104, "mm", "Myanmar" },
  388. { 516, "na", "Namibia" },
  389. { 520, "nr", "Nauru" },
  390. { 524, "np", "Nepal" },
  391. { 528, "nl", "Netherlands" },
  392. { 530, "an", "Netherlands Antilles" },
  393. { 540, "nc", "New Caledonia" },
  394. { 554, "nz", "New Zealand" },
  395. { 558, "ni", "Nicaragua" },
  396. { 562, "ne", "Niger" },
  397. { 566, "ng", "Nigeria" },
  398. { 570, "nu", "Niue" },
  399. { 574, "nf", "Norfolk Island" },
  400. { 580, "mp", "Northern Mariana Islands" },
  401. { 578, "no", "Norway" },
  402. { 512, "om", "Oman" },
  403. { 586, "pk", "Pakistan" },
  404. { 585, "pw", "Palau" },
  405. { 275, "ps", "Palestinian Territory" },
  406. { 591, "pa", "Panama" },
  407. { 598, "pg", "Papua New Guinea" },
  408. { 600, "py", "Paraguay" },
  409. { 604, "pe", "Peru" },
  410. { 608, "ph", "Philippines" },
  411. { 612, "pn", "Pitcairn" },
  412. { 616, "pl", "Poland" },
  413. { 620, "pt", "Portugal" },
  414. { 630, "pr", "Puerto Rico" },
  415. { 634, "qa", "Qatar" },
  416. { 638, "re", "Reunion" },
  417. { 642, "ro", "Romania" },
  418. { 643, "ru", "Russia" },
  419. { 646, "rw", "Rwanda" },
  420. { 659, "kn", "Saint Kitts & Nevis" },
  421. { 662, "lc", "Saint Lucia" },
  422. { 670, "vc", "Saint Vincent" },
  423. { 882, "ws", "Samoa" },
  424. { 674, "sm", "San Marino" },
  425. { 678, "st", "Sao Tome & Principe" },
  426. { 682, "sa", "Saudi Arabia" },
  427. { 686, "sn", "Senegal" },
  428. { 891, "cs", "Serbia and Montenegro" },
  429. { 690, "sc", "Seychelles" },
  430. { 694, "sl", "Sierra Leone" },
  431. { 702, "sg", "Singapore" },
  432. { 703, "sk", "Slovakia" },
  433. { 705, "si", "Slovenia" },
  434. { 90, "sb", "Solomon Islands" },
  435. { 706, "so", "Somalia" },
  436. { 710, "za", "South Africa" },
  437. { 239, "gs", "South Georgia" },
  438. { 724, "es", "Spain" },
  439. { 144, "lk", "Sri Lanka" },
  440. { 654, "sh", "St. Helena" },
  441. { 666, "pm", "St. Pierre & Miquelon" },
  442. { 736, "sd", "Sudan" },
  443. { 740, "sr", "Suriname" },
  444. { 744, "sj", "Svalbard & Jan Mayen Islands" },
  445. { 748, "sz", "Swaziland" },
  446. { 752, "se", "Sweden" },
  447. { 756, "ch", "Switzerland" },
  448. { 760, "sy", "Syrian Arab Republic" },
  449. { 626, "tl", "Timor-Leste" },
  450. { 158, "tw", "Taiwan" },
  451. { 762, "tj", "Tajikistan" },
  452. { 834, "tz", "Tanzania" },
  453. { 764, "th", "Thailand" },
  454. { 768, "tg", "Togo" },
  455. { 772, "tk", "Tokelau" },
  456. { 776, "to", "Tonga" },
  457. { 780, "tt", "Trinidad & Tobago" },
  458. { 788, "tn", "Tunisia" },
  459. { 792, "tr", "Turkey" },
  460. { 795, "tm", "Turkmenistan" },
  461. { 796, "tc", "Turks & Caicos Islands" },
  462. { 798, "tv", "Tuvalu" },
  463. { 800, "ug", "Uganda" },
  464. { 804, "ua", "Ukraine" },
  465. { 784, "ae", "United Arab Emirates" },
  466. { 826, "gb", "United Kingdom" },
  467. { 840, "us", "United States" },
  468. { 581, "um", "United States Minor Outlying Islands" },
  469. { 858, "uy", "Uruguay" },
  470. { 860, "uz", "Uzbekistan" },
  471. { 548, "vu", "Vanuatu" },
  472. { 862, "ve", "Venezuela" },
  473. { 704, "vn", "Vietnam" },
  474. { 92, "vg", "Virgin Islands (British)" },
  475. { 850, "vi", "Virgin Islands (US)" },
  476. { 876, "wf", "Wallis & Futuna Islands" },
  477. { 732, "eh", "Western Sahara" },
  478. { 887, "ye", "Yemen" },
  479. { 894, "zm", "Zambia" },
  480. { 716, "zw", "Zimbabwe" }
  481. };
  482. /*
  483. * Check if start of 'str' is simply an IPv4 address.
  484. */
  485. #define BYTE_OK(x) ((x) >= 0 && (x) <= 255)
  486. static int is_addr(char *str, char **end)
  487. {
  488. int a0, a1, a2, a3, num, rc = 0, length = 0;
  489. num = sscanf(str,"%3d.%3d.%3d.%3d%n",&a0,&a1,&a2,&a3,&length);
  490. if( (num == 4) &&
  491. BYTE_OK(a0) && BYTE_OK(a1) && BYTE_OK(a2) && BYTE_OK(a3) &&
  492. length >= (3+4))
  493. {
  494. rc = 1;
  495. *end = str + length;
  496. }
  497. return rc;
  498. }
  499. /*
  500. * Find the country-code and name from the CNAME. E.g.:
  501. * version 1: CNAME = zzno.countries.nerd.dk with address 127.0.2.66
  502. * yields ccode_A" = "no" and cnumber 578 (2.66).
  503. * version 2: CNAME = <a.b.c.d>.zz.countries.nerd.dk with address 127.0.2.66
  504. * yields cnumber 578 (2.66). ccode_A is "";
  505. */
  506. static void find_country_from_cname(const char *cname, struct in_addr addr)
  507. {
  508. const struct search_list *country;
  509. char ccode_A2[3], *ccopy, *dot_4;
  510. int cnumber, z0, z1, ver_1, ver_2;
  511. unsigned long ip;
  512. ip = ntohl(addr.s_addr);
  513. z0 = tolower(cname[0]);
  514. z1 = tolower(cname[1]);
  515. ccopy = strdup(cname);
  516. dot_4 = NULL;
  517. ver_1 = (z0 == 'z' && z1 == 'z' && !strcasecmp(cname+4,nerd_ver1));
  518. ver_2 = (is_addr(ccopy,&dot_4) && !strcasecmp(dot_4,nerd_ver2));
  519. if (ver_1)
  520. {
  521. const char *dot = strchr(cname, '.');
  522. if ((z0 != 'z' && z1 != 'z') || dot != cname+4)
  523. {
  524. printf("Unexpected CNAME %s (ver_1)\n", cname);
  525. return;
  526. }
  527. }
  528. else if (ver_2)
  529. {
  530. z0 = tolower(dot_4[1]);
  531. z1 = tolower(dot_4[2]);
  532. if (z0 != 'z' && z1 != 'z')
  533. {
  534. printf("Unexpected CNAME %s (ver_2)\n", cname);
  535. return;
  536. }
  537. }
  538. else
  539. {
  540. printf("Unexpected CNAME %s (ver?)\n", cname);
  541. return;
  542. }
  543. if (ver_1)
  544. {
  545. ccode_A2[0] = (char)tolower(cname[2]);
  546. ccode_A2[1] = (char)tolower(cname[3]);
  547. ccode_A2[2] = '\0';
  548. }
  549. else
  550. ccode_A2[0] = '\0';
  551. cnumber = ip & 0xFFFF;
  552. TRACE(("Found country-code `%s', number %d\n",
  553. ver_1 ? ccode_A2 : "<n/a>", cnumber));
  554. country = list_lookup(cnumber, country_list,
  555. sizeof(country_list) / sizeof(country_list[0]));
  556. if (!country)
  557. printf("Name for country-number %d not found.\n", cnumber);
  558. else
  559. {
  560. if (ver_1 && *(unsigned short*)&country->short_name != *(unsigned*)&ccode_A2)
  561. printf("short-name mismatch; %s vs %s\n", country->short_name, ccode_A2);
  562. printf("%s (%s), number %d.\n",
  563. country->long_name, country->short_name, cnumber);
  564. }
  565. free(ccopy);
  566. }