diff options
| author | Daniel Stenberg <daniel@haxx.se> | 2003-10-07 21:54:04 +0000 | 
|---|---|---|
| committer | Daniel Stenberg <daniel@haxx.se> | 2003-10-07 21:54:04 +0000 | 
| commit | 0436fbe226ca8ea71a751f4a86a228632e5cbc63 (patch) | |
| tree | 5cf6478e89608a8000bd36014ba4032bcc9c0528 /ares/adig.c | |
| parent | 6494889e3ba6b1432258f0a8ed402723607cff21 (diff) | |
ares 1.1.1 with collected applied patches
Diffstat (limited to 'ares/adig.c')
| -rw-r--r-- | ares/adig.c | 623 | 
1 files changed, 623 insertions, 0 deletions
| diff --git a/ares/adig.c b/ares/adig.c new file mode 100644 index 000000000..db7f32de2 --- /dev/null +++ b/ares/adig.c @@ -0,0 +1,623 @@ +/* Copyright 1998 by the Massachusetts Institute of Technology. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose.  It is provided "as is" + * without express or implied warranty. + */ + +static const char rcsid[] = "$Id$"; + +#include <sys/types.h> + +#ifdef WIN32 +#include "nameser.h" +#else +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <unistd.h> +#include <netdb.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include "ares.h" +#include "ares_dns.h" + +#ifndef INADDR_NONE +#define	INADDR_NONE 0xffffffff +#endif + +/* Mac OS X portability check */ +#ifndef T_SRV +#define T_SRV 33 /* server selection */ +#endif + +extern int optind; +extern char *optarg; + +struct nv { +  const char *name; +  int value; +}; + +static const struct nv flags[] = { +  { "usevc",		ARES_FLAG_USEVC }, +  { "primary",		ARES_FLAG_PRIMARY }, +  { "igntc",		ARES_FLAG_IGNTC }, +  { "norecurse",	ARES_FLAG_NORECURSE }, +  { "stayopen",		ARES_FLAG_STAYOPEN }, +  { "noaliases",	ARES_FLAG_NOALIASES } +}; +static const int nflags = sizeof(flags) / sizeof(flags[0]); + +static const struct nv classes[] = { +  { "IN",	C_IN }, +  { "CHAOS",	C_CHAOS }, +  { "HS",	C_HS }, +  { "ANY",	C_ANY } +}; +static const int nclasses = sizeof(classes) / sizeof(classes[0]); + +static const struct nv types[] = { +  { "A",	T_A }, +  { "NS",	T_NS }, +  { "MD",	T_MD }, +  { "MF",	T_MF }, +  { "CNAME",	T_CNAME }, +  { "SOA",	T_SOA }, +  { "MB",	T_MB }, +  { "MG",	T_MG }, +  { "MR",	T_MR }, +  { "NULL",	T_NULL }, +  { "WKS",	T_WKS }, +  { "PTR",	T_PTR }, +  { "HINFO",	T_HINFO }, +  { "MINFO",	T_MINFO }, +  { "MX",	T_MX }, +  { "TXT",	T_TXT }, +  { "RP",	T_RP }, +  { "AFSDB",	T_AFSDB }, +  { "X25",	T_X25 }, +  { "ISDN",	T_ISDN }, +  { "RT",	T_RT }, +  { "NSAP",	T_NSAP }, +  { "NSAP_PTR",	T_NSAP_PTR }, +  { "SIG",	T_SIG }, +  { "KEY",	T_KEY }, +  { "PX",	T_PX }, +  { "GPOS",	T_GPOS }, +  { "AAAA",	T_AAAA }, +  { "LOC",	T_LOC }, +  { "SRV",	T_SRV }, +  { "AXFR",	T_AXFR }, +  { "MAILB",	T_MAILB }, +  { "MAILA",	T_MAILA }, +  { "ANY",	T_ANY } +}; +static const int ntypes = sizeof(types) / sizeof(types[0]); + +static const char *opcodes[] = { +  "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY", +  "(unknown)", "(unknown)", "(unknown)", "(unknown)", +  "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA", +  "ZONEINIT", "ZONEREF" +}; + +static const char *rcodes[] = { +  "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED", +  "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)", +  "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE" +}; + +static void callback(void *arg, int status, unsigned char *abuf, int alen); +static const unsigned char *display_question(const unsigned char *aptr, +					     const unsigned char *abuf, +					     int alen); +static const unsigned char *display_rr(const unsigned char *aptr, +				       const unsigned char *abuf, int alen); +static const char *type_name(int type); +static const char *class_name(int dnsclass); +static void usage(void); + +int main(int argc, char **argv) +{ +  ares_channel channel; +  int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A; +  int status, nfds, count; +  struct ares_options options; +  struct hostent *hostent; +  fd_set read_fds, write_fds; +  struct timeval *tvp, tv; +  char *errmem; + +#ifdef WIN32 +  WORD wVersionRequested = MAKEWORD(1,1); +  WSADATA wsaData; +  WSAStartup(wVersionRequested, &wsaData); +#endif   + +  options.flags = ARES_FLAG_NOCHECKRESP; +  options.servers = NULL; +  options.nservers = 0; +  while ((c = getopt(argc, argv, "f:s:c:t:T:U:")) != -1) +    { +      switch (c) +	{ +	case 'f': +	  /* Add a flag. */ +	  for (i = 0; i < nflags; i++) +	    { +	      if (strcmp(flags[i].name, optarg) == 0) +		break; +	    } +	  if (i == nflags) +	    usage(); +	  options.flags |= flags[i].value; +	  break; + +	case 's': +	  /* Add a server, and specify servers in the option mask. */ +	  hostent = gethostbyname(optarg); +	  if (!hostent || hostent->h_addrtype != AF_INET) +	    { +	      fprintf(stderr, "adig: server %s not found.\n", optarg); +	      return 1; +	    } +	  options.servers = realloc(options.servers, (options.nservers + 1) +				    * sizeof(struct in_addr)); +	  if (!options.servers) +	    { +	      fprintf(stderr, "Out of memory!\n"); +	      return 1; +	    } +	  memcpy(&options.servers[options.nservers], hostent->h_addr, +		 sizeof(struct in_addr)); +	  options.nservers++; +	  optmask |= ARES_OPT_SERVERS; +	  break; + +	case 'c': +	  /* Set the query class. */ +	  for (i = 0; i < nclasses; i++) +	    { +	      if (strcasecmp(classes[i].name, optarg) == 0) +		break; +	    } +	  if (i == nclasses) +	    usage(); +	  dnsclass = classes[i].value; +	  break; + +	case 't': +	  /* Set the query type. */ +	  for (i = 0; i < ntypes; i++) +	    { +	      if (strcasecmp(types[i].name, optarg) == 0) +		break; +	    } +	  if (i == ntypes) +	    usage(); +	  type = types[i].value; +	  break; + +	case 'T': +	  /* Set the TCP port number. */ +	  if (!isdigit((unsigned char)*optarg)) +	    usage(); +	  options.tcp_port = strtol(optarg, NULL, 0); +	  optmask |= ARES_OPT_TCP_PORT; +	  break; + +	case 'U': +	  /* Set the UDP port number. */ +	  if (!isdigit((unsigned char)*optarg)) +	    usage(); +	  options.udp_port = strtol(optarg, NULL, 0); +	  optmask |= ARES_OPT_UDP_PORT; +	  break; +	} +    } +  argc -= optind; +  argv += optind; +  if (argc == 0) +    usage(); + +  status = ares_init_options(&channel, &options, optmask); + +  if (status != ARES_SUCCESS) +    { +      fprintf(stderr, "ares_init_options: %s\n", +	      ares_strerror(status, &errmem)); +      ares_free_errmem(errmem); +      return 1; +    } + +  /* Initiate the queries, one per command-line argument.  If there is +   * only one query to do, supply NULL as the callback argument; +   * otherwise, supply the query name as an argument so we can +   * distinguish responses for the user when printing them out. +   */ +  if (argc == 1) +    ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL); +  else +    { +      for (; *argv; argv++) +	ares_query(channel, *argv, dnsclass, type, callback, *argv); +    } + +  /* Wait for all queries to complete. */ +  while (1) +    { +      FD_ZERO(&read_fds); +      FD_ZERO(&write_fds); +      nfds = ares_fds(channel, &read_fds, &write_fds); +      if (nfds == 0) +	break; +      tvp = ares_timeout(channel, NULL, &tv); +      count = select(nfds, &read_fds, &write_fds, NULL, tvp); +      if (count < 0 && errno != EINVAL) +	{ +	  perror("select"); +	  return 1; +	} +      ares_process(channel, &read_fds, &write_fds); +    } + +  ares_destroy(channel); +  return 0; +} + +static void callback(void *arg, int status, unsigned char *abuf, int alen) +{ +  char *name = (char *) arg, *errmem; +  int id, qr, opcode, aa, tc, rd, ra, rcode, i; +  unsigned int qdcount, ancount, nscount, arcount; +  const unsigned char *aptr; + +  /* Display the query name if given. */ +  if (name) +    printf("Answer for query %s:\n", name); + +  /* Display an error message if there was an error, but only stop if +   * we actually didn't get an answer buffer. +   */ +  if (status != ARES_SUCCESS) +    { +      printf("%s\n", ares_strerror(status, &errmem)); +      ares_free_errmem(errmem); +      if (!abuf) +	return; +    } + +  /* Won't happen, but check anyway, for safety. */ +  if (alen < HFIXEDSZ) +    return; + +  /* Parse the answer header. */ +  id = DNS_HEADER_QID(abuf); +  qr = DNS_HEADER_QR(abuf); +  opcode = DNS_HEADER_OPCODE(abuf); +  aa = DNS_HEADER_AA(abuf); +  tc = DNS_HEADER_TC(abuf); +  rd = DNS_HEADER_RD(abuf); +  ra = DNS_HEADER_RA(abuf); +  rcode = DNS_HEADER_RCODE(abuf); +  qdcount = DNS_HEADER_QDCOUNT(abuf); +  ancount = DNS_HEADER_ANCOUNT(abuf); +  nscount = DNS_HEADER_NSCOUNT(abuf); +  arcount = DNS_HEADER_ARCOUNT(abuf); + +  /* Display the answer header. */ +  printf("id: %d\n", id); +  printf("flags: %s%s%s%s%s\n", +	 qr ? "qr " : "", +	 aa ? "aa " : "", +	 tc ? "tc " : "", +	 rd ? "rd " : "", +	 ra ? "ra " : ""); +  printf("opcode: %s\n", opcodes[opcode]); +  printf("rcode: %s\n", rcodes[rcode]); + +  /* Display the questions. */ +  printf("Questions:\n"); +  aptr = abuf + HFIXEDSZ; +  for (i = 0; i < qdcount; i++) +    { +      aptr = display_question(aptr, abuf, alen); +      if (aptr == NULL) +	return; +    } + +  /* Display the answers. */ +  printf("Answers:\n"); +  for (i = 0; i < ancount; i++) +    { +      aptr = display_rr(aptr, abuf, alen); +      if (aptr == NULL) +	return; +    } + +  /* Display the NS records. */ +  printf("NS records:\n"); +  for (i = 0; i < nscount; i++) +    { +      aptr = display_rr(aptr, abuf, alen); +      if (aptr == NULL) +	return; +    } + +  /* Display the additional records. */ +  printf("Additional records:\n"); +  for (i = 0; i < arcount; i++) +    { +      aptr = display_rr(aptr, abuf, alen); +      if (aptr == NULL) +	return; +    } +} + +static const unsigned char *display_question(const unsigned char *aptr, +					     const unsigned char *abuf, +					     int alen) +{ +  char *name; +  int type, dnsclass, status, len; + +  /* Parse the question name. */ +  status = ares_expand_name(aptr, abuf, alen, &name, &len); +  if (status != ARES_SUCCESS) +    return NULL; +  aptr += len; + +  /* Make sure there's enough data after the name for the fixed part +   * of the question. +   */ +  if (aptr + QFIXEDSZ > abuf + alen) +    { +      free(name); +      return NULL; +    } + +  /* Parse the question type and class. */ +  type = DNS_QUESTION_TYPE(aptr); +  dnsclass = DNS_QUESTION_CLASS(aptr); +  aptr += QFIXEDSZ; + +  /* Display the question, in a format sort of similar to how we will +   * display RRs. +   */ +  printf("\t%-15s.\t", name); +  if (dnsclass != C_IN) +    printf("\t%s", class_name(dnsclass)); +  printf("\t%s\n", type_name(type)); +  free(name); +  return aptr; +} + +static const unsigned char *display_rr(const unsigned char *aptr, +				       const unsigned char *abuf, int alen) +{ +  const unsigned char *p; +  char *name; +  int type, dnsclass, ttl, dlen, status, len; +  struct in_addr addr; + +  /* Parse the RR name. */ +  status = ares_expand_name(aptr, abuf, alen, &name, &len); +  if (status != ARES_SUCCESS) +    return NULL; +  aptr += len; + +  /* Make sure there is enough data after the RR name for the fixed +   * part of the RR. +   */ +  if (aptr + RRFIXEDSZ > abuf + alen) +    { +      free(name); +      return NULL; +    } + +  /* Parse the fixed part of the RR, and advance to the RR data +   * field. */ +  type = DNS_RR_TYPE(aptr); +  dnsclass = DNS_RR_CLASS(aptr); +  ttl = DNS_RR_TTL(aptr); +  dlen = DNS_RR_LEN(aptr); +  aptr += RRFIXEDSZ; +  if (aptr + dlen > abuf + alen) +    { +      free(name); +      return NULL; +    } + +  /* Display the RR name, class, and type. */ +  printf("\t%-15s.\t%d", name, ttl); +  if (dnsclass != C_IN) +    printf("\t%s", class_name(dnsclass)); +  printf("\t%s", type_name(type)); +  free(name); + +  /* Display the RR data.  Don't touch aptr. */ +  switch (type) +    { +    case T_CNAME: +    case T_MB: +    case T_MD: +    case T_MF: +    case T_MG: +    case T_MR: +    case T_NS: +    case T_PTR: +      /* For these types, the RR data is just a domain name. */ +      status = ares_expand_name(aptr, abuf, alen, &name, &len); +      if (status != ARES_SUCCESS) +	return NULL; +      printf("\t%s.", name); +      free(name); +      break; + +    case T_HINFO: +      /* The RR data is two length-counted character strings. */ +      p = aptr; +      len = *p; +      if (p + len + 1 > aptr + dlen) +	return NULL; +      printf("\t%.*s", len, p + 1); +      p += len + 1; +      len = *p; +      if (p + len + 1 > aptr + dlen) +	return NULL; +      printf("\t%.*s", len, p + 1); +      break; + +    case T_MINFO: +      /* The RR data is two domain names. */ +      p = aptr; +      status = ares_expand_name(p, abuf, alen, &name, &len); +      if (status != ARES_SUCCESS) +	return NULL; +      printf("\t%s.", name); +      free(name); +      p += len; +      status = ares_expand_name(p, abuf, alen, &name, &len); +      if (status != ARES_SUCCESS) +	return NULL; +      printf("\t%s.", name); +      free(name); +      break; + +    case T_MX: +      /* The RR data is two bytes giving a preference ordering, and +       * then a domain name. +       */ +      if (dlen < 2) +	return NULL; +      printf("\t%d", (aptr[0] << 8) | aptr[1]); +      status = ares_expand_name(aptr + 2, abuf, alen, &name, &len); +      if (status != ARES_SUCCESS) +	return NULL; +      printf("\t%s.", name); +      free(name); +      break; + +    case T_SOA: +      /* The RR data is two domain names and then five four-byte +       * numbers giving the serial number and some timeouts. +       */ +      p = aptr; +      status = ares_expand_name(p, abuf, alen, &name, &len); +      if (status != ARES_SUCCESS) +	return NULL; +      printf("\t%s.\n", name); +      free(name); +      p += len; +      status = ares_expand_name(p, abuf, alen, &name, &len); +      if (status != ARES_SUCCESS) +	return NULL; +      printf("\t\t\t\t\t\t%s.\n", name); +      free(name); +      p += len; +      if (p + 20 > aptr + dlen) +	return NULL; +      printf("\t\t\t\t\t\t( %d %d %d %d %d )", +	     (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3], +	     (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7], +	     (p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11], +	     (p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15], +	     (p[16] << 24) | (p[17] << 16) | (p[18] << 8) | p[19]); +      break; + +    case T_TXT: +      /* The RR data is one or more length-counted character +       * strings. */ +      p = aptr; +      while (p < aptr + dlen) +	{ +	  len = *p; +	  if (p + len + 1 > aptr + dlen) +	    return NULL; +	  printf("\t%.*s", len, p + 1); +	  p += len + 1; +	} +      break; + +    case T_A: +      /* The RR data is a four-byte Internet address. */ +      if (dlen != 4) +	return NULL; +      memcpy(&addr, aptr, sizeof(struct in_addr)); +      printf("\t%s", inet_ntoa(addr)); +      break; + +    case T_WKS: +      /* Not implemented yet */ +      break; + +    case T_SRV: +      /* The RR data is three two-byte numbers representing the +       * priority, weight, and port, followed by a domain name. +       */ +       +      printf("\t%d", DNS__16BIT(aptr)); +      printf(" %d", DNS__16BIT(aptr + 2)); +      printf(" %d", DNS__16BIT(aptr + 4)); +       +      status = ares_expand_name(aptr + 6, abuf, alen, &name, &len); +      if (status != ARES_SUCCESS) +        return NULL; +      printf("\t%s.", name); +      free(name); +      break; +       +    default: +      printf("\t[Unknown RR; cannot parse]"); +    } +  printf("\n"); + +  return aptr + dlen; +} + +static const char *type_name(int type) +{ +  int i; + +  for (i = 0; i < ntypes; i++) +    { +      if (types[i].value == type) +	return types[i].name; +    } +  return "(unknown)"; +} + +static const char *class_name(int dnsclass) +{ +  int i; + +  for (i = 0; i < nclasses; i++) +    { +      if (classes[i].value == dnsclass) +	return classes[i].name; +    } +  return "(unknown)"; +} + +static void usage(void) +{ +  fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] " +	  "[-t type] [-p port] name ...\n"); +  exit(1); +} | 
