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);
+}

Reply via email to