Port the getaddrinfo(1) utility from NetBSD

Submitted by:	Lohith Bellad <lohithbsd@gmail.com>
Reviewed by:	hiren (earlier rev), ae
Obtained from:	NetBSD
MFC after:	1 week
Relnotes:	yes
Sponsored by:	Dell EMC
Differential Revision:	https://reviews.freebsd.org/D9365
This commit is contained in:
Eric van Gyzen 2017-03-20 16:44:55 +00:00
parent 4056f95699
commit f5b9907c86
8 changed files with 917 additions and 1 deletions

View File

@ -7,7 +7,7 @@ LIB= netbsd
CFLAGS+= -I${.CURDIR}
SRCS+= strsuftoll.c util.c util.h
SRCS+= sockaddr_snprintf.c strsuftoll.c util.c util.h
INTERNALLIB=

View File

@ -0,0 +1,317 @@
/* $NetBSD: sockaddr_snprintf.c,v 1.14 2016/12/29 18:30:55 christos Exp $ */
/*-
* Copyright (c) 2004, 2016 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#ifdef HAVE_NET_IF_DL_H
#include <net/if_dl.h>
#endif
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <util.h>
#include <libutil.h>
#include <netdb.h>
#ifdef BSD4_4
# define SALEN(sa) ((sa)->sa ## _len)
#else
# define SALEN(sa) ((unsigned)sizeof(*sa))
#endif
static int
debug_in(char *str, size_t len, const struct sockaddr_in *sin)
{
return snprintf(str, len, "sin_len=%u, sin_family=%u, sin_port=%u, "
"sin_addr.s_addr=%08x",
SALEN(sin), sin->sin_family, sin->sin_port,
sin->sin_addr.s_addr);
}
static int
debug_in6(char *str, size_t len, const struct sockaddr_in6 *sin6)
{
const uint8_t *s = sin6->sin6_addr.s6_addr;
return snprintf(str, len, "sin6_len=%u, sin6_family=%u, sin6_port=%u, "
"sin6_flowinfo=%u, "
"sin6_addr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
"%02x:%02x:%02x:%02x:%02x:%02x, sin6_scope_id=%u",
SALEN(sin6), sin6->sin6_family, sin6->sin6_port,
sin6->sin6_flowinfo, s[0x0], s[0x1], s[0x2], s[0x3], s[0x4], s[0x5],
s[0x6], s[0x7], s[0x8], s[0x9], s[0xa], s[0xb], s[0xc], s[0xd],
s[0xe], s[0xf], sin6->sin6_scope_id);
}
static int
debug_un(char *str, size_t len, const struct sockaddr_un *sun)
{
return snprintf(str, len, "sun_len=%u, sun_family=%u, sun_path=%*s",
SALEN(sun), sun->sun_family, (int)sizeof(sun->sun_path),
sun->sun_path);
}
#ifdef HAVE_NET_IF_DL_H
static int
debug_dl(char *str, size_t len, const struct sockaddr_dl *sdl)
{
const uint8_t *s = (const void *)sdl->sdl_data;
return snprintf(str, len, "sdl_len=%u, sdl_family=%u, sdl_index=%u, "
"sdl_type=%u, sdl_nlen=%u, sdl_alen=%u, sdl_slen=%u, sdl_data="
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
SALEN(sdl), sdl->sdl_family, sdl->sdl_index,
sdl->sdl_type, sdl->sdl_nlen, sdl->sdl_alen, sdl->sdl_slen,
s[0x0], s[0x1], s[0x2], s[0x3], s[0x4], s[0x5],
s[0x6], s[0x7], s[0x8], s[0x9], s[0xa], s[0xb]);
}
#endif
int
sockaddr_snprintf(char * const sbuf, const size_t len, const char * const fmt,
const struct sockaddr * const sa)
{
const void *a = NULL;
char abuf[1024], nbuf[1024], *addr = NULL;
char Abuf[1024], pbuf[32], *name = NULL, *port = NULL;
char *ebuf = &sbuf[len - 1], *buf = sbuf;
const char *ptr, *s;
size_t salen;
int p = -1;
const struct sockaddr_in *sin4 = NULL;
const struct sockaddr_in6 *sin6 = NULL;
const struct sockaddr_un *sun = NULL;
#ifdef HAVE_NET_IF_DL_H
const struct sockaddr_dl *sdl = NULL;
char *w = NULL;
#endif
int na = 1;
#define ADDC(c) do { if (buf < ebuf) *buf++ = c; else buf++; } \
while (/*CONSTCOND*/0)
#define ADDS(p) do { for (s = p; *s; s++) ADDC(*s); } \
while (/*CONSTCOND*/0)
#define ADDNA() do { if (na) ADDS("N/A"); } \
while (/*CONSTCOND*/0)
switch (sa->sa_family) {
case AF_UNSPEC:
goto done;
case AF_LOCAL:
salen = sizeof(*sun);
sun = ((const struct sockaddr_un *)(const void *)sa);
(void)strlcpy(addr = abuf, sun->sun_path, sizeof(abuf));
break;
case AF_INET:
salen = sizeof(*sin4);
sin4 = ((const struct sockaddr_in *)(const void *)sa);
p = ntohs(sin4->sin_port);
a = &sin4->sin_addr;
break;
case AF_INET6:
salen = sizeof(*sin6);
sin6 = ((const struct sockaddr_in6 *)(const void *)sa);
p = ntohs(sin6->sin6_port);
a = &sin6->sin6_addr;
break;
#ifdef HAVE_NET_IF_DL_H
case AF_LINK:
sdl = ((const struct sockaddr_dl *)(const void *)sa);
addr = abuf;
if (sdl->sdl_slen == 0 && sdl->sdl_nlen == 0
&& sdl->sdl_alen == 0) {
salen = sizeof(*sdl);
(void)snprintf(abuf, sizeof(abuf), "link#%hu",
sdl->sdl_index);
} else {
salen = sdl->sdl_slen + sdl->sdl_nlen + sdl->sdl_alen;
if (salen < sizeof(*sdl))
salen = sizeof(*sdl);
(void)strlcpy(abuf, link_ntoa(sdl), sizeof(abuf));
if ((w = strchr(addr, ':')) != NULL) {
*w++ = '\0';
addr = w;
}
}
break;
#endif
default:
errno = EAFNOSUPPORT;
return -1;
}
if (addr == abuf)
name = addr;
if (a && getnameinfo(sa, (socklen_t)salen, addr = abuf,
(unsigned int)sizeof(abuf), NULL, 0,
NI_NUMERICHOST|NI_NUMERICSERV) != 0)
return -1;
for (ptr = fmt; *ptr; ptr++) {
if (*ptr != '%') {
ADDC(*ptr);
continue;
}
next_char:
switch (*++ptr) {
case '?':
na = 0;
goto next_char;
case 'a':
ADDS(addr);
break;
case 'p':
if (p != -1) {
(void)snprintf(nbuf, sizeof(nbuf), "%d", p);
ADDS(nbuf);
} else
ADDNA();
break;
case 'f':
(void)snprintf(nbuf, sizeof(nbuf), "%d", sa->sa_family);
ADDS(nbuf);
break;
case 'l':
(void)snprintf(nbuf, sizeof(nbuf), "%zu", salen);
ADDS(nbuf);
break;
case 'A':
if (name)
ADDS(name);
else if (!a)
ADDNA();
else {
getnameinfo(sa, (socklen_t)salen, name = Abuf,
(unsigned int)sizeof(nbuf), NULL, 0, 0);
ADDS(name);
}
break;
case 'P':
if (port)
ADDS(port);
else if (p == -1)
ADDNA();
else {
getnameinfo(sa, (socklen_t)salen, NULL, 0,
port = pbuf,
(unsigned int)sizeof(pbuf), 0);
ADDS(port);
}
break;
case 'I':
#ifdef HAVE_NET_IF_DL_H
if (sdl && addr != abuf) {
ADDS(abuf);
} else
#endif
{
ADDNA();
}
break;
case 'F':
if (sin6) {
(void)snprintf(nbuf, sizeof(nbuf), "%d",
sin6->sin6_flowinfo);
ADDS(nbuf);
break;
} else {
ADDNA();
}
break;
case 'S':
if (sin6) {
(void)snprintf(nbuf, sizeof(nbuf), "%d",
sin6->sin6_scope_id);
ADDS(nbuf);
break;
} else {
ADDNA();
}
break;
case 'R':
{
ADDNA();
}
break;
case 'D':
switch (sa->sa_family) {
case AF_LOCAL:
debug_un(nbuf, sizeof(nbuf), sun);
break;
case AF_INET:
debug_in(nbuf, sizeof(nbuf), sin4);
break;
case AF_INET6:
debug_in6(nbuf, sizeof(nbuf), sin6);
break;
#ifdef HAVE_NET_IF_DL_H
case AF_LINK:
debug_dl(nbuf, sizeof(nbuf), sdl);
break;
#endif
default:
abort();
}
ADDS(nbuf);
break;
default:
ADDC('%');
if (na == 0)
ADDC('?');
if (*ptr == '\0')
goto done;
/*FALLTHROUGH*/
case '%':
ADDC(*ptr);
break;
}
na = 1;
}
done:
if (buf < ebuf)
*buf = '\0';
else if (len != 0)
sbuf[len - 1] = '\0';
return (int)(buf - sbuf);
}

