|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/* tests/resolve/addrinfo-test.c */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Copyright 2004 by the Massachusetts Institute of Technology.
|
|
Packit |
fd8b60 |
* All Rights Reserved.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Export of this software from the United States of America may
|
|
Packit |
fd8b60 |
* require a specific license from the United States Government.
|
|
Packit |
fd8b60 |
* It is the responsibility of any person or organization contemplating
|
|
Packit |
fd8b60 |
* export to obtain such a license before exporting.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
|
Packit |
fd8b60 |
* distribute this software and its documentation for any purpose and
|
|
Packit |
fd8b60 |
* without fee is hereby granted, provided that the above copyright
|
|
Packit |
fd8b60 |
* notice appear in all copies and that both that copyright notice and
|
|
Packit |
fd8b60 |
* this permission notice appear in supporting documentation, and that
|
|
Packit |
fd8b60 |
* the name of M.I.T. not be used in advertising or publicity pertaining
|
|
Packit |
fd8b60 |
* to distribution of the software without specific, written prior
|
|
Packit |
fd8b60 |
* permission. Furthermore if you modify this software you must label
|
|
Packit |
fd8b60 |
* your software as modified software and not distribute it in such a
|
|
Packit |
fd8b60 |
* fashion that it might be confused with the original M.I.T. software.
|
|
Packit |
fd8b60 |
* M.I.T. makes no representations about the suitability of
|
|
Packit |
fd8b60 |
* this software for any purpose. It is provided "as is" without express
|
|
Packit |
fd8b60 |
* or implied warranty.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* A simple program to test the functionality of the getaddrinfo function.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Usage:
|
|
Packit |
fd8b60 |
* addrinfo-test [-t|-u|-R|-I] [-d|-s|-r] [-p port] [-P] [hostname]
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* When invoked with no arguments, NULL is used for the node name,
|
|
Packit |
fd8b60 |
* which (at least with a non-null "port") means a socket address
|
|
Packit |
fd8b60 |
* is desired that can be used with connect() or bind() (depending
|
|
Packit |
fd8b60 |
* on whether "-P" is given).
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <k5-platform.h>
|
|
Packit |
fd8b60 |
#include <sys/types.h>
|
|
Packit |
fd8b60 |
#include <sys/socket.h>
|
|
Packit |
fd8b60 |
#include <netdb.h>
|
|
Packit |
fd8b60 |
#include <netinet/in.h> /* needed for IPPROTO_* on NetBSD */
|
|
Packit |
fd8b60 |
#ifdef USE_FAKE_ADDRINFO
|
|
Packit |
fd8b60 |
#include "fake-addrinfo.h"
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static const char *protoname (int p) {
|
|
Packit |
fd8b60 |
static char buf[30];
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#define X(N) if (p == IPPROTO_ ## N) return #N
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
X(TCP);
|
|
Packit |
fd8b60 |
X(UDP);
|
|
Packit |
fd8b60 |
X(ICMP);
|
|
Packit |
fd8b60 |
#ifdef IPPROTO_IPV6
|
|
Packit |
fd8b60 |
X(IPV6);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#ifdef IPPROTO_GRE
|
|
Packit |
fd8b60 |
X(GRE);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#ifdef IPPROTO_NONE
|
|
Packit |
fd8b60 |
X(NONE);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
X(RAW);
|
|
Packit |
fd8b60 |
#ifdef IPPROTO_COMP
|
|
Packit |
fd8b60 |
X(COMP);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
snprintf(buf, sizeof(buf), " %-2d", p);
|
|
Packit |
fd8b60 |
return buf;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static const char *socktypename (int t) {
|
|
Packit |
fd8b60 |
static char buf[30];
|
|
Packit |
fd8b60 |
switch (t) {
|
|
Packit |
fd8b60 |
case SOCK_DGRAM: return "DGRAM";
|
|
Packit |
fd8b60 |
case SOCK_STREAM: return "STREAM";
|
|
Packit |
fd8b60 |
case SOCK_RAW: return "RAW";
|
|
Packit |
fd8b60 |
case SOCK_RDM: return "RDM";
|
|
Packit |
fd8b60 |
case SOCK_SEQPACKET: return "SEQPACKET";
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
snprintf(buf, sizeof(buf), " %-2d", t);
|
|
Packit |
fd8b60 |
return buf;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static char *whoami;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void usage () {
|
|
Packit |
fd8b60 |
fprintf(stderr,
|
|
Packit |
fd8b60 |
"usage:\n"
|
|
Packit |
fd8b60 |
"\t%s [ options ] [host]\n"
|
|
Packit |
fd8b60 |
"options:\n"
|
|
Packit |
fd8b60 |
"\t-t\tspecify protocol IPPROTO_TCP\n"
|
|
Packit |
fd8b60 |
"\t-u\tspecify protocol IPPROTO_UDP\n"
|
|
Packit |
fd8b60 |
"\t-R\tspecify protocol IPPROTO_RAW\n"
|
|
Packit |
fd8b60 |
"\t-I\tspecify protocol IPPROTO_ICMP\n"
|
|
Packit |
fd8b60 |
"\n"
|
|
Packit |
fd8b60 |
"\t-d\tspecify socket type SOCK_DGRAM\n"
|
|
Packit |
fd8b60 |
"\t-s\tspecify socket type SOCK_STREAM\n"
|
|
Packit |
fd8b60 |
"\t-r\tspecify socket type SOCK_RAW\n"
|
|
Packit |
fd8b60 |
"\n"
|
|
Packit |
fd8b60 |
"\t-4\tspecify address family AF_INET\n"
|
|
Packit |
fd8b60 |
#ifdef AF_INET6
|
|
Packit |
fd8b60 |
"\t-6\tspecify address family AF_INET6\n"
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
"\n"
|
|
Packit |
fd8b60 |
"\t-p P\tspecify port P (service name or port number)\n"
|
|
Packit |
fd8b60 |
"\t-N\thostname is numeric, skip DNS query\n"
|
|
Packit |
fd8b60 |
"\t-n\tservice/port is numeric (sets AI_NUMERICSERV)\n"
|
|
Packit |
fd8b60 |
"\t-P\tset AI_PASSIVE\n"
|
|
Packit |
fd8b60 |
"\n"
|
|
Packit |
fd8b60 |
"default: protocol 0, socket type 0, address family 0, null port\n"
|
|
Packit |
fd8b60 |
,
|
|
Packit |
fd8b60 |
whoami);
|
|
Packit |
fd8b60 |
/* [ -t | -u | -R | -I ] [ -d | -s | -r ] [ -p port ] */
|
|
Packit |
fd8b60 |
exit (1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static const char *familyname (int f) {
|
|
Packit |
fd8b60 |
static char buf[30];
|
|
Packit |
fd8b60 |
switch (f) {
|
|
Packit |
fd8b60 |
default:
|
|
Packit |
fd8b60 |
snprintf(buf, sizeof(buf), "AF %d", f);
|
|
Packit |
fd8b60 |
return buf;
|
|
Packit |
fd8b60 |
case AF_INET: return "AF_INET";
|
|
Packit |
fd8b60 |
#ifdef AF_INET6
|
|
Packit |
fd8b60 |
case AF_INET6: return "AF_INET6";
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#define eaistr(X) (X == EAI_SYSTEM ? strerror(errno) : gai_strerror(X))
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
int main (int argc, char *argv[])
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct addrinfo *ap, *ap2;
|
|
Packit |
fd8b60 |
int err, numerichost = 0, numericserv = 0;
|
|
Packit |
fd8b60 |
char *hname, *port = 0, *sep;
|
|
Packit |
fd8b60 |
struct addrinfo hints;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
whoami = strrchr(argv[0], '/');
|
|
Packit |
fd8b60 |
if (whoami == 0)
|
|
Packit |
fd8b60 |
whoami = argv[0];
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
whoami = whoami+1;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
memset(&hints, 0, sizeof(hints));
|
|
Packit |
fd8b60 |
hints.ai_flags = 0;
|
|
Packit |
fd8b60 |
hints.ai_socktype = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hname = 0;
|
|
Packit |
fd8b60 |
hints.ai_family = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (argc == 1)
|
|
Packit |
fd8b60 |
usage ();
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
while (++argv, --argc > 0) {
|
|
Packit |
fd8b60 |
char *arg;
|
|
Packit |
fd8b60 |
arg = *argv;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (*arg != '-')
|
|
Packit |
fd8b60 |
hname = arg;
|
|
Packit |
fd8b60 |
else if (arg[1] == 0 || arg[2] != 0)
|
|
Packit |
fd8b60 |
usage ();
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
switch (arg[1]) {
|
|
Packit |
fd8b60 |
case 'u':
|
|
Packit |
fd8b60 |
hints.ai_protocol = IPPROTO_UDP;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 't':
|
|
Packit |
fd8b60 |
hints.ai_protocol = IPPROTO_TCP;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'R':
|
|
Packit |
fd8b60 |
hints.ai_protocol = IPPROTO_RAW;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'I':
|
|
Packit |
fd8b60 |
hints.ai_protocol = IPPROTO_ICMP;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'd':
|
|
Packit |
fd8b60 |
hints.ai_socktype = SOCK_DGRAM;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 's':
|
|
Packit |
fd8b60 |
hints.ai_socktype = SOCK_STREAM;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'r':
|
|
Packit |
fd8b60 |
hints.ai_socktype = SOCK_RAW;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'p':
|
|
Packit |
fd8b60 |
if (argv[1] == 0 || argv[1][0] == 0 || argv[1][0] == '-')
|
|
Packit |
fd8b60 |
usage ();
|
|
Packit |
fd8b60 |
port = argv[1];
|
|
Packit |
fd8b60 |
argc--, argv++;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case '4':
|
|
Packit |
fd8b60 |
hints.ai_family = AF_INET;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
#ifdef AF_INET6
|
|
Packit |
fd8b60 |
case '6':
|
|
Packit |
fd8b60 |
hints.ai_family = AF_INET6;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
case 'N':
|
|
Packit |
fd8b60 |
numerichost = 1;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'n':
|
|
Packit |
fd8b60 |
numericserv = 1;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'P':
|
|
Packit |
fd8b60 |
hints.ai_flags |= AI_PASSIVE;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
default:
|
|
Packit |
fd8b60 |
usage ();
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (hname && !numerichost)
|
|
Packit |
fd8b60 |
hints.ai_flags |= AI_CANONNAME;
|
|
Packit |
fd8b60 |
if (numerichost) {
|
|
Packit |
fd8b60 |
#ifdef AI_NUMERICHOST
|
|
Packit |
fd8b60 |
hints.ai_flags |= AI_NUMERICHOST;
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
fprintf(stderr, "AI_NUMERICHOST not defined on this platform\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (numericserv) {
|
|
Packit |
fd8b60 |
#ifdef AI_NUMERICSERV
|
|
Packit |
fd8b60 |
hints.ai_flags |= AI_NUMERICSERV;
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
fprintf(stderr, "AI_NUMERICSERV not defined on this platform\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
printf("getaddrinfo(hostname %s, service %s,\n"
|
|
Packit |
fd8b60 |
" hints { ",
|
|
Packit |
fd8b60 |
hname ? hname : "(null)", port ? port : "(null)");
|
|
Packit |
fd8b60 |
sep = "";
|
|
Packit |
fd8b60 |
#define Z(FLAG) if (hints.ai_flags & AI_##FLAG) printf("%s%s", sep, #FLAG), sep = "|"
|
|
Packit |
fd8b60 |
Z(CANONNAME);
|
|
Packit |
fd8b60 |
Z(PASSIVE);
|
|
Packit |
fd8b60 |
#ifdef AI_NUMERICHOST
|
|
Packit |
fd8b60 |
Z(NUMERICHOST);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#ifdef AI_NUMERICSERV
|
|
Packit |
fd8b60 |
Z(NUMERICSERV);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
if (sep[0] == 0)
|
|
Packit |
fd8b60 |
printf ("no-flags");
|
|
Packit |
fd8b60 |
if (hints.ai_family)
|
|
Packit |
fd8b60 |
printf(" %s", familyname(hints.ai_family));
|
|
Packit |
fd8b60 |
if (hints.ai_socktype)
|
|
Packit |
fd8b60 |
printf(" SOCK_%s", socktypename(hints.ai_socktype));
|
|
Packit |
fd8b60 |
if (hints.ai_protocol)
|
|
Packit |
fd8b60 |
printf(" IPPROTO_%s", protoname(hints.ai_protocol));
|
|
Packit |
fd8b60 |
printf(" }):\n");
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
err = getaddrinfo(hname, port, &hints, &ap);
|
|
Packit |
fd8b60 |
if (err) {
|
|
Packit |
fd8b60 |
printf("\terror => %s\n", eaistr(err));
|
|
Packit |
fd8b60 |
return 1;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (ap2 = ap; ap2; ap2 = ap2->ai_next) {
|
|
Packit |
fd8b60 |
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
|
|
Packit |
fd8b60 |
/* If we don't do this, even AIX's own getnameinfo will reject
|
|
Packit |
fd8b60 |
the sockaddr structures. The sa_len field doesn't get set
|
|
Packit |
fd8b60 |
either, on AIX, but getnameinfo won't complain. */
|
|
Packit |
fd8b60 |
if (ap2->ai_addr->sa_family == 0) {
|
|
Packit |
fd8b60 |
printf("BAD: sa_family zero! fixing...\n");
|
|
Packit |
fd8b60 |
ap2->ai_addr->sa_family = ap2->ai_family;
|
|
Packit |
fd8b60 |
} else if (ap2->ai_addr->sa_family != ap2->ai_family) {
|
|
Packit |
fd8b60 |
printf("BAD: sa_family != ai_family! fixing...\n");
|
|
Packit |
fd8b60 |
ap2->ai_addr->sa_family = ap2->ai_family;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof(hbuf),
|
|
Packit |
fd8b60 |
pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
|
|
Packit |
fd8b60 |
strlcpy(hbuf, "...", sizeof(hbuf));
|
|
Packit |
fd8b60 |
strlcpy(pbuf, "...", sizeof(pbuf));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
printf("%p:\n"
|
|
Packit |
fd8b60 |
"\tfamily = %s\tproto = %-4s\tsocktype = %s\n",
|
|
Packit |
fd8b60 |
(void *) ap2, familyname(ap2->ai_family),
|
|
Packit |
fd8b60 |
protoname (ap2->ai_protocol),
|
|
Packit |
fd8b60 |
socktypename (ap2->ai_socktype));
|
|
Packit |
fd8b60 |
if (ap2->ai_canonname) {
|
|
Packit |
fd8b60 |
if (ap2->ai_canonname[0])
|
|
Packit |
fd8b60 |
printf("\tcanonname = %s\n", ap2->ai_canonname);
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
printf("BAD: ai_canonname is set but empty!\n");
|
|
Packit |
fd8b60 |
} else if (ap2 == ap && (hints.ai_flags & AI_CANONNAME)) {
|
|
Packit |
fd8b60 |
printf("BAD: first ai_canonname is null!\n");
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
printf("\taddr = %-28s\tport = %s\n", hbuf, pbuf);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
err = getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof (hbuf),
|
|
Packit |
fd8b60 |
pbuf, sizeof(pbuf), NI_NAMEREQD);
|
|
Packit |
fd8b60 |
if (err)
|
|
Packit |
fd8b60 |
printf("\tgetnameinfo(NI_NAMEREQD): %s\n", eaistr(err));
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
printf("\tgetnameinfo => %s, %s\n", hbuf, pbuf);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
freeaddrinfo(ap);
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|