host.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /* host.c - DNS lookup utility
  2. *
  3. * Copyright 2014 Rich Felker <dalias@aerifal.cx>
  4. *
  5. * No standard, but there's a version in bind9
  6. * See https://www.ietf.org/rfc/rfc1035.txt
  7. * See https://www.ietf.org/rfc/rfc3596.txt
  8. USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN))
  9. config HOST
  10. bool "host"
  11. default y
  12. help
  13. usage: host [-v] [-t TYPE] NAME [SERVER]
  14. Look up DNS records for NAME, either domain name or IPv4/IPv6 address to
  15. reverse lookup, from SERVER or default DNS server(s).
  16. -a All records
  17. -t TYPE Record TYPE (number or ANY A AAAA CNAME MX NS PTR SOA SRV TXT)
  18. -v Verbose
  19. */
  20. #define FOR_host
  21. #include "toys.h"
  22. #include <resolv.h>
  23. GLOBALS(
  24. char *t;
  25. char **nsname;
  26. unsigned nslen;
  27. )
  28. static const struct rrt {
  29. char *name, *msg;
  30. int type;
  31. } rrt[] = { { "A", "has address", 1 }, { "NS", "name server", 2 },
  32. { "CNAME", "is a nickname for", 5 }, { "SOA", "start of authority", 6 },
  33. { "PTR", "domain name pointer", 12 }, { "MX", "mail is handled", 15 },
  34. { "TXT", "descriptive text", 16 }, { "AAAA", "has address", 28 },
  35. { "SRV", "mail is handled", 33 }
  36. };
  37. int xdn_expand(char *packet, char *endpkt, char *comp, char *expand, int elen)
  38. {
  39. int i = dn_expand(packet, endpkt, comp, expand, elen);
  40. if (i<1) error_exit("bad dn_expand");
  41. return i;
  42. }
  43. // Fetch "nameserve" lines from /etc/resolv.conf. Ignores 'options' lines
  44. static void get_nsname(char **pline, long len)
  45. {
  46. char *line, *p;
  47. if (!len) return;
  48. line = *pline;
  49. if (strstart(&line, "nameserver") && isspace(*line)) {
  50. while (isspace(*line)) line++;
  51. for (p = line; *p && !isspace(*p) && *p!='#'; p++);
  52. if (p == line) return;
  53. *p = 0;
  54. if (!(TT.nslen&8))
  55. TT.nsname = xrealloc(TT.nsname, (TT.nslen+8)*sizeof(void *));
  56. TT.nsname[TT.nslen++] = xstrdup(line);
  57. }
  58. }
  59. void host_main(void)
  60. {
  61. int verbose = FLAG(a)||FLAG(v), type, abuf_len = 65536, //Largest TCP response
  62. i, j, sec, rcode, qlen, alen QUIET, pllen = 0, t2len = 2048;
  63. unsigned count, ttl;
  64. char *abuf = xmalloc(abuf_len), *name = *toys.optargs, *p, *ss,
  65. *t2 = toybuf+t2len;
  66. struct addrinfo *ai;
  67. // What kind of query are we doing?
  68. if (!TT.t && FLAG(a)) TT.t = "255";
  69. if (!getaddrinfo(name, 0,&(struct addrinfo){.ai_flags=AI_NUMERICHOST}, &ai)) {
  70. name = toybuf;
  71. if (ai->ai_family == AF_INET) {
  72. p = (void *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
  73. sprintf(name, "%d.%d.%d.%d.in-addr.arpa", p[3], p[2], p[1], p[0]);
  74. } else if (ai->ai_family == AF_INET6) {
  75. p = (void *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
  76. for (j = 0, i = 15; i>=0; i--)
  77. j += sprintf(name+j, "%x.%x.", p[i]&15, p[i]>>4);
  78. strcpy(name+j, "ip6.arpa");
  79. }
  80. if (!TT.t) TT.t = "12";
  81. } else if (!TT.t) TT.t = "1";
  82. // Prepare query packet of appropriate type
  83. if (TT.t[0]-'0'<10) type = atoi(TT.t); // TODO
  84. else if (!strcasecmp(TT.t, "any") || strcmp(TT.t, "*")) type = 255;
  85. else {
  86. for (i = 0; i<ARRAY_LEN(rrt); i++) if (!strcasecmp(TT.t, rrt[i].name)) {
  87. type = rrt[i].type;
  88. break;
  89. }
  90. if (i == ARRAY_LEN(rrt)) error_exit("bad -t: %s", TT.t);
  91. }
  92. qlen = res_mkquery(0, name, 1, type, 0, 0, 0, t2, 280); //t2len);
  93. if (qlen<0) error_exit("bad NAME: %s", name);
  94. // Grab nameservers
  95. if (toys.optargs[1]) TT.nsname = toys.optargs+1;
  96. else do_lines(xopen("/etc/resolv.conf", O_RDONLY), '\n', get_nsname);
  97. if (!TT.nsname) error_exit("No nameservers");
  98. // Send one query packet to each server until we receive response
  99. while (*TT.nsname) {
  100. if (verbose) printf("Using domain server %s:\n", *TT.nsname);
  101. ai = xgetaddrinfo(*TT.nsname, "53", 0, SOCK_DGRAM, 0, 0);
  102. i = xsocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  103. xconnect(i, ai->ai_addr, ai->ai_addrlen);
  104. setsockopt(i, SOL_SOCKET, SO_RCVTIMEO, &(struct timeval){ .tv_sec = 5 },
  105. sizeof(struct timeval));
  106. send(i, t2, qlen, 0);
  107. if (16 < (alen = recv(i, abuf, abuf_len, 0))) break;
  108. if (!*++TT.nsname) error_exit("Host not found.");
  109. close(i);
  110. }
  111. // Did it error?
  112. rcode = abuf[3]&7;
  113. if (verbose) {
  114. printf("rcode = %d, ancount = %d\n", rcode, (int)peek_be(abuf+6, 2));
  115. if (!(abuf[2]&4)) puts("The following answer is not authoritative:");
  116. }
  117. if (rcode) error_exit("Host not found: %s",
  118. (char *[]){ "Format error", "Server failure",
  119. "Non-existant domain", "Not implemented", "Refused", ""}[rcode-1]);
  120. // Print the result
  121. p = abuf + 12;
  122. for (sec = 0; sec<(2<<verbose); sec++) {
  123. count = peek_be(abuf+4+2*sec, 2);
  124. if (verbose && count>0 && sec>1)
  125. puts(sec==2 ? "For authoritative answers, see:"
  126. : "Additional information:");
  127. for (; count--; p += pllen) {
  128. p += xdn_expand(abuf, abuf+alen, p, toybuf, 4096-t2len);
  129. if (alen-(p-abuf)<10) error_exit("tilt");
  130. type = peek_be(p, 2);
  131. p += 4;
  132. if (!sec) continue;
  133. ttl = peek_be(p, 4);
  134. p += 4;
  135. pllen = peek_be(p, 2);
  136. p += 2;
  137. if ((p-abuf)+pllen>alen) error_exit("tilt");
  138. if (type==1 || type == 28)
  139. inet_ntop(type==1 ? AF_INET : AF_INET6, p, t2, t2len);
  140. else if (type==2 || type==5) xdn_expand(abuf, abuf+alen, p, t2, t2len);
  141. else if (type==16) sprintf(t2, "\"%.*s\"", minof(pllen, t2len), p);
  142. else if (type==6) {
  143. ss = p+xdn_expand(abuf, abuf+alen, p, t2, t2len-1);
  144. j = strlen(t2);
  145. t2[j++] = ' ';
  146. ss += xdn_expand(abuf, abuf+alen, ss, t2+j, t2len-j);
  147. j += strlen(t2+j);
  148. snprintf(t2+j, t2len-j, "(\n\t\t%u\t;serial (version)\n\t\t%u\t"
  149. ";refresh period\n\t\t%u\t;retry interval\n\t\t%u\t;expire time\n"
  150. "\t\t%u\t;default ttl\n\t\t)", (unsigned)peek_be(ss, 4),
  151. (unsigned)peek_be(ss+4, 4), (unsigned)peek_be(ss+8, 4),
  152. (unsigned)peek_be(ss+12, 4), (unsigned)peek_be(ss+16, 4));
  153. } else if (type==15) {
  154. j = peek_be(p, 2);
  155. j = sprintf(t2, verbose ? "%d " : "(pri=%d) by ", j);
  156. xdn_expand(abuf, abuf+alen, p+2, t2+j, t2len-j);
  157. } else if (type==33) {
  158. j = sprintf(t2, "%u %u %u ", (int)peek_be(p, 2), (int)peek_be(p+2, 2),
  159. (int)peek_be(p+4, 2));
  160. xdn_expand(abuf, abuf+alen, p+6, t2+j, t2len-j);
  161. } else {
  162. printf("%s unsupported RR type %u\n", toybuf, type);
  163. continue;
  164. }
  165. for (i = 0; rrt[i].type != type; i++);
  166. if (verbose) printf("%s\t%u\tIN %s\t%s\n", toybuf, ttl, rrt[i].name, t2);
  167. else printf("%s %s %s\n", toybuf, rrt[type].msg, t2);
  168. }
  169. }
  170. if (CFG_TOYBOX_FREE) free(abuf);
  171. toys.exitval = rcode;
  172. }