Subject: IPv6 with gethostbyname2 and gethostbyaddr
To: None <tech-net@netbsd.org>
From: Jeremy C. Reed <reed@reedmedia.net>
List: tech-net
Date: 07/04/2002 11:17:39
(If this is the wrong list, please let me know about a better one.)

I read that gethostbyname2 and gethostbyaddr for IPv6 is being deprecated
and that I should use getaddrinfo or getnodebyname instead. And inet_aton
manual recommends getaddrinfo and getnameinfo for IPv6.

But how can I get gethostbyname2 and gethostbyaddr to work for IPv6?

Here are some examples:

 $ ./a.out -6 ::1
 Hostname: ::1
 Address: 0.0.0.0
 $ ./a.out -6 -x ::1
 Problem looking up "::1": Resolver Error 0 (no error)
 $ ./a.out -6 localhost
 Hostname: localhost
 Address: 0.0.0.0

I wanted the above to return:
 Hostname: localhost
 Address: ::1

 $ ./a.out -6 -x 3ffe:8050:201:1860:290:27ff:feab:19a7:
 Problem looking up "3ffe:8050:201:1860:290:27ff:feab:19a7:": Resolver
 Error 0 (no error)

I was hoping that would return something like:
 Hostname: www.netbsd.org
 Address: 3ffe:8050:201:1860:290:27ff:feab:19a7:

My /etc/hosts has:
::1                    localhost

My /etc/nsswitch.conf has:
hosts:          files dns

My code is below signature. Any suggestions? Or should I just use
getaddrinfo, getnameinfo or getnodebyname?

   Jeremy C. Reed
   http://bsd.reedmedia.net/

#include <string.h>
#include <stdio.h>
#include <netdb.h>       /* gethostbyname() and related */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>  /* AF_INET manifest constant */
#include <stdlib.h>

int main(argc, argv)
  int argc;
  char *argv[];
{
  char *hostname = NULL;
  int addrtype;
  int rval = 0, reverse = 0, ipv6 = 0;
  struct sockaddr_in name;

  if (argc == 1) {
    fprintf (stderr, "gethost: neither action flags nor hostname given.\n");
    exit(1);
  }

  while (*++argv) {
    if (*argv[0] == '-') {
      if (!strcmp(*argv, "-x")) {
        reverse = 1;
        continue;
      }
      if (!strcmp(*argv, "-6")) {
        ipv6 = 1;
        continue;
      }
    }

    hostname = (char *)malloc(strlen(*argv) + 1);
    if (hostname) {
      strncpy(hostname, *argv, strlen(*argv));
    }

  }

  if (hostname) {
    struct hostent *h;

    if (reverse && 0 == inet_aton(hostname, &name.sin_addr)) {
      fprintf(stderr,
              "Problem looking up \"%s\": %s\n", hostname, hstrerror(h_errno));
      exit (1);
    }

    if (ipv6 || strchr(hostname, ':')) addrtype = AF_INET6;
    else addrtype = AF_INET;

    if (reverse) h = gethostbyaddr((char *) &name.sin_addr,
                                   sizeof(&name.sin_addr), addrtype);
    else h = gethostbyname2(hostname, addrtype);

    if (h) {
      int idx = 0;

      printf("Hostname: %s\n", h->h_name);
      while (h->h_aliases[idx])
        printf("Alias: %s\n", h->h_aliases[idx++]);
      switch (h->h_addrtype) {
        case AF_INET:
        case AF_INET6:
          for (idx = 0; h->h_addr_list[idx]; ++idx)
            printf("Address: %u.%u.%u.%u\n",
                    (0xff & h->h_addr_list[idx][0]),
                    (0xff & h->h_addr_list[idx][1]),
                    (0xff & h->h_addr_list[idx][2]),
                    (0xff & h->h_addr_list[idx][3]) );
          break;
        default:
          break;
      }
    } else {
      /* not all OSes have h_errno & hstrerror() - Solaris doesn't */
       fprintf(stderr,
               "Problem looking up \"%s\": %s\n", hostname, hstrerror(h_errno));
       rval = 1;
    }

  }

  free(hostname);
  return(rval);
}