christos@netbsd.org suggested we replace whois

with one that is KNF, has ipv6, better error
handling, and recursion. I settled on OpenBSDs.
Christos found some nits and had me commit as
is. Christos will follow up with fixes shortly.
This commit is contained in:
jrf 2003-10-09 14:21:49 +00:00
parent fbacec1288
commit df042318ea
2 changed files with 510 additions and 772 deletions

View File

@ -1,4 +1,5 @@
.\" $NetBSD: whois.1,v 1.20 2003/08/07 11:17:19 agc Exp $
.\" $NetBSD: whois.1,v 1.21 2003/10/09 14:21:49 jrf Exp $
.\" $OpenBSD: whois.1,v 1.22 2003/09/02 18:50:07 jmc Exp $
.\"
.\" Copyright (c) 1985, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -29,257 +30,275 @@
.\"
.\" @(#)whois.1 8.2 (Berkeley) 6/20/94
.\"
.Dd January 12, 2002
.Dd January 6, 2003
.Dt WHOIS 1
.Os
.Sh NAME
.Nm whois
.Nd TCP/IP Internet directory service, RIPE version
.Nd Internet domain name and network number directory service
.Sh SYNOPSIS
.Nm
.Op Fl 46aFSrR
.Op Fl h Ar host
.Nm whois
.Op Fl aAdgilmQrR6
.Oo
.Fl c Ar country-code | Fl h Ar host
.Oc
.Op Fl p Ar port
.Op Fl i Ar attributes
.Op Fl s Ar sources
.Op Fl T Ns Ar \ types
.Op Fl L | m | M
.Ar identifier
.Nm
.Fl t Ar type
.Nm
.Fl v Ar type
.Ar name Op Ar ...
.Sh DESCRIPTION
The
.Nm
program is a client implementation of the WHOIS protocol for querying
databases and directory services on the Internet.
Most often, it is used to query the domain name contact and administration
databases of Internet Domain Name Registrars.
utility looks up records in the databases maintained by several
Network Information Centers
.Pq Tn NICs .
.Pp
The WHOIS protocol does not specify very much of the format of
either the query or the servers' response.
In essence, the protocol calls for a
.Tn NETASCII
word or phrase to be sent on a
.Tn TCP
connection to a
.Tn WHOIS
server, which then sends some amount of
.Tn NETASCII
in response on the same connection,
closing the connection when it has finished sending.
Necessarily, both the format and the content of the response will be server-dependent
.Po
e.g. what you get back depends on who you ask, and what you ask
.Pc .
.Pp
By default,
.Nm
will send the query to
.Qq whois.internic.net .
.Pp
When
.Nm
is used to query an Internet domain name registrar's database, the
.Ar identifier
can be either a name
.Po
e.g.
.Qq Karrenberg
.Pc ,
a
.Tn NIC-handle
.Po
e.g.
.Qq DK58
.Pc ,
an IP network number
.Po
e.g.
.Qq 192.87.45.0/24
.Pc ,
or a domain name
.Po
e.g.
.Qq ripe.net
.Pc .
.Sh OPTIONS
.Bl -tag -width indent
.It Fl h Ar host
Query a host other than the default.
.It Fl p Ar port
Connect to a
.Tn TCP
port other than 43 (the default).
.El
.Pp
By default,
.Nm
will attempt to connect to a WHOIS server with both IPv6 and IPv4,
in that order.
To force one or the other transport:
.Bl -tag -width indent
.It Fl 4
connect with IPv4/TCP only.
.It Fl 6
connect with IPv6/TCP only.
.El
.Ss RIPE specific extensions
This version of
.Nm
implements protocol extensions compatible with a version of the RIPE
database WHOIS server that supports classless IP addresses.
All IP network numbers are considered classless IP network numbers of
the form prefix/length, like 192.87.45.0/24 for a class C sized network
number and 128.86.0.0/16 for a class B sized network number.
Any length can be given.
If no length is given, the server assumes a host lookup (i.e. length 32).
.Pp
By default, the server will return the first less specific network
number, which can be an exact match if available in the database.
.Bl -tag -width indent
The options are as follows:
.Bl -tag -width Ds
.It Fl a
This causes the server to include information from
non-RIPE WHOIS databases in the reply.
Currently these are the public parts of the US NIC and NSFNET databases.
Please note that the RIPE NCC does not maintain these databases.
The information is included for for your convenience only.
.It Fl F
fast output.
Force the WHOIS server to not reformat the output.
This can save time for large objects.
The output of the RIPE WHOIS server will be in two letter short form.
This option implies -r.
.It Fl L
lookup all less specific networks.
Has effect only when looking up IP network numbers.
.It Fl m
lookup first level more specific networks.
Has effect only when looking up IP network numbers.
.It Fl M
lookup all more specific networks.
Has effect only when looking up IP network numbers.
.It Fl r
non-recursive lookup.
This will cause the server to not lookup referenced objects.
.It Fl R
suppress referrals.
Forces local copy of a domain object to be shown even if it contains referral.
.It Fl i Ar attributes
attributes is a comma separated list of attributes.
the WHOIS server will return all objects that match the search keys
in one of these attributes.
.It Fl s Ar sources
sources is a comma separated list of database sources.
The WHOIS server will only search the databases that match the
specified sources.
.It Fl S
requests the server to leave out "syntactic sugar" that may normally
be inserted in some database objects.
.It Fl t Ar type
requests the server to send a template for an object with type "type".
.It Fl v Ar type
requests the server to send a verbose template for an object with type "type".
.It Fl T Ar types
types is a comma separated list of object types.
requests the server to only send back objects that match one of the "types".
.El
.Sh EXAMPLES
.Bd -literal -offset indent
$ whois karrenberg
person: Daniel Karrenberg
address: RIPE Network Coordination Centre
address: Kruislaan 409
address: NL-1098 SJ Amsterdam
address: Netherlands
phone: +31 20 5925065
fax-no: +31 20 5925155
e-mail: dfk@ripe.net
nic-hdl: DK58
changed: dfk@ripe.net 920407
changed: ripe-dbm@ripe.net 920407
source: RIPE
$ whois -h whois.ripe.net -r 192.87.45.0/24
inetnum: 192.87.45.0
netname: RIPE-NCC
descr: RIPE Network Coordination Centre
descr: Amsterdam, Netherlands
country: NL
admin-c: Daniel Karrenberg
tech-c: Marten Terpstra
connect: RIPE NSF WCW
aut-sys: AS3333
ias-int: 192.87.45.80 AS1104
ias-int: 192.87.45.6 AS2122
ias-int: 192.87.45.254 AS2600
rev-srv: ns.ripe.net
rev-srv: ns.eu.net
notify: ops@ripe.net
changed: tony@ripe.net 940110
source: RIPE
.Ed
.Ss Other Useful WHOIS Servers
Herewith follows an incomplete list of other potentially useful
WHOIS servers on the Internet.
Use the American Registry for Internet Numbers
.Pq Tn ARIN
database.
It contains network numbers used in those parts of the world
covered neither by
.Tn APNIC
nor by
.Tn RIPE .
.Pp
For information about IP address allocations,
the registrars who handle those allocations are:
.Bl -tag -width indent
.It whois.arin.net
American Registry for Internet Numbers.
.It whois.apnic.net
Asia-Pacific Network Information Center.
.It whois.ripe.net
Reseaux IP Europeens - Network Coordination Center.
.El
.Pp
Internet domain names can now be registered through many different
competing registrars, many of whom (but probably not all of whom)
operate WHOIS servers:
.Bl -tag -width indent
.It whois.networksolutions.com
Network Solutions, operators of the InterNIC.
.It whois.ripe.net
RIPE domains, assignments, \*[Am] routing info.
.It whois.ra.net
Merit/IRR routing info.
.It whois.geektools.com
recursing proxies that query internic.net.
.It whois.fucknsi.com
a meta-WHOIS server that attempts to query all the registrars.
.It whois.opensrs.net
same as above, but also authoritative for OpenSRS domain names.
.El
.Sh RIPE VERSION
This is the RIPE version of the WHOIS client program.
For questions refer to
.Aq ncc@ripe.net .
For more information about the RIPE database please also refer to
.Aq ncc@ripe.net .
.Sh SEE ALSO
.Xr networks 5 ,
.Xr bind 8 ,
.Pa http://www.domainbuyersguide.com/
.Rs
.%R RFC
.%N 812
.%D March 1982
.%T "NICNAME/WHOIS"
.%O (Obsolete)
.Re
.Rs
.%R RFC
.%N 954
.%D October 1985
.%T "NICNAME/WHOIS"
.Re
.Sh BUGS
Most of the extra flags are ONLY supported by the RIPE whois server,
or copies of the same version of the software.
Usage of these flags may cause errors on other whois servers.
(Hint: All point of contact handles in the
.Tn ARIN
whois database end with
.Qq Li -ARIN . )
.It Fl A
Use the Asia/Pacific Network Information Center
.Pq Tn APNIC
database.
It contains network numbers used in East Asia, Australia,
New Zealand, and the Pacific islands.
.It Fl c Ar country-code
This is the equivalent of using the
.Fl h
option with an argument of
.Qq Ar country-code Ns Li .whois-servers.net .
.It Fl d
Use the US Department of Defense database.
It contains points of contact for subdomains of
.Tn \&.MIL .
.It Fl g
Use the US non-military federal government database, which contains points of
contact for subdomains of
.Tn \&.GOV .
.It Fl h Ar host
Use the specified host instead of the default NIC
(whois.crsnic.net).
Either a host name or an IP address may be specified.
.Pp
By default
.Nm
uses
.Xr getaddrinfo 3
functions, thus search order depends on the function.
constructs the name of a whois server to use from the top-level domain
.Pq Tn TLD
of the supplied (single) argument, and appending
.Qq Li .whois-servers.net .
This effectively allows a suitable whois server to be selected
automatically for a large number of
.Tn TLDs .
.Pp
In the event that an IP
address is specified, the whois server will default to the American
Registry for Internet Numbers
.Pq Tn ARIN .
If a query to
.Tn ARIN
references
.Tn APNIC , LACNIC ,
or
.Tn RIPE ,
that server will be queried also, provided that the
.Fl Q
option is not specified.
.Pp
If the query is not a domain name or IP address,
.Nm
will fall back to
.Pa whois.crsnic.net .
.It Fl i
Use the Network Solutions Registry for Internet Numbers
.Pq Tn whois.networksolutions.com
database.
Historically, it contained network numbers and domain contact information
for most of
.Tn \&.COM ,
.Tn \&.NET ,
.Tn \&.ORG
and
.Tn \&.EDU
domains.
However, the registration of these domains is now done by a number of
independent and competing registrars and this database holds no information
on the domains registered by organizations other than Network Solutions, Inc.
Also, note that the
.Tn InterNIC
database
.Pq Pa whois.internic.net
is no longer handled by Network Solutions, Inc.
For details, see
.Pa http://www.internic.net/ .
.Pp
(Hint: Contact information, identified by the term
.Em handle ,
can be looked up by prefixing
.Qq Li \&!
or
.Qq Li handle\ \&
to the
.Tn NIC
handle in the query.)
.It Fl l
Use the Latin American and Caribbean IP address Regional Registry
.Pq Tn LACNIC
database.
It contains network numbers used in much of Latin America and the
Caribbean.
.It Fl m
Use the Route Arbiter Database
.Pq Tn RADB
database.
It contains route policy specifications for a large
number of operators' networks.
.It Fl p Ar port
Connect to the whois server on
.Ar port .
If this option is not specified,
.Nm
defaults to the
.Dq whois
port listed in
.Pa /etc/services
(port 43).
.It Fl Q
Do a quick lookup.
This means that
.Nm
will not attempt to lookup the name in the authoratative whois
server (if one is listed) nor will it contact InterNic if a lookup
fails.
This flag has no effect when combined with any other flag.
.It Fl r
Use the R\(aaeseaux IP Europ\(aaeens
.Pq Tn RIPE
database.
It contains network numbers and domain contact information for Europe.
.It Fl R
Use the Russia Network Information Center
.Pq Tn RIPN
database.
It contains network numbers and domain contact information
for subdomains of
.Tn \&.RU .
This option is deprecated; use the
.Fl c
option with an argument of
.Qq Li RU
instead.
.It Fl 6
Use the IPv6 Resource Center
.Pq Tn 6bone
database.
It contains network names and addresses for the IPv6 network.
.El
.Pp
The default action, unless directed otherwise with a special
.Ar name ,
is to do a very broad search, looking for matches to
.Ar name
in all types of records and most fields (name, nicknames, hostname, net
address, etc.) in the database.
For more information as to what
.Ar name
operands have special meaning, and how to guide the search, use
the special name
.Dq help .
.Ss Special cases
Queries beginning with an exclamation point
.Ql \&!
are assumed to be
.Tn NSI
contact handles.
Unless a host or domain is specified on the command line,
.Pq Tn whois.networksolutions.com
will be used as the
.Nm
database.
.Pp
Similarly, queries beginning with
.Dq COCO-
are assumed to be
.Tn CORE
contact handles.
Unless a host or domain is specified on the command line,
.Pq Tn whois.corenic.net
will be used as the
.Nm
database.
.Sh EXAMPLES
Most types of data, such as domain names and
.Tn IP
addresses, can be used as arguments to
.Nm
without any options, and
.Nm
will choose the correct whois server to query.
Some exceptions, where
.Nm
will not be able to handle data correctly, are detailed below.
.Pp
To obtain contact information about an
administrator located in the Russian
.Tn TLD
domain
.Qq Li RU ,
use the
.Fl c
option as shown in the following example, where
.Ar CONTACT-ID
is substituted with the actual contact identifier.
.Pp
.Dl "whois -c RU CONTACT-ID"
.Pp
(Note: This example is specific to the
.Tn TLD
.Qq Li RU ,
but other
.Tn TLDs
can be queried by using a similar syntax.)
.Pp
The following example demonstrates how to obtain information about an
.Tn IPv6
address or hostname using the
.Fl 6
option, which directs the query to
.Tn 6bone .
.Pp
.Dl "whois -6 IPv6-IP-Address"
.Pp
The following example demonstrates how to query
a whois server using a non-standard port, where
.Dq Li query-data
is the query to be sent to
.Dq Li whois.example.com
on port
.Dq Li rwhois
(written numerically as 4321).
.Pp
.Dl "whois -h whois.example.com -p rwhois query-data"
.Sh SEE ALSO
.Rs
.%A Ken Harrenstien
.%A Vic White
.%T NICNAME/WHOIS
.%D 1 March 1982
.%O RFC 812
.Re
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.3 .

View File

@ -1,21 +1,9 @@
/* $NetBSD: whois.c,v 1.21 2003/08/07 11:17:20 agc Exp $ */
/* $NetBSD: whois.c,v 1.22 2003/10/09 14:21:49 jrf Exp $ */
/* $OpenBSD: whois.c,v 1.28 2003/09/18 22:16:15 fgsch Exp $ */
/*
* RIPE version marten@ripe.net
* many changes & networkupdate by david@ripe.net
* cosmetics by steven@dante.org.uk -- gcc stopped complaining mostly,
* code is still messy, though.
*
* 1.15 94/09/07
*
* 1.2 9705/02
* "-v" option added; ambrose@ripe.net
* "whois.ripe.net" replaced by "bsdbase.ripe.net"; ambrose@ripe.net
* "bsdbase.ripe.net" replaced by "joshua.ripe.net"; marek@ripe.net
* "joshua.ripe.net" replaced by "whois.ripe.net"; roman@ripe.net 981105
*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved.
* Copyright (c) 1980, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -42,550 +30,281 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
The Regents of the University of California. All rights reserved.\n");
#endif /* not lint */
#ifndef RIPE
#ifndef lint
#if 0
static char sccsid[] = "@(#)whois.c 8.1 (Berkeley) 6/6/93";
static const char sccsid[] = "@(#)whois.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: whois.c,v 1.21 2003/08/07 11:17:20 agc Exp $");
__RCSID("$NetBSD: whois.c,v 1.22 2003/10/09 14:21:49 jrf Exp $");
#endif
#endif /* not lint */
#endif /* not RIPE */
#ifdef RIPE
#ifndef lint
char sccsid[] =
"@(#)whois.c 5.11 (Berkeley) 3/2/91 - RIPE 1.15 94/09/07 marten@ripe.net";
#endif /* not lint */
#ifndef lint
__RCSID("$NetBSD: whois.c,v 1.21 2003/08/07 11:17:20 agc Exp $");
#endif
#endif /* RIPE */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <err.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pwd.h>
#include <signal.h>
#define index(s,c) strchr((const char*)(s),(int)(c))
#define rindex(s,c) strrchr((const char*)(s),(int)(c))
#define bzero(s,n) memset((void*)s,0,(size_t)n)
#define NICHOST "whois.crsnic.net"
#define INICHOST "whois.networksolutions.com"
#define CNICHOST "whois.corenic.net"
#define DNICHOST "whois.nic.mil"
#define GNICHOST "whois.nic.gov"
#define ANICHOST "whois.arin.net"
#define RNICHOST "whois.ripe.net"
#define PNICHOST "whois.apnic.net"
#define RUNICHOST "whois.ripn.net"
#define MNICHOST "whois.ra.net"
#define LNICHOST "whois.lacnic.net"
#define SNICHOST "whois.6bone.net"
#define BNICHOST "whois.registro.br"
#define QNICHOST_TAIL ".whois-servers.net"
#ifdef HASMEMMOVE
# define bcopy(s,d,n) memmove((void*)(d),(void*)(s),(size_t)(n))
#else
# define bcopy(s,d,n) memcpy((void*)(d),(void*)(s),(size_t)(n))
#endif /* HASMEMMOVE */
#define WHOIS_PORT "whois"
#define WHOIS_SERVER_ID "Whois Server:"
/*
#define WHOIS_RECURSE 0x01
#define WHOIS_QUICK 0x02
# the following defines can be used but are not fully functional anymore...
#
# CLEVER- Use a educated guess of the whereabouts of the nearest server
# This is done by taking the top-level domain of the current
# machine, and looking for a CNAME record for a server with name
# <top-level-domain>-whois.ripe.net
# If this machine does not exsist or the current machine's top-level
# domain could not be found,it will fall back to whois.ripe.net
# the default for this RIPE version of whois
# The CLEVER option implies the RIPE option.
const char *port = WHOIS_PORT;
const char *ip_whois[] = { LNICHOST, RNICHOST, PNICHOST, BNICHOST, NULL };
# TOPDOMAIN=\"<top-level-domain>\"
# - This option will fix the default host to be
# <top-level-domain>-whois.ripe.net, which may point to a secondary
# server inside your top-level domain. If there is no such secondary
# server, it will point to whois.ripe.net, the default. This option
# overrules the CLEVER option.
# The TOPDOMAIN option implies the RIPE option.
*/
#if defined(TOPDOMAIN) || defined(CLEVER)
#ifndef RIPE
#define RIPE
#endif /* !RIPE */
#endif /* TOPDOMAIN || CLEVER */
#define NICHOST "whois.internic.net"
int main(int, char **);
static void usage(void);
static void closesocket(int, int);
static void termhandler(int);
void
usage(void)
{
#ifdef RIPE
#ifdef NETWORKUPDATE
(void)fprintf(stderr, "\nUsage: networkupdate [-46] [-h hostname] [-p port]");
#else
(void)fprintf(stderr, "\nUsage: whois [-46aFLmMrSvR] [-h hostname] [-s sources] [-T types] [-i attr] keys\n");
(void)fprintf(stderr, " whois -t type");
(void)fprintf(stderr, " whois -v type");
#endif
#else
(void)fprintf(stderr, "\nUsage: whois [-46] [-h hostname] [-p port] name ...");
#endif
(void)fprintf(stderr, "\n\nWhere:\n\n");
(void)fprintf(stderr, "-4 Use IPv4 Only\n");
(void)fprintf(stderr, "-6 Use IPv6 Only\n");
#ifdef RIPE
#ifndef NETWORKUPDATE
(void)fprintf(stderr, "-a search all databases\n");
(void)fprintf(stderr, "-F fast raw output\n");
#endif
#endif
(void)fprintf(stderr, "-h hostname search alternate server\n");
#ifdef RIPE
#ifndef NETWORKUPDATE
(void)fprintf(stderr, "-i [attr][[,attr] ... ] do an inverse lookup for specified attributes\n");
(void)fprintf(stderr, "-L find all Less specific matches\n");
(void)fprintf(stderr, "-m find first level more specific matches\n");
(void)fprintf(stderr, "-M find all More specific matches\n");
#endif
#endif
(void)fprintf(stderr, "-p port port to connect to\n");
#ifdef RIPE
#ifndef NETWORKUPDATE
(void)fprintf(stderr, "-r turn off recursive lookups\n");
(void)fprintf(stderr, "-s source[[,source] ... ] search databases with source 'source'\n");
(void)fprintf(stderr, "-S tell server to leave out 'syntactic sugar'\n");
(void)fprintf(stderr, "-t type requests template for object of type 'type'\n");
(void)fprintf(stderr, "-v type requests verbose template for object of type 'type'\n");
(void)fprintf(stderr, "-R force to show local copy of the domain object even if it contains referral\n");
(void)fprintf(stderr, "-T type[[,type] ... ] only look for objects of type 'type'\n\n");
(void)fprintf(stderr, "Please note that most of these flags are NOT understood by\n");
(void)fprintf(stderr, "non RIPE whois servers\n");
#endif
#endif
(void)fprintf(stderr, "\n");
exit(1);
}
int s;
void
closesocket(int s, int child)
{
/* printf("close connection child=%i\n", child); */
close(s);
#ifdef NETWORKUPDATE
if (child==0) {
kill(getppid(), SIGTERM);
}
#endif
exit(0);
}
void
termhandler(int sig)
{
closesocket(s,1);
}
#ifdef RIPE
#define occurs(str,pat) ((int) strstr((str),(pat)))
#endif
static __dead void usage(void);
static int whois(const char *, const char *, const char *, int);
static char *choose_server(const char *, const char *);
int
main(int argc, char *argv[])
{
extern char *optarg;
extern int optind;
FILE *sfi;
FILE *sfo;
int ch;
struct addrinfo *dst, hints;
int af=PF_UNSPEC;
int error;
char *host, *whoishost;
int optp=0;
char *optport="whois";
#ifdef DEBUG
int verb=1;
#else /*DEBUG */
int verb=0;
int ch, flags, rval;
char *host, *name, *country, *server;
#ifdef SOCKS
SOCKSinit(argv[0]);
#endif
#ifdef RIPE
int opthost=0;
#ifndef NETWORKUPDATE
/* normal whois client */
char *string;
int alldatabases=0;
int optsource=0, optrecur=0, optfast=0, opttempl=0, optverbose=0;
int optobjtype=0, optsugar=0, optinverselookup=0, optgetupdates=0;
int optL=0, optm=0, optM=0, optchanged=0, optnonreferral=0;
char *source=NULL, *templ=NULL, *verbose=NULL, *objtype=NULL,
*inverselookup=NULL, *getupdates=NULL;
#else /* NETWORKUPDATE */
/* networkupdate client */
int prev;
char domainname[64]; /* that's what sys/param.h says */
struct passwd *passwdentry;
int child;
#endif
#ifdef CLEVER
int myerror;
char *mytoplevel;
char *myhost;
#endif
#endif
#ifdef TOPDOMAIN
char topdomain[] = TOPDOMAIN "-whois.ripe.net";
host = topdomain;
#else
host = NICHOST;
#endif
#ifdef RIPE
#ifdef NETWORKUPDATE
while ((ch = getopt(argc, argv, "46h:p:")) != -1)
#else
while ((ch = getopt(argc, argv, "46acFg:h:i:LmMp:rs:SRt:T:v:")) != -1)
#endif
#else
while ((ch = getopt(argc, argv, "46h:p:")) != -1)
#endif
switch((char)ch) {
case '4':
af = PF_INET;
break;
case '6':
af = PF_INET6;
break;
case 'h':
host = optarg;
opthost = 1;
break;
case 'p':
optport=optarg;
optp =1;
break;
#ifdef RIPE
#ifndef NETWORKUPDATE
case 'a':
alldatabases=1;
break;
case 'c':
optchanged=1;
break;
case 'F':
optfast = 1;
break;
case 'g':
getupdates=optarg;
optgetupdates=1;
break;
case 'i':
inverselookup=optarg;
optinverselookup = 1;
break;
case 'L':
if (optM || optm) {
fprintf(stderr, "Only one of -L, -m or -M allowed\n\n");
usage();
}
optL=1;
break;
case 'm':
if (optM || optL) {
fprintf(stderr, "Only one of -L, -m or -M allowed\n\n");
usage();
}
optm=1;
break;
case 'M':
if (optL || optm) {
fprintf(stderr, "Only one of -L, -m or -M allowed\n\n");
usage();
}
optM=1;
break;
case 's':
source = optarg;
optsource=1;
break;
case 'S':
optsugar=1;
break;
case 'R':
optnonreferral=1;
break;
case 'r':
optrecur=1;
break;
case 't':
templ=optarg;
opttempl=1;
break;
case 'v':
verbose=optarg;
optverbose=1;
break;
case 'T':
objtype=optarg;
optobjtype=1;
break;
#endif
#endif
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
country = host = server = NULL;
flags = rval = 0;
while ((ch = getopt(argc, argv, "aAc:dgh:ilmp:qQrR6")) != -1)
switch(ch) {
case 'a':
host = ANICHOST;
break;
case 'A':
host = PNICHOST;
break;
case 'c':
country = optarg;
break;
case 'd':
host = DNICHOST;
break;
case 'g':
host = GNICHOST;
break;
case 'h':
host = optarg;
break;
case 'i':
host = INICHOST;
break;
case 'l':
host = LNICHOST;
break;
case 'm':
host = MNICHOST;
break;
case 'p':
port = optarg;
break;
case 'q':
/* deprecated, now the default */
break;
case 'Q':
flags |= WHOIS_QUICK;
break;
case 'r':
host = RNICHOST;
break;
case 'R':
host = RUNICHOST;
break;
case '6':
host = SNICHOST;
break;
default:
usage();
}
argc -= optind;
argv += optind;
#ifdef RIPE
#ifdef NETWORKUPDATE
if (argc>0)
usage();
#else
if ((argc<=0) && !opttempl && !optverbose && !optgetupdates && (!(opttempl && optgetupdates)))
usage();
#endif
#else
if (argc<=0)
usage();
#endif
if (!argc || (country != NULL && host != NULL))
usage();
if (!opthost) {
#ifdef CLEVER
whoishost=(char *)calloc(MAXHOSTNAMELEN, sizeof(char));
if (!whoishost)
err(1, "malloc");
myhost =(char *)calloc(MAXHOSTNAMELEN, sizeof(char));
if (!myhost)
err(1, "malloc");
myerror = gethostname(myhost, MAXHOSTNAMELEN);
if (myerror >= 0) {
if (occurs(myhost, ".")) {
mytoplevel = rindex(myhost,'.');
mytoplevel++;
(void) snprintf(whoishost, MAXHOSTNAMELEN, "%s-whois.ripe.net",
mytoplevel);
if (verb) fprintf(stderr, "Clever guess: %s\n", whoishost);
}
}
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
error = getaddrinfo(host, optport, &hints, &dst);
if ((error) && (verb))
fprintf(stderr,"No such host: %s\n", whoishost);
if (error) {
#endif
whoishost=NICHOST;
if (verb)
fprintf(stderr, "Default host: %s\n\n", whoishost);
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
error = getaddrinfo(host, optport , &hints, &dst);
if (error) {
fprintf(stderr,"No such host: %s\n", whoishost);
if (verb) fprintf(stderr, "Now I give up ...\n");
perror("Unknown host");
exit(1);
}
#ifdef CLEVER
}
#endif
}
else {
if (verb)
fprintf(stderr, "Trying: %s\n\n", host);
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
error = getaddrinfo(host, optport, &hints, &dst);
if (error) {
(void)fprintf(stderr, "whois: %s: ", host);
perror("Unknown host");
exit(1);
}
}
for (/*nothing*/; dst; dst = dst->ai_next) {
s = socket(dst->ai_family, dst->ai_socktype, dst->ai_protocol);
if (s < 0)
continue;
if (connect(s, dst->ai_addr, dst->ai_addrlen) < 0) {
close(s);
if (verb) (void)fprintf(stderr, "whois: connect miss\n");
continue;
}
/*okay*/
break;
}
if (dst == NULL) {
perror("whois: connect");
exit(1);
}
if (verb) (void)fprintf(stderr, "whois: connect success\n");
#ifndef NETWORKUPDATE
sfi = fdopen(s, "r");
sfo = fdopen(s, "w");
if (sfi == NULL || sfo == NULL) {
perror("whois: fdopen");
(void)close(s);
exit(1);
}
#endif
signal(SIGTERM, termhandler);
#ifdef RIPE
#ifdef NETWORKUPDATE
if ((child=fork())==0) {
sfo = fdopen(s, "w");
if (sfo == NULL) {
perror("whois: fdopen");
(void)close(s);
exit(1);
}
if (gethostname(domainname, sizeof(domainname))) {
fprintf(stderr, "error when doing gethostname()");
exit(1);
}
passwdentry=getpwuid(getuid());
fprintf(sfo, "-Vnc2.0 -U %s %s\n", passwdentry->pw_name, domainname);
fflush(sfo);
prev='\0';
while ((ch=getchar()) != EOF) {
fputc(ch, sfo);
if (ch=='\n') fflush(sfo);
if (feof(sfo)) closesocket(s, child);
if ((ch=='.') && (prev=='\n')) closesocket(s, child);
if (!isspace(ch) || ((!isspace(prev)) && (ch=='\n'))) prev=ch;
}
closesocket(s, child);
}
sfi = fdopen(s, "r");
if (sfi == NULL) {
perror("whois: fdopen");
(void)close(s);
exit(1);
}
#else
if (alldatabases)
(void)fprintf(sfo, "-a ");
if (optchanged)
(void)fprintf(sfo, "-c ");
if (optfast)
(void)fprintf(sfo, "-F ");
if (optgetupdates)
(void)fprintf(sfo, "-g %s ", getupdates);
if (optinverselookup)
(void)fprintf(sfo, "-i %s ", inverselookup);
if (optL)
(void)fprintf(sfo, "-L ");
if (optm)
(void)fprintf(sfo, "-m ");
if (optM)
(void)fprintf(sfo, "-M ");
if (optrecur)
(void)fprintf(sfo, "-r ");
if (optsource)
(void)fprintf(sfo, "-s %s ", source);
if (optsugar)
(void)fprintf(sfo, "-S ");
if (optnonreferral)
(void)fprintf(sfo, "-R ");
if (opttempl)
(void)fprintf(sfo, "-t %s ", templ);
if (optverbose)
(void)fprintf(sfo, "-v %s ", verbose);
if (optobjtype)
(void)fprintf(sfo, "-T %s ", objtype);
/* we can only send the -V when we are sure that we are dealing with
a RIPE whois server :-( */
whoishost = strdup(host);
if (!whoishost)
err(1, "malloc");
for (string=whoishost;(*string=(char)tolower(*string));string++);
if (strstr(whoishost, "ripe.net") ||
strstr(whoishost, "ra.net") ||
strstr(whoishost, "apnic.net") ||
strstr(whoishost, "mci.net") ||
strstr(whoishost, "isi.edu") ||
strstr(whoishost, "garr.it") ||
strstr(whoishost, "ans.net") ||
alldatabases || optfast || optgetupdates || optinverselookup ||
optL || optm || optM || optrecur || optsugar || optsource ||
opttempl || optverbose || optobjtype)
(void)fprintf(sfo, "-VwC2.0 ");
#endif
#endif
#ifndef NETWORKUPDATE
while (argc-- > 1)
(void)fprintf(sfo, "%s ", *argv++);
if (*argv) (void)fputs(*argv, sfo);
(void)fputs("\r\n", sfo);
(void)fflush(sfo);
#endif
while ((ch = getc(sfi)) != EOF)
putchar(ch);
closesocket(s, 1);
exit(0);
if (host == NULL && country == NULL && !(flags & WHOIS_QUICK))
flags |= WHOIS_RECURSE;
for (name = *argv; (name = *argv) != NULL; argv++)
rval += whois(name, host ? host : choose_server(name, country),
port, flags);
exit(rval);
}
static int
whois(const char *query, const char *server, const char *port, int flags)
{
FILE *sfi, *sfo;
char *buf, *p, *nhost, *nbuf = NULL;
size_t len;
int i, s, error;
const char *reason = NULL;
struct addrinfo hints, *res, *ai;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = 0;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(server, port, &hints, &res);
if (error) {
warnx("%s: %s", server, gai_strerror(error));
return (1);
}
for (s = -1, ai = res; ai != NULL; ai = ai->ai_next) {
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (s < 0) {
reason = "socket";
continue;
}
if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
reason = "connect";
close(s);
s = -1;
continue;
}
break; /*okay*/
}
if (s < 0) {
if (reason)
warn("%s: %s", server, reason);
else
warn("unknown error in connection attempt");
freeaddrinfo(res);
return (1);
}
sfi = fdopen(s, "r");
sfo = fdopen(s, "w");
if (sfi == NULL || sfo == NULL)
err(1, "fdopen");
(void)fprintf(sfo, "%s\r\n", query);
(void)fflush(sfo);
nhost = NULL;
while ((buf = fgetln(sfi, &len)) != NULL) {
p = buf + len - 1;
if (isspace((unsigned char)*p)) {
do
*p = '\0';
while (p > buf && isspace((unsigned char)*--p));
} else {
if ((nbuf = malloc(len + 1)) == NULL)
err(1, "malloc");
memcpy(nbuf, buf, len);
nbuf[len] = '\0';
buf = nbuf;
}
(void)puts(buf);
if (nhost != NULL || !(flags & WHOIS_RECURSE))
continue;
if ((p = strstr(buf, WHOIS_SERVER_ID))) {
p += sizeof(WHOIS_SERVER_ID) - 1;
while (isblank(*p))
p++;
if ((len = strcspn(p, " \t\n\r"))) {
if ((nhost = malloc(len + 1)) == NULL)
err(1, "malloc");
memcpy(nhost, p, len);
nhost[len] = '\0';
}
} else if (strcmp(server, ANICHOST) == 0) {
for (p = buf; *p != '\0'; p++)
*p = tolower((unsigned char)*p);
for (i = 0; ip_whois[i] != NULL; i++) {
if (strstr(buf, ip_whois[i]) != NULL) {
nhost = strdup(ip_whois[i]);
if (nhost == NULL)
err(1, "strdup");
break;
}
}
}
}
if (nbuf != NULL)
free(nbuf);
if (nhost != NULL) {
error = whois(query, nhost, port, 0);
free(nhost);
}
freeaddrinfo(res);
return (error);
}
/*
* If no country is specified determine the top level domain from the query.
* If the TLD is a number, query ARIN, otherwise, use TLD.whois-server.net.
* If the domain does not contain '.', check to see if it is an NSI handle
* (starts with '!') or a CORE handle (COCO-[0-9]+ or COHO-[0-9]+).
* Fall back to NICHOST for the non-handle case.
*/
static char *
choose_server(const char *name, const char *country)
{
static char *server;
const char *qhead;
char *ep;
size_t len;
if (country != NULL)
qhead = country;
else if ((qhead = strrchr(name, '.')) == NULL) {
if (*name == '!')
return (INICHOST);
else if ((strncasecmp(name, "COCO-", 5) == 0 ||
strncasecmp(name, "COHO-", 5) == 0) &&
strtol(name + 5, &ep, 10) > 0 && *ep == '\0')
return (CNICHOST);
else
return (NICHOST);
} else if (isdigit(*(++qhead)))
return (ANICHOST);
len = strlen(qhead) + sizeof(QNICHOST_TAIL);
if ((server = realloc(server, len)) == NULL)
err(1, "realloc");
strlcpy(server, qhead, len);
strlcat(server, QNICHOST_TAIL, len);
return (server);
}
static __dead void
usage(void)
{
extern char *__progname;
(void)fprintf(stderr,
"usage: %s [-aAdgilmQrR6] [-c country-code | -h hostname] "
"[-p port] name ...\n", __progname);
exit(1);
}