PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/nslook.c

https://gitlab.com/jyrgenn/nslook-c
C | 424 lines | 362 code | 41 blank | 21 comment | 71 complexity | dde1f98656014a6c02525586cde351a6 MD5 | raw file
  1. /*
  2. * nslook.c - simple, concise address and host name lookup. Actually
  3. * this is just a front end to getaddrinfo()/getnameinfo().
  4. */
  5. #define __USE_GNU
  6. #define __USE_POSIX /* and still no AI_IDN... */
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <arpa/inet.h>
  10. #include <netinet/in.h>
  11. #include <netdb.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #include <sysexits.h>
  17. #include <errno.h>
  18. #include "version.h" /* for VERSION */
  19. #define F_SHORT 0
  20. #define F_LONG 1
  21. #define F_MEDIUM 2
  22. #define F_AIDUMP 3 /* extensive struct addrinfo dump */
  23. #define MAXDOMAINNAMELEN 255 /* according to RFC 1034 */
  24. char *progname;
  25. int show_usage = 0; /* show usage if non-zero */
  26. int reverse = 0; /* do reverse mapping */
  27. int canonical_name = 0; /* look for canonical name */
  28. int format = F_SHORT; /* output format */
  29. char *input = NULL; /* file to take input from */
  30. int one_result = 0; /* show one result only (for scripts) */
  31. int resolve_v4 = 1; /* resolve to IPv4 addresses */
  32. int resolve_v6 = 1; /* resolve to IPv6 addresses */
  33. int had_errors = 0; /* non-zero if errors were seen */
  34. char *ip_dotted(unsigned long *addrp); /* Return dotted decimal notation. */
  35. void usage(void);
  36. void do_lookup (char *astring);
  37. int lookup_address(char *astring);
  38. void lookup_name(char *name);
  39. const char *get_ipaddr(struct sockaddr *sa, socklen_t salen);
  40. const char *get_hostname(struct addrinfo *ai);
  41. void dump_addrinfo(struct addrinfo *ai);
  42. const char *ptr_or(char *ptr, char *alt);
  43. void display_result(char *name, const char *ipaddr, struct addrinfo *ai);
  44. const char *str_ai_flags(int ai_flags);
  45. const char *str_ai_family(int ai_family);
  46. const char *str_ai_socktype(int ai_socktype);
  47. const char *str_ai_protocol(int ai_protocol);
  48. int main(int argc, char **argv)
  49. {
  50. int opt; /* option character */
  51. char *cp;
  52. FILE *in;
  53. char buffer[2048]; /* hope this won't break */
  54. progname = argv[0];
  55. if ((cp = strrchr(progname, '/'))) {
  56. progname = cp + 1;
  57. }
  58. while ((opt = getopt(argc, argv, "146clmrf:xV")) != -1) {
  59. switch (opt) {
  60. case '1':
  61. one_result = 1;
  62. break;
  63. case 'x':
  64. format = F_AIDUMP;
  65. break;
  66. case '4':
  67. resolve_v6 = 0;
  68. break;
  69. case '6':
  70. resolve_v4 = 0;
  71. break;
  72. case 'l': /* long */
  73. format = F_LONG;
  74. break;
  75. case 'm': /* medium output format */
  76. format = F_MEDIUM;
  77. break;
  78. case 'f': /* read arguments from file or stdin */
  79. input = optarg;
  80. break;
  81. case 'r': /* normal and reverse mapping */
  82. reverse = 1;
  83. break;
  84. case 'c': /* canonical name */
  85. canonical_name = 1;
  86. break;
  87. case 'V': /* print version */
  88. puts(VERSION);
  89. exit(0);
  90. break;
  91. case '?': /* give usage message */
  92. show_usage++;
  93. break;
  94. }
  95. }
  96. if (show_usage || optind > argc || (input == NULL && optind >= argc)) {
  97. usage();
  98. exit(EX_USAGE);
  99. }
  100. if (input) {
  101. if (strcmp(input, "-")) {
  102. if ((in = fopen(input, "r")) == NULL) {
  103. fprintf(stderr, "%s: cannot open %s: %s\n",
  104. progname, input, strerror(errno));
  105. }
  106. } else {
  107. in = stdin;
  108. }
  109. while (fscanf(in, "%s", buffer) != EOF) {
  110. do_lookup(buffer);
  111. }
  112. } else {
  113. while (optind < argc) {
  114. do_lookup(argv[optind++]);
  115. }
  116. }
  117. return had_errors ? EX_NOHOST : EX_OK;
  118. }
  119. void do_lookup (char *astring)
  120. {
  121. if (!lookup_address(astring)) {
  122. lookup_name(astring);
  123. }
  124. }
  125. /* Try to interpret the argument string as an IPv4 or IPv6 address, look it up,
  126. * and show the result. If the argument string does not contain the textual
  127. * representation of an IP address, return 0, otherwise 1.
  128. *
  129. */
  130. int lookup_address(char *astring)
  131. {
  132. int isv6addr = 0;
  133. struct sockaddr *sa_ptr; /* points to sa_v4 or sa_v6 */
  134. socklen_t salen; /* length of *sa_ptr */
  135. char hostname[MAXDOMAINNAMELEN+1]; /* host name buffer */
  136. int error; /* ... of getnameinfo() */
  137. /* 1st try: parse string into v4 address */
  138. struct in_addr v4addr;
  139. struct in6_addr v6addr;
  140. memset(&v4addr, 0, sizeof(v4addr));
  141. if (!inet_pton(AF_INET, astring, &v4addr)) {
  142. memset(&v6addr, 0, sizeof(v6addr));
  143. if (!inet_pton(AF_INET6, astring, &v6addr)) {
  144. /* not an IPv6 address either, so return failure */
  145. return 0;
  146. } else {
  147. isv6addr = 1;
  148. }
  149. }
  150. if (isv6addr) {
  151. struct sockaddr_in6 sa_v6;
  152. memset(&sa_v6, 0, sizeof(sa_v6));
  153. sa_v6.sin6_family = AF_INET6;
  154. memcpy(&sa_v6.sin6_addr, &v6addr, sizeof(v6addr));
  155. sa_ptr = (struct sockaddr *) &sa_v6;
  156. salen = sizeof(sa_v6);
  157. } else {
  158. struct sockaddr_in sa_v4;
  159. memset(&sa_v4, 0, sizeof(sa_v4));
  160. sa_v4.sin_family = AF_INET;
  161. memcpy(&sa_v4.sin_addr, &v4addr, sizeof(v4addr));
  162. sa_ptr = (struct sockaddr *) &sa_v4;
  163. salen = sizeof(sa_v4);
  164. }
  165. error = getnameinfo(sa_ptr, salen, hostname, sizeof(hostname),
  166. NULL, 0, 0);
  167. if (error) {
  168. fprintf(stderr, "%s: %s: %s\n",
  169. progname, astring, gai_strerror(error));
  170. had_errors++;
  171. return 0;
  172. }
  173. if (canonical_name) {
  174. puts(hostname);
  175. } else {
  176. const char *ipaddr = get_ipaddr(sa_ptr, salen);
  177. switch (format) {
  178. case F_LONG:
  179. printf("hostname: %s\n", hostname);
  180. printf("ip address: %s\n", ipaddr);
  181. break;
  182. case F_MEDIUM:
  183. printf("%-39s %s\n", ipaddr, hostname);
  184. break;
  185. case F_SHORT:
  186. puts(hostname);
  187. break;
  188. }
  189. }
  190. return 1;
  191. }
  192. /* Look up the argument hostname and display the result(s) as requested by the
  193. * user.
  194. */
  195. void lookup_name(char *name)
  196. {
  197. int error;
  198. struct addrinfo hints;
  199. struct addrinfo *ai_result;
  200. memset(&hints, 0, sizeof(hints));
  201. if (!resolve_v4) {
  202. hints.ai_family = AF_INET6;
  203. } else if (!resolve_v6) {
  204. hints.ai_family = AF_INET;
  205. } else {
  206. hints.ai_family = AF_UNSPEC;
  207. }
  208. if (canonical_name) {
  209. hints.ai_flags |= AI_CANONNAME;
  210. }
  211. /* try to find host entry */
  212. error = getaddrinfo(name, NULL, &hints, &ai_result);
  213. if (error) {
  214. fprintf(stderr, "%s: %s: %s\n",
  215. progname, name, gai_strerror(error));
  216. had_errors++;
  217. return;
  218. }
  219. if (canonical_name && format == F_SHORT) {
  220. puts(ai_result->ai_canonname);
  221. } else {
  222. const char *prev_ipaddr = "";
  223. if (format == F_LONG) {
  224. printf("query: %s\n", name);
  225. }
  226. while (ai_result) {
  227. const char *ipaddr = get_ipaddr(ai_result->ai_addr,
  228. ai_result->ai_addrlen);
  229. if (strcmp(ipaddr, prev_ipaddr) || format == F_AIDUMP) {
  230. display_result(name, ipaddr, ai_result);
  231. }
  232. if (one_result) {
  233. return;
  234. }
  235. prev_ipaddr = strdup(ipaddr);
  236. ai_result = ai_result->ai_next;
  237. }
  238. }
  239. }
  240. void display_result(char *name, const char *ipaddr, struct addrinfo *ai)
  241. {
  242. char *hostname = ai->ai_canonname;
  243. switch (format) {
  244. case F_LONG:
  245. if (hostname) {
  246. printf("hostname: %s\n",
  247. hostname);
  248. }
  249. printf("ip address: %s\n", ipaddr);
  250. if (reverse) {
  251. printf("reverse: %s\n",
  252. get_hostname(ai));
  253. }
  254. break;
  255. case F_MEDIUM:
  256. if (!hostname) {
  257. hostname = name;
  258. }
  259. printf("%-39s %s\n", ipaddr, hostname);
  260. break;
  261. case F_SHORT:
  262. printf("%s\n", ipaddr);
  263. break;
  264. case F_AIDUMP:
  265. dump_addrinfo(ai);
  266. }
  267. }
  268. void dump_addrinfo(struct addrinfo *ai)
  269. {
  270. printf("%-13s 0x%x %s\n", "ai_flags:",
  271. ai->ai_flags, str_ai_flags(ai->ai_flags));
  272. printf("%-13s %s\n", "ai_family:", str_ai_family(ai->ai_family));
  273. printf("%-13s %s\n", "ai_socktype:", str_ai_socktype(ai->ai_socktype));
  274. printf("%-13s %s\n", "ai_protocol:", str_ai_protocol(ai->ai_protocol));
  275. printf("%-13s %d\n", "ai_addrlen:", ai->ai_addrlen);
  276. printf("%-13s %s\n", "ai_addr:",
  277. get_ipaddr(ai->ai_addr, ai->ai_addrlen));
  278. printf("%-13s %s\n", "ai_canonname:", ptr_or(ai->ai_canonname, 0));
  279. printf("%-13s %p\n\n", "ai_next:", ptr_or((char *) ai->ai_next, 0));
  280. }
  281. const char *str_ai_flags(int ai_flags)
  282. {
  283. static char buf[300];
  284. buf[0] = 0;
  285. if (ai_flags & AI_V4MAPPED) strcat(buf, " AI_V4MAPPED");
  286. if (ai_flags & AI_ADDRCONFIG) strcat(buf, " AI_ADDRCONFIG");
  287. if (ai_flags & AI_NUMERICHOST) strcat(buf, " AI_NUMERICHOST");
  288. if (ai_flags & AI_PASSIVE) strcat(buf, " AI_PASSIVE");
  289. if (ai_flags & AI_NUMERICSERV) strcat(buf, " AI_NUMERICSERV");
  290. if (ai_flags & AI_CANONNAME) strcat(buf, " AI_CANONNAME");
  291. if (ai_flags & AI_ALL) strcat(buf, " AI_ALL");
  292. #ifdef AI_IDN
  293. if (ai_flags & AI_IDN) strcat(buf, " AI_IDN");
  294. if (ai_flags & AI_CANONIDN) strcat(buf, " AI_CANONIDN");
  295. if (ai_flags & AI_IDN_ALLOW_UNASSIGNED) {
  296. strcat(buf, " AI_IDN_ALLOW_UNASSIGNED");
  297. }
  298. if (ai_flags & AI_IDN_USE_STD3_ASCII_RULES) {
  299. strcat(buf, " AI_IDN_USE_STD3_ASCII_RULES");
  300. }
  301. #endif /* AI_IDN */
  302. return buf;
  303. }
  304. const char *str_ai_family(int ai_family)
  305. {
  306. static char buf[100];
  307. switch (ai_family) {
  308. case AF_INET: return "AF_INET";
  309. case AF_INET6: return "AF_INET6";
  310. case AF_UNSPEC: return "AF_UNSPEC";
  311. default:
  312. snprintf(buf, 100, "unknown (%d)", ai_family);
  313. return buf;
  314. }
  315. }
  316. const char *str_ai_socktype(int ai_socktype)
  317. {
  318. static char buf[100];
  319. switch (ai_socktype) {
  320. case SOCK_STREAM: return "SOCK_STREAM";
  321. case SOCK_DGRAM: return "SOCK_DGRAM";
  322. case SOCK_RAW: return "SOCK_RAW";
  323. case 0: return "0";
  324. default:
  325. snprintf(buf, 100, "unknown (%d)", ai_socktype);
  326. return buf;
  327. }
  328. }
  329. const char *str_ai_protocol(int ai_protocol)
  330. {
  331. static char buf[100];
  332. struct protoent *pe = getprotobynumber(ai_protocol);
  333. if (pe) {
  334. return pe->p_name;
  335. } else {
  336. snprintf(buf, 100, "unknown (%d)", ai_protocol);
  337. return buf;
  338. }
  339. }
  340. const char *ptr_or(char *ptr, char *alt)
  341. {
  342. if (ptr) {
  343. return ptr;
  344. } else if (alt) {
  345. return alt;
  346. } else {
  347. return "<null>";
  348. }
  349. }
  350. void usage(void)
  351. {
  352. fprintf(stderr, "\
  353. Usage: %s [-146clmrx] hostname ...\n\
  354. %s [-146clmrx] IP-address ...\n\
  355. %s [-146clmrx] -f file\n",
  356. progname, progname, progname);
  357. }
  358. /* return IP address string of a sockaddr.
  359. */
  360. const char *get_ipaddr(struct sockaddr *sa, socklen_t salen)
  361. {
  362. static char buffer[256];
  363. if (getnameinfo(sa, salen, buffer, sizeof(buffer), NULL, 0,
  364. NI_NUMERICHOST) == 0)
  365. {
  366. return buffer;
  367. }
  368. return "unknown";
  369. }
  370. /* return host name of a sockaddr, NULL if no hostname associated with the
  371. * address or if reverse lookup is disabled
  372. */
  373. const char *get_hostname(struct addrinfo *ai)
  374. {
  375. static char name[MAXDOMAINNAMELEN+1];
  376. if (!getnameinfo(ai->ai_addr, ai->ai_addrlen, name, sizeof(name),
  377. NULL, 0, NI_NAMEREQD))
  378. {
  379. return name;
  380. }
  381. return "(none)";
  382. }
  383. /* EOF */