Date: Mon, 20 Mar 2017 16:44:56 +0000 (UTC) From: Eric van Gyzen <vangyzen@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r315640 - in head: lib/libnetbsd usr.bin usr.bin/getaddrinfo Message-ID: <201703201644.v2KGiuPo014564@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: vangyzen Date: Mon Mar 20 16:44:55 2017 New Revision: 315640 URL: https://svnweb.freebsd.org/changeset/base/315640 Log: 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 Added: head/lib/libnetbsd/sockaddr_snprintf.c (contents, props changed) head/usr.bin/getaddrinfo/ head/usr.bin/getaddrinfo/Makefile (contents, props changed) head/usr.bin/getaddrinfo/getaddrinfo.1 (contents, props changed) head/usr.bin/getaddrinfo/getaddrinfo.c (contents, props changed) head/usr.bin/getaddrinfo/tables.awk (contents, props changed) Modified: head/lib/libnetbsd/Makefile head/lib/libnetbsd/util.h head/usr.bin/Makefile Modified: head/lib/libnetbsd/Makefile ============================================================================== --- head/lib/libnetbsd/Makefile Mon Mar 20 16:30:02 2017 (r315639) +++ head/lib/libnetbsd/Makefile Mon Mar 20 16:44:55 2017 (r315640) @@ -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= Added: head/lib/libnetbsd/sockaddr_snprintf.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libnetbsd/sockaddr_snprintf.c Mon Mar 20 16:44:55 2017 (r315640) @@ -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); +} Modified: head/lib/libnetbsd/util.h ============================================================================== --- head/lib/libnetbsd/util.h Mon Mar 20 16:30:02 2017 (r315639) +++ head/lib/libnetbsd/util.h Mon Mar 20 16:44:55 2017 (r315640) @@ -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 Modified: head/usr.bin/Makefile ============================================================================== --- head/usr.bin/Makefile Mon Mar 20 16:30:02 2017 (r315639) +++ head/usr.bin/Makefile Mon Mar 20 16:44:55 2017 (r315640) @@ -50,6 +50,7 @@ SUBDIR= alias \ fsync \ gcore \ gencat \ + getaddrinfo \ getconf \ getent \ getopt \ Added: head/usr.bin/getaddrinfo/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.bin/getaddrinfo/Makefile Mon Mar 20 16:44:55 2017 (r315640) @@ -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> Added: head/usr.bin/getaddrinfo/getaddrinfo.1 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.bin/getaddrinfo/getaddrinfo.1 Mon Mar 20 16:44:55 2017 (r315640) @@ -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 . Added: head/usr.bin/getaddrinfo/getaddrinfo.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.bin/getaddrinfo/getaddrinfo.c Mon Mar 20 16:44:55 2017 (r315640) @@ -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"); + } +} Added: head/usr.bin/getaddrinfo/tables.awk ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.bin/getaddrinfo/tables.awk Mon Mar 20 16:44:55 2017 (r315640) @@ -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"); +}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703201644.v2KGiuPo014564>