diff options
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/Makefile | 1 | ||||
-rw-r--r-- | usr.bin/getaddrinfo/Makefile | 22 | ||||
-rw-r--r-- | usr.bin/getaddrinfo/getaddrinfo.1 | 184 | ||||
-rw-r--r-- | usr.bin/getaddrinfo/getaddrinfo.c | 331 | ||||
-rw-r--r-- | usr.bin/getaddrinfo/tables.awk | 63 |
5 files changed, 601 insertions, 0 deletions
diff --git a/usr.bin/Makefile b/usr.bin/Makefile index b87c26a..fdd14b6 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -52,6 +52,7 @@ SUBDIR= alias \ fsync \ gcore \ gencat \ + getaddrinfo \ getconf \ getent \ getopt \ diff --git a/usr.bin/getaddrinfo/Makefile b/usr.bin/getaddrinfo/Makefile new file mode 100644 index 0000000..6efb164 --- /dev/null +++ b/usr.bin/getaddrinfo/Makefile @@ -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> diff --git a/usr.bin/getaddrinfo/getaddrinfo.1 b/usr.bin/getaddrinfo/getaddrinfo.1 new file mode 100644 index 0000000..fa83a3a --- /dev/null +++ b/usr.bin/getaddrinfo/getaddrinfo.1 @@ -0,0 +1,184 @@ +.\" $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 28, 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 , +followed by +.Fx 11.1 +and +.Fx 12.0 . diff --git a/usr.bin/getaddrinfo/getaddrinfo.c b/usr.bin/getaddrinfo/getaddrinfo.c new file mode 100644 index 0000000..a42fe1a --- /dev/null +++ b/usr.bin/getaddrinfo/getaddrinfo.c @@ -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"); + } +} diff --git a/usr.bin/getaddrinfo/tables.awk b/usr.bin/getaddrinfo/tables.awk new file mode 100644 index 0000000..fc51e96 --- /dev/null +++ b/usr.bin/getaddrinfo/tables.awk @@ -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"); +} |