add IPv6 patch
This commit is contained in:
parent
9274c7d458
commit
3807536449
|
@ -286,6 +286,7 @@ There's a BIG swamp lurking where network code of any sort lives.
|
||||||
#undef HAVE_TTYENT_H
|
#undef HAVE_TTYENT_H
|
||||||
#define HAVE_SIGSETJMP
|
#define HAVE_SIGSETJMP
|
||||||
#define HAVE_SOCKLEN_T
|
#define HAVE_SOCKLEN_T
|
||||||
|
#define INET6
|
||||||
#endif /* linux */
|
#endif /* linux */
|
||||||
|
|
||||||
/* irix 5.x; may not be correct for earlier ones */
|
/* irix 5.x; may not be correct for earlier ones */
|
||||||
|
|
550
netcat.c
550
netcat.c
|
@ -86,6 +86,12 @@
|
||||||
#define SAI struct sockaddr_in /* ... whoever came up with this model */
|
#define SAI struct sockaddr_in /* ... whoever came up with this model */
|
||||||
#define IA struct in_addr /* ... should be taken out and shot, */
|
#define IA struct in_addr /* ... should be taken out and shot, */
|
||||||
/* ... not that TLI is any better. sigh.. */
|
/* ... not that TLI is any better. sigh.. */
|
||||||
|
#ifdef INET6
|
||||||
|
#define SS struct sockaddr
|
||||||
|
#define SAI6 struct sockaddr_in6
|
||||||
|
#define IA6 struct in6_addr
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SLEAZE_PORT 31337 /* for UDP-scan RTT trick, change if ya want */
|
#define SLEAZE_PORT 31337 /* for UDP-scan RTT trick, change if ya want */
|
||||||
#define USHORT unsigned short /* use these for options an' stuff */
|
#define USHORT unsigned short /* use these for options an' stuff */
|
||||||
#define BIGSIZ 8192 /* big buffers */
|
#define BIGSIZ 8192 /* big buffers */
|
||||||
|
@ -117,6 +123,15 @@ struct host_poop {
|
||||||
};
|
};
|
||||||
#define HINF struct host_poop
|
#define HINF struct host_poop
|
||||||
|
|
||||||
|
#ifdef INET6
|
||||||
|
struct host6_poop {
|
||||||
|
char name[MAXHOSTNAMELEN]; /* dns name */
|
||||||
|
char addrs[8][64]; /* ascii-format IP addresses */
|
||||||
|
struct in6_addr iaddrs[8]; /* real addresses: in_addr.s_addr: ulong */
|
||||||
|
};
|
||||||
|
#define HINF6 struct host6_poop
|
||||||
|
#endif
|
||||||
|
|
||||||
struct port_poop {
|
struct port_poop {
|
||||||
char name [64]; /* name in /etc/services */
|
char name [64]; /* name in /etc/services */
|
||||||
USHORT num; /* real host-order number */
|
USHORT num; /* real host-order number */
|
||||||
|
@ -156,6 +171,10 @@ static char hexnibs[20] = "0123456789abcdef ";
|
||||||
/* will malloc up the following globals: */
|
/* will malloc up the following globals: */
|
||||||
struct timeval * timer1 = NULL;
|
struct timeval * timer1 = NULL;
|
||||||
struct timeval * timer2 = NULL;
|
struct timeval * timer2 = NULL;
|
||||||
|
#ifdef INET6
|
||||||
|
SAI6 * lclend6 = NULL; /* sockaddr_in6 structs */
|
||||||
|
SAI6 * remend6 = NULL;
|
||||||
|
#endif
|
||||||
SAI * lclend = NULL; /* sockaddr_in structs */
|
SAI * lclend = NULL; /* sockaddr_in structs */
|
||||||
SAI * remend = NULL;
|
SAI * remend = NULL;
|
||||||
HINF ** gates = NULL; /* LSRR hop hostpoop */
|
HINF ** gates = NULL; /* LSRR hop hostpoop */
|
||||||
|
@ -349,6 +368,40 @@ int comparehosts (poop, hp)
|
||||||
/* ... do we need to do anything over and above that?? */
|
/* ... do we need to do anything over and above that?? */
|
||||||
} /* comparehosts */
|
} /* comparehosts */
|
||||||
|
|
||||||
|
#ifdef INET6
|
||||||
|
char *inet_ntoa6 (struct in6_addr *s)
|
||||||
|
{
|
||||||
|
static char buf[1024];
|
||||||
|
|
||||||
|
if (IN6_IS_ADDR_V4MAPPED(s))
|
||||||
|
inet_ntop (AF_INET, s+12, buf, sizeof (buf));
|
||||||
|
else
|
||||||
|
inet_ntop (AF_INET6, s, buf, sizeof (buf));
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int comparehosts6 (poop, hp)
|
||||||
|
HINF6 * poop;
|
||||||
|
struct hostent * hp;
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
h_errno = 0;
|
||||||
|
/* The DNS spec is officially case-insensitive, but for those times when you
|
||||||
|
*really* wanna see any and all discrepancies, by all means define this. */
|
||||||
|
#ifdef ANAL
|
||||||
|
if (strcmp (poop->name, hp->h_name) != 0) { /* case-sensitive */
|
||||||
|
#else
|
||||||
|
if (strcasecmp (poop->name, hp->h_name) != 0) { /* normal */
|
||||||
|
#endif
|
||||||
|
holler ("DNS fwd/rev mismatch: %s != %s", poop->name, hp->h_name);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
/* ... do we need to do anything over and above that?? */
|
||||||
|
} /* comparehosts */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* gethostpoop :
|
/* gethostpoop :
|
||||||
resolve a host 8 ways from sunday; return a new host_poop struct with its
|
resolve a host 8 ways from sunday; return a new host_poop struct with its
|
||||||
info. The argument can be a name or [ascii] IP address; it will try its
|
info. The argument can be a name or [ascii] IP address; it will try its
|
||||||
|
@ -447,6 +500,82 @@ HINF * gethostpoop (name, numeric)
|
||||||
return (poop);
|
return (poop);
|
||||||
} /* gethostpoop */
|
} /* gethostpoop */
|
||||||
|
|
||||||
|
#ifdef INET6
|
||||||
|
HINF6 * gethost6poop (name, numeric)
|
||||||
|
char *name;
|
||||||
|
USHORT numeric;
|
||||||
|
{
|
||||||
|
struct hostent *hostent;
|
||||||
|
struct in6_addr iaddr;
|
||||||
|
register HINF6 *poop = NULL;
|
||||||
|
register int x;
|
||||||
|
|
||||||
|
/* If we want to see all the DNS stuff, do the following hair --
|
||||||
|
if inet_addr, do reverse and forward with any warnings; otherwise try
|
||||||
|
to do forward and reverse with any warnings. In other words, as long
|
||||||
|
as we're here, do a complete DNS check on these clowns. Yes, it slows
|
||||||
|
things down a bit for a first run, but once it's cached, who cares? */
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
h_errno = 0;
|
||||||
|
if (name)
|
||||||
|
poop = (HINF6 *) Hmalloc (sizeof (HINF6));
|
||||||
|
if (!poop)
|
||||||
|
bail ("gethost6poop fuxored");
|
||||||
|
strcpy (poop->name, unknown); /* preload it */
|
||||||
|
|
||||||
|
if (! inet_pton (AF_INET6, name, &iaddr)) { /* here's the great split: names... */
|
||||||
|
if (numeric)
|
||||||
|
bail ("Can't parse %s as an IP address", name);
|
||||||
|
hostent = gethostbyname2 (name, AF_INET6);
|
||||||
|
if (!hostent)
|
||||||
|
/* failure to look up a name is fatal, since we can't do anything with it */
|
||||||
|
bail ("%s: forward host lookup failed: ", name);
|
||||||
|
strncpy (poop->name, hostent->h_name, MAXHOSTNAMELEN - 2);
|
||||||
|
for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) {
|
||||||
|
memcpy (&poop->iaddrs[x], hostent->h_addr_list[x], sizeof (IA6));
|
||||||
|
strncpy (poop->addrs[x], inet_ntoa6 (&poop->iaddrs[x]), sizeof (poop->addrs[0]));
|
||||||
|
} /* for x -> addrs, part A */
|
||||||
|
if (!o_verbose) /* if we didn't want to see the */
|
||||||
|
return (poop); /* inverse stuff, we're done. */
|
||||||
|
/* do inverse lookups in separate loop based on our collected forward addrs,
|
||||||
|
since gethostby* tends to crap into the same buffer over and over */
|
||||||
|
for (x = 0; !IN6_IS_ADDR_UNSPECIFIED(&poop->iaddrs[x]) && (x < 8); x++) {
|
||||||
|
hostent = gethostbyaddr ((char *) &poop->iaddrs[x], sizeof (IA6), AF_INET6);
|
||||||
|
if (!hostent || !hostent->h_name)
|
||||||
|
holler ("Warning: inverse host lookup failed for %s: ", poop->addrs[x]);
|
||||||
|
else
|
||||||
|
(void) comparehosts6 (poop, hostent);
|
||||||
|
} /* for x -> addrs, part B */
|
||||||
|
|
||||||
|
} else { /* not INADDR_NONE: numeric addresses... */
|
||||||
|
inet_ntop (AF_INET6, &iaddr, poop->addrs[0], sizeof (poop->addrs[0]));
|
||||||
|
memcpy (poop->iaddrs, &iaddr, sizeof (IA6));
|
||||||
|
if (numeric) /* if numeric-only, we're done */
|
||||||
|
return (poop);
|
||||||
|
if (!o_verbose) /* likewise if we don't want */
|
||||||
|
return (poop); /* the full DNS hair */
|
||||||
|
hostent = gethostbyaddr ((char *) &iaddr, sizeof (IA6), AF_INET6);
|
||||||
|
/* numeric or not, failure to look up a PTR is *not* considered fatal */
|
||||||
|
if (!hostent)
|
||||||
|
holler ("%s: inverse host lookup failed: ", name);
|
||||||
|
else {
|
||||||
|
strncpy (poop->name, hostent->h_name, MAXHOSTNAMELEN - 2);
|
||||||
|
hostent = gethostbyname2 (poop->name, AF_INET6);
|
||||||
|
if (!hostent || !hostent->h_addr_list[0])
|
||||||
|
holler ("Warning: forward host lookup failed for %s: ", poop->name);
|
||||||
|
else
|
||||||
|
(void) comparehosts6 (poop, hostent);
|
||||||
|
} /* if hostent */
|
||||||
|
} /* INADDR_NONE Great Split */
|
||||||
|
|
||||||
|
/* whatever-all went down previously, we should now have a host_poop struct
|
||||||
|
with at least one IP address in it. */
|
||||||
|
h_errno = 0;
|
||||||
|
return (poop);
|
||||||
|
} /* gethost6poop */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* getportpoop :
|
/* getportpoop :
|
||||||
Same general idea as gethostpoop -- look up a port in /etc/services, fill
|
Same general idea as gethostpoop -- look up a port in /etc/services, fill
|
||||||
in global port_poop, but return the actual port *number*. Pass ONE of:
|
in global port_poop, but return the actual port *number*. Pass ONE of:
|
||||||
|
@ -982,9 +1111,9 @@ dol_noop:
|
||||||
x = 1;
|
x = 1;
|
||||||
if (x) /* guilty! */
|
if (x) /* guilty! */
|
||||||
bail ("invalid connection to [%s] from %s [%s] %d",
|
bail ("invalid connection to [%s] from %s [%s] %d",
|
||||||
cp, whozis->name, whozis->addrs[0], z);
|
cp, whozis->name, whozis->addrs[0], z);
|
||||||
holler ("connect to [%s] from %s [%s] %d", /* oh, you're okay.. */
|
holler ("connect to [%s] from %s [%s] %d", /* oh, you're okay.. */
|
||||||
cp, whozis->name, whozis->addrs[0], z);
|
cp, whozis->name, whozis->addrs[0], z);
|
||||||
return (nnetfd); /* open! */
|
return (nnetfd); /* open! */
|
||||||
|
|
||||||
dol_tmo:
|
dol_tmo:
|
||||||
|
@ -1038,6 +1167,305 @@ udptest (fd, where)
|
||||||
return (-1);
|
return (-1);
|
||||||
} /* udptest */
|
} /* udptest */
|
||||||
|
|
||||||
|
#ifdef INET6
|
||||||
|
/* doconnect6 :
|
||||||
|
do all the socket stuff, and return an fd for one of
|
||||||
|
an open outbound TCP connection
|
||||||
|
a UDP stub-socket thingie
|
||||||
|
with appropriate socket options set up if we wanted source-routing, or
|
||||||
|
an unconnected TCP or UDP socket to listen on.
|
||||||
|
Examines various global o_blah flags to figure out what-all to do. */
|
||||||
|
int doconnect6 (rad, rp, lad, lp)
|
||||||
|
IA6 *rad;
|
||||||
|
USHORT rp;
|
||||||
|
IA6 *lad;
|
||||||
|
USHORT lp;
|
||||||
|
{
|
||||||
|
register int nnetfd;
|
||||||
|
register int rr;
|
||||||
|
int x, y;
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
/* grab a socket; set opts */
|
||||||
|
newskt:
|
||||||
|
if (o_udpmode)
|
||||||
|
nnetfd = socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
else
|
||||||
|
nnetfd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (nnetfd < 0)
|
||||||
|
bail ("Can't get socket");
|
||||||
|
if (nnetfd == 0) /* if stdin was closed this might *be* 0, */
|
||||||
|
goto newskt; /* so grab another. See text for why... */
|
||||||
|
x = 1;
|
||||||
|
rr = setsockopt (nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x));
|
||||||
|
if (rr == -1)
|
||||||
|
holler ("nnetfd reuseaddr failed"); /* ??? */
|
||||||
|
#ifdef SO_REUSEPORT /* doesnt exist everywhere... */
|
||||||
|
rr = setsockopt (nnetfd, SOL_SOCKET, SO_REUSEPORT, &x, sizeof (x));
|
||||||
|
if (rr == -1)
|
||||||
|
holler ("nnetfd reuseport failed"); /* ??? */
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
/* If you want to screw with RCVBUF/SNDBUF, do it here. Liudvikas Bukys at
|
||||||
|
Rochester sent this example, which would involve YET MORE options and is
|
||||||
|
just archived here in case you want to mess with it. o_xxxbuf are global
|
||||||
|
integers set in main() getopt loop, and check for rr == 0 afterward. */
|
||||||
|
rr = setsockopt (nnetfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf);
|
||||||
|
rr = setsockopt (nnetfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* fill in all the right sockaddr crud */
|
||||||
|
lclend6->sin6_family = AF_INET6;
|
||||||
|
remend6->sin6_family = AF_INET6;
|
||||||
|
|
||||||
|
/* if lad/lp, do appropriate binding */
|
||||||
|
if (lad)
|
||||||
|
memcpy (&lclend6->sin6_addr, lad, sizeof (IA6));
|
||||||
|
else
|
||||||
|
memcpy (&lclend6->sin6_addr, &in6addr_any, sizeof (IA6));
|
||||||
|
if (lp)
|
||||||
|
lclend6->sin6_port = htons (lp);
|
||||||
|
rr = 0;
|
||||||
|
if (lad || lp) {
|
||||||
|
x = (int) lp;
|
||||||
|
/* try a few times for the local bind, a la ftp-data-port... */
|
||||||
|
for (y = 4; y > 0; y--) {
|
||||||
|
rr = bind (nnetfd, (SA *) lclend6, sizeof (SAI6));
|
||||||
|
if (rr == 0)
|
||||||
|
break;
|
||||||
|
if (errno != EADDRINUSE)
|
||||||
|
break;
|
||||||
|
else {
|
||||||
|
holler ("retrying local %s:%d", inet_ntoa6 (&lclend6->sin6_addr), lp);
|
||||||
|
sleep (2);
|
||||||
|
errno = 0; /* clear from sleep */
|
||||||
|
} /* if EADDRINUSE */
|
||||||
|
} /* for y counter */
|
||||||
|
} /* if lad or lp */
|
||||||
|
if (rr)
|
||||||
|
bail ("Can't grab %s:%d with bind", inet_ntoa6 (&lclend6->sin6_addr), lp);
|
||||||
|
|
||||||
|
if (o_listen)
|
||||||
|
return (nnetfd); /* thanks, that's all for today */
|
||||||
|
|
||||||
|
memcpy (&remend6->sin6_addr, rad, sizeof (IA6));
|
||||||
|
remend6->sin6_port = htons (rp);
|
||||||
|
|
||||||
|
if (gatesidx) { /* if we wanted any srcrt hops ... */
|
||||||
|
holler ("Warning: source routing unavailable on this machine, ignoring");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if gatesidx */
|
||||||
|
/* wrap connect inside a timer, and hit it */
|
||||||
|
arm_timer (1, o_wait);
|
||||||
|
if (setjmp (jbuf) == 0) {
|
||||||
|
rr = connect (nnetfd, (SA *) remend6, sizeof (SAI6));
|
||||||
|
} else { /* setjmp: connect failed... */
|
||||||
|
rr = -1;
|
||||||
|
errno = ETIMEDOUT; /* fake it */
|
||||||
|
}
|
||||||
|
arm_timer (0, 0);
|
||||||
|
if (rr == 0)
|
||||||
|
return (nnetfd);
|
||||||
|
close (nnetfd); /* clean up junked socket FD!! */
|
||||||
|
return (-1);
|
||||||
|
} /* doconnect6 */
|
||||||
|
|
||||||
|
/* dolisten6 :
|
||||||
|
just like doconnect6, and in fact calls a hunk of doconnect6, but listens for
|
||||||
|
incoming and returns an open connection *from* someplace. If we were
|
||||||
|
given host/port args, any connections from elsewhere are rejected. This
|
||||||
|
in conjunction with local-address binding should limit things nicely... */
|
||||||
|
int dolisten6 (rad, rp, lad, lp)
|
||||||
|
IA6 *rad;
|
||||||
|
USHORT rp;
|
||||||
|
IA6 *lad;
|
||||||
|
USHORT lp;
|
||||||
|
{
|
||||||
|
register int nnetfd;
|
||||||
|
register int rr;
|
||||||
|
HINF6 *whozis = NULL;
|
||||||
|
socklen_t x;
|
||||||
|
char *cp;
|
||||||
|
USHORT z;
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
/* Pass everything off to doconnect6, who in o_listen mode just gets a socket */
|
||||||
|
nnetfd = doconnect6 (rad, rp, lad, lp);
|
||||||
|
if (nnetfd <= 0)
|
||||||
|
return (-1);
|
||||||
|
if (o_udpmode) { /* apparently UDP can listen ON */
|
||||||
|
if (!lp) /* "port 0", but that's not useful */
|
||||||
|
bail ("UDP listen needs -p arg");
|
||||||
|
} else {
|
||||||
|
rr = listen (nnetfd, 1); /* gotta listen() before we can get */
|
||||||
|
if (rr < 0) /* our local random port. sheesh. */
|
||||||
|
bail ("local listen fuxored");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Various things that follow temporarily trash bigbuf_net, which might contain
|
||||||
|
a copy of any recvfrom()ed packet, but we'll read() another copy later. */
|
||||||
|
|
||||||
|
/* I can't believe I have to do all this to get my own goddamn bound address
|
||||||
|
and port number. It should just get filled in during bind() or something.
|
||||||
|
All this is only useful if we didn't say -p for listening, since if we
|
||||||
|
said -p we *know* what port we're listening on. At any rate we won't bother
|
||||||
|
with it all unless we wanted to see it, although listening quietly on a
|
||||||
|
random unknown port is probably not very useful without "netstat". */
|
||||||
|
if (o_verbose) {
|
||||||
|
x = sizeof (SAI6); /* how 'bout getsockNUM instead, pinheads?! */
|
||||||
|
rr = getsockname (nnetfd, (SA *) lclend6, &x);
|
||||||
|
if (rr < 0)
|
||||||
|
holler ("local getsockname failed");
|
||||||
|
strcpy (bigbuf_net, "listening on ["); /* buffer reuse... */
|
||||||
|
if (!IN6_IS_ADDR_UNSPECIFIED(&lclend6->sin6_addr))
|
||||||
|
strcat (bigbuf_net, inet_ntoa6 (&lclend6->sin6_addr));
|
||||||
|
else
|
||||||
|
strcat (bigbuf_net, "any");
|
||||||
|
strcat (bigbuf_net, "] %d ...");
|
||||||
|
z = ntohs (lclend6->sin6_port);
|
||||||
|
holler (bigbuf_net, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verbose -- whew!! */
|
||||||
|
/* UDP is a speeeeecial case -- we have to do I/O *and* get the calling
|
||||||
|
party's particulars all at once, listen() and accept() don't apply.
|
||||||
|
At least in the BSD universe, however, recvfrom/PEEK is enough to tell
|
||||||
|
us something came in, and we can set things up so straight read/write
|
||||||
|
actually does work after all. Yow. YMMV on strange platforms! */
|
||||||
|
if (o_udpmode) {
|
||||||
|
x = sizeof (SAI6); /* retval for recvfrom */
|
||||||
|
arm_timer (2, o_wait); /* might as well timeout this, too */
|
||||||
|
if (setjmp (jbuf) == 0) { /* do timeout for initial connect */
|
||||||
|
/* and here we block... */
|
||||||
|
rr = recvfrom (nnetfd, bigbuf_net, BIGSIZ, MSG_PEEK, (SA *) remend6, &x);
|
||||||
|
Debug (("dolisten/recvfrom ding, rr = %d, netbuf %s ",
|
||||||
|
rr, bigbuf_net))
|
||||||
|
} else
|
||||||
|
goto dol_tmo; /* timeout */
|
||||||
|
arm_timer (0, 0);
|
||||||
|
/* I'm not completely clear on how this works -- BSD seems to make UDP
|
||||||
|
just magically work in a connect()ed context, but we'll undoubtedly run
|
||||||
|
into systems this deal doesn't work on. For now, we apparently have to
|
||||||
|
issue a connect() on our just-tickled socket so we can write() back.
|
||||||
|
Again, why the fuck doesn't it just get filled in and taken care of?!
|
||||||
|
This hack is anything but optimal. Basically, if you want your listener
|
||||||
|
to also be able to send data back, you need this connect() line, which
|
||||||
|
also has the side effect that now anything from a different source or even a
|
||||||
|
different port on the other end won't show up and will cause ICMP errors.
|
||||||
|
I guess that's what they meant by "connect".
|
||||||
|
Let's try to remember what the "U" is *really* for, eh? */
|
||||||
|
rr = connect (nnetfd, (SA *) remend6, sizeof (SAI6));
|
||||||
|
goto whoisit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* o_udpmode */
|
||||||
|
/* fall here for TCP */
|
||||||
|
x = sizeof (SAI6); /* retval for accept */
|
||||||
|
arm_timer (2, o_wait); /* wrap this in a timer, too; 0 = forever */
|
||||||
|
if (setjmp (jbuf) == 0) {
|
||||||
|
rr = accept (nnetfd, (SA *) remend6, &x);
|
||||||
|
} else
|
||||||
|
goto dol_tmo; /* timeout */
|
||||||
|
arm_timer (0, 0);
|
||||||
|
close (nnetfd); /* dump the old socket */
|
||||||
|
nnetfd = rr; /* here's our new one */
|
||||||
|
|
||||||
|
whoisit:
|
||||||
|
if (rr < 0)
|
||||||
|
goto dol_err; /* bail out if any errors so far */
|
||||||
|
|
||||||
|
/* find out what address the connection was *to* on our end, in case we're
|
||||||
|
doing a listen-on-any on a multihomed machine. This allows one to
|
||||||
|
offer different services via different alias addresses, such as the
|
||||||
|
"virtual web site" hack. */
|
||||||
|
memset (bigbuf_net, 0, 64);
|
||||||
|
cp = &bigbuf_net[32];
|
||||||
|
x = sizeof (SAI6);
|
||||||
|
rr = getsockname (nnetfd, (SA *) lclend6, &x);
|
||||||
|
if (rr < 0)
|
||||||
|
holler ("post-rcv getsockname failed");
|
||||||
|
strcpy (cp, inet_ntoa6 (&lclend6->sin6_addr));
|
||||||
|
|
||||||
|
/* now check out who it is. We don't care about mismatched DNS names here,
|
||||||
|
but any ADDR and PORT we specified had better fucking well match the caller.
|
||||||
|
Converting from addr to inet_ntoa and back again is a bit of a kludge, but
|
||||||
|
gethostpoop wants a string and there's much gnarlier code out there already,
|
||||||
|
so I don't feel bad.
|
||||||
|
The *real* question is why BFD sockets wasn't designed to allow listens for
|
||||||
|
connections *from* specific hosts/ports, instead of requiring the caller to
|
||||||
|
accept the connection and then reject undesireable ones by closing. In
|
||||||
|
other words, we need a TCP MSG_PEEK. */
|
||||||
|
z = ntohs (remend6->sin6_port);
|
||||||
|
strcpy (bigbuf_net, inet_ntoa6 (&remend6->sin6_addr));
|
||||||
|
whozis = gethost6poop (bigbuf_net, o_nflag);
|
||||||
|
errno = 0;
|
||||||
|
x = 0; /* use as a flag... */
|
||||||
|
if (rad) /* xxx: fix to go down the *list* if we have one? */
|
||||||
|
if (memcmp (rad, whozis->iaddrs, sizeof (SAI6)))
|
||||||
|
x = 1;
|
||||||
|
if (rp)
|
||||||
|
if (z != rp)
|
||||||
|
x = 1;
|
||||||
|
if (x) /* guilty! */
|
||||||
|
bail ("invalid connection to [%s] from %s [%s] %d",
|
||||||
|
cp, whozis->name, whozis->addrs[0], z);
|
||||||
|
holler ("connect to [%s] from %s [%s] %d", /* oh, you're okay.. */
|
||||||
|
cp, whozis->name, whozis->addrs[0], z);
|
||||||
|
return (nnetfd); /* open! */
|
||||||
|
|
||||||
|
dol_tmo:
|
||||||
|
errno = ETIMEDOUT; /* fake it */
|
||||||
|
dol_err:
|
||||||
|
close (nnetfd);
|
||||||
|
return (-1);
|
||||||
|
} /* dolisten */
|
||||||
|
|
||||||
|
/* udptest :
|
||||||
|
fire a couple of packets at a UDP target port, just to see if it's really
|
||||||
|
there. On BSD kernels, ICMP host/port-unreachable errors get delivered to
|
||||||
|
our socket as ECONNREFUSED write errors. On SV kernels, we lose; we'll have
|
||||||
|
to collect and analyze raw ICMP ourselves a la satan's probe_udp_ports
|
||||||
|
backend. Guess where one could swipe the appropriate code from...
|
||||||
|
|
||||||
|
Use the time delay between writes if given, otherwise use the "tcp ping"
|
||||||
|
trick for getting the RTT. [I got that idea from pluvius, and warped it.]
|
||||||
|
Return either the original fd, or clean up and return -1. */
|
||||||
|
int
|
||||||
|
udptest6 (fd, where)
|
||||||
|
int fd;
|
||||||
|
IA6 *where;
|
||||||
|
{
|
||||||
|
register int rr;
|
||||||
|
|
||||||
|
rr = write (fd, bigbuf_in, 1);
|
||||||
|
if (rr != 1)
|
||||||
|
holler ("udptest first write failed?! errno %d", errno);
|
||||||
|
if (o_wait)
|
||||||
|
sleep (o_wait);
|
||||||
|
else {
|
||||||
|
/* use the tcp-ping trick: try connecting to a normally refused port, which
|
||||||
|
causes us to block for the time that SYN gets there and RST gets back.
|
||||||
|
Not completely reliable, but it *does* mostly work. */
|
||||||
|
o_udpmode = 0; /* so doconnect6 does TCP this time */
|
||||||
|
/* Set a temporary connect timeout, so packet filtration doesnt cause
|
||||||
|
us to hang forever, and hit it */
|
||||||
|
o_wait = 5; /* enough that we'll notice?? */
|
||||||
|
rr = doconnect6 (where, SLEAZE_PORT, 0, 0);
|
||||||
|
if (rr > 0)
|
||||||
|
close (rr); /* in case it *did* open */
|
||||||
|
o_wait = 0; /* reset it */
|
||||||
|
o_udpmode++; /* we *are* still doing UDP, right? */
|
||||||
|
} /* if o_wait */
|
||||||
|
errno = 0; /* clear from sleep */
|
||||||
|
rr = write (fd, bigbuf_in, 1);
|
||||||
|
if (rr == 1) /* if write error, no UDP listener */
|
||||||
|
return (fd);
|
||||||
|
close (fd); /* use it or lose it! */
|
||||||
|
return (-1);
|
||||||
|
} /* udptest */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* oprint :
|
/* oprint :
|
||||||
Hexdump bytes shoveled either way to a running logfile, in the format:
|
Hexdump bytes shoveled either way to a running logfile, in the format:
|
||||||
D offset - - - - --- 16 bytes --- - - - - # .... ascii .....
|
D offset - - - - --- 16 bytes --- - - - - # .... ascii .....
|
||||||
|
@ -1385,6 +1813,8 @@ options:");
|
||||||
-e filename program to exec after connect [dangerous!!]");
|
-e filename program to exec after connect [dangerous!!]");
|
||||||
#endif
|
#endif
|
||||||
holler ("\
|
holler ("\
|
||||||
|
-4 Use IPv4 (default)\n\
|
||||||
|
-6 Use IPv6\n\
|
||||||
-b allow broadcasts\n\
|
-b allow broadcasts\n\
|
||||||
-g gateway source-routing hop point[s], up to 8\n\
|
-g gateway source-routing hop point[s], up to 8\n\
|
||||||
-G num source-routing pointer: 4, 8, 12, ...\n\
|
-G num source-routing pointer: 4, 8, 12, ...\n\
|
||||||
|
@ -1428,6 +1858,13 @@ main (argc, argv)
|
||||||
HINF * wherefrom = NULL;
|
HINF * wherefrom = NULL;
|
||||||
IA * ouraddr = NULL;
|
IA * ouraddr = NULL;
|
||||||
IA * themaddr = NULL;
|
IA * themaddr = NULL;
|
||||||
|
#ifdef INET6
|
||||||
|
HINF6 * whereto6 = NULL;
|
||||||
|
HINF6 * wherefrom6 = NULL;
|
||||||
|
IA6 * ouraddr6 = NULL;
|
||||||
|
IA6 * themaddr6 = NULL;
|
||||||
|
int want6 = 0;
|
||||||
|
#endif
|
||||||
USHORT o_lport = 0;
|
USHORT o_lport = 0;
|
||||||
USHORT ourport = 0;
|
USHORT ourport = 0;
|
||||||
USHORT loport = 0; /* for scanning stuff */
|
USHORT loport = 0; /* for scanning stuff */
|
||||||
|
@ -1443,6 +1880,10 @@ main (argc, argv)
|
||||||
/* round up the usual suspects, i.e. malloc up all the stuff we need */
|
/* round up the usual suspects, i.e. malloc up all the stuff we need */
|
||||||
lclend = (SAI *) Hmalloc (sizeof (SA));
|
lclend = (SAI *) Hmalloc (sizeof (SA));
|
||||||
remend = (SAI *) Hmalloc (sizeof (SA));
|
remend = (SAI *) Hmalloc (sizeof (SA));
|
||||||
|
#ifdef INET6
|
||||||
|
lclend6 = (SAI6 *) Hmalloc (sizeof (SS));
|
||||||
|
remend6 = (SAI6 *) Hmalloc (sizeof (SS));
|
||||||
|
#endif
|
||||||
bigbuf_in = Hmalloc (BIGSIZ);
|
bigbuf_in = Hmalloc (BIGSIZ);
|
||||||
bigbuf_net = Hmalloc (BIGSIZ);
|
bigbuf_net = Hmalloc (BIGSIZ);
|
||||||
ding1 = (fd_set *) Hmalloc (sizeof (fd_set));
|
ding1 = (fd_set *) Hmalloc (sizeof (fd_set));
|
||||||
|
@ -1511,9 +1952,17 @@ main (argc, argv)
|
||||||
|
|
||||||
/* If your shitbox doesn't have getopt, step into the nineties already. */
|
/* If your shitbox doesn't have getopt, step into the nineties already. */
|
||||||
/* optarg, optind = next-argv-component [i.e. flag arg]; optopt = last-char */
|
/* optarg, optind = next-argv-component [i.e. flag arg]; optopt = last-char */
|
||||||
while ((x = getopt (argc, argv, "abc:e:g:G:hi:lno:p:q:rs:tuvw:z")) != EOF) {
|
while ((x = getopt (argc, argv, "46abc:e:g:G:hi:lno:p:q:rs:tuvw:z")) != EOF) {
|
||||||
/* Debug (("in go: x now %c, optarg %x optind %d", x, optarg, optind)) */
|
/* Debug (("in go: x now %c, optarg %x optind %d", x, optarg, optind)) */
|
||||||
switch (x) {
|
switch (x) {
|
||||||
|
#ifdef INET6
|
||||||
|
case '4':
|
||||||
|
want6 = 0;
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
want6 = 1;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case 'a':
|
case 'a':
|
||||||
bail ("all-A-records NIY");
|
bail ("all-A-records NIY");
|
||||||
o_alla++; break;
|
o_alla++; break;
|
||||||
|
@ -1578,8 +2027,16 @@ main (argc, argv)
|
||||||
/* do a full lookup [since everything else goes through the same mill],
|
/* do a full lookup [since everything else goes through the same mill],
|
||||||
unless -n was previously specified. In fact, careful placement of -n can
|
unless -n was previously specified. In fact, careful placement of -n can
|
||||||
be useful, so we'll still pass o_nflag here instead of forcing numeric. */
|
be useful, so we'll still pass o_nflag here instead of forcing numeric. */
|
||||||
wherefrom = gethostpoop (optarg, o_nflag);
|
#ifdef INET6
|
||||||
ouraddr = &wherefrom->iaddrs[0];
|
if (want6) {
|
||||||
|
wherefrom6 = gethost6poop (optarg, o_nflag);
|
||||||
|
ouraddr6 = &wherefrom6->iaddrs[0];
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
wherefrom = gethostpoop (optarg, o_nflag);
|
||||||
|
ouraddr = &wherefrom->iaddrs[0];
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#ifdef TELNET
|
#ifdef TELNET
|
||||||
case 't': /* do telnet fakeout */
|
case 't': /* do telnet fakeout */
|
||||||
|
@ -1633,12 +2090,24 @@ Debug (("after go: x now %c, optarg %x optind %d", x, optarg, optind))
|
||||||
/* gonna only use first addr of host-list, like our IQ was normal; if you wanna
|
/* gonna only use first addr of host-list, like our IQ was normal; if you wanna
|
||||||
get fancy with addresses, look up the list yourself and plug 'em in for now.
|
get fancy with addresses, look up the list yourself and plug 'em in for now.
|
||||||
unless we finally implement -a, that is. */
|
unless we finally implement -a, that is. */
|
||||||
if (argv[optind])
|
if (argv[optind]) {
|
||||||
whereto = gethostpoop (argv[optind], o_nflag);
|
#ifdef INET6
|
||||||
if (whereto && whereto->iaddrs)
|
if (want6) {
|
||||||
themaddr = &whereto->iaddrs[0];
|
whereto6 = gethost6poop (argv[optind], o_nflag);
|
||||||
if (themaddr)
|
if (whereto6 && whereto6->iaddrs)
|
||||||
optind++; /* skip past valid host lookup */
|
themaddr6 = &whereto6->iaddrs[0];
|
||||||
|
if (themaddr6)
|
||||||
|
optind++; /* skip past valid host lookup */
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
whereto = gethostpoop (argv[optind], o_nflag);
|
||||||
|
if (whereto && whereto->iaddrs)
|
||||||
|
themaddr = &whereto->iaddrs[0];
|
||||||
|
if (themaddr)
|
||||||
|
optind++; /* skip past valid host lookup */
|
||||||
|
}
|
||||||
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
h_errno = 0;
|
h_errno = 0;
|
||||||
|
|
||||||
|
@ -1653,7 +2122,12 @@ Debug (("after go: x now %c, optarg %x optind %d", x, optarg, optind))
|
||||||
if (curport == 0) /* if given, demand correctness */
|
if (curport == 0) /* if given, demand correctness */
|
||||||
bail ("invalid port %s", argv[optind]);
|
bail ("invalid port %s", argv[optind]);
|
||||||
} /* if port-arg */
|
} /* if port-arg */
|
||||||
netfd = dolisten (themaddr, curport, ouraddr, o_lport);
|
#ifdef INET6
|
||||||
|
if (want6)
|
||||||
|
netfd = dolisten6 (themaddr6, curport, ouraddr6, o_lport);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
netfd = dolisten (themaddr, curport, ouraddr, o_lport);
|
||||||
/* dolisten does its own connect reporting, so we don't holler anything here */
|
/* dolisten does its own connect reporting, so we don't holler anything here */
|
||||||
if (netfd > 0) {
|
if (netfd > 0) {
|
||||||
#ifdef GAPING_SECURITY_HOLE
|
#ifdef GAPING_SECURITY_HOLE
|
||||||
|
@ -1672,8 +2146,16 @@ Debug (("after go: x now %c, optarg %x optind %d", x, optarg, optind))
|
||||||
} /* o_listen */
|
} /* o_listen */
|
||||||
|
|
||||||
/* 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)
|
#ifdef INET6
|
||||||
bail ("no destination");
|
if (want6) {
|
||||||
|
if (! themaddr6)
|
||||||
|
bail ("no destination");
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (! themaddr)
|
||||||
|
bail ("no destination");
|
||||||
|
}
|
||||||
if (argv[optind] == NULL)
|
if (argv[optind] == NULL)
|
||||||
bail ("no port[s] to connect to");
|
bail ("no port[s] to connect to");
|
||||||
if (argv[optind + 1]) /* look ahead: any more port args given? */
|
if (argv[optind + 1]) /* look ahead: any more port args given? */
|
||||||
|
@ -1716,15 +2198,32 @@ Debug (("Single %d, curport %d", Single, curport))
|
||||||
ourport += 8192; /* if it *still* conflicts, use -s. */
|
ourport += 8192; /* if it *still* conflicts, use -s. */
|
||||||
}
|
}
|
||||||
curport = getportpoop (NULL, curport);
|
curport = getportpoop (NULL, curport);
|
||||||
netfd = doconnect (themaddr, curport, ouraddr, ourport);
|
#ifdef INET6
|
||||||
|
if (want6)
|
||||||
|
netfd = doconnect6 (themaddr6, curport, ouraddr6, ourport);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
netfd = doconnect (themaddr, curport, ouraddr, ourport);
|
||||||
Debug (("netfd %d from port %d to port %d", netfd, ourport, curport))
|
Debug (("netfd %d from port %d to port %d", netfd, ourport, curport))
|
||||||
if (netfd > 0)
|
if (netfd > 0)
|
||||||
if (o_zero && o_udpmode) /* if UDP scanning... */
|
if (o_zero && o_udpmode) { /* if UDP scanning... */
|
||||||
netfd = udptest (netfd, themaddr);
|
#ifdef INET6
|
||||||
|
if (want6)
|
||||||
|
netfd = udptest6 (netfd, themaddr6);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
netfd = udptest (netfd, themaddr);
|
||||||
|
}
|
||||||
if (netfd > 0) { /* Yow, are we OPEN YET?! */
|
if (netfd > 0) { /* Yow, are we OPEN YET?! */
|
||||||
x = 0; /* pre-exit status */
|
x = 0; /* pre-exit status */
|
||||||
holler ("%s [%s] %d (%s) open",
|
#ifdef INET6
|
||||||
whereto->name, whereto->addrs[0], curport, portpoop->name);
|
if (want6)
|
||||||
|
holler ("%s [%s] %d (%s) open",
|
||||||
|
whereto6->name, whereto6->addrs[0], curport, portpoop->name);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
holler ("%s [%s] %d (%s) open",
|
||||||
|
whereto->name, whereto->addrs[0], curport, portpoop->name);
|
||||||
#ifdef GAPING_SECURITY_HOLE
|
#ifdef GAPING_SECURITY_HOLE
|
||||||
if (pr00gie) /* exec is valid for outbound, too */
|
if (pr00gie) /* exec is valid for outbound, too */
|
||||||
doexec (netfd);
|
doexec (netfd);
|
||||||
|
@ -1735,9 +2234,16 @@ Debug (("netfd %d from port %d to port %d", netfd, ourport, curport))
|
||||||
x = 1; /* preload exit status for later */
|
x = 1; /* preload exit status for later */
|
||||||
/* if we're scanning at a "one -v" verbosity level, don't print refusals.
|
/* if we're scanning at a "one -v" verbosity level, don't print refusals.
|
||||||
Give it another -v if you want to see everything. */
|
Give it another -v if you want to see everything. */
|
||||||
if ((Single || (o_verbose > 1)) || (errno != ECONNREFUSED))
|
if ((Single || (o_verbose > 1)) || (errno != ECONNREFUSED)) {
|
||||||
holler ("%s [%s] %d (%s)",
|
#ifdef INET6
|
||||||
whereto->name, whereto->addrs[0], curport, portpoop->name);
|
if (want6)
|
||||||
|
holler ("%s [%s] %d (%s)",
|
||||||
|
whereto6->name, whereto6->addrs[0], curport, portpoop->name);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
holler ("%s [%s] %d (%s)",
|
||||||
|
whereto->name, whereto->addrs[0], curport, portpoop->name);
|
||||||
|
}
|
||||||
} /* if netfd */
|
} /* if netfd */
|
||||||
close (netfd); /* just in case we didn't already */
|
close (netfd); /* just in case we didn't already */
|
||||||
if (o_interval)
|
if (o_interval)
|
||||||
|
|
Loading…
Reference in New Issue