Home | History | Annotate | Download | only in pending
      1 /* host.c - DNS lookup utility
      2  *
      3  * Copyright 2014 Rich Felker <dalias (at) aerifal.cx>
      4  *
      5  * No standard, but there's a version in bind9
      6 
      7 USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN))
      8 
      9 config HOST
     10   bool "host"
     11   default n
     12   help
     13     usage: host [-av] [-t TYPE] NAME [SERVER]
     14 
     15     Perform DNS lookup on NAME, which can be a domain name to lookup,
     16     or an ipv4 dotted or ipv6 colon seprated address to reverse lookup.
     17     SERVER (if present) is the DNS server to use.
     18 
     19     -a	no idea
     20     -t	not a clue
     21     -v	verbose
     22 */
     23 
     24 #define FOR_host
     25 #include "toys.h"
     26 
     27 GLOBALS(
     28   char *type_str;
     29 )
     30 
     31 #include <resolv.h>
     32 
     33 #define PL_IP 1
     34 #define PL_NAME 2
     35 #define PL_DATA 3
     36 #define PL_TEXT 4
     37 #define PL_SOA 5
     38 #define PL_MX 6
     39 #define PL_SRV 7
     40 
     41 static const struct rrt {
     42   const char *name;
     43   const char *msg;
     44   int pl;
     45   int af;
     46 } rrt[] = {
     47   [1] = { "A", "has address", PL_IP, AF_INET },
     48   [28] = { "AAAA", "has address", PL_IP, AF_INET6 },
     49   [2] = { "NS", "name server", PL_NAME },
     50   [5] = { "CNAME", "is a nickname for", PL_NAME },
     51   [16] = { "TXT", "descriptive text", PL_TEXT },
     52   [6] = { "SOA", "start of authority", PL_SOA },
     53   [12] = { "PTR", "domain name pointer", PL_NAME },
     54   [15] = { "MX", "mail is handled", PL_MX },
     55   [33] = { "SRV", "mail is handled", PL_SRV },
     56   [255] = { "*", 0, 0 },
     57 };
     58 
     59 static const char rct[16][32] = {
     60   "Success",
     61   "Format error",
     62   "Server failure",
     63   "Non-existant domain",
     64   "Not implemented",
     65   "Refused",
     66 };
     67 
     68 void host_main(void)
     69 {
     70   int verbose=(toys.optflags & (FLAG_a|FLAG_v)), type,
     71       i, j, ret, sec, count, rcode, qlen, alen, pllen = 0;
     72   unsigned ttl, pri, v[5];
     73   unsigned char qbuf[280], abuf[512], *p;
     74   char *name, *nsname, rrname[256], plname[640], ptrbuf[64];
     75   struct addrinfo *ai, iplit_hints = { .ai_flags = AI_NUMERICHOST };
     76 
     77   name = *toys.optargs;
     78   nsname = toys.optargs[1];
     79 
     80   if (!TT.type_str && (toys.optflags & FLAG_a)) TT.type_str = "255";
     81   if (!getaddrinfo(name, 0, &iplit_hints, &ai)) {
     82     unsigned char *a;
     83     static const char xdigits[] = "0123456789abcdef";
     84 
     85     if (ai->ai_family == AF_INET) {
     86       a = (void *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
     87       snprintf(ptrbuf, sizeof(ptrbuf), "%d.%d.%d.%d.in-addr.arpa",
     88         a[3], a[2], a[1], a[0]);
     89     } else if (ai->ai_family == AF_INET6) {
     90       a = (void *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
     91       for (j=0, i=15; i>=0; i--) {
     92         ptrbuf[j++] = xdigits[a[i]&15];
     93         ptrbuf[j++] = '.';
     94         ptrbuf[j++] = xdigits[a[i]>>4];
     95         ptrbuf[j++] = '.';
     96       }
     97       strcpy(ptrbuf+j, "ip6.arpa");
     98     }
     99     name = ptrbuf;
    100     if (!TT.type_str) TT.type_str="12";
    101   } else if (!TT.type_str) TT.type_str="1";
    102 
    103   if (TT.type_str[0]-'0' < 10u) type = atoi(TT.type_str);
    104   else {
    105     type = -1;
    106     for (i=0; i < sizeof rrt / sizeof *rrt; i++) {
    107       if (rrt[i].name && !strcasecmp(TT.type_str, rrt[i].name)) {
    108         type = i;
    109         break;
    110       }
    111     }
    112     if (!strcasecmp(TT.type_str, "any")) type = 255;
    113     if (type < 0) error_exit("Invalid query type: %s", TT.type_str);
    114   }
    115 
    116   qlen = res_mkquery(0, name, 1, type, 0, 0, 0, qbuf, sizeof qbuf);
    117   if (qlen < 0) error_exit("Invalid query parameters: %s", name);
    118 
    119   if (nsname) {
    120     struct addrinfo ns_hints = { .ai_socktype = SOCK_DGRAM };
    121 
    122     if ((ret = getaddrinfo(nsname, "53", &ns_hints, &ai)) < 0)
    123       error_exit("Error looking up server name: %s", gai_strerror(ret));
    124     int s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    125     if (s < 0 || connect(s, ai->ai_addr, ai->ai_addrlen) < 0)
    126       perror_exit("Socket error");
    127     setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &(struct timeval){ .tv_sec = 5 },
    128       sizeof(struct timeval));
    129     printf("Using domain server %s:\n", nsname);
    130     send(s, qbuf, qlen, 0);
    131     alen = recv(s, abuf, sizeof abuf, 0);
    132   } else alen = res_send(qbuf, qlen, abuf, sizeof abuf);
    133 
    134   if (alen < 12) error_exit("Host not found.");
    135 
    136   rcode = abuf[3] & 15;
    137 
    138   if (verbose) {
    139     printf("rcode = %d (%s), ancount = %d\n",
    140       rcode, rct[rcode], 256*abuf[6] + abuf[7]);
    141     if (!(abuf[2] & 4)) printf("The following answer is not authoritative:\n");
    142   }
    143 
    144   if (rcode) error_exit("Host not found.");
    145 
    146   p = abuf + 12;
    147   for (sec=0; sec<4; sec++) {
    148     count = 256*abuf[4+2*sec] + abuf[5+2*sec];
    149     if (verbose && count>0 && sec>1)
    150       puts(sec==2 ? "For authoritative answers, see:"
    151         : "Additional information:");
    152 
    153     for (; count--; p += pllen) {
    154       p += dn_expand(abuf, abuf+alen, p, rrname, sizeof(rrname));
    155       type = (p[0]<<8) + p[1];
    156       p += 4;
    157       if (!sec) continue;
    158       ttl = (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
    159       p += 4;
    160       pllen = (p[0]<<8) + p[1];
    161       p += 2;
    162 
    163       switch (type<sizeof(rrt)/sizeof(*rrt) ? rrt[type].pl : 0) {
    164       case PL_IP:
    165         inet_ntop(rrt[type].af, p, plname, sizeof plname);
    166         break;
    167       case PL_NAME:
    168         dn_expand(abuf, abuf+alen, p, plname, sizeof plname);
    169         break;
    170       case PL_TEXT:
    171         snprintf(plname, sizeof plname, "\"%.*s\"", pllen, p);
    172         break;
    173       case PL_SOA:
    174         i = dn_expand(abuf, abuf+alen, p, plname, sizeof plname - 1);
    175         strcat(plname, " ");
    176         i += dn_expand(abuf, abuf+alen, p+i, plname+strlen(plname),
    177           sizeof(plname)-strlen(plname));
    178         for (j=0; j<5; j++)
    179           v[j] = (p[i+4*j]<<24)+(p[1+i+4*j]<<16)+(p[2+i+4*j]<<8)+p[3+i+4*j];
    180         snprintf(plname+strlen(plname), sizeof(plname)-strlen(plname),
    181           "(\n\t\t%u\t;serial (version)\n"
    182           "\t\t%u\t;refresh period\n"
    183           "\t\t%u\t;retry interval\n"
    184           "\t\t%u\t;expire time\n"
    185           "\t\t%u\t;default ttl\n"
    186           "\t\t)", v[0], v[1], v[2], v[3], v[4]);
    187         break;
    188       case PL_MX:
    189         pri = (p[0]<<8)+p[1];
    190         snprintf(plname, sizeof(plname), verbose ? "%d " : "(pri=%d) by ", pri);
    191         dn_expand(abuf, abuf+alen, p+2, plname+strlen(plname),
    192           sizeof plname - strlen(plname));
    193         break;
    194       case PL_SRV:
    195         for (j=0; j<3; j++) v[j] = (p[2*j]<<8) + p[1+2*j];
    196         snprintf(plname, sizeof(plname), "%u %u %u ", v[0], v[1], v[2]);
    197         dn_expand(abuf, abuf+alen, p+6, plname+strlen(plname),
    198           sizeof plname - strlen(plname));
    199         break;
    200       default:
    201         printf("%s unsupported RR type %u\n", rrname, type);
    202         continue;
    203       }
    204 
    205       if (verbose)
    206         printf("%s\t%u\tIN %s\t%s\n", rrname, ttl, rrt[type].name, plname);
    207       else if (rrt[type].msg)
    208         printf("%s %s %s\n", rrname, rrt[type].msg, plname);
    209     }
    210     if (!verbose && sec==1) break;
    211   }
    212 
    213   toys.exitval = rcode;
    214 }
    215