Module Name: src Committed By: riastradh Date: Mon Sep 30 06:19:22 UTC 2013
Added Files: src/usr.bin/getaddrinfo: Makefile getaddrinfo.1 getaddrinfo.c tables.awk Log Message: New utility getaddrinfo(1) to reflect getaddrinfo(3). Discussed on tech-userlevel back in April: https://mail-index.netbsd.org/tech-userlevel/2013/04/25/msg007719.html Not hooked into the build or sets yet. To generate a diff of this commit: cvs rdiff -u -r0 -r1.1 src/usr.bin/getaddrinfo/Makefile \ src/usr.bin/getaddrinfo/getaddrinfo.1 \ src/usr.bin/getaddrinfo/getaddrinfo.c src/usr.bin/getaddrinfo/tables.awk Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Added files: Index: src/usr.bin/getaddrinfo/Makefile diff -u /dev/null src/usr.bin/getaddrinfo/Makefile:1.1 --- /dev/null Mon Sep 30 06:19:22 2013 +++ src/usr.bin/getaddrinfo/Makefile Mon Sep 30 06:19:22 2013 @@ -0,0 +1,20 @@ +# $NetBSD: Makefile,v 1.1 2013/09/30 06:19:22 riastradh Exp $ + +PROG= getaddrinfo + +DPADD+= ${LIBUTIL} +LDADD+= -lutil + +WARNS= 5 + +SYS_SOCKET_H?= ${NETBSDSRCDIR}/sys/sys/socket.h + +CPPFLAGS+= -I. +DPSRCS+= tables.h +CLEANFILES+= tables.h +tables.h: tables.awk ${SYS_SOCKET_H} + ${_MKTARGET_CREATE} + ${TOOL_AWK} -f ${.ALLSRC} > ${.TARGET}.tmp \ + && mv -f -- ${.TARGET}.tmp ${.TARGET} + +.include <bsd.prog.mk> Index: src/usr.bin/getaddrinfo/getaddrinfo.1 diff -u /dev/null src/usr.bin/getaddrinfo/getaddrinfo.1:1.1 --- /dev/null Mon Sep 30 06:19:22 2013 +++ src/usr.bin/getaddrinfo/getaddrinfo.1 Mon Sep 30 06:19:22 2013 @@ -0,0 +1,174 @@ +.\" $NetBSD: getaddrinfo.1,v 1.1 2013/09/30 06:19:22 riastradh 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 April 25, 2013 +.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 t Ar socktype +.Op Fl s Ar service +.Op Ar hostname +.Sh DESCRIPTION +The +.Nm +utility resolves host and service names to socket addresses as if with +the +.Xr getaddrinfo 3 +routine and formats them to standard output. +.Pp +The output is a sequence of lines of space-separated fields: +.Dl socket-type address-family protocol [af-specific data ...] +.Pp +For the internet family, the address-family-specific data are the +internet address and the port number. +.Pp +Although the +.Nm +utility may query the DNS to give answers, depending on the +system's +.Xr nsswitch.conf 5 +configuration, it is not intended to be a general-purpose utility to +query the DNS; use the +.Xr dig 1 +utility for that. +.Pp +The following 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 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 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 s Ar service +Specify a service to look up. +If no service is specified, a hostname must be specified. +.It Fl p Ar protocol +Specify a protocol. +Protocols may be numeric, or symbolic as listed in +.Xr protocols 5 . +.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 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 +.Pp +The +.Nm +utility exits 0 on success, and \*[Gt]0 if an error occurs. +.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 +The unspecified service manifested as a port number of zero. +.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 dig 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 . Index: src/usr.bin/getaddrinfo/getaddrinfo.c diff -u /dev/null src/usr.bin/getaddrinfo/getaddrinfo.c:1.1 --- /dev/null Mon Sep 30 06:19:22 2013 +++ src/usr.bin/getaddrinfo/getaddrinfo.c Mon Sep 30 06:19:22 2013 @@ -0,0 +1,308 @@ +/* $NetBSD: getaddrinfo.c,v 1.1 2013/09/30 06:19:22 riastradh 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> +__RCSID("$NetBSD: getaddrinfo.c,v 1.1 2013/09/30 06:19:22 riastradh Exp $"); + +#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 <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(); + } + + 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]; + + 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"); + } +} Index: src/usr.bin/getaddrinfo/tables.awk diff -u /dev/null src/usr.bin/getaddrinfo/tables.awk:1.1 --- /dev/null Mon Sep 30 06:19:22 2013 +++ src/usr.bin/getaddrinfo/tables.awk Mon Sep 30 06:19:22 2013 @@ -0,0 +1,62 @@ +#!/usr/bin/awk -f + +# $NetBSD: tables.awk,v 1.1 2013/09/30 06:19:22 riastradh 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_]*$/ { + afs[n_afs++] = substr($2, 4) +} + +$2 ~ /^SOCK_[A-Z0-9_]*$/ { + 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"); +}