View File

@ -37,6 +37,8 @@
#include <libutil.h>
char *flags_to_string(u_long flags, const char *def);
int sockaddr_snprintf(char *, size_t, const char *,
const struct sockaddr *);
int string_to_flags(char **stringp, u_long *setp, u_long *clrp);
#endif

View File

@ -50,6 +50,7 @@ SUBDIR= alias \
fsync \
gcore \
gencat \
getaddrinfo \
getconf \
getent \
getopt \

View File

@ -0,0 +1,22 @@
# $NetBSD: Makefile,v 1.2 2014/04/29 01:21:02 christos Exp $
# $FreeBSD$
.include <bsd.own.mk>
PROG= getaddrinfo
CFLAGS+= -I${.CURDIR}/../../lib/libnetbsd
LIBNETBSDDIR= ${.OBJDIR}/../../lib/libnetbsd
LIBNETBSD= ${LIBNETBSDDIR}/libnetbsd.a
DPADD+= ${LIBNETBSD}
LDADD+= ${LIBNETBSD}
LIBADD+= util
SYS_SOCKET_H?= ${.CURDIR}/../../sys/sys/socket.h
CFLAGS+= -I.
DPSRCS+= tables.h
CLEANFILES+= tables.h
tables.h: tables.awk ${SYS_SOCKET_H}
LC_ALL=C awk -f ${.ALLSRC} > ${.TARGET}
.include <bsd.prog.mk>

