More robust handling of whois referrals from RIRs.

An example problem case is 163.1.0.0 (University of Oxford)
which is in an APNIC ERX address range. Previously we assumed
that ARIN has the correct information for all ERX allocations,
but in this case ARIN refers back to APNIC, rather than referring
to RIPE. This caused whois to loop.

Whois will no longer loop back and forth forever between two RIRs
that don't have an answer, but instead try the other RIRs in turn.
This commit is contained in:
Tony Finch 2016-11-17 15:19:06 +00:00
parent ead1785e1e
commit 3997df0cde
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=308762

View file

@ -119,12 +119,38 @@ static struct {
{ NULL, 0 }
};
/*
* We have a list of patterns for RIRs that assert ignorance rather than
* providing referrals. If that happens, we guess that ARIN will be more
* helpful. But, before following a referral to an RIR, we check if we have
* asked that RIR already, and if so we make another guess.
*/
static const char *actually_arin[] = {
"netname: ERX-NETBLOCK\n", /* APNIC */
"netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n",
NULL
};
static struct {
int loop;
const char *host;
} try_rir[] = {
{ 0, ANICHOST },
{ 0, RNICHOST },
{ 0, PNICHOST },
{ 0, FNICHOST },
{ 0, LNICHOST },
{ 0, NULL }
};
static void
reset_rir(void) {
int i;
for (i = 0; try_rir[i].host != NULL; i++)
try_rir[i].loop = 0;
}
static const char *port = DEFAULT_PORT;
static const char *choose_server(char *);
@ -232,6 +258,7 @@ main(int argc, char *argv[])
} else
whois(*argv, host != NULL ? host :
choose_server(*argv), flags);
reset_rir();
argv++;
}
exit(0);
@ -420,7 +447,7 @@ whois(const char *query, const char *hostname, int flags)
FILE *fp;
struct addrinfo *hostres;
char *buf, *host, *nhost, *p;
int s, f;
int comment, s, f;
size_t len, i;
hostres = gethostinfo(hostname, 1);
@ -467,12 +494,28 @@ whois(const char *query, const char *hostname, int flags)
fprintf(fp, "%s\r\n", query);
fflush(fp);
comment = 0;
if (!(flags & WHOIS_SPAM_ME) &&
(strcasecmp(hostname, ANICHOST) == 0 ||
strcasecmp(hostname, RNICHOST) == 0)) {
comment = 2;
}
nhost = NULL;
while ((buf = fgetln(fp, &len)) != NULL) {
/* Nominet */
if (!(flags & WHOIS_SPAM_ME) &&
len == 5 && strncmp(buf, "-- \r\n", 5) == 0)
break;
/* RIRs */
if (comment == 1 && buf[0] == '#')
break;
else if (comment == 2) {
if (strchr("#%\r\n", buf[0]) != NULL)
continue;
else
comment = 1;
}
printf("%.*s", (int)len, buf);
@ -487,8 +530,7 @@ whois(const char *query, const char *hostname, int flags)
SCAN(p, buf+len, *p == ' ');
host = p;
SCAN(p, buf+len, ishost(*p));
/* avoid loops */
if (strncmp(hostname, host, p - host) != 0)
if (p > host)
s_asprintf(&nhost, "%.*s",
(int)(p - host), host);
break;
@ -511,8 +553,37 @@ whois(const char *query, const char *hostname, int flags)
}
fclose(fp);
freeaddrinfo(hostres);
f = 0;
for (i = 0; try_rir[i].host != NULL; i++) {
/* Remember visits to RIRs */
if (try_rir[i].loop == 0 &&
strcasecmp(try_rir[i].host, hostname) == 0)
try_rir[i].loop = 1;
/* Do we need to find an alternative RIR? */
if (try_rir[i].loop != 0 && nhost != NULL &&
strcasecmp(try_rir[i].host, nhost) == 0) {
free(nhost);
nhost = NULL;
f = 1;
}
}
if (f) {
/* Find a replacement RIR */
for (i = 0; try_rir[i].host != NULL; i++) {
if (try_rir[i].loop == 0) {
s_asprintf(&nhost, "%s",
try_rir[i].host);
break;
}
}
}
if (nhost != NULL) {
whois(query, nhost, flags);
/* Ignore self-referrals */
if (strcasecmp(hostname, nhost) != 0) {
printf("# %s\n\n", nhost);
whois(query, nhost, flags);
}
free(nhost);
}
}