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