View File

@ -0,0 +1,180 @@
.\" $FreeBSD$
.\" $NetBSD: getaddrinfo.1,v 1.5 2014/04/22 06:02:06 wiz Exp $
.\"
.\" Copyright (c) 2013 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This documentation is derived from text contributed to The NetBSD
.\" Foundation by Taylor R. Campbell.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd March 20, 2017
.Dt GETADDRINFO 1
.Os
.Sh NAME
.Nm getaddrinfo
.Nd resolve names to socket addresses
.Sh SYNOPSIS
.Nm
.Op Fl cNnP
.Op Fl f Ar family
.Op Fl p Ar protocol
.Op Fl s Ar service Ns Op Ns / Ns Ar protocol
.Op Fl t Ar socktype
.Op Ar hostname
.Sh DESCRIPTION
The
.Nm
utility resolves host and service names to socket addresses with
.Xr getaddrinfo 3
and prints them to standard output in a user-friendly format.
.Pp
The output is a sequence of lines with space-separated fields:
.Pp
.Dl socket-type address-family protocol [af-specific data ...]
.Pp
For the
.Dq inet
and
.Dq inet6
address families, the af-specific data are the IP/IPv6 address and port
number.
.Pp
Depending on the settings in
.Xr nsswitch.conf 5 ,
.Nm
might query DNS for answers.
However, it is not intended to be a general-purpose DNS query utility.
Use
.Xr drill 1
for that.
.Pp
These options are available:
.Bl -tag -width Ds
.It Fl c
Look up a canonical name as if with the
.Dv AI_CANONNAME
flag to
.Xr getaddrinfo 3
and print it on the first line before the socket addresses.
.It Fl f Ar family
Specify an address family.
Address families are named like the
.Dv AF_...
constants for address family numbers in the
.Aq Pa sys/socket.h
header file but without the
.Dv AF_
prefix and lowercase.
For example,
.Dq inet
corresponds with
.Dv AF_INET .
.It Fl N
Treat the service as numeric and do not attempt service name
resolution, as if with the
.Dv AI_NUMERICSERV
flag to
.Xr getaddrinfo 3 .
.It Fl n
Treat the hostname as a numeric address and do not attempt name
resolution, as if with the
.Dv AI_NUMERICHOST
flag to
.Xr getaddrinfo 3 .
.It Fl P
Return socket addresses intended for use with
.Xr bind 2 ,
as if with the
.Dv AI_PASSIVE
flag to
.Xr getaddrinfo 3 .
By default, the socket addresses are intended for use with
.Xr connect 2 ,
.Xr sendto 2 ,
or
.Xr sendmsg 2 .
.It Fl p Ar protocol
Specify a protocol.
Protocols are numeric or symbolic as listed in
.Xr protocols 5 .
.It Fl s Ar service Ns Op Ns / Ns Ar protocol
Specify a service to look up.
Services are symbolic or numeric with an optional
protocol suffix as listed in
.Xr services 5 .
If a service is not specified, a hostname is required.
.It Fl t Ar socktype
Specify a socket type.
Socket types are named like the
.Dv SOCK_...
constants for socket type numbers in the
.Aq Pa sys/socket.h
header file but without the
.Dv SOCK_
prefix and lowercase.
For example,
.Dq dgram
corresponds with
.Dv SOCK_DGRAM .
.El
.Sh EXIT STATUS
.Ex -std getaddrinfo
.Sh EXAMPLES
Look up
.Dq www.NetBSD.org :
.Bd -literal -offset indent
$ getaddrinfo www.NetBSD.org
dgram inet6 udp 2001:4f8:3:7:2e0:81ff:fe52:9ab6 0
dgram inet udp 149.20.53.67 0
stream inet6 tcp 2001:4f8:3:7:2e0:81ff:fe52:9ab6 0
stream inet tcp 149.20.53.67 0
.Ed
.Pp
The port number here is zero because no service was specified.
.Pp
Look up
.Dq morden.NetBSD.org
for stream sockets on port 80, and show the canonical name:
.Bd -literal -offset indent
$ getaddrinfo -c -t stream -s 80 morden.NetBSD.org
canonname ftp.NetBSD.org
stream inet6 tcp 2001:470:1f05:3d::21 80
stream inet tcp 199.233.217.249 80
.Ed
.Sh SEE ALSO
.Xr drill 1 ,
.Xr getent 1 ,
.Xr getaddrinfo 3 ,
.Xr getnameinfo 3 ,
.Xr resolver 3 ,
.Xr hosts 5 ,
.Xr nsswitch.conf 5 ,
.Xr protocols 5 ,
.Xr resolv.conf 5 ,
.Xr services 5
.Sh HISTORY
The
.Nm
command first appeared in
.Nx 7.0 .

