Module Name: src Committed By: christos Date: Mon Jan 27 18:30:19 UTC 2025
Modified Files: src/usr.bin: Makefile Added Files: src/usr.bin/getnameinfo: Makefile getnameinfo.1 getnameinfo.c Log Message: PR/57953: Attaullah Ansari: Add getnameinfo program To generate a diff of this commit: cvs rdiff -u -r1.241 -r1.242 src/usr.bin/Makefile cvs rdiff -u -r0 -r1.1 src/usr.bin/getnameinfo/Makefile \ src/usr.bin/getnameinfo/getnameinfo.1 \ src/usr.bin/getnameinfo/getnameinfo.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/Makefile diff -u src/usr.bin/Makefile:1.241 src/usr.bin/Makefile:1.242 --- src/usr.bin/Makefile:1.241 Mon Oct 28 13:55:12 2024 +++ src/usr.bin/Makefile Mon Jan 27 13:30:19 2025 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.241 2024/10/28 17:55:12 nia Exp $ +# $NetBSD: Makefile,v 1.242 2025/01/27 18:30:19 christos Exp $ # from: @(#)Makefile 8.3 (Berkeley) 1/7/94 .include <bsd.own.mk> @@ -12,7 +12,7 @@ SUBDIR= aiomixer apply asa at audio audi eject elf2aout elf2ecoff env error expand extattr \ false fdformat fgen fincore find finger flock fmt fold fpr from \ fsplit fstat ftp gcore genassym gencat getaddrinfo getconf getent \ - getopt gettext gprof \ + getnameinfo getopt gettext gprof \ head hexdump iconv id indent infocmp innetgr ipcrm ipcs join jot \ kdump ktrace ktruss lam last lastcomm ldd leave \ locale locate lock logger login logname look lorder m4 \ Added files: Index: src/usr.bin/getnameinfo/Makefile diff -u /dev/null src/usr.bin/getnameinfo/Makefile:1.1 --- /dev/null Mon Jan 27 13:30:19 2025 +++ src/usr.bin/getnameinfo/Makefile Mon Jan 27 13:30:19 2025 @@ -0,0 +1,9 @@ +# $NetBSD: Makefile,v 1.1 2025/01/27 18:30:19 christos Exp $ + +.include <bsd.own.mk> + +PROG = getnameinfo + +WARNS = 5 + +.include <bsd.prog.mk> Index: src/usr.bin/getnameinfo/getnameinfo.1 diff -u /dev/null src/usr.bin/getnameinfo/getnameinfo.1:1.1 --- /dev/null Mon Jan 27 13:30:19 2025 +++ src/usr.bin/getnameinfo/getnameinfo.1 Mon Jan 27 13:30:19 2025 @@ -0,0 +1,142 @@ +.\" $NetBSD: getnameinfo.1,v 1.1 2025/01/27 18:30:19 christos Exp $ +.\" +.\" Copyright (c) 2025 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This documentation is derived from text contributed to The NetBSD +.\" Foundation by Attaullah Ansari. +.\" +.\" 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 January 16, 2025 +.Dt GETNAMEINFO 1 +.Os +.Sh NAME +.Nm getnameinfo +.Nd resolve IP addresses and ports to host and service names +.Sh SYNOPSIS +.Nm +.Op Fl 46rufnNHS +.Op Fl p Ar port +.Ar IP-address +.Sh DESCRIPTION +The +.Nm +utility resolves IP addresses and port numbers to hostnames and service names +as if with the +.Xr getnameinfo 3 +library routine and formats them to standard output. +.Pp +The output is a single line of space-separated fields: +.Pp +.Dl hostname service +.Pp +Depending on the flags specified, the output may consist only of the hostname +or service name, or their numeric representations. +By default, both are shown. +.Pp +Although +.Nm +may query the DNS or other sources for name resolution depending on the +system's +.Xr nsswitch.conf 5 +configuration, it is not intended to replace DNS-specific tools like +.Xr dig 1 . +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl 4 +Restrict the lookup to IPv4 addresses only. +.It Fl 6 +Restrict the lookup to IPv6 addresses only. +.It Fl r +Ensure that a name is returned. +If no name can be resolved, an error is reported. +This is equivalent to the +.Dv NI_NAMEREQD +flag in +.Xr getnameinfo 3 . +.It Fl u +Use UDP instead of the default TCP. +This is equivalent to the +.Dv NI_DGRAM +flag in +.Xr getnameinfo 3 . +.It Fl f +Suppress the fully-qualified domain name (FQDN). +This is equivalent to the +.Dv NI_NOFQDN +flag in +.Xr getnameinfo 3 . +.It Fl n +Display the numeric host address instead of resolving to a hostname. +This is equivalent to the +.Dv NI_NUMERICHOST +flag in +.Xr getnameinfo 3 . +.It Fl N +Display the numeric service name instead of resolving to a service name. +This is equivalent to the +.Dv NI_NUMERICSERV +flag in +.Xr getnameinfo 3 . +.It Fl H +Display only the hostname, omitting the service name. +.It Fl S +Display only the service name, omitting the hostname. +.It Fl p Ar port +Specify the port number to be used in the lookup. +.El +.Sh EXIT STATUS +.Ex -std getnameinfo +.Sh EXAMPLES +Look up the hostname and service name for an IPv4 address: +.Bd -literal -offset indent +$ getnameinfo -4 -p 80 93.184.216.34 +example.com http +.Ed +.Pp +Look up the numeric host and service for an IPv6 address: +.Bd -literal -offset indent +$ getnameinfo -nN -p 443 2606:2800:220:1:248:1893:25c8:1946 +2606:2800:220:1:248:1893:25c8:1946 443 +.Ed +.Pp +Resolve an address to its hostname but suppress the service name: +.Bd -literal -offset indent +$ getnameinfo -H -p 22 192.0.2.1 +example-host +.Ed +.Pp +Resolve a hostname and service for a UDP connection: +.Bd -literal -offset indent +$ getnameinfo -u -p 53 198.51.100.2 +example-dns-server domain +.Ed +.Sh SEE ALSO +.Xr dig 1 , +.Xr getaddrinfo 1 , +.Xr getaddrinfo 3 , +.Xr getnameinfo 3 , +.Xr inet 3 , +.Xr hosts 5 , +.Xr nsswitch.conf 5 Index: src/usr.bin/getnameinfo/getnameinfo.c diff -u /dev/null src/usr.bin/getnameinfo/getnameinfo.c:1.1 --- /dev/null Mon Jan 27 13:30:19 2025 +++ src/usr.bin/getnameinfo/getnameinfo.c Mon Jan 27 13:30:19 2025 @@ -0,0 +1,262 @@ +/* $NetBSD: getnameinfo.c,v 1.1 2025/01/27 18:30:19 christos Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Attaullah Ansari. + * + * 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> +#ifndef lint +__RCSID("$NetBSD: getnameinfo.c,v 1.1 2025/01/27 18:30:19 christos Exp $"); +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <netdb.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +/* + * getnameinfo: Resolve IP addresses and ports to hostnames and service names, + * similar to the getnameinfo function in the standard library. + * + * usage: + * getnameinfo [-46rufnNHS] [-p port] <IP-address> + * + * -4: Restrict lookup to IPv4 addresses only + * -6: Restrict lookup to IPv6 addresses only + * -r: Ensure that the name is returned (error if no name is found) + * -u: Use UDP instead of the default TCP + * -f: Suppress the fully-qualified domain name (FQDN) + * -n: Display the numeric host address instead of the hostname + * -N: Display the numeric service name instead of the service name + * -H: Display only the hostname, omitting the service name + * -S: Display only the service name, omitting the hostname + * -p: Specify the port number to be used in the lookup + */ + + +static void usage(void) __dead; +static void print_result(int, int, char *, char *); +static in_port_t get_port(const char *); +static uint8_t get_family(const char *); + +int +main(int argc, char **argv) +{ + int hostlen = NI_MAXHOST, servlen = NI_MAXSERV; + char hostname[hostlen], service[servlen]; + bool hostname_only = false, service_only = false; + int family = AF_UNSPEC; + int flags = 0; + char *address = NULL; + in_port_t port = 0; + struct sockaddr_storage addr_st; + struct sockaddr_in *addr_in; + struct sockaddr_in6 *addr_in6; + int addr_stlen; + int ch; + int error; + + setprogname(argv[0]); + + while ((ch = getopt(argc, argv, "46rufnNHSp:")) != -1) { + switch (ch) { + case '4': + if (family != AF_UNSPEC) + goto opt46; + family = AF_INET; + break; + case '6': + if (family != AF_UNSPEC) + goto opt46; + family = AF_INET6; + break; + case 'r': + flags |= NI_NAMEREQD; + break; + case 'u': + flags |= NI_DGRAM; + break; + case 'f': + flags |= NI_NOFQDN; + break; + case 'n': + flags |= NI_NUMERICHOST; + break; + case 'N': + flags |= NI_NUMERICSERV; + break; + case 'H': + if (service_only) + goto optHS; + hostname_only = true; + break; + case 'S': + if (hostname_only) + goto optHS; + service_only = true; + break; + case 'p': + port = get_port(optarg); + break; + case '?': + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + if (argc > 1) { + warnx("Too many addresses"); + usage(); + } + + if (argc == 0 && (hostname_only || + (hostname_only == 0 && service_only == 0))) { + warnx("No IP address provided"); + usage(); + } + + if (port == 0 && (service_only || + (hostname_only == 0 && service_only == 0))) { + warnx("No port number provided"); + usage(); + } + + if (argc == 1) { + address = argv[0]; + if (family == AF_UNSPEC) + family = get_family(address); + } + + switch (family) { + case AF_INET: + addr_in = (struct sockaddr_in *)&addr_st; + addr_in->sin_family = family; + addr_in->sin_port = htons(port); + if (inet_pton(family, address, &addr_in->sin_addr) == 0) { + warnx("Invalid IPv4 address: %s", address); + return EXIT_FAILURE; + } + addr_stlen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + addr_in6 = (struct sockaddr_in6 *)&addr_st; + addr_in6->sin6_family = family; + addr_in6->sin6_port = htons(port); + if (inet_pton(family, address, &addr_in6->sin6_addr) == 0) { + warnx("Invalid IPv6 address: %s", address); + return EXIT_FAILURE; + } + addr_stlen = sizeof(struct sockaddr_in6); + break; + default: + warnx("Unsupported family %d", family); + return EXIT_FAILURE; + } + + if (hostname_only) + servlen = 0; + else if (service_only) + hostlen = 0; + + error = getnameinfo((struct sockaddr *)&addr_st, addr_stlen, + hostname, hostlen, service, servlen, flags); + if (error) + errx(EXIT_FAILURE, "%s", gai_strerror(error)); + + print_result(hostname_only, service_only, hostname, service); + + return EXIT_SUCCESS; +opt46: + warnx("Options -4 and -6 cannot be used together"); + usage(); +optHS: + warnx("Options -H and -S cannot be used together"); + usage(); +} + +static uint8_t +get_family(const char* address) +{ + struct in_addr ipv4_addr; + struct in6_addr ipv6_addr; + + if (inet_pton(AF_INET, address, &ipv4_addr) == 1) + return AF_INET; + + if (inet_pton(AF_INET6, address, &ipv6_addr) == 1) + return AF_INET6; + + errx(EXIT_FAILURE, "Invalid addrsss %s", address); +} + +static in_port_t +get_port(const char *port_str) +{ + int r; + intmax_t port = strtoi(port_str, NULL, 0, 0, 65535, &r); + if (r) + errc(EXIT_FAILURE, r, "Invalid port number %s", port_str); + + return (in_port_t)port; +} + +static void +print_result(int hostname_only, int service_only, char *hostname, char *service) +{ + int n; + if (hostname_only) + n = printf("%s\n", hostname); + else if (service_only) + n = printf("%s\n", service); + else + n = printf("%s %s\n", hostname, service); + if (n < 0) + err(EXIT_FAILURE, "printf"); +} + + +static void __dead +usage(void) +{ + (void)fprintf(stderr, "Usage: %s", getprogname()); + (void)fprintf(stderr, " [-46rufnNHS] [-p port] <IP-address>\n"); + exit(EXIT_FAILURE); +}