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