View File

@ -0,0 +1,331 @@
/* $NetBSD: getaddrinfo.c,v 1.4 2014/04/22 02:23:03 ginsbach Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Taylor R. Campbell.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <netdb.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
#include "tables.h"
static void usage(void) __dead;
static void printaddrinfo(struct addrinfo *);
static bool parse_af(const char *, int *);
static bool parse_protocol(const char *, int *);
static bool parse_socktype(const char *, int *);
static bool parse_numeric_tabular(const char *, int *, const char *const *,
size_t);
int
main(int argc, char **argv)
{
static const struct addrinfo zero_addrinfo;
struct addrinfo hints = zero_addrinfo;
struct addrinfo *addrinfo;
const char *hostname = NULL, *service = NULL;
int ch;
int error;
setprogname(argv[0]);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = 0;
hints.ai_protocol = 0;
hints.ai_flags = 0;
while ((ch = getopt(argc, argv, "cf:nNp:Ps:t:")) != -1) {
switch (ch) {
case 'c':
hints.ai_flags |= AI_CANONNAME;
break;
case 'f':
if (!parse_af(optarg, &hints.ai_family)) {
warnx("invalid address family: %s", optarg);
usage();
}
break;
case 'n':
hints.ai_flags |= AI_NUMERICHOST;
break;
case 'N':
hints.ai_flags |= AI_NUMERICSERV;
break;
case 's':
service = optarg;
break;
case 'p':
if (!parse_protocol(optarg, &hints.ai_protocol)) {
warnx("invalid protocol: %s", optarg);
usage();
}
break;
case 'P':
hints.ai_flags |= AI_PASSIVE;
break;
case 't':
if (!parse_socktype(optarg, &hints.ai_socktype)) {
warnx("invalid socket type: %s", optarg);
usage();
}
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (!((argc == 1) || ((argc == 0) && (hints.ai_flags & AI_PASSIVE))))
usage();
if (argc == 1)
hostname = argv[0];
if (service != NULL) {
char *p;
if ((p = strchr(service, '/')) != NULL) {
if (hints.ai_protocol != 0) {
warnx("protocol already specified");
usage();
}
*p = '\0';
p++;
if (!parse_protocol(p, &hints.ai_protocol)) {
warnx("invalid protocol: %s", p);
usage();
}
}
}
error = getaddrinfo(hostname, service, &hints, &addrinfo);
if (error)
errx(1, "%s", gai_strerror(error));
if ((hints.ai_flags & AI_CANONNAME) && (addrinfo != NULL)) {
if (printf("canonname %s\n", addrinfo->ai_canonname) < 0)
err(1, "printf");
}
printaddrinfo(addrinfo);
freeaddrinfo(addrinfo);
return 0;
}
static void __dead
usage(void)
{
(void)fprintf(stderr, "Usage: %s", getprogname());
(void)fprintf(stderr,
" [-f <family>] [-p <protocol>] [-t <socktype>] [-s <service>]\n");
(void)fprintf(stderr, " [-cnNP] [<hostname>]\n");
exit(1);
}
static bool
parse_af(const char *string, int *afp)
{
return parse_numeric_tabular(string, afp, address_families,
__arraycount(address_families));
}
static bool
parse_protocol(const char *string, int *protop)
{
struct protoent *protoent;
char *end;
long value;
errno = 0;
value = strtol(string, &end, 0);
if ((string[0] == '\0') || (*end != '\0'))
goto numeric_failed;
if ((errno == ERANGE) && ((value == LONG_MAX) || (value == LONG_MIN)))
goto numeric_failed;
if ((value > INT_MAX) || (value < INT_MIN))
goto numeric_failed;
*protop = value;
return true;
numeric_failed:
protoent = getprotobyname(string);
if (protoent == NULL)
goto protoent_failed;
*protop = protoent->p_proto;
return true;
protoent_failed:
return false;
}
static bool
parse_socktype(const char *string, int *typep)
{
return parse_numeric_tabular(string, typep, socket_types,
__arraycount(socket_types));
}
static bool
parse_numeric_tabular(const char *string, int *valuep,
const char *const *table, size_t n)
{
char *end;
long value;
size_t i;
assert((uintmax_t)n <= (uintmax_t)INT_MAX);
errno = 0;
value = strtol(string, &end, 0);
if ((string[0] == '\0') || (*end != '\0'))
goto numeric_failed;
if ((errno == ERANGE) && ((value == LONG_MAX) || (value == LONG_MIN)))
goto numeric_failed;
if ((value > INT_MAX) || (value < INT_MIN))
goto numeric_failed;
*valuep = value;
return true;
numeric_failed:
for (i = 0; i < n; i++)
if ((table[i] != NULL) && (strcmp(string, table[i]) == 0))
break;
if (i == n)
goto table_failed;
*valuep = i;
return true;
table_failed:
return false;
}
static void
printaddrinfo(struct addrinfo *addrinfo)
{
struct addrinfo *ai;
char buf[1024];
int n;
struct protoent *protoent;
for (ai = addrinfo; ai != NULL; ai = ai->ai_next) {
/* Print the socket type. */
if ((ai->ai_socktype >= 0) &&
((size_t)ai->ai_socktype < __arraycount(socket_types)) &&
(socket_types[ai->ai_socktype] != NULL))
n = printf("%s", socket_types[ai->ai_socktype]);
else
n = printf("%d", ai->ai_socktype);
if (n < 0)
err(1, "printf");
/* Print the address family. */
if ((ai->ai_family >= 0) &&
((size_t)ai->ai_family < __arraycount(address_families)) &&
(address_families[ai->ai_family] != NULL))
n = printf(" %s", address_families[ai->ai_family]);
else
n = printf(" %d", ai->ai_family);
if (n < 0)
err(1, "printf");
/* Print the protocol number. */
protoent = getprotobynumber(ai->ai_protocol);
if (protoent == NULL)
n = printf(" %d", ai->ai_protocol);
else
n = printf(" %s", protoent->p_name);
if (n < 0)
err(1, "printf");
/* Format the sockaddr. */
switch (ai->ai_family) {
case AF_INET:
case AF_INET6:
n = sockaddr_snprintf(buf, sizeof(buf), " %a %p",
ai->ai_addr);
break;
default:
n = sockaddr_snprintf(buf, sizeof(buf),
"%a %p %I %F %R %S", ai->ai_addr);
}
/*
* Check for sockaddr_snprintf failure.
*
* XXX sockaddr_snprintf's error reporting is botched
* -- man page says it sets errno, but if getnameinfo
* fails, errno is not where it reports the error...
*/
if (n < 0) {
warnx("sockaddr_snprintf failed");
continue;
}
if (sizeof(buf) <= (size_t)n)
warnx("truncated sockaddr_snprintf output");
/* Print the formatted sockaddr. */
if (printf("%s\n", buf) < 0)
err(1, "printf");
}
}

