[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

getaddrinfo and IPv6/IPv4 addresses



Hello,

In an application, I use getaddrinfo() with PF_INET6 in the hints
structure to look up addresses for a host that only has an IPv4 address
specified in /etc/hosts.

Sometimes, getaddrinfo() returns a proper IPv6 address of the form
::ffff:xx.xx.xx.xx, with the x'es being the IPv4 address. At other times,
the call to getaddrinfo() fails with the error EAI_NODATA, "No address
associated with hostname".

I can show some output from my home-written wrapper for getaddrinfo()
that also shows the problem:

h83% getaddrinfo -n h90
IPv4 130.236.239.90
h83% getaddrinfo -n h83
IPv6 ::ffff:130.236.239.83
IPv4 130.236.239.83
UNIX localhost
h83% getaddrinfo -n h90
IPv6 ::ffff:130.236.239.90
IPv4 130.236.239.90
h83% 

The commands were entered in the above sequence. Why does it give a
different result the first and last time? I have attached the source to
the getaddrinfo command in case it would help.

Both systems are debian potato using glibc 2.1.2. h90 runs a name server
and my 6bone tunnel.

I'd appreciate any input at all that could help me with this problem.

Regards,

Pontus

-- 
Pontus Lidman, pontus@mathcore.com, Software Engineer
No matter how cynical you get, it's impossible to keep up.
Scene: www.dc-s.com | MUD: tyme.envy.com 6969 | irc: irc.quakenet.eu.org
/*  getaddrinfo, a wrapper for the system call getaddrinfo(3)
    Version: 0.1

    Copyright (C) 2000 Pontus Lidman, pontus@lysator.liu.se

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <netinet/in.h>
#include <sys/un.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>

int numeric=0,verbose=0;

struct option options[]={

  { "passive",  no_argument,0,0 },
  { "canonical",no_argument,0,0 },  
  { "verbose",  no_argument,&verbose,1 },
  { "numeric",  no_argument,&numeric,1 },
  { 0,0,0,0 }
}; 

int option_index=0;

const char *proto_arr[]={
  "IPv4","IPv6","UNIX"
};

int main(int argc, char **argv) {

  struct addrinfo hints;
  struct addrinfo *resultp;
  char c;
  char *host=NULL;
  char *service=NULL;
  int err;
  struct sockaddr *sa;
  int size;
  int proto;
  int nameinfoflags=0;

  char hostbuf[NI_MAXHOST];
  char servbuf[NI_MAXSERV];

  while (1) {
    c=getopt_long(argc,argv,"pcvn",options,&option_index);
    if (c==-1) break;

    switch(c) {
    case 0:
      
    case 'n':
      numeric=1;
      break;
    case 'v':
      verbose=1;
      break;
    }
  }

  if (argc-optind < 1) {
    fprintf(stderr,"You must provide a hostname");
    exit(1);
  }

  host=argv[optind];
  if (argc-optind==2) {
    service=argv[optind+1];
  }

  if (numeric) nameinfoflags |= (NI_NUMERICHOST | NI_NUMERICSERV);

  bzero(&hints,sizeof(hints));
  hints.ai_family=PF_UNSPEC;
  if ((err=getaddrinfo(host,service,&hints,&resultp))) {
    fprintf(stderr,"%s\n",gai_strerror(err));
    exit(1);
  }

  while (resultp) {
    sa=resultp->ai_addr;
    size=0;
    switch(sa->sa_family) {
    case PF_INET:
      size=sizeof(struct sockaddr_in);
      proto=0;
      break;
    case PF_INET6:
      size=sizeof(struct sockaddr_in6);
      proto=1;
      break;
    case PF_LOCAL:
      size=sizeof(struct sockaddr_un);
      proto=2;
      break;
    default:
      fprintf(stderr,"Unknown protocol family in result: %d\n",sa->sa_family);
    }
    if (size) {
      if ((err=getnameinfo(sa,size,hostbuf,sizeof(hostbuf),servbuf,sizeof(servbuf),nameinfoflags))) {
	fprintf(stderr,"%s\n",gai_strerror(err));
      } else {
	if (service)
	  printf("%s %s %s\n",proto_arr[proto],hostbuf,servbuf);
	else
	  printf("%s %s\n",proto_arr[proto],hostbuf);
      }
    }
    
    resultp=resultp->ai_next;
  }
  
  freeaddrinfo(resultp);
  return 0;
}

Reply to: