#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <resolv.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define NAME 1
#define ADDR 2
#define CANN 4
#define ALIA 8
#define LABL 16
#define NUMB 32
#define HELP 64
#define RAWE 128
#define RESD 256
#define VERB 512

#define DEFAULT (LABL|0)

int main(int ac, char **av) {
  int options = DEFAULT;
  int aliasnum = -1;
  struct hostent *hostent;
  char *p = av[0];
  char *h = 0;

  int did_reset = 0;
  int got_options = 0;
  static char addrbuf[32];
  unsigned char a[4];
  int ai[4];
  int i;
  char x;

more:

  while (ac > 1) {
    av++; ac--;
    if (**av == '-') {
      while (*(++*av)) {
	switch (**av) {
	case 'a':		/* addresses only */
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ ADDR;
	  break;
	case 'c':		/* canonical entries only */
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ CANN;
	  break;
	case 'C':		/* number of aliases only */
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ NUMB;
	  break;
	case 'D':		/* debug resolver */
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ RESD;
	  break;
	case 'l':		/* only show aliases */
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ ALIA;
	  break;
	case 'n':		/* names only */
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ NAME;
	  break;
	case 'q':		/* toggle printing field labels */
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ LABL;
	  break;
	case 'r':		/* toggle printing raw hostent */
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ RAWE;
	  break;
	case 's':		/* specify server(s) */
	  if (!**av) {
	    if (--ac > 1) {
	      if (**++av == '-') 
		break;
	    } else {
	      break;
	    }
	  }
	  if (sscanf(*av, "%d.%d.%d.%d%c", &ai[0], &ai[1], &ai[2], &ai[3], &x) != 4
	      || ai[0] < 0 || ai[0] > 255 || ai[1] < 0 || ai[1] > 255
	      || ai[2] < 0 || ai[2] > 255 || ai[3] < 0 || ai[3] > 255) {
	    hostent  = gethostbyname(*av);
	    if (!hostent)
	      break;
	    for (i=0; i<4; i++)
	      ai[i] = hostent->h_addr_list[0][i];
	  }
	  for (i=0; i<4; i++)
	    a[i] = (unsigned char)(ai[i] & 0xFF);
	  snprintf(addrbuf, 32, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
	  if (!(did_reset++))
	    _res.nscount = 0;
	  _res.options |= RES_INIT;
	  _res.nsaddr_list[_res.nscount].sin_family = AF_INET;
	  _res.nsaddr_list[_res.nscount].sin_port = htons(53);
	  *(unsigned long *)&_res.nsaddr_list[_res.nscount++].sin_addr = inet_addr(addrbuf);
	  if (options & VERB)
	    printf("Server: %s -> %08x \n",addrbuf,inet_addr(addrbuf));
	  goto more;
	case 'A':		/* only show aliases */
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ ALIA;
	  break;
	case 'v':
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ VERB;
	  break;
	case '?':
	case 'h':
	  if (!got_options) {
	      options = DEFAULT;
	      got_options++;
	  }
	  options = options ^ HELP;
	  break;
	default:
	  if (isdigit(**av)) {	/* only show specific alias */
	    aliasnum = strtol(*av,0,0);
	    options = options & ~CANN;
	  }
	}
      }
    } else {
      h = *av;
    }
  }

  if (options & RESD)
    _res.options |= RES_DEBUG;

  if (!h || !*h || (options & HELP)) {
    fprintf(stderr,"Usage: %s [-{a,n,c,q,A,C,#,sIP}] {name,addr}\n",p);
    fprintf(stderr," a=addr n=name c=canonical q=nolabels A=aliases C=counts #=entry# s=server\n");
    exit(2);
  } else {	
    p = h;
  }

  if (p) {
    if (isdigit(*p)) {
      i = 0;
      do {
	a[i++] = strtoul(p,NULL,0L);
	p = strchr(p,'.');
      } while (p && isdigit(*++p) && i<4);
      if (i!=4) {
	fprintf(stderr,"Unable to parse host address %s\n",av[1]);
      }
      hostent = gethostbyaddr(a,4,AF_INET);
    } else {
      hostent  = gethostbyname(p);
    }
    if (!hostent) {
      perror("gethostbyname(2) failed");
      exit(1); 
    } else {
      int j;
      unsigned char u;
      
      if (options & RAWE) {
	  char **hptr;

	  printf("h_name = %s.\n",hostent->h_name ? hostent->h_name : "(null)");
	  hptr = hostent->h_aliases;
	  printf("h_aliases = \n");
	  j = 0;
	  while (*hptr) 
	      printf(" %d: %s.\n",j++,*hptr++);
	  printf("addrtype = %d (0x%08x)\n",hostent->h_addrtype,hostent->h_addrtype);
	  printf("addrlen = %d\n",hostent->h_length);
	  hptr = hostent->h_addr_list;
	  while (*hptr) {
	      unsigned char *cptr;
	      fputc(' ',stdout);
	      cptr = (unsigned char *)*hptr;
	      for (j=0; j<hostent->h_length; j++) 
		  printf("%d.",*cptr++);
	      cptr = (unsigned char *)*hptr;
	      printf(" = ");
	      for (j=0; j<hostent->h_length; j++) 
		  printf("%02x.",*cptr++);
	      fputc('\n',stdout);
	      hptr++;
	  }
      }
      if (options & NUMB) {
	int nalias, naddrs;
	
	nalias = naddrs = 0;
	for (i=0; hostent->h_aliases[i]; i++) {
	  nalias++;
	}
	for (i=0; hostent->h_addr_list[i]; i++) {
	  naddrs++;
	}
	if (!(options & NAME)) {
	  if (options & LABL) {
	    printf("addresses: %d",naddrs);
	  } else {
	    printf("%d",naddrs);
	  }
	}
	if (!(options & ADDR)) {
	  if (options & LABL) {
	    if (!(options & NAME)) 
	      putchar('\n');
	    printf("aliases: %d",nalias);    
	  } else {
	    if (!(options & NAME)) 
	      putchar(' ');
	    printf("%d",nalias);
	  }
	}
	putchar('\n');
	exit(0);
      }
	
      if (!(options & ADDR) && !(options & ALIA)) {
	if (!(options & NAME) && !(options & CANN) && (options & LABL)) {
	  printf("h_name: ");
	}
	printf("%s",hostent->h_name);
	if ((options & CANN))
	  putchar(' ');
	else
	  putchar('\n');
      }
      if (!(options & ADDR) && !(options & CANN)) {
	for (i=0; hostent->h_aliases[i]; i++) {
	  if (aliasnum<0 || aliasnum == i) {
	    if (options & LABL)
	      printf("h_aliases[%d]: ",i);
	    printf("%s\n",hostent->h_aliases[i]);
	  }
	}
	if ((options & ALIA))
	  exit(0);
      }
      if (!(options & ADDR) && !(options & CANN) && !(options & NAME)) {
	if (hostent->h_addrtype != AF_INET || hostent->h_length != 4)
	  printf("h_addrrtype: %d\nh_length: %d\n",hostent->h_addrtype,hostent->h_length);
      }
      if (!(options & NAME)) {
	for (i=0; hostent->h_addr_list[i]; i++) {
	  if (aliasnum<0 || aliasnum == i-1) {
	    if (!(options & ADDR) && !(options & CANN) && (options & LABL)) {
	      printf("h_addr_list[%u]: ",i);
	    }
	    u = hostent->h_addr_list[i][0];
	    printf("%u",u);
	    for (j=1; j<hostent->h_length; j++) {
	      putchar('.');
	      u = hostent->h_addr_list[i][j];
	      printf("%u",u);
	    }
	    putchar('\n');
	    if ((options & CANN)) 
	      break;
	  }
	}
      }
    }
  }
  if ((options & NAME) && (options & CANN))
    putchar('\n');
  exit(0);
}


syntax highlighted by Code2HTML, v. 0.9.1