View File

@ -0,0 +1,63 @@
#!/usr/bin/awk -f
# $FreeBSD$
# $NetBSD: tables.awk,v 1.2 2014/02/27 01:17:13 ginsbach Exp $
# Copyright (c) 2013 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Taylor R. Campbell.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
BEGIN {
n_afs = 0
n_socktypes = 0
}
!(($1 == "#define") && ($3 ~ /^[0-9]*$/)) {
next
}
($2 ~ /^AF_[A-Z0-9_]*$/) && ($2 != "AF_MAX") {
afs[n_afs++] = substr($2, 4)
}
($2 ~ /^SOCK_[A-Z0-9_]*$/) && ($2 != "SOCK_MAXADDRLEN") {
socktypes[n_socktypes++] = substr($2, 6)
}
END {
printf("/* Do not edit! This file was generated automagically! */\n");
printf("\nstatic const char *const address_families[] = {\n");
for (i = 0; i < n_afs; i++)
printf("\t[AF_%s] = \"%s\",\n", afs[i], tolower(afs[i]));
printf("};\n");
printf("\nstatic const char *const socket_types[] = {\n");
for (i = 0; i < n_socktypes; i++)
printf("\t[SOCK_%s] = \"%s\",\n", socktypes[i],
tolower(socktypes[i]));
printf("};\n");
}