home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.ee.lbl.gov
/
2014.05.ftp.ee.lbl.gov.tar
/
ftp.ee.lbl.gov
/
hf-1.2.tar.gz
/
hf-1.2.tar
/
hf-1.2
/
hf.l
< prev
next >
Wrap
Text File
|
2009-12-09
|
20KB
|
1,035 lines
N [0-9]
O ({N}{1,3})
C [0-9A-Fa-f]
H ({C}{1,4})
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <netdb.h>
#include <resolv.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "gnuc.h"
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
#include "nb_dns.h"
#include "setsignal.h"
#include "version.h"
#undef yywrap
#ifdef FLEX_SCANNER
#define YY_NO_UNPUT
#endif
int yywrap(void);
int yylex(void);
void convert(const char *, int);
#ifdef HAVE_ASYNC_DNS
#define ECHO \
if (!lookup_pass) { (void) fwrite( yytext, yyleng, 1, yyout ); }
int lookup_pass; /* true if lookup only */
#endif
int linemode; /* convert at most one entry per line */
int triedone;
%%
::{O}(\.{O}){3} convert(yytext, 1);
{O}(\.{O}){3} convert(yytext, 0);
{H}(:{H}){7} convert(yytext, 1);
{H}:(:{H}){1,6} convert(yytext, 1);
({H}:){2}(:{H}){1,5} convert(yytext, 1);
({H}:){3}(:{H}){1,4} convert(yytext, 1);
({H}:){4}(:{H}){1,3} convert(yytext, 1);
({H}:){5}(:{H}){1,2} convert(yytext, 1);
({H}:){6}:{H} convert(yytext, 1);
({O}\.){1,3} ECHO; /* anti-backtrack */
{O}((\.{O}){1,2}) ECHO; /* anti-backtrack */
{N}+ ECHO;
[^0-9\n]+ ECHO;
[^0-9\n]+\n {
ECHO;
triedone = 0;
}
\n {
ECHO;
triedone = 0;
}
%%
/*
* Copyright (c) 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2009
* 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: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2009\n\
The Regents of the University of California. All rights reserved.\n";
static const char rcsid[] =
"@(#) $Id: hf.l 175 2009-12-09 18:59:04Z leres $ (LBL)";
#endif
#define HSIZE 8192 /* must be a power of two */
struct htable {
char addr[NS_IN6ADDRSZ];
int af; /* address family */
int alen;
int state;
char *name; /* overloaded variable */
struct htable *next;
} htable[HSIZE];
#define STATE_FREE 0 /* not in use */
#define STATE_RAW 1 /* couldn't translate */
#define STATE_SENTPTR 2
#define STATE_HAVEPTR 3
#define STATE_SENTA 4
#define STATE_HAVEA 5
int strip = 1; /* strip local domain when possible */
int lcase = 1; /* force lowercase */
int shortdomain; /* strip entire domain */
const char defaultefmt[] = "%h";
const char *efmt = defaultefmt; /* expansion format */
#ifdef HAVE_ASYNC_DNS
int asyncdns; /* 2 pass async dns hack */
int numasync; /* number of outstanding async requests */
int asyncfd;
#endif
int networknumber; /* convert to network numbers */
int check; /* check PTR's against A records */
#ifdef DEBUG
int debug = 0;
#endif
int tmo; /* seconds to wait for a answer from the dns */
int doingdns; /* true if we're waiting for the nameserver */
jmp_buf alrmenv; /* longjmp() buffer */
char *prog;
char domain[64]; /* current domain name (including '.') */
int domainlen; /* length of domain name */
char azero[NS_IN6ADDRSZ];
#ifdef HAVE_ASYNC_DNS
struct nb_dns_info *nd;
#endif
int targc;
char **targv;
extern char *optarg;
extern int optind, opterr;
/* ANSI C defines this */
#ifndef __STDC__
extern char *malloc();
#endif
/* Forwards */
char *a2h(const char *, int, int);
char *addr2host(const char *, int, int);
#ifdef HAVE_ASYNC_DNS
void asyncreap(int);
#endif
struct htable *cacheaddr(const char *, int, int, int, const char *);
#ifdef DEBUG
void dump(void);
#endif
const char *format(const char *, const char *, const char *);
int getdomain(void);
struct htable *hash(const char *, int, int);
#ifdef HAVE_ASYNC_DNS
int ispipe(FILE *);
#endif
struct htable *lookupaddr(const char *, int, int);
int main(int, char **);
void massagename(char *);
RETSIGTYPE timeout(int);
void usage(void) __attribute__((noreturn));
int
main(argc, argv)
int argc;
char **argv;
{
char *cp;
int op;
#ifdef HAVE_ASYNC_DNS
char errstr[NB_DNS_ERRSIZE];
#endif
if (argv[0] == NULL)
prog = "hf";
else if ((cp = strrchr(argv[0], '/')) != NULL)
prog = cp + 1;
else
prog = argv[0];
opterr = 0;
while ((op = getopt(argc, argv, "1abcdf:ilnNt:")) != EOF)
switch (op) {
case '1':
++linemode;
break;
case 'a':
#ifdef HAVE_ASYNC_DNS
++asyncdns;
#else
fprintf(stderr,
"%s: warning: -a not supported; ignored\n", prog);
#endif
break;
case 'b':
efmt = "%h(%i)";
break;
case 'c':
++check;
break;
#ifdef DEBUG
case 'd':
++debug;
break;
#endif
case 'f':
if (*optarg == '\0')
efmt = defaultefmt;
else
efmt = optarg;
break;
case 'i':
lcase = 0;
break;
case 'l':
strip = 0;
break;
case 'n':
#ifdef notdef
++networknumber;
#else
fprintf(stderr, "%s: -n not currently impemented\n",
prog);
exit(1);
#endif
break;
case 'N':
++shortdomain;
break;
case 't':
tmo = atoi(optarg);
if (tmo <= 0)
usage();
break;
default:
usage();
}
#ifdef HAVE_ASYNC_DNS
if (asyncdns) {
nd = nb_dns_init(errstr);
if (nd == NULL) {
fprintf(stderr, "%s: nb_dns_init: %s\n", prog, errstr);
exit(1);
}
asyncfd = nb_dns_fd(nd);
/* If no explicit timeout, use resolver retransmit */
if (tmo == 0)
tmo = _res.retrans;
}
#endif
/* Figure out our domain, if necessary */
if (!strip || shortdomain || !getdomain())
domain[0] = '\0';
/* Up number of retries, we really want answers */
_res.retry = 20;
/* Don't search, we'll use only FQDNs */
_res.options &= ~RES_DNSRCH;
/* Setup alarm catcher if -t */
#ifdef HAVE_ASYNC_DNS
if (!asyncdns)
#endif
if (tmo > 0)
(void)setsignal(SIGALRM, timeout);
/* Let yywrap() figure out if there are any arguments to open */
targc = argc - optind;
targv = &argv[optind];
yyin = NULL;
(void)yywrap();
/* Process file opened by yywrap() or stdin if no arguments */
if (yyin) {
#ifdef HAVE_ASYNC_DNS
/* XXX depends on the type of stdin */
/* XXX can we do a test rewind? */
#ifdef notdef
if (asyncdns && yyin == stdin)
fprintf(stderr,
"%s: warning: can't use -a on stdin\n", prog);
#endif
#endif
yylex();
}
#ifdef DEBUG
if (debug) {
fflush(stdout);
dump();
}
#endif
exit(0);
}
int
yywrap()
{
char *file;
static int didany = 0;
/* Close file, if necessary */
if (yyin) {
#ifdef HAVE_ASYNC_DNS
if (asyncdns) {
if (lookup_pass) {
if (fseek(yyin, 0L, SEEK_SET) < 0) {
fprintf(stderr,
"%s: fseek/rewind: %s\n",
prog, strerror(errno));
exit(1);
}
yyrestart(yyin);
lookup_pass = 0;
asyncreap(1);
return (0);
}
numasync = 0;
}
#endif
if (yyin != stdin)
(void)fclose(yyin);
yyin = NULL;
}
/* Spin through arguments until we run out or successfully open one */
while (targc > 0) {
file = targv[0];
--targc;
++targv;
++didany;
if ((yyin = fopen(file, "r")) != NULL) {
#ifdef HAVE_ASYNC_DNS
if (asyncdns)
lookup_pass = 1;
#endif
return (0);
}
perror(file);
}
if (!didany) {
++didany;
yyin = stdin;
#ifdef HAVE_ASYNC_DNS
if (asyncdns) {
if (ispipe(yyin)) {
fprintf(stderr,
"%s: warning: can't use -a on a pipe\n",
prog);
asyncdns = 0;
} else
lookup_pass = 1;
}
#endif
return (0);
}
return (1);
}
const char *
format(const char *fmt, const char *hnstr, const char *ipstr)
{
char *cp;
const char *cp2, *item;
size_t len, ilen, llen, dlen, nlen, hlen, itemlen;
static char buf[1024];
/* ip address length */
ilen = strlen(ipstr);
/* Normally we are passed the long hostname */
if (hnstr != NULL) {
/* Long hostname length */
llen = strlen(hnstr);
/* Local domain truncated hostname length */
dlen = llen;
if (*domain != '\0') {
cp2 = hnstr + (llen - domainlen);
if (cp2 > hnstr && strcasecmp(cp2, domain) == 0)
dlen = cp2 - hnstr;
}
/* Local domain truncated hostname length */
cp = strchr(hnstr, '.');
if (cp == NULL)
nlen = llen;
else
nlen = cp - hnstr;
/* Default hostname length */
if (shortdomain)
hlen = nlen;
else
hlen = dlen;
} else {
/* We only have the ip address string */
hnstr = ipstr;
llen = strlen(hnstr);
dlen = llen;
nlen = llen;
hlen = llen;
}
cp = buf;
/* Leave room for EOS */
len = sizeof(buf) - 1;
cp2 = fmt;
while (*cp2 != '\0' && len > 0) {
if (*cp2 != '%') {
*cp++ = *cp2++;
--len;
continue;
}
++cp2;
switch (*cp2) {
case 'h':
/* Default hostname */
item = hnstr;
itemlen = hlen;
break;
case 'D':
/* Local domain truncated hostname */
item = hnstr;
itemlen = dlen;
break;
case 'N':
/* Domain truncated hostname */
item = hnstr;
itemlen = nlen;
break;
case 'i':
/* ip address */
item = ipstr;
itemlen = ilen;
break;
case 'l':
/* Long hostname */
item = hnstr;
itemlen = llen;
break;
default:
/* Random character */
*cp++ = *cp2++;
--len;
continue;
}
if (itemlen > len)
itemlen = len;
strncpy(cp, item, itemlen);
cp += itemlen;
len -= itemlen;
++cp2;
}
*cp = '\0';
return (buf);
}
int
getdomain()
{
char *cp;
struct hostent *hp;
char host[128];
if (gethostname(host, sizeof(host) - 1) < 0)
return (0);
if ((cp = strchr(host, '.')) == NULL) {
/* Not already canonical */
if (tmo > 0)
alarm(tmo);
doingdns = 1;
if (setjmp(alrmenv))
return (0);
hp = gethostbyname(host);
doingdns = 0;
if (hp == NULL)
return (0);
if ((cp = strchr(hp->h_name, '.')) == NULL)
return (0);
}
(void)strncpy(domain, cp, sizeof(domain));
domain[sizeof(domain) - 1] = '\0';
if (lcase)
for (cp = domain; *cp; ++cp)
if (isupper((int)*cp))
*cp = tolower(*cp);
domainlen = strlen(domain);
return (1);
}
RETSIGTYPE
timeout(int signo)
{
if (doingdns) {
doingdns = 0;
longjmp(alrmenv, 1);
}
return RETSIGVAL;
}
/* Convert address to hostname via the dns */
char *
a2h(const char *ap, int alen, int af)
{
char **pp;
size_t len;
static struct hostent *hp;
static char *host = NULL;
static size_t hostlen = 0;
/* Look up the PTR */
if (tmo > 0)
alarm(tmo);
doingdns = 1;
if (setjmp(alrmenv))
return (NULL);
hp = gethostbyaddr(ap, alen, af);
doingdns = 0;
if (hp == NULL)
return (NULL);
len = strlen(hp->h_name) + 1;
if (hostlen < len) {
if (len < 132)
len = 132;
if (host == NULL)
host = malloc(len);
else
host = realloc(host, len);
if (host == NULL) {
hostlen = 0;
return (NULL);
}
hostlen = len;
}
(void)strcpy(host, hp->h_name);
/* Done if we aren't checking */
if (!check)
return (host);
#ifndef HAVE_GETHOSTBYNAME2
if (af != AF_INET)
return (NULL);
#endif
/* Check PTR against the A record */
if (tmo > 0)
alarm(tmo);
doingdns = 1;
if (setjmp(alrmenv))
return (NULL);
#ifdef HAVE_GETHOSTBYNAME2
hp = gethostbyname2(host, af);
#else
hp = gethostbyname(host);
#endif
doingdns = 0;
if (hp == NULL)
return (NULL);
if (af != hp->h_addrtype)
return (NULL);
/* Spin through ip addresses looking for a match */
for (pp = hp->h_addr_list; *pp != NULL; ++pp)
if (memcmp(ap, *pp, alen) == 0)
return (host);
return (NULL);
}
/* Convert address to hostname via the cache and/or dns */
char *
addr2host(const char *ap, int alen, int af)
{
int state;
char *host;
struct htable *p;
/* First look in hash table */
p = lookupaddr(ap, alen, af);
if (p != NULL)
return (p->name);
/* Lookup this host */
host = a2h(ap, alen, af);
state = STATE_RAW;
if (host != NULL) {
if (check)
state = STATE_HAVEA;
else
state = STATE_HAVEPTR;
massagename(host);
}
p = cacheaddr(ap, state, alen, af, host);
if (p != NULL)
return (p->name);
return (host);
}
/* Look hash table entry for address */
struct htable *
lookupaddr(const char *ap, int alen, int af)
{
struct htable *p;
for (p = hash(ap, alen, af); p != NULL; p = p->next)
if (p->af == af && memcmp(p->addr, ap, alen) == 0)
return (p);
return (NULL);
}
void
massagename(char *name)
{
char *cp;
if (lcase)
for (cp = name; *cp; ++cp)
if (isupper((int)*cp))
*cp = tolower(*cp);
}
struct htable *
cacheaddr(const char *ap, int state, int alen, int af, const char *host)
{
struct htable *p, *p2;
/* Don't cache zero */
if (memcmp(ap, azero, alen) == 0)
return (NULL);
/* Look for existing slot in hash table */
for (p = hash(ap, alen, af); p != NULL; p = p->next)
if (p->state != STATE_FREE &&
p->af == af &&
memcmp(p->addr, ap, alen) == 0)
break;
/* Allocate a new slot */
if (p == NULL) {
p = hash(ap, alen, af);
if (p->state != STATE_FREE) {
/* Handle the collision */
p2 = (struct htable *)malloc(sizeof(struct htable));
/* Lose, lose */
if (p2 == NULL)
return (NULL);
memset((char *)p2, 0, sizeof(struct htable));
p2->next = p->next;
p->next = p2;
p = p2;
}
}
/* Install new host */
memmove(p->addr, ap, alen);
p->alen = alen;
p->af = af;
if (host != NULL)
p->name = strdup(host);
if (state != 0)
p->state = state;
if (p->state == STATE_FREE)
abort();
/* Return answer entry */
return (p);
}
#ifdef DEBUG
void
dump()
{
char *cp;
int i, j, n, d;
struct htable *p, *p2;
char buf[132];
d = n = 0;
for (p = htable, i = 0; i < HSIZE; ++p, ++i)
if (p->name) {
++n;
j = 0;
for (p2 = p; p2; p2 = p2->next) {
if ((cp = p2->name) == NULL)
cp = "<nil>";
else if (cp == (char *)1)
cp = "<raw>";
(void)fprintf(stderr, "%4d:%d ", i, j);
if (inet_ntop(p2->af, p2->addr,
buf, sizeof(buf)) == NULL)
(void)fprintf(stderr, "?");
else
(void)fprintf(stderr, "%s", buf);
switch (p2->state) {
case STATE_HAVEA:
(void)fprintf(stderr, " HAVEA");
break;
case STATE_HAVEPTR:
(void)fprintf(stderr, " HAVEPTR");
break;
case STATE_SENTPTR:
(void)fprintf(stderr, " SENTPTR");
break;
case STATE_RAW:
(void)fprintf(stderr, " RAW");
break;
default:
(void)fprintf(stderr, " #%d",
p2->state);
break;
}
(void)fprintf(stderr, " \"%s\"\n", cp);
++d;
++j;
}
}
d -= n;
(void)fprintf(stderr, "%d entries (%d dynamically linked)\n", n, d);
}
#endif
#ifdef HAVE_ASYNC_DNS
void
asyncreap(int ateof)
{
char *host;
int n;
char **pp;
struct htable *p;
struct nb_dns_result *nr;
struct hostent *hp;
fd_set fds;
struct timeval to;
char errstr[NB_DNS_ERRSIZE];
struct nb_dns_result xxxnr;
nr = &xxxnr;
memset(nr, 0, sizeof(*nr));
while (numasync > 0) {
FD_ZERO(&fds);
FD_SET(asyncfd, &fds);
/* If we're not at EOF, just poll */
if (!ateof) {
to.tv_sec = 0;
to.tv_usec = 0;
} else {
to.tv_sec = tmo;
to.tv_usec = 0;
}
n = select(asyncfd + 1, &fds, NULL, NULL, &to);
if (n < 0) {
fprintf(stderr, "%s: select: %s\n",
prog, strerror(errno));
exit(1);
}
/* Done if timed out */
if (n == 0)
break;
n = nb_dns_activity(nd, nr, errstr);
if (n < 0) {
fprintf(stderr, "%s: nb_dns_activity: %s\n",
prog, errstr);
exit(1);
}
/* Bail if reply doesn't match any current queries */
if (n == 0)
continue;
/* Decrement outstanding request counter */
--numasync;
/* Bail if not a good answer */
if (nr->host_errno != NETDB_SUCCESS)
continue;
/* Bail if no hostname (probably shouldn't happen) */
hp = nr->hostent;
host = hp->h_name;
if (host == NULL)
continue;
/* Recover hash table pointer */
p = (struct htable *)nr->cookie;
switch (p->state) {
case STATE_SENTPTR:
/* Are we done? */
if (!check) {
p->state = STATE_HAVEPTR;
break;
}
/* Now look up the A record */
if (nb_dns_host_request2(nd, host, p->af,
(void *)p, errstr) < 0) {
fprintf(stderr, "%s: nb_dns_host_request: %s\n",
prog, errstr);
p->state = STATE_RAW;
free(p->name);
p->name = NULL;
break;
}
/* Cache the fact that we're looking */
++numasync;
p->state = STATE_SENTA;
break;
case STATE_SENTA:
/* Check A against our address */
if (p->af != hp->h_addrtype) {
p->state = STATE_RAW;
free(p->name);
p->name = NULL;
break;
}
/* Spin through ip addresses looking for a match */
for (pp = hp->h_addr_list; *pp != NULL; ++pp)
if (memcmp(p->addr, *pp, p->alen) == 0)
break;
if (pp == NULL) {
p->state = STATE_RAW;
free(p->name);
p->name = NULL;
break;
}
p->state = STATE_HAVEA;
break;
default:
abort();
}
massagename(host);
if (p->name != NULL)
abort();
if (host != NULL)
p->name = strdup(host);
}
}
#endif
void
convert(const char *ipstr, int isv6)
{
const char *hnstr;
int alen;
int af;
#ifdef HAVE_ASYNC_DNS
struct htable *p;
char errstr[NB_DNS_ERRSIZE];
static int num = 0;
#endif
char addr[NS_IN6ADDRSZ];
if (isv6) {
#ifdef AF_INET6
af = AF_INET6;
alen = NS_IN6ADDRSZ;
#else
#ifdef HAVE_ASYNC_DNS
if (!asyncdns || !lookup_pass)
#endif
fputs(ipstr, stdout);
return;
#endif
} else {
af = AF_INET;
alen = NS_INADDRSZ;
}
#ifdef HAVE_ASYNC_DNS
if (asyncdns && lookup_pass) {
if (inet_pton(af, ipstr, addr) != 1)
return;
/* Done if already in hash table */
if (lookupaddr(addr, alen, af) != NULL)
return;
p = cacheaddr(addr, STATE_SENTPTR, alen, af, NULL);
if (p == NULL)
return;
if (nb_dns_addr_request2(nd, addr, af,
(void *)p, errstr) >= 0) {
/* Cache the fact that we're looking */
++numasync;
++num;
} else
fprintf(stderr, "%s: nb_dns_host_request: %s\n",
prog, errstr);
/* reap replies after we send a number of queries */
if (num > 10) {
asyncreap(0);
num = 0;
}
return;
}
#endif
/* Only attempt to translate one address per line */
if (linemode && triedone) {
fputs(ipstr, stdout);
return;
}
++triedone;
if (inet_pton(af, ipstr, addr) == 1)
hnstr = addr2host(addr, alen, af);
else
hnstr = NULL;
fputs(format(efmt, hnstr, ipstr), stdout);
}
struct htable *
hash(const char *ap, int alen, int af)
{
u_int32_t h;
switch (alen) {
case NS_INADDRSZ:
memmove(&h, ap, sizeof(h));
break;
case NS_IN6ADDRSZ:
memmove(&h, ap + NS_IN6ADDRSZ - sizeof(h), sizeof(h));
break;
default:
abort();
}
return (&htable[h & (HSIZE - 1)]);
}
#ifdef HAVE_ASYNC_DNS
int
ispipe(FILE *f)
{
struct stat sbuf;
if (fstat(fileno(f), &sbuf) < 0) {
fprintf(stderr, "%s: fstat: %s\n", prog, strerror(errno));
exit(1);
}
if ((sbuf.st_mode & S_IFMT) != S_IFREG)
return (1);
return (0);
}
#endif
void
usage()
{
(void)fprintf(stderr, "Version %s\n", version);
(void)fprintf(stderr, "usage: %s [-1abcdilN] [-t secs] [-f format]"
" [file ...]\n", prog);
exit(1);
}