version 1.12, 2000/09/26 02:51:22 |
version 1.13, 2000/09/26 05:03:31 |
|
|
#include <setjmp.h> |
#include <setjmp.h> |
#include <signal.h> |
#include <signal.h> |
#include <fcntl.h> |
#include <fcntl.h> |
|
#include <stdarg.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
|
|
int netfd = -1; |
int netfd = -1; |
int ofd = 0; /* hexdump output fd */ |
int ofd = 0; /* hexdump output fd */ |
|
|
extern int h_errno; |
/* extern int h_errno; */ |
/* stolen almost wholesale from bsd herror.c */ |
|
static char *h_errs[] = { |
|
"Error 0", /* but we *don't* use this */ |
|
"Unknown host", /* 1 HOST_NOT_FOUND */ |
|
"Host name lookup failure", /* 2 TRY_AGAIN */ |
|
"Unknown server error", /* 3 NO_RECOVERY */ |
|
"No address associated with name", /* 4 NO_ADDRESS */ |
|
}; |
|
|
|
int gatesidx = 0; /* LSRR hop count */ |
int gatesidx = 0; /* LSRR hop count */ |
int gatesptr = 4; /* initial LSRR pointer, settable */ |
int gatesptr = 4; /* initial LSRR pointer, settable */ |
|
|
u_short o_zero = 0; |
u_short o_zero = 0; |
|
|
/* Function Prototype's */ |
/* Function Prototype's */ |
void usage __P((int)); |
|
void help __P(()); |
void help __P(()); |
|
void usage __P((int)); |
|
void nlog __P((int, char *, ...)); |
|
|
/* |
/* |
* support routines -- the bulk of this thing. Placed in such an order that |
* support routines -- the bulk of this thing. Placed in such an order that |
|
|
{ |
{ |
errno = 0; |
errno = 0; |
if (o_verbose > 1) /* normally we don't care */ |
if (o_verbose > 1) /* normally we don't care */ |
errx(1, "Sent %i Rcvd %i", wrote_net, wrote_out); |
nlog(1, "Sent %i Rcvd %i", wrote_net, wrote_out); |
errx(1, " punt!"); |
nlog(1, " punt!"); |
} |
} |
|
|
/* timeout and other signal handling cruft */ |
/* timeout and other signal handling cruft */ |
|
|
signal(SIGALRM, SIG_IGN); |
signal(SIGALRM, SIG_IGN); |
alarm(0); |
alarm(0); |
if (jval == 0) |
if (jval == 0) |
errx(1, "spurious timer interrupt!"); |
nlog(1, "spurious timer interrupt!"); |
longjmp(jbuf, jval); |
longjmp(jbuf, jval); |
} |
} |
|
|
|
|
errno = 0; |
errno = 0; |
h_errno = 0; |
h_errno = 0; |
if (strcasecmp(hinfo->name, hp->h_name) != 0) { |
if (strcasecmp(hinfo->name, hp->h_name) != 0) { |
warn("DNS fwd/rev mismatch: %s != %s", hinfo->name, hp->h_name); |
nlog(0, "DNS fwd/rev mismatch: %s != %s", hinfo->name, hp->h_name); |
return (1); |
return (1); |
} |
} |
return (0); |
return (0); |
|
|
hinfo = (struct host_info *) calloc(1, sizeof(struct host_info)); |
hinfo = (struct host_info *) calloc(1, sizeof(struct host_info)); |
|
|
if (!hinfo) |
if (!hinfo) |
errx(1, "error obtaining host information"); |
nlog(1, "error obtaining host information"); |
|
|
strlcpy(hinfo->name, "(UNKNOWN)", sizeof(hinfo->name)); |
strlcpy(hinfo->name, "(UNKNOWN)", sizeof(hinfo->name)); |
if (inet_aton(name, &iaddr) == 0) { |
if (inet_aton(name, &iaddr) == 0) { |
if (numeric) |
if (numeric) |
errx(1, "Can't parse %s as an IP address", name); |
nlog(1, "Can't parse %s as an IP address", name); |
|
|
/* |
/* |
* failure to look up a name is fatal, |
* failure to look up a name is fatal, |
|
|
*/ |
*/ |
hostent = gethostbyname(name); |
hostent = gethostbyname(name); |
if (!hostent) |
if (!hostent) |
errx(1, "%s: forward host lookup failed: ", name); |
nlog(1, "%s: forward host lookup failed: ", name); |
|
|
strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN); |
strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN); |
for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) { |
for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) { |
|
|
hostent = gethostbyaddr((char *) &hinfo->iaddrs[x], |
hostent = gethostbyaddr((char *) &hinfo->iaddrs[x], |
sizeof(struct in_addr), AF_INET); |
sizeof(struct in_addr), AF_INET); |
if ((!hostent) || (!hostent->h_name)) |
if ((!hostent) || (!hostent->h_name)) |
warn("Warning: inverse host lookup failed for %s: ", |
nlog(0, "Warning: inverse host lookup failed for %s: ", |
hinfo->addrs[x]); |
hinfo->addrs[x]); |
else |
else |
(void) comparehosts(hinfo, hostent); |
(void) comparehosts(hinfo, hostent); |
|
|
* *not* considered fatal |
* *not* considered fatal |
*/ |
*/ |
if (!hostent) |
if (!hostent) |
warn("%s: inverse host lookup failed: ", name); |
nlog(0, "%s: inverse host lookup failed: ", name); |
else { |
else { |
strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN); |
strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN); |
hostent = gethostbyname(hinfo->name); |
hostent = gethostbyname(hinfo->name); |
if ((!hostent) || (!hostent->h_addr_list[0])) |
if ((!hostent) || (!hostent->h_addr_list[0])) |
warn("Warning: forward host lookup failed for %s: ", |
nlog(0, "Warning: forward host lookup failed for %s: ", |
hinfo->name); |
hinfo->name); |
else |
else |
(void) comparehosts(hinfo, hostent); |
(void) comparehosts(hinfo, hostent); |
|
|
if (servent) { |
if (servent) { |
y = ntohs(servent->s_port); |
y = ntohs(servent->s_port); |
if (x != y) /* "never happen" */ |
if (x != y) /* "never happen" */ |
warn("Warning: port-bynum mismatch, %d != %d", x, y); |
nlog(0, "Warning: port-bynum mismatch, %d != %d", x, y); |
strlcpy(pinfo->name, servent->s_name, |
strlcpy(pinfo->name, servent->s_name, |
sizeof(pinfo->name)); |
sizeof(pinfo->name)); |
} |
} |
|
|
u_short x; |
u_short x; |
|
|
if (!block) |
if (!block) |
errx(1, "loadports: no block?!"); |
nlog(1, "loadports: no block?!"); |
if ((!lo) || (!hi)) |
if ((!lo) || (!hi)) |
errx(1, "loadports: bogus values %d, %d", lo, hi); |
nlog(1, "loadports: bogus values %d, %d", lo, hi); |
x = hi; |
x = hi; |
while (lo <= x) { |
while (lo <= x) { |
block[x] = 1; |
block[x] = 1; |
|
|
else |
else |
nnetfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
nnetfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
if (nnetfd < 0) |
if (nnetfd < 0) |
errx(1, "Can't get socket"); |
nlog(1, "Can't get socket"); |
if (nnetfd == 0) /* if stdin was closed this might *be* 0, */ |
if (nnetfd == 0) /* if stdin was closed this might *be* 0, */ |
goto newskt; /* so grab another. See text for why... */ |
goto newskt; /* so grab another. See text for why... */ |
x = 1; |
x = 1; |
rr = setsockopt(nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); |
rr = setsockopt(nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); |
if (rr == -1) |
if (rr == -1) |
errx(1, NULL); |
nlog(1, NULL); |
|
|
/* fill in all the right sockaddr crud */ |
/* fill in all the right sockaddr crud */ |
lclend->sin_family = AF_INET; |
lclend->sin_family = AF_INET; |
|
|
if (errno != EADDRINUSE) |
if (errno != EADDRINUSE) |
break; |
break; |
else { |
else { |
warn("retrying local %s:%d", inet_ntoa(lclend->sin_addr), lp); |
nlog(0, "retrying local %s:%d", inet_ntoa(lclend->sin_addr), lp); |
sleep(2); |
sleep(2); |
errno = 0; /* clear from sleep */ |
errno = 0; /* clear from sleep */ |
} |
} |
} |
} |
} |
} |
if (rr) |
if (rr) |
errx(1, "Can't grab %s:%d with bind", |
nlog(1, "Can't grab %s:%d with bind", |
inet_ntoa(lclend->sin_addr), lp); |
inet_ntoa(lclend->sin_addr), lp); |
|
|
if (o_listen) |
if (o_listen) |
|
|
return (-1); |
return (-1); |
if (o_udpmode) { |
if (o_udpmode) { |
if (!lp) |
if (!lp) |
errx(1, "UDP listen needs -p arg"); |
nlog(1, "UDP listen needs -p arg"); |
} else { |
} else { |
rr = listen(nnetfd, 1); |
rr = listen(nnetfd, 1); |
if (rr < 0) |
if (rr < 0) |
errx(1, "error listening"); |
nlog(1, "error listening"); |
} |
} |
|
|
if (o_verbose) { |
if (o_verbose) { |
x = sizeof(struct sockaddr); |
x = sizeof(struct sockaddr); |
rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x); |
rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x); |
if (rr < 0) |
if (rr < 0) |
warn("local getsockname failed"); |
nlog(0, "local getsockname failed"); |
strcpy(bigbuf_net, "listening on ["); /* buffer reuse... */ |
strcpy(bigbuf_net, "listening on ["); /* buffer reuse... */ |
if (lclend->sin_addr.s_addr) |
if (lclend->sin_addr.s_addr) |
strcat(bigbuf_net, inet_ntoa(lclend->sin_addr)); |
strcat(bigbuf_net, inet_ntoa(lclend->sin_addr)); |
|
|
strcat(bigbuf_net, "any"); |
strcat(bigbuf_net, "any"); |
strcat(bigbuf_net, "] %d ..."); |
strcat(bigbuf_net, "] %d ..."); |
z = ntohs(lclend->sin_port); |
z = ntohs(lclend->sin_port); |
warn("%s %d", bigbuf_net, z); |
nlog(0, "%s %d", bigbuf_net, z); |
} /* verbose -- whew!! */ |
} /* verbose -- whew!! */ |
/* |
/* |
* UDP is a speeeeecial case -- we have to do I/O *and* get the |
* UDP is a speeeeecial case -- we have to do I/O *and* get the |
|
|
x = sizeof(struct sockaddr); |
x = sizeof(struct sockaddr); |
rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x); |
rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x); |
if (rr < 0 && o_verbose) |
if (rr < 0 && o_verbose) |
warn("post-rcv getsockname failed"); |
nlog(0, "post-rcv getsockname failed"); |
strcpy(cp, inet_ntoa(lclend->sin_addr)); |
strcpy(cp, inet_ntoa(lclend->sin_addr)); |
|
|
z = ntohs(remend->sin_port); |
z = ntohs(remend->sin_port); |
|
|
x = 1; |
x = 1; |
} |
} |
if (x) { |
if (x) { |
errx(1, "invalid connection to [%s] from %s [%s] %d", |
nlog(1, "invalid connection to [%s] from %s [%s] %d", |
cp, whozis->name, whozis->addrs[0], z); |
cp, whozis->name, whozis->addrs[0], z); |
} |
} |
if (o_verbose) { |
if (o_verbose) { |
warn("connect to [%s] from %s [%s] %d", |
nlog(0, "connect to [%s] from %s [%s] %d", |
cp, whozis->name, whozis->addrs[0], z); |
cp, whozis->name, whozis->addrs[0], z); |
} |
} |
return (nnetfd); |
return (nnetfd); |
|
|
|
|
rr = write(fd, bigbuf_in, 1); |
rr = write(fd, bigbuf_in, 1); |
if (rr != 1 && o_verbose) |
if (rr != 1 && o_verbose) |
warn("udptest first write failed?! errno %d", errno); |
nlog(0, "udptest first write failed?! errno %d", errno); |
if (o_wait) |
if (o_wait) |
sleep(o_wait); |
sleep(o_wait); |
else { |
else { |
|
|
unsigned int y; |
unsigned int y; |
|
|
if (!ofd) |
if (!ofd) |
errx(1, "oprint called with no open fd?!"); |
nlog(1, "oprint called with no open fd?!"); |
if (n == 0) |
if (n == 0) |
return; |
return; |
|
|
|
|
*a = '\n'; /* finish the line */ |
*a = '\n'; /* finish the line */ |
x = write(ofd, stage, soc); |
x = write(ofd, stage, soc); |
if (x < 0) |
if (x < 0) |
errx(1, "ofd write err"); |
nlog(1, "ofd write err"); |
} |
} |
} |
} |
|
|
|
|
* *ds1 |= (1 << fd), etc. |
* *ds1 |= (1 << fd), etc. |
*/ |
*/ |
if (fd > FD_SETSIZE) { |
if (fd > FD_SETSIZE) { |
warn("Preposterous fd value %d", fd); |
nlog(0, "Preposterous fd value %d", fd); |
return (1); |
return (1); |
} |
} |
FD_SET(fd, &fds1); |
FD_SET(fd, &fds1); |
|
|
rr = select(getdtablesize(), &fds2, 0, 0, tv); |
rr = select(getdtablesize(), &fds2, 0, 0, tv); |
if (rr < 0) { |
if (rr < 0) { |
if (errno != EINTR) { |
if (errno != EINTR) { |
warn("Select Failure"); |
nlog(0, "Select Failure"); |
close(fd); |
close(fd); |
return (1); |
return (1); |
} |
} |
|
|
if (!netretry) { |
if (!netretry) { |
if (o_verbose) /* normally we don't |
if (o_verbose) /* normally we don't |
* care */ |
* care */ |
warn("net timeout"); |
nlog(0, "net timeout"); |
close(fd); |
close(fd); |
return (0); /* not an error! */ |
return (0); /* not an error! */ |
} |
} |
|
|
} |
} |
/* net write retries sometimes happen on UDP connections */ |
/* net write retries sometimes happen on UDP connections */ |
if (!wretry) { /* is something hung? */ |
if (!wretry) { /* is something hung? */ |
warn("too many output retries"); |
nlog(0, "too many output retries"); |
return (1); |
return (1); |
} |
} |
if (rnleft) { |
if (rnleft) { |
|
|
* here */ |
* here */ |
cp[BIGSIZ-1] = '\0'; |
cp[BIGSIZ-1] = '\0'; |
if (insaved <= 0) |
if (insaved <= 0) |
errx(1, "wrong"); |
nlog(1, "wrong"); |
x = findline(cp, insaved); |
x = findline(cp, insaved); |
if (x) |
if (x) |
insaved -= x; /* remaining chunk size to be sent */ |
insaved -= x; /* remaining chunk size to be sent */ |
|
|
if ((x) && (x == (x & 0x1c))) |
if ((x) && (x == (x & 0x1c))) |
gatesptr = x; |
gatesptr = x; |
else |
else |
errx(1, "invalid hop pointer %d, must be multiple of 4 <= 28", x); |
nlog(1, "invalid hop pointer %d, must be multiple of 4 <= 28", x); |
break; |
break; |
case 'g': /* srcroute hop[s] */ |
case 'g': /* srcroute hop[s] */ |
if (gatesidx > 8) |
if (gatesidx > 8) |
errx(1, "Too many -g hops!"); |
nlog(1, "Too many -g hops!"); |
if (gates == NULL) |
if (gates == NULL) |
gates = (struct host_info **) calloc(1, |
gates = (struct host_info **) calloc(1, |
sizeof(struct host_info *) * 10); |
sizeof(struct host_info *) * 10); |
|
|
case 'i': /* line-interval time */ |
case 'i': /* line-interval time */ |
o_interval = atoi(optarg) & 0xffff; |
o_interval = atoi(optarg) & 0xffff; |
if (!o_interval) |
if (!o_interval) |
errx(1, "invalid interval time %s", optarg); |
nlog(1, "invalid interval time %s", optarg); |
break; |
break; |
case 'l': /* listen mode */ |
case 'l': /* listen mode */ |
o_listen++; |
o_listen++; |
|
|
case 'p': /* local source port */ |
case 'p': /* local source port */ |
o_lport = getpinfo(optarg, 0); |
o_lport = getpinfo(optarg, 0); |
if (o_lport == 0) |
if (o_lport == 0) |
errx(1, "invalid local port %s", optarg); |
nlog(1, "invalid local port %s", optarg); |
break; |
break; |
case 'r': /* randomize various things */ |
case 'r': /* randomize various things */ |
o_random++; |
o_random++; |
|
|
case 'w': /* wait time */ |
case 'w': /* wait time */ |
o_wait = atoi(optarg); |
o_wait = atoi(optarg); |
if (o_wait <= 0) |
if (o_wait <= 0) |
errx(1, "invalid wait-time %s", optarg); |
nlog(1, "invalid wait-time %s", optarg); |
timer1.tv_sec = o_wait; |
timer1.tv_sec = o_wait; |
timer1.tv_usec = 0; |
timer1.tv_usec = 0; |
break; |
break; |
|
|
if (o_wfile) { |
if (o_wfile) { |
ofd = open(stage, O_WRONLY | O_CREAT | O_TRUNC, 0664); |
ofd = open(stage, O_WRONLY | O_CREAT | O_TRUNC, 0664); |
if (ofd <= 0) /* must be > extant 0/1/2 */ |
if (ofd <= 0) /* must be > extant 0/1/2 */ |
errx(1, "Can't open %s", stage); |
nlog(1, "Can't open %s", stage); |
stage = (unsigned char *) calloc(1, 100); |
stage = (unsigned char *) calloc(1, 100); |
} |
} |
/* optind is now index of first non -x arg */ |
/* optind is now index of first non -x arg */ |
|
|
if (argv[optind]) { |
if (argv[optind]) { |
curport = getpinfo(argv[optind], 0); |
curport = getpinfo(argv[optind], 0); |
if (curport == 0) |
if (curport == 0) |
errx(1, "invalid port %s", argv[optind]); |
nlog(1, "invalid port %s", argv[optind]); |
} |
} |
netfd = dolisten(themaddr, curport, ouraddr, o_lport); |
netfd = dolisten(themaddr, curport, ouraddr, o_lport); |
if (netfd > 0) { |
if (netfd > 0) { |
x = readwrite(netfd); |
x = readwrite(netfd); |
if (o_verbose) |
if (o_verbose) |
warn("Sent %i Rcvd %i", wrote_net, wrote_out); |
nlog(0, "Sent %i Rcvd %i", wrote_net, wrote_out); |
exit(x); |
exit(x); |
} else |
} else |
errx(1, "no connection"); |
nlog(1, "no connection"); |
} |
} |
/* fall thru to outbound connects. Now we're more picky about args... */ |
/* fall thru to outbound connects. Now we're more picky about args... */ |
if (!themaddr) |
if (!themaddr) |
errx(1, "no destination"); |
nlog(1, "no destination"); |
if (argv[optind] == NULL) |
if (argv[optind] == NULL) |
errx(1, "no port[s] to connect to"); |
nlog(1, "no port[s] to connect to"); |
if (argv[optind + 1]) |
if (argv[optind + 1]) |
Single = 0; |
Single = 0; |
ourport = o_lport; |
ourport = o_lport; |
|
|
cp++; |
cp++; |
hiport = getpinfo(cp, 0); |
hiport = getpinfo(cp, 0); |
if (hiport == 0) |
if (hiport == 0) |
errx(1, "invalid port %s", cp); |
nlog(1, "invalid port %s", cp); |
} /* if found a dash */ |
} /* if found a dash */ |
loport = getpinfo(argv[optind], 0); |
loport = getpinfo(argv[optind], 0); |
if (loport == 0) |
if (loport == 0) |
errx(1, "invalid port %s", argv[optind]); |
nlog(1, "invalid port %s", argv[optind]); |
if (hiport > loport) { /* was it genuinely a range? */ |
if (hiport > loport) { /* was it genuinely a range? */ |
Single = 0; /* multi-mode, case B */ |
Single = 0; /* multi-mode, case B */ |
if (o_random) { /* maybe populate the random array */ |
if (o_random) { /* maybe populate the random array */ |
|
|
if (netfd > 0) { |
if (netfd > 0) { |
x = 0; |
x = 0; |
if (o_verbose) { |
if (o_verbose) { |
warn("%s [%s] %d (%s) open", |
nlog(0, "%s [%s] %d (%s) open", |
whereto->name, |
whereto->name, |
whereto->addrs[0], curport, |
whereto->addrs[0], curport, |
pinfo->name); |
pinfo->name); |
|
|
x = 1; |
x = 1; |
if ((Single || (o_verbose > 1)) |
if ((Single || (o_verbose > 1)) |
|| (errno != ECONNREFUSED)) { |
|| (errno != ECONNREFUSED)) { |
warn("%s [%s] %d (%s)", |
nlog(0, "%s [%s] %d (%s)", |
whereto->name, whereto->addrs[0], |
whereto->name, whereto->addrs[0], |
curport, pinfo->name); |
curport, pinfo->name); |
} |
} |
} |
} |
close(netfd); |
close(netfd); |
|
|
} |
} |
|
|
errno = 0; |
errno = 0; |
if (o_verbose > 1) |
nlog(0, "Sent %i Rcvd %i", wrote_net, wrote_out); |
warn("Sent %i Rcvd %i", wrote_net, wrote_out); |
|
if (Single) |
if (Single) |
exit(x); |
exit(x); |
exit(0); |
exit(0); |
|
} |
|
|
|
/* |
|
* nlog: |
|
* dual purpose function, does both warn() and err() |
|
* and pays attention to o_verbose. |
|
*/ |
|
void |
|
nlog(doexit, fmt) |
|
char *fmt; |
|
{ |
|
va_list args; |
|
|
|
if (o_verbose || doexit) { |
|
va_start(args, fmt); |
|
vfprintf(stderr, fmt, args); |
|
if (h_errno) |
|
herror(NULL); |
|
else |
|
putc('\n', stderr); |
|
} |
|
|
|
if (doexit) |
|
exit(1); |
} |
} |
|
|
void |
void |