Subject: Re: IPv6 with gethostbyname2 and gethostbyaddr
To: Jeremy C. Reed <reed@reedmedia.net>
From: None <itojun@iijlab.net>
List: tech-net
Date: 07/05/2002 06:03:12
>(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:

	i see three problems in your code:
	- use of inet_aton(3), which is IPv4 only.  use inet_pton(3) instead.
	- hardcoded use of sockaddr_in.  sockaddr_in6 is bigger than
	  sockaddr_in, so it won't fit.
	- misuse of strncpy - strncpy does not terminate copied buffer with \0

	here's the working version so far, but i really recommend you to
	use getaddrinfo/getnameinfo, it's easier and clean.
	the code is not totally correct as it passes numeric form (::1)
	to gethostbyname2(), which does not work.

itojun


#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 = AF_INET;
  int rval = 0, reverse = 0, ipv6 = 0;
  union {
    struct in6_addr in6;
    struct in_addr in;
  } addrbuf;
  char buf[128];

  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;
	addrtype = AF_INET6;
        continue;
      }
    }

    hostname = (char *)malloc(strlen(*argv) + 1);
    if (hostname) {
      strncpy(hostname, *argv, strlen(*argv));
      hostname[strlen(*argv)] = '\0';
    }

  }

  if (hostname) {
    struct hostent *h;

    if (reverse && 0 == inet_pton(addrtype, hostname, &addrbuf)) {
      fprintf(stderr,
              "Problem looking up \"%s\": %s\n", hostname, hstrerror(h_errno));
      exit (1);
    }

    if (ipv6 || strchr(hostname, ':'))

    if (reverse)
      h = gethostbyaddr(addrtype == AF_INET ? &addrbuf.in : &addrbuf.in6,
	addrtype == AF_INET ? sizeof(addrbuf.in) : sizeof(addrbuf.in6),
	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) {
	    inet_ntop(addrtype, h->h_addr_list[idx], buf, sizeof(buf));
            printf("Address: %s\n", buf);
	  }
          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);
}