/*
* 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.
*/
/*
* getnameinfo: Resolve IP addresses and ports to hostnames and service names,
* similar to the getnameinfo function in the standard library.
*
* usage:
* getnameinfo [-46FHNnrSu] [-f family] [-p port] <IP-address>
*
* -4: Restrict lookup to IPv4 addresses only
* -6: Restrict lookup to IPv6 addresses only
* -F: Suppress the fully-qualified domain name (FQDN)
* -f: Specify address family to look up
* -H: Display only the hostname, omitting the service name
* -N: Display the numeric service name instead of the service name
* -n: Display the numeric host address instead of the hostname
* -p: Specify the port number to be used in the lookup
* -r: Ensure that the name is returned (error if no name is found)
* -S: Display only the service name, omitting the hostname
* -u: Use UDP instead of the default TCP
*/
int
main(int argc, char **argv)
{
socklen_t hostlen = NI_MAXHOST, servlen = NI_MAXSERV, addrlen;
char hostname[NI_MAXHOST], service[NI_MAXSERV];
bool hostname_only = false, service_only = false;
uint8_t 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;
struct sockaddr_un *addr_un;
struct sockaddr_dl *addr_dl;
int ch;
int error;
setprogname(argv[0]);
while ((ch = getopt(argc, argv, "46Ff:HNnp:rSu")) != -1) {
switch (ch) {
case '4':
if (family != AF_UNSPEC)
goto opt46f;
family = AF_INET;
break;
case '6':
if (family != AF_UNSPEC)
goto opt46f;
family = AF_INET6;
break;
case 'r':
flags |= NI_NAMEREQD;
break;
case 'u':
flags |= NI_DGRAM;
break;
case 'f':
if (family != AF_UNSPEC)
goto opt46f;
family = get_family(optarg);
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 && !service_only))) {
warnx("No IP address provided");
usage();
}
if (port == 0 && (service_only ||
(!hostname_only && !service_only))) {
warnx("No port number provided");
usage();
}
if (argc == 1) {
address = argv[0];
if (family == AF_UNSPEC)
family = get_family_from_address(address);
}