summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorericj <>2000-09-26 01:15:50 +0000
committerericj <>2000-09-26 01:15:50 +0000
commitbdd702e3e925d77913544e8ce0945ea251363607 (patch)
tree454b6ba26f447df245ee486c769e6bbed4af426b /src
parentb8d571f7a917ee7e6a5117dcf667928c27d38c09 (diff)
downloadopenbsd-bdd702e3e925d77913544e8ce0945ea251363607.tar.gz
openbsd-bdd702e3e925d77913544e8ce0945ea251363607.tar.bz2
openbsd-bdd702e3e925d77913544e8ce0945ea251363607.zip
Alot of cleanups to netcat
use errx/warn instead of homegrown functions indent properly to make the code readable get rid of generic.h as its not used dont declare optarg register is depreciated get rid of undocumented options -a and -e throw out IP_OPTIONS code for now, its not on by default and doesnt work properly make usage more like other bsd commands
Diffstat (limited to 'src')
-rw-r--r--src/usr.bin/nc/generic.h377
-rw-r--r--src/usr.bin/nc/netcat.c1401
2 files changed, 571 insertions, 1207 deletions
diff --git a/src/usr.bin/nc/generic.h b/src/usr.bin/nc/generic.h
deleted file mode 100644
index b3dd5f5dc6..0000000000
--- a/src/usr.bin/nc/generic.h
+++ /dev/null
@@ -1,377 +0,0 @@
1/* generic.h -- anything you don't #undef at the end remains in effect.
2 The ONLY things that go in here are generic indicator flags; it's up
3 to your programs to declare and call things based on those flags.
4
5 You should only need to make changes via a minimal system-specific section
6 at the end of this file. To build a new section, rip through this and
7 check everything it mentions on your platform, and #undef that which needs
8 it. If you generate a system-specific section you didn't find in here,
9 please mail me a copy so I can update the "master".
10
11 I realize I'm probably inventing another pseudo-standard here, but
12 goddamnit, everybody ELSE has already, and I can't include all of their
13 hairball schemes too. HAVE_xx conforms to the gnu/autoconf usage and
14 seems to be the most common format. In fact, I dug a lot of these out
15 of autoconf and tried to common them all together using "stupidh" to
16 collect data from platforms.
17
18 In disgust... _H* 940910, 941115, 950511. Pseudo-version: 1.3
19
20 Updated 951104 with many patches from netcat feedback, and properly
21 closed a lot of slop in open-ended comments: version 1.4
22 960217 + nextstep: version 1.5
23*/
24
25#ifndef GENERIC_H /* only run through this once */
26#define GENERIC_H
27
28/* =============================== */
29/* System calls, lib routines, etc */
30/* =============================== */
31
32/* How does your system declare malloc, void or char? Usually void, but go
33 ask the SunOS people why they had to be different... */
34#define VOID_MALLOC
35
36/* notably from fwtk/firewall.h: posix locking? */
37#define HAVE_FLOCK /* otherwise it's lockf() */
38
39/* if you don't have setsid(), you might have setpgrp(). */
40#define HAVE_SETSID
41
42/* random() is generally considered better than rand() */
43#define HAVE_RANDOM
44
45/* the srand48/lrand48/etc family is s'posedly even better */
46#define HAVE_RAND48
47/* bmc@telebase and others have suggested these macros if a box *does* have
48 rand48. Will consider for later if we're doing something that really
49 requires stronger random numbers, but netcat and such certainly doesn't.
50#define srandom(seed) srand48((long) seed)
51#define random() lrand48() */
52
53/* if your machine doesn't have lstat(), it should have stat() [dos...] */
54#define HAVE_LSTAT
55
56/* different kinds of term ioctls. How to recognize them, very roughly:
57 sysv/POSIX_ME_HARDER: termio[s].h, struct termio[s], tty.c_*[]
58 bsd/old stuff: sgtty.h, ioctl(TIOCSETP), sgttyb.sg_*, tchars.t_* */
59#define HAVE_TERMIOS
60
61/* dbm vs ndbm */
62#define HAVE_NDBM
63
64/* extended utmp/wtmp stuff. MOST machines still do NOT have this SV-ism */
65#define UTMPX
66
67/* some systems have nice() which takes *relative* values... [resource.h] */
68#define HAVE_SETPRIORITY
69
70/* a sysvism, I think, but ... */
71#define HAVE_SYSINFO
72
73/* ============= */
74/* Include files */
75/* ============= */
76
77/* Presence of these can be determined via a script that sniffs them
78 out if you aren't sure. See "stupidh"... */
79
80/* stdlib comes with most modern compilers, but ya never know */
81#define HAVE_STDLIB_H
82
83/* not on a DOS box! */
84#define HAVE_UNISTD_H
85
86/* stdarg is a weird one */
87#define HAVE_STDARG_H
88
89/* dir.h or maybe ndir.h otherwise. */
90#define HAVE_DIRENT_H
91
92/* string or strings */
93#define HAVE_STRINGS_H
94
95/* if you don't have lastlog.h, what you want might be in login.h */
96#define HAVE_LASTLOG_H
97
98/* predefines for _PATH_various */
99#define HAVE_PATHS_H
100
101/* some SV-flavors break select stuff out separately */
102#define HAVE_SELECT_H
103
104/* assorted others */
105#define HAVE_PARAM_H /* in sys/ */
106#define HAVE_SYSMACROS_H /* in sys/ */
107#define HAVE_TTYENT_H /* securetty et al */
108
109/* ==================== */
110
111/* Still maybe have to do something about the following, if it's even
112 worth it. I just grepped a lot of these out of various code, without
113 looking them up yet:
114
115#define HAVE_EINPROGRESS
116#define HAVE_F_SETOWN
117HAVE_FILIO_H ... fionbio, fiosetown, etc... will need for hairier
118 select loops.
119#define HAVE_SETENV ... now *there's* a hairy one; **environ is portable
120#define BIG_ENDIAN/little_endian ... *please* try to avoid this stupidity
121 and LSBFIRST/MSBFIRST
122#define HAVE_GETUSERSHELL ... you could always pull it out of getpwent()
123#define HAVE_SETE[UG]ID ... lib or syscall, it varies on diff platforms
124#define HAVE_STRCHR ... should actually be handled by string/strings
125#define HAVE_PSTAT
126#define HAVE_ST_BLKSIZE ... a stat() thing?
127#define HAVE_IP_TOS
128#define HAVE_STRFTIME ... screw this, we'll just INCLUDE one for lame
129 old boxes that don't have it [sunos 3.x, early 4.x?]
130#define HAVE_VFPRINTF
131#define HAVE_SHADOW_PASSWD ... in its multitudinous schemes?? ... how
132 about sumpin' like #define SHADOW_PASSWD_TYPE ... could get grody.
133 ... looks like sysv /etc/shadow, getspent() family is common.
134#define SIG* ... what a swamp, punt for now; should all be in signal.h
135#define HAVE_STRCSPN ... see larry wall's comment in the fwtk regex code
136#define ULTRIX_AUTH ... bwahaha.
137#define HAVE_YP or NIS or whatever you wanna call it this week
138randomness about VARARGS??
139--- later stuff to be considered ---
140#define UINT4 ... u-int on alpha/osf, i.e. __alpha/__osf__, ulong elsewhere?
141 dont name it that, though, it'll conflict with extant .h files like md5
142randomness about machine/endian.h, machine/inline.h -- bsdi, net/2
143randomness about _PATH_WTMP vs WTMP_FILE and where they even live!!
144#define HAVE_SYS_ERRLIST ... whether it's in stdio.h or not [bsd 4.4]
145--- still more stuff
146#define HAVE_SETENV
147#define _PATH_UTMP vs UTMP_FILE, a la deslogind?!
148#define HAVE_DAEMON
149#define HAVE_INETADDR [vixie bind?]
150lseek: SEEK_SET vs L_SET and associated lossage [epi-notes, old 386Mach]
151bsdi: ioctl_compat.h ?
152--- takin' some ifdefs from CNS krb:
153F_GETOWN/F_SETOWN
154CRAY: long = 8 bytes, etc [class with alpha?]
155CGETENT
156SIGINFO
157SIGTSTP SIGTTOU SIGWINCH
158SPX?
159SYSV_TERMIO -- covered elsewhere, I hope
160TIOCEXT TIOCFLUSH TIOC[GS]WINSIZ
161NEWINIT: something about init cleaning up dead login processes [telnet?]
162PARENT_DOES_UTMP, too [telnet]
163VDISCARD
164VEOL/VEOL2/VLNEXT VREPRINT -- termios stuff?, and related...
165STREAMSPTY/STREAMSPTYEM
166AF_INET/AF_UNSPEC, PF_*
167ECHOCTL/ECHOKE
168F_ULOCK [?!]
169setpgrp/getpgrp() ONEARG business..
170HAVE_ALLOCA
171HAVE_GETUTENT
172HAVE_SYS_SELECT_H [irix!]
173HAVE_DIRENT [old 386mach has *direct.h*!]
174HAVE_SIGSET
175HAVE_VFORK_H and HAVE_VFORK
176HAVE_VHANGUP
177HAVE_VSPRINTF
178HAVE_IPTOS_*
179HAVE_STRCASECMP, STRNCASECMP
180HAVE_SYS_FCNTL_H
181HAVE_SYS_TIME_H
182HAVE_UTIMES
183NOTTYENT [?]
184HAVE_FCHMOD
185HAVE_GETUSERSHELL
186HAVE_SIGCONTEXT [stack hair, very machine-specific]
187YYLINENO?
188POSIX_SIGNALS
189POSIX_TERMIOS
190SETPROCTITLE -- breaks some places, like fbsd sendmail
191SIG* -- actual signal names? some are missing
192SIOCGIFCONF
193SO_BROADCAST
194SHMEM [krb tickets]
195VARARGS, or HAVE_VARARGS
196CBAUD
197... and B300, B9600, etc etc
198HAVE_BZERO vs memset/memcpy
199HAVE_SETVBUF
200HAVE_STRDUP
201HAVE_GETENV
202HAVE_STRSAVE
203HAVE_STBLKSIZE [stat?]
204HAVE_STREAM_H -- in sys/, ref sendmail 8.7 for IP_SRCROUTE
205FCHMOD
206INITGROUPS -- most machines seem to *have*
207SETREUID
208SNPRINTF
209SETPGRP semantics bsd vs. sys5 style
210
211There's also the issue about WHERE various .h files live, sys/ or otherwise.
212There's a BIG swamp lurking where network code of any sort lives.
213*/
214
215/* ======================== */
216/* System-specific sections */
217/* ======================== */
218
219/* By turning OFF various bits of the above, you can customize for
220 a given platform. Yes, we're ignoring the stock compiler predefines
221 and using our own plugged in via the Makefile. */
222
223/* DOS boxes, with MSC; you may need to adapt to a different compiler. */
224/* looks like later ones *do* have dirent.h, for example */
225#ifdef MSDOS
226#undef HAVE_FLOCK
227#undef HAVE_RANDOM
228#undef HAVE_LSTAT
229#undef HAVE_TERMIOS
230#undef UTMPX
231#undef HAVE_SYSINFO
232#undef HAVE_UNISTD_H
233#undef HAVE_DIRENT_H /* unless you have the k00l little wrapper from L5!! */
234#undef HAVE_STRINGS_H
235#undef HAVE_LASTLOG_H
236#undef HAVE_PATHS_H
237#undef HAVE_PARAM_H
238#undef HAVE_SYSMACROS_H
239#undef HAVE_SELECT_H
240#undef HAVE_TTYENT_H
241#endif /* MSDOS */
242
243/* buglix 4.x; dunno about 3.x on down. should be bsd4.2 */
244#ifdef ULTRIX
245#undef UTMPX
246#undef HAVE_PATHS_H
247#undef HAVE_SYSMACROS_H
248#undef HAVE_SELECT_H
249#endif /* buglix */
250
251/* some of this might still be broken on older sunoses */
252#ifdef SUNOS
253#undef VOID_MALLOC
254#undef UTMPX
255#undef HAVE_PATHS_H
256#undef HAVE_SELECT_H
257#endif /* sunos */
258
259/* "contact your vendor for a fix" */
260#ifdef SOLARIS
261/* has UTMPX */
262#undef HAVE_RANDOM
263#undef HAVE_SETPRIORITY
264#undef HAVE_STRINGS_H /* this is genuinely the case, go figure */
265#undef HAVE_PATHS_H
266#undef HAVE_SELECT_H
267#undef HAVE_TTYENT_H
268#endif /* SOLARIS */
269
270/* whatever aix variant MIT had at the time; 3.2.x?? */
271#ifdef AIX
272#undef UTMPX
273#undef HAVE_LASTLOG_H
274#define HAVE_LOGIN_H /* "special", in the educational sense */
275#endif /* aix */
276
277/* linux, which is trying as desperately as the gnu folks can to be
278 POSIXLY_CORRECT. I think I'm gonna hurl... */
279#ifdef LINUX
280#undef UTMPX
281#undef HAVE_SYSINFO
282#undef HAVE_SELECT_H
283#undef HAVE_TTYENT_H
284#endif /* linux */
285
286/* irix 5.x; may not be correct for earlier ones */
287#ifdef IRIX
288/* wow, does irix really have everything?! */
289#endif /* irix */
290
291/* osf on alphas */
292#ifdef OSF
293#undef UTMPX
294#undef HAVE_SELECT_H
295#endif /* osf */
296
297/* they's some FUCKED UP paths in this one! */
298#ifdef FREEBSD
299#undef UTMPX
300#undef HAVE_SYSINFO
301#undef HAVE_LASTLOG_H
302#undef HAVE_SYSMACROS_H
303#undef HAVE_SELECT_H /* actually a lie, but only for kernel */
304#endif /* freebsd */
305
306/* Originally from the sidewinder site, of all places, but subsequently
307 checked further under a more normal bsdi 2.0 */
308#ifdef BSDI
309#undef UTMPX
310#undef HAVE_LASTLOG_H
311#undef HAVE_SYSMACROS_H
312/* and their malloc.h was in sys/ ?! */
313#undef HAVE_SELECT_H
314#endif /* bsdi */
315
316/* netbsd/44lite, jives with amiga-netbsd from cactus */
317#ifdef NETBSD
318#undef UTMPX
319#undef HAVE_SYSINFO
320#undef HAVE_LASTLOG_H
321#undef HAVE_SELECT_H
322#endif /* netbsd */
323
324/* Hpux 9.0x, from BBN and various patches sent in */
325#ifdef HPUX
326#undef HAVE_RANDOM /* but *does* have ?rand48 -- need to consider.. */
327#undef HAVE_UTMPX
328#undef HAVE_LASTLOG_H /* has utmp/wtmp/btmp nonsense, and pututline() */
329#undef HAVE_PATHS_H
330#undef HAVE_SELECT_H
331#undef HAVE_TTYENT_H
332#endif /* hockeypux */
333
334/* Unixware [a loose definition of "unix", to be sure], 1.1.2 [at least]
335 from Brian Clapper. He wasn't sure about 2.0... */
336#ifdef UNIXWARE
337/* has UTMPX */
338#undef HAVE_SETPRIORITY
339/* NOTE: UnixWare does provide the BSD stuff, in "/usr/ucbinclude" (headers)
340 and "/usr/ucblib" (libraries). However, I've run into problems linking
341 stuff out of that version of the C library, when objects are also coming
342 out of the "regular" C library. My advice: Avoid the BSD compatibility
343 stuff wherever possible. Brian Clapper <bmc@telebase.com> */
344#undef HAVE_STRINGS_H
345#undef HAVE_PATHS_H
346#undef HAVE_TTYENT_H
347#endif /* UNIXWARE */
348
349/* A/UX 3.1.x from darieb@sandia.gov */
350#ifdef AUX
351#undef HAVE_RANDOM
352#undef HAVE_SELECT_H /* xxx: untested */
353#endif /* a/ux */
354
355/* NeXTSTEP 3.2 motorola mudge@l0pht.com xxx should also work with
356 white hardware and Sparc/HPPA. Should work with 3.3 too as it's
357 4.3 / 4.4 bsd wrapped around mach */
358#ifdef NEXT
359#undef UTMPX
360#undef HAVE_SELECT_X
361#endif /* NeXTSTEP 3.2 motorola */
362
363/* Make some "generic" assumptions if all else fails */
364#ifdef GENERIC
365#undef HAVE_FLOCK
366#if defined(SYSV) && (SYSV < 4) /* TW leftover: old SV doesnt have symlinks */
367#undef HAVE_LSTAT
368#endif /* old SYSV */
369#undef HAVE_TERMIOS
370#undef UTMPX
371#undef HAVE_PATHS_H
372#undef HAVE_SELECT_H
373#endif /* generic */
374
375/* ================ */
376#endif /* GENERIC_H */
377
diff --git a/src/usr.bin/nc/netcat.c b/src/usr.bin/nc/netcat.c
index ad9f6ce862..ae9d4d9df1 100644
--- a/src/usr.bin/nc/netcat.c
+++ b/src/usr.bin/nc/netcat.c
@@ -1,3 +1,5 @@
1/* $OpenBSD: netcat.c,v 1.11 2000/09/26 01:15:49 ericj Exp $ */
2
1/* Netcat 1.10 RELEASE 960320 3/* Netcat 1.10 RELEASE 960320
2 * 4 *
3 * A damn useful little "backend" utility begun 950915 or thereabouts, 5 * A damn useful little "backend" utility begun 950915 or thereabouts,
@@ -26,11 +28,7 @@
26 * backend progs to do various encryption modes??!?! 28 * backend progs to do various encryption modes??!?!
27*/ 29*/
28 30
29#include "generic.h" /* same as with L5, skey, etc */
30 31
31/* conditional includes -- a very messy section which you may have to dink
32 for your own architecture [and please send diffs...]: */
33/* #undef _POSIX_SOURCE /* might need this for something? */
34#define HAVE_BIND /* ASSUMPTION -- seems to work everywhere! */ 32#define HAVE_BIND /* ASSUMPTION -- seems to work everywhere! */
35 33
36#include <sys/types.h> 34#include <sys/types.h>
@@ -44,6 +42,7 @@
44#include <netdb.h> /* hostent, gethostby*, getservby* */ 42#include <netdb.h> /* hostent, gethostby*, getservby* */
45#include <stdio.h> 43#include <stdio.h>
46#include <string.h> 44#include <string.h>
45#include <err.h>
47#include <errno.h> 46#include <errno.h>
48#include <setjmp.h> 47#include <setjmp.h>
49#include <signal.h> 48#include <signal.h>
@@ -51,22 +50,17 @@
51#include <stdlib.h> 50#include <stdlib.h>
52#include <unistd.h> 51#include <unistd.h>
53 52
54#ifdef HAVE_RANDOM /* aficionados of ?rand48() should realize */ 53/* Random Numbers aren't too needed here */
55#define SRAND srandom /* that this doesn't need *strong* random */ 54#define SRAND srandom
56#define RAND random /* numbers just to mix up port numbers!! */ 55#define RAND random
57#else
58#define SRAND srand
59#define RAND rand
60#endif /* HAVE_RANDOM */
61 56
62#define SLEAZE_PORT 31337 /* for UDP-scan RTT trick, change if ya want */ 57#define SLEAZE_PORT 31337 /* for UDP-scan RTT trick, change if ya want */
63#define BIGSIZ 8192 /* big buffers */ 58#define BIGSIZ 8192 /* big buffers */
64 59
65struct host_info { 60struct host_info {
66 char name[MAXHOSTNAMELEN]; /* dns name */ 61 char name[MAXHOSTNAMELEN]; /* DNS name */
67 char addrs[8][24]; /* ascii-format IP addresses */ 62 char addrs[8][24]; /* ascii-format IP addresses */
68 struct in_addr iaddrs[8]; /* real addresses: in_addr.s_addr: 63 struct in_addr iaddrs[8]; /* in_addr.s_addr: ulong */
69 * ulong */
70}; 64};
71 65
72struct port_info { 66struct port_info {
@@ -76,7 +70,7 @@ struct port_info {
76}; 70};
77 71
78/* globals: */ 72/* globals: */
79jmp_buf jbuf; /* timer crud */ 73jmp_buf jbuf; /* timer jump buffer*/
80int jval = 0; /* timer crud */ 74int jval = 0; /* timer crud */
81int netfd = -1; 75int netfd = -1;
82int ofd = 0; /* hexdump output fd */ 76int ofd = 0; /* hexdump output fd */
@@ -84,10 +78,10 @@ int ofd = 0; /* hexdump output fd */
84extern int h_errno; 78extern int h_errno;
85/* stolen almost wholesale from bsd herror.c */ 79/* stolen almost wholesale from bsd herror.c */
86static char *h_errs[] = { 80static char *h_errs[] = {
87 "Error 0", /* but we *don't* use this */ 81 "Error 0", /* but we *don't* use this */
88 "Unknown host", /* 1 HOST_NOT_FOUND */ 82 "Unknown host", /* 1 HOST_NOT_FOUND */
89 "Host name lookup failure", /* 2 TRY_AGAIN */ 83 "Host name lookup failure", /* 2 TRY_AGAIN */
90 "Unknown server error", /* 3 NO_RECOVERY */ 84 "Unknown server error", /* 3 NO_RECOVERY */
91 "No address associated with name", /* 4 NO_ADDRESS */ 85 "No address associated with name", /* 4 NO_ADDRESS */
92}; 86};
93 87
@@ -97,20 +91,19 @@ u_short Single = 1; /* zero if scanning */
97unsigned int insaved = 0; /* stdin-buffer size for multi-mode */ 91unsigned int insaved = 0; /* stdin-buffer size for multi-mode */
98unsigned int wrote_out = 0; /* total stdout bytes */ 92unsigned int wrote_out = 0; /* total stdout bytes */
99unsigned int wrote_net = 0; /* total net bytes */ 93unsigned int wrote_net = 0; /* total net bytes */
100static char wrote_txt[] = " sent %d, rcvd %d";
101static char hexnibs[20] = "0123456789abcdef "; 94static char hexnibs[20] = "0123456789abcdef ";
102 95
103/* will malloc up the following globals: */ 96/* will malloc up the following globals: */
104struct timeval timer1, timer2; 97struct timeval timer1, timer2;
105struct sockaddr_in *lclend = NULL; /* sockaddr_in structs */ 98struct sockaddr_in *lclend = NULL; /* sockaddr_in structs */
106struct sockaddr_in *remend = NULL; 99struct sockaddr_in *remend = NULL;
107struct host_info **gates = NULL; /* LSRR hop hostpoop */ 100struct host_info **gates = NULL; /* LSRR hop hinfo */
108char *optbuf = NULL; /* LSRR or sockopts */ 101char *optbuf = NULL; /* LSRR or sockopts */
109char *bigbuf_in; /* data buffers */ 102char *bigbuf_in; /* data buffers */
110char *bigbuf_net; 103char *bigbuf_net;
111fd_set fds1, fds2; 104fd_set fds1, fds2;
112struct port_info *portpoop = NULL; /* for getportpoop / getservby* */ 105struct port_info *pinfo = NULL; /* for getpinfo / getservby* */
113unsigned char *stage = NULL; /* hexdump line buffer */ 106unsigned char *stage = NULL; /* hexdump line buffer */
114 107
115/* global cmd flags: */ 108/* global cmd flags: */
116u_short o_alla = 0; 109u_short o_alla = 0;
@@ -123,72 +116,27 @@ u_short o_udpmode = 0;
123u_short o_verbose = 0; 116u_short o_verbose = 0;
124unsigned int o_wait = 0; 117unsigned int o_wait = 0;
125u_short o_zero = 0; 118u_short o_zero = 0;
126/* o_tn in optional section */
127
128/* Debug macro: squirt whatever message and sleep a bit so we can see it go
129 by. need to call like Debug ((stuff)) [with no ; ] so macro args match!
130 Beware: writes to stdOUT... */
131#ifdef DEBUG
132#define Debug(x) printf x; printf ("\n"); fflush (stdout); sleep (1);
133#else
134#define Debug(x) /* nil... */
135#endif
136 119
120/* Function Prototype's */
121void usage __P((int));
122void help __P(());
137 123
138/* support routines -- the bulk of this thing. Placed in such an order that 124/*
139 we don't have to forward-declare anything: */ 125 * support routines -- the bulk of this thing. Placed in such an order that
140 126 * we don't have to forward-declare anything:
141/* holler : 127 */
142 fake varargs -- need to do this way because we wind up calling through
143 more levels of indirection than vanilla varargs can handle, and not all
144 machines have vfprintf/vsyslog/whatever! 6 params oughta be enough. */
145void
146holler(str, p1, p2, p3, p4, p5, p6)
147 char *str;
148 char *p1, *p2, *p3, *p4, *p5, *p6;
149{
150 if (o_verbose) {
151 fprintf(stderr, str, p1, p2, p3, p4, p5, p6);
152#ifdef HAVE_BIND
153 if (h_errno) { /* if host-lookup variety of error ... */
154 if (h_errno > 4) /* oh no you don't, either */
155 fprintf(stderr, "preposterous h_errno: %d", h_errno);
156 else
157 fprintf(stderr, "%s", h_errs[h_errno]);
158 h_errno = 0; /* and reset for next call */
159 }
160#endif
161 if (errno) { /* this gives funny-looking messages, but */
162 perror(" "); /* it's more portable than
163 * sys_errlist[]... */
164 } else /* xxx: do something better? */
165 fprintf(stderr, "\n");
166 fflush(stderr);
167 }
168}
169
170/* bail :
171 error-exit handler, callable from anywhere */
172void
173bail(str, p1, p2, p3, p4, p5, p6)
174 char *str;
175 char *p1, *p2, *p3, *p4, *p5, *p6;
176{
177 o_verbose = 1;
178 holler(str, p1, p2, p3, p4, p5, p6);
179 close(netfd);
180 exit(1);
181}
182 128
183/* catch : 129/*
184 no-brainer interrupt handler */ 130 * catch :
131 * no-brainer interrupt handler
132 */
185void 133void
186catch() 134catch()
187{ 135{
188 errno = 0; 136 errno = 0;
189 if (o_verbose > 1) /* normally we don't care */ 137 if (o_verbose > 1) /* normally we don't care */
190 bail(wrote_txt, wrote_net, wrote_out); 138 errx(1, "Sent %i Rcvd %i", wrote_net, wrote_out);
191 bail(" punt!"); 139 errx(1, " punt!");
192} 140}
193 141
194/* timeout and other signal handling cruft */ 142/* timeout and other signal handling cruft */
@@ -198,39 +146,43 @@ tmtravel()
198 signal(SIGALRM, SIG_IGN); 146 signal(SIGALRM, SIG_IGN);
199 alarm(0); 147 alarm(0);
200 if (jval == 0) 148 if (jval == 0)
201 bail("spurious timer interrupt!"); 149 errx(1, "spurious timer interrupt!");
202 longjmp(jbuf, jval); 150 longjmp(jbuf, jval);
203} 151}
204 152
205/* arm : 153/*
206 set the timer. Zero secs arg means unarm */ 154 * arm :
155 * set the timer. Zero secs arg means unarm
156 */
207void 157void
208arm(num, secs) 158arm(num, secs)
209 unsigned int num; 159 unsigned int num;
210 unsigned int secs; 160 unsigned int secs;
211{ 161{
212 if (secs == 0) { /* reset */ 162 if (secs == 0) {
213 signal(SIGALRM, SIG_IGN); 163 signal(SIGALRM, SIG_IGN);
214 alarm(0); 164 alarm(0);
215 jval = 0; 165 jval = 0;
216 } else { /* set */ 166 } else {
217 signal(SIGALRM, tmtravel); 167 signal(SIGALRM, tmtravel);
218 alarm(secs); 168 alarm(secs);
219 jval = num; 169 jval = num;
220 } /* if secs */ 170 }
221} 171}
222 172
223/* findline : 173/*
224 find the next newline in a buffer; return inclusive size of that "line", 174 * findline :
225 or the entire buffer size, so the caller knows how much to then write(). 175 * find the next newline in a buffer; return inclusive size of that "line",
226 Not distinguishing \n vs \r\n for the nonce; it just works as is... */ 176 * or the entire buffer size, so the caller knows how much to then write().
177 * Not distinguishing \n vs \r\n for the nonce; it just works as is...
178 */
227unsigned int 179unsigned int
228findline(buf, siz) 180findline(buf, siz)
229 char *buf; 181 char *buf;
230 unsigned int siz; 182 unsigned int siz;
231{ 183{
232 register char *p; 184 char *p;
233 register int x; 185 int x;
234 if (!buf) /* various sanity checks... */ 186 if (!buf) /* various sanity checks... */
235 return (0); 187 return (0);
236 if (siz > BIGSIZ) 188 if (siz > BIGSIZ)
@@ -240,159 +192,170 @@ findline(buf, siz)
240 if (*p == '\n') { 192 if (*p == '\n') {
241 x = (int) (p - buf); 193 x = (int) (p - buf);
242 x++; /* 'sokay if it points just past the end! */ 194 x++; /* 'sokay if it points just past the end! */
243 Debug(("findline returning %d", x))
244 return (x); 195 return (x);
245 } 196 }
246 p++; 197 p++;
247 } /* for */ 198 }
248 Debug(("findline returning whole thing: %d", siz))
249 return (siz); 199 return (siz);
250} 200}
251 201
252/* comparehosts : 202/*
253 cross-check the host_info we have so far against new gethostby*() info, 203 * comparehosts :
254 and holler about mismatches. Perhaps gratuitous, but it can't hurt to 204 * cross-check the host_info we have so far against new gethostby*() info,
255 point out when someone's DNS is fukt. Returns 1 if mismatch, in case 205 * and holler about mismatches. Perhaps gratuitous, but it can't hurt to
256 someone else wants to do something about it. */ 206 * point out when someone's DNS is fukt. Returns 1 if mismatch, in case
207 * someone else wants to do something about it.
208 */
257int 209int
258comparehosts(poop, hp) 210comparehosts(hinfo, hp)
259 struct host_info *poop; 211 struct host_info *hinfo;
260 struct hostent *hp; 212 struct hostent *hp;
261{ 213{
262 errno = 0; 214 errno = 0;
263 h_errno = 0; 215 h_errno = 0;
264 if (strcasecmp(poop->name, hp->h_name) != 0) { /* normal */ 216 if (strcasecmp(hinfo->name, hp->h_name) != 0) {
265 holler("DNS fwd/rev mismatch: %s != %s", poop->name, hp->h_name); 217 warn("DNS fwd/rev mismatch: %s != %s", hinfo->name, hp->h_name);
266 return (1); 218 return (1);
267 } 219 }
268 return (0); 220 return (0);
269/* ... do we need to do anything over and above that?? */
270} 221}
271 222
272/* gethostpoop : 223/*
273 resolve a host 8 ways from sunday; return a new host_info struct with its 224 * gethinfo:
274 info. The argument can be a name or [ascii] IP address; it will try its 225 * resolve a host 8 ways from sunday; return a new host_info struct with its
275 damndest to deal with it. "numeric" governs whether we do any DNS at all, 226 * info. The argument can be a name or [ascii] IP address; it will try its
276 and we also check o_verbose for what's appropriate work to do. */ 227 * damndest to deal with it. "numeric" governs whether we do any DNS at all,
228 * and we also check o_verbose for what's appropriate work to do.
229 */
277struct host_info * 230struct host_info *
278gethostpoop(name, numeric) 231gethinfo(name, numeric)
279 char *name; 232 char *name;
280 u_short numeric; 233 u_short numeric;
281{ 234{
282 struct hostent *hostent; 235 struct hostent *hostent;
283 struct in_addr iaddr; 236 struct in_addr iaddr;
284 register struct host_info *poop = NULL; 237 struct host_info *hinfo = NULL;
285 register int x; 238 int x;
286
287/* I really want to strangle the twit who dreamed up all these sockaddr and
288 hostent abstractions, and then forced them all to be incompatible with
289 each other so you *HAVE* to do all this ridiculous casting back and forth.
290 If that wasn't bad enough, all the doc insists on referring to local ports
291 and addresses as "names", which makes NO sense down at the bare metal.
292
293 What an absolutely horrid paradigm, and to think of all the people who
294 have been wasting significant amounts of time fighting with this stupid
295 deliberate obfuscation over the last 10 years... then again, I like
296 languages wherein a pointer is a pointer, what you put there is your own
297 business, the compiler stays out of your face, and sheep are nervous.
298 Maybe that's why my C code reads like assembler half the time... */
299
300/* If we want to see all the DNS stuff, do the following hair --
301 if inet_aton, do reverse and forward with any warnings; otherwise try
302 to do forward and reverse with any warnings. In other words, as long
303 as we're here, do a complete DNS check on these clowns. Yes, it slows
304 things down a bit for a first run, but once it's cached, who cares? */
305 239
306 errno = 0; 240 errno = 0;
307 h_errno = 0; 241 h_errno = 0;
308 if (name) 242 if (name)
309 poop = (struct host_info *) calloc(1, sizeof(struct host_info)); 243 hinfo = (struct host_info *) calloc(1, sizeof(struct host_info));
310 if (!poop) 244
311 bail("gethostpoop fuxored"); 245 if (!hinfo)
312 strlcpy(poop->name, "(UNKNOWN)", sizeof(poop->name)); 246 errx(1, "error obtaining host information");
313 if (inet_aton(name, &iaddr) == 0) {
314 247
248 strlcpy(hinfo->name, "(UNKNOWN)", sizeof(hinfo->name));
249 if (inet_aton(name, &iaddr) == 0) {
315 if (numeric) 250 if (numeric)
316 bail("Can't parse %s as an IP address", name); 251 errx(1, "Can't parse %s as an IP address", name);
252
253 /*
254 * failure to look up a name is fatal,
255 * since we can't do anything with it.
256 */
317 hostent = gethostbyname(name); 257 hostent = gethostbyname(name);
318 if (!hostent) 258 if (!hostent)
319/* failure to look up a name is fatal, since we can't do anything with it */ 259 errx(1, "%s: forward host lookup failed: ", name);
320 bail("%s: forward host lookup failed: ", name); 260
321 strlcpy(poop->name, hostent->h_name, MAXHOSTNAMELEN); 261 strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN);
322 for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) { 262 for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) {
323 memcpy(&poop->iaddrs[x], hostent->h_addr_list[x], 263 memcpy(&hinfo->iaddrs[x], hostent->h_addr_list[x],
324 sizeof(struct in_addr)); 264 sizeof(struct in_addr));
325 strlcpy(poop->addrs[x], inet_ntoa(poop->iaddrs[x]), 265 strlcpy(hinfo->addrs[x], inet_ntoa(hinfo->iaddrs[x]),
326 sizeof(poop->addrs[0])); 266 sizeof(hinfo->addrs[0]));
327 } 267 }
328 if (!o_verbose) /* if we didn't want to see the */ 268 /* Go ahead and return if we don't want to view more */
329 return (poop); /* inverse stuff, we're done. */ 269 if (!o_verbose)
330/* do inverse lookups in separate loop based on our collected forward addrs, 270 return (hinfo);
331 since gethostby* tends to crap into the same buffer over and over */ 271
332 for (x = 0; poop->iaddrs[x].s_addr && (x < 8); x++) { 272 /*
333 hostent = gethostbyaddr((char *) &poop->iaddrs[x], 273 * Do inverse lookups in separate loop based on our collected
274 * forward addrs, since gethostby* tends to crap into the same
275 * buffer over and over.
276 */
277 for (x = 0; hinfo->iaddrs[x].s_addr && (x < 8); x++) {
278 hostent = gethostbyaddr((char *) &hinfo->iaddrs[x],
334 sizeof(struct in_addr), AF_INET); 279 sizeof(struct in_addr), AF_INET);
335 if ((!hostent) || (!hostent->h_name)) 280 if ((!hostent) || (!hostent->h_name))
336 holler("Warning: inverse host lookup failed for %s: ", 281 warn("Warning: inverse host lookup failed for %s: ",
337 poop->addrs[x]); 282 hinfo->addrs[x]);
338 else 283 else
339 (void) comparehosts(poop, hostent); 284 (void) comparehosts(hinfo, hostent);
340 } /* for x -> addrs, part B */ 285 }
341 286
342 } else { /* not INADDR_NONE: numeric addresses... */ 287 } else { /* not INADDR_NONE: numeric addresses... */
343 memcpy(poop->iaddrs, &iaddr, sizeof(struct in_addr)); 288 memcpy(hinfo->iaddrs, &iaddr, sizeof(struct in_addr));
344 strlcpy(poop->addrs[0], inet_ntoa(iaddr), sizeof(poop->addrs)); 289 strlcpy(hinfo->addrs[0], inet_ntoa(iaddr), sizeof(hinfo->addrs));
345 if (numeric) /* if numeric-only, we're done */ 290 /* If all that's wanted is numeric IP, go ahead and leave */
346 return (poop); 291 if (numeric)
347 if (!o_verbose) /* likewise if we don't want */ 292 return (hinfo);
348 return (poop); /* the full DNS hair */ 293
349 hostent = gethostbyaddr((char *) &iaddr, sizeof(struct in_addr), AF_INET); 294 /* Go ahead and return if we don't want to view more */
350/* numeric or not, failure to look up a PTR is *not* considered fatal */ 295 if (!o_verbose)
296 return (hinfo);
297
298 hostent = gethostbyaddr((char *) &iaddr,
299 sizeof(struct in_addr), AF_INET);
300
301 /*
302 * numeric or not, failure to look up a PTR is
303 * *not* considered fatal
304 */
351 if (!hostent) 305 if (!hostent)
352 holler("%s: inverse host lookup failed: ", name); 306 warn("%s: inverse host lookup failed: ", name);
353 else { 307 else {
354 strlcpy(poop->name, hostent->h_name, MAXHOSTNAMELEN); 308 strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN);
355 hostent = gethostbyname(poop->name); 309 hostent = gethostbyname(hinfo->name);
356 if ((!hostent) || (!hostent->h_addr_list[0])) 310 if ((!hostent) || (!hostent->h_addr_list[0]))
357 holler("Warning: forward host lookup failed for %s: ", 311 warn("Warning: forward host lookup failed for %s: ",
358 poop->name); 312 hinfo->name);
359 else 313 else
360 (void) comparehosts(poop, hostent); 314 (void) comparehosts(hinfo, hostent);
361 } /* if hostent */ 315 }
362 } /* INADDR_NONE Great Split */ 316 }
363 317
364/* whatever-all went down previously, we should now have a host_info struct 318 /*
365 with at least one IP address in it. */ 319 * Whatever-all went down previously, we should now have a host_info
320 * struct with at least one IP address in it.
321 */
366 h_errno = 0; 322 h_errno = 0;
367 return (poop); 323 return (hinfo);
368} 324}
369 325
370/* getportpoop : 326/*
371 Same general idea as gethostpoop -- look up a port in /etc/services, fill 327 * getpinfo:
372 in global port_info, but return the actual port *number*. Pass ONE of: 328 * Same general idea as gethinfo-- look up a port in /etc/services, fill
373 pstring to resolve stuff like "23" or "exec"; 329 * in global port_info, but return the actual port *number*. Pass ONE of:
374 pnum to reverse-resolve something that's already a number. 330 * pstring to resolve stuff like "23" or "exec";
375 If o_nflag is on, fill in what we can but skip the getservby??? stuff. 331 * pnum to reverse-resolve something that's already a number.
376 Might as well have consistent behavior here, and it *is* faster. */ 332 * If o_nflag is on, fill in what we can but skip the getservby??? stuff.
333 * Might as well have consistent behavior here, and it *is* faster.
334 */
377u_short 335u_short
378getportpoop(pstring, pnum) 336getpinfo(pstring, pnum)
379 char *pstring; 337 char *pstring;
380 unsigned int pnum; 338 unsigned int pnum;
381{ 339{
382 struct servent *servent; 340 struct servent *servent;
383 register int x; 341 int x;
384 register int y; 342 int y;
385 char *whichp = "tcp"; 343 char *whichp = "tcp";
386 if (o_udpmode) 344 if (o_udpmode)
387 whichp = "udp"; 345 whichp = "udp";
388 portpoop->name[0] = '?';/* fast preload */
389 portpoop->name[1] = '\0';
390 346
391/* case 1: reverse-lookup of a number; placed first since this case is much 347 pinfo->name[0] = '?';/* fast preload */
392 more frequent if we're scanning */ 348 pinfo->name[1] = '\0';
349
350 /*
351 * case 1: reverse-lookup of a number; placed first since this case
352 * is much more frequent if we're scanning.
353 */
393 if (pnum) { 354 if (pnum) {
394 if (pstring) /* one or the other, pleeze */ 355 /* Can't be both */
356 if (pstring)
395 return (0); 357 return (0);
358
396 x = pnum; 359 x = pnum;
397 if (o_nflag) /* go faster, skip getservbyblah */ 360 if (o_nflag) /* go faster, skip getservbyblah */
398 goto gp_finish; 361 goto gp_finish;
@@ -401,80 +364,77 @@ getportpoop(pstring, pnum)
401 if (servent) { 364 if (servent) {
402 y = ntohs(servent->s_port); 365 y = ntohs(servent->s_port);
403 if (x != y) /* "never happen" */ 366 if (x != y) /* "never happen" */
404 holler("Warning: port-bynum mismatch, %d != %d", x, y); 367 warn("Warning: port-bynum mismatch, %d != %d", x, y);
405 strlcpy(portpoop->name, servent->s_name, 368 strlcpy(pinfo->name, servent->s_name,
406 sizeof(portpoop->name)); 369 sizeof(pinfo->name));
407 } 370 }
408 goto gp_finish; 371 goto gp_finish;
409 } /* if pnum */ 372 }
410 /* case 2: resolve a string, but we still give preference to numbers 373 /*
374 * case 2: resolve a string, but we still give preference to numbers
411 * instead of trying to resolve conflicts. None of the entries in *my* 375 * instead of trying to resolve conflicts. None of the entries in *my*
412 * extensive /etc/services begins with a digit, so this should "always 376 * extensive /etc/services begins with a digit, so this should "always
413 * work" unless you're at 3com and have some company-internal services 377 * work" unless you're at 3com and have some company-internal services
414 * defined... */ 378 * defined.
379 */
415 if (pstring) { 380 if (pstring) {
416 if (pnum) /* one or the other, pleeze */ 381 /* Can't be both */
382 if (pnum)
417 return (0); 383 return (0);
384
418 x = atoi(pstring); 385 x = atoi(pstring);
419 if (x) 386 if (x)
420 return (getportpoop(NULL, x)); /* recurse for 387 return (getpinfo(NULL, x)); /* recurse for
421 * numeric-string-arg */ 388 * numeric-string-arg */
422 if (o_nflag) /* can't use names! */ 389 if (o_nflag) /* can't use names! */
423 return (0); 390 return (0);
424 servent = getservbyname(pstring, whichp); 391 servent = getservbyname(pstring, whichp);
425 if (servent) { 392 if (servent) {
426 strlcpy(portpoop->name, servent->s_name, 393 strlcpy(pinfo->name, servent->s_name,
427 sizeof(portpoop->name)); 394 sizeof(pinfo->name));
428 x = ntohs(servent->s_port); 395 x = ntohs(servent->s_port);
429 goto gp_finish; 396 goto gp_finish;
430 } /* if servent */ 397 } /* if servent */
431 } /* if pstring */ 398 } /* if pstring */
432 return (0); /* catches any problems so far */ 399 return (0); /* catches any problems so far */
433 400
434/* Obligatory netdb.h-inspired rant: servent.s_port is supposed to be an int.
435 Despite this, we still have to treat it as a short when copying it around.
436 Not only that, but we have to convert it *back* into net order for
437 getservbyport to work. Manpages generally aren't clear on all this, but
438 there are plenty of examples in which it is just quietly done. More BSD
439 lossage... since everything getserv* ever deals with is local to our own
440 host, why bother with all this network-order/host-order crap at all?!
441 That should be saved for when we want to actually plug the port[s] into
442 some real network calls -- and guess what, we have to *re*-convert at that
443 point as well. Fuckheads. */
444
445gp_finish: 401gp_finish:
446/* Fall here whether or not we have a valid servent at this point, with 402 /*
447 x containing our [host-order and therefore useful, dammit] port number */ 403 * Fall here whether or not we have a valid servent at this point, with
448 sprintf(portpoop->anum, "%d", x); /* always load any numeric 404 * x containing our [host-order and therefore useful, dammit] port number.
405 */
406 sprintf(pinfo->anum, "%d", x); /* always load any numeric
449 * specs! */ 407 * specs! */
450 portpoop->num = (x & 0xffff); /* u_short, remember... */ 408 pinfo->num = (x & 0xffff); /* u_short, remember... */
451 return (portpoop->num); 409 return (pinfo->num);
452} 410}
453 411
454/* nextport : 412/*
455 Come up with the next port to try, be it random or whatever. "block" is 413 * nextport :
456 a ptr to randports array, whose bytes [so far] carry these meanings: 414 * Come up with the next port to try, be it random or whatever. "block" is
457 0 ignore 415 * a ptr to randports array, whose bytes [so far] carry these meanings:
458 1 to be tested 416 * 0 ignore
459 2 tested [which is set as we find them here] 417 * 1 to be tested
460 returns a u_short random port, or 0 if all the t-b-t ones are used up. */ 418 * 2 tested [which is set as we find them here]
419 * returns a u_short random port, or 0 if all the t-b-t ones are used up.
420 */
461u_short 421u_short
462nextport(block) 422nextport(block)
463 char *block; 423 char *block;
464{ 424{
465 register unsigned int x; 425 unsigned int x;
466 register unsigned int y; 426 unsigned int y;
467 427
468 y = 70000; /* high safety count for rnd-tries */ 428 y = 70000; /* high safety count for rnd-tries */
469 while (y > 0) { 429 while (y > 0) {
470 x = (RAND() & 0xffff); 430 x = (RAND() & 0xffff);
471 if (block[x] == 1) { /* try to find a not-done one... */ 431 if (block[x] == 1) { /* try to find a not-done one... */
472 block[x] = 2; 432 block[x] = 2;
473 break; 433 break;
474 } 434 }
475 x = 0; /* bummer. */ 435 x = 0;
476 y--; 436 y--;
477 } /* while y */ 437 }
478 if (x) 438 if (x)
479 return (x); 439 return (x);
480 440
@@ -485,16 +445,18 @@ nextport(block)
485 break; 445 break;
486 } 446 }
487 y--; 447 y--;
488 } /* while y */ 448 }
489 if (y) 449 if (y)
490 return (y); /* at least one left */ 450 return (y); /* at least one left */
491 451
492 return (0); /* no more left! */ 452 return (0);
493} 453}
494 454
495/* loadports : 455/*
496 set "to be tested" indications in BLOCK, from LO to HI. Almost too small 456 * loadports :
497 to be a separate routine, but makes main() a little cleaner... */ 457 * set "to be tested" indications in BLOCK, from LO to HI. Almost too small
458 * to be a separate routine, but makes main() a little cleaner.
459 */
498void 460void
499loadports(block, lo, hi) 461loadports(block, lo, hi)
500 char *block; 462 char *block;
@@ -504,9 +466,9 @@ loadports(block, lo, hi)
504 u_short x; 466 u_short x;
505 467
506 if (!block) 468 if (!block)
507 bail("loadports: no block?!"); 469 errx(1, "loadports: no block?!");
508 if ((!lo) || (!hi)) 470 if ((!lo) || (!hi))
509 bail("loadports: bogus values %d, %d", lo, hi); 471 errx(1, "loadports: bogus values %d, %d", lo, hi);
510 x = hi; 472 x = hi;
511 while (lo <= x) { 473 while (lo <= x) {
512 block[x] = 1; 474 block[x] = 1;
@@ -514,42 +476,16 @@ loadports(block, lo, hi)
514 } 476 }
515} 477}
516 478
517#ifdef GAPING_SECURITY_HOLE
518char *pr00gie = NULL; /* global ptr to -e arg */
519 479
520/* doexec : 480/*
521 fiddle all the file descriptors around, and hand off to another prog. Sort 481 * doconnect :
522 of like a one-off "poor man's inetd". This is the only section of code 482 * do all the socket stuff, and return an fd for one of
523 that would be security-critical, which is why it's ifdefed out by default. 483 * an open outbound TCP connection
524 Use at your own hairy risk; if you leave shells lying around behind open 484 * a UDP stub-socket thingie
525 listening ports you deserve to lose!! */ 485 * with appropriate socket options set up if we wanted source-routing, or
526doexec(fd) 486 * an unconnected TCP or UDP socket to listen on.
527 int fd; 487 * Examines various global o_blah flags to figure out what-all to do.
528{ 488 */
529 register char *p;
530
531 dup2(fd, 0); /* the precise order of fiddlage */
532 close(fd); /* is apparently crucial; this is */
533 dup2(0, 1); /* swiped directly out of "inetd". */
534 dup2(0, 2);
535 p = strrchr(pr00gie, '/'); /* shorter argv[0] */
536 if (p)
537 p++;
538 else
539 p = pr00gie;
540 Debug(("gonna exec %s as %s...", pr00gie, p))
541 execl(pr00gie, p, NULL);
542 bail("exec %s failed", pr00gie); /* this gets sent out. Hmm... */
543}
544#endif /* GAPING_SECURITY_HOLE */
545
546/* doconnect :
547 do all the socket stuff, and return an fd for one of
548 an open outbound TCP connection
549 a UDP stub-socket thingie
550 with appropriate socket options set up if we wanted source-routing, or
551 an unconnected TCP or UDP socket to listen on.
552 Examines various global o_blah flags to figure out what-all to do. */
553int 489int
554doconnect(rad, rp, lad, lp) 490doconnect(rad, rp, lad, lp)
555 struct in_addr *rad; 491 struct in_addr *rad;
@@ -557,55 +493,43 @@ doconnect(rad, rp, lad, lp)
557 struct in_addr *lad; 493 struct in_addr *lad;
558 u_short lp; 494 u_short lp;
559{ 495{
560 register int nnetfd; 496 int nnetfd;
561 register int rr; 497 int rr;
562 int x, y; 498 int x, y;
563 errno = 0; 499 errno = 0;
564 500
565/* grab a socket; set opts */ 501 /* grab a socket; set opts */
566newskt: 502newskt:
567 if (o_udpmode) 503 if (o_udpmode)
568 nnetfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 504 nnetfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
569 else 505 else
570 nnetfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 506 nnetfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
571 if (nnetfd < 0) 507 if (nnetfd < 0)
572 bail("Can't get socket"); 508 errx(1, "Can't get socket");
573 if (nnetfd == 0) /* if stdin was closed this might *be* 0, */ 509 if (nnetfd == 0) /* if stdin was closed this might *be* 0, */
574 goto newskt; /* so grab another. See text for why... */ 510 goto newskt; /* so grab another. See text for why... */
575 x = 1; 511 x = 1;
576 rr = setsockopt(nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 512 rr = setsockopt(nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
577 if (rr == -1) 513 if (rr == -1)
578 holler("nnetfd reuseaddr failed"); /* ??? */ 514 warn("nnetfd reuseaddr failed"); /* ??? */
579#ifdef SO_REUSEPORT /* doesnt exist everywhere... */
580 rr = setsockopt(nnetfd, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
581 if (rr == -1)
582 holler("nnetfd reuseport failed"); /* ??? */
583#endif
584#if 0
585/* If you want to screw with RCVBUF/SNDBUF, do it here. Liudvikas Bukys at
586 Rochester sent this example, which would involve YET MORE options and is
587 just archived here in case you want to mess with it. o_xxxbuf are global
588 integers set in main() getopt loop, and check for rr == 0 afterward. */
589 rr = setsockopt(nnetfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf);
590 rr = setsockopt(nnetfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf);
591#endif
592 515
593 /* fill in all the right sockaddr crud */ 516 /* fill in all the right sockaddr crud */
594 lclend->sin_family = AF_INET; 517 lclend->sin_family = AF_INET;
595 518
596/* fill in all the right sockaddr crud */ 519 /* fill in all the right sockaddr crud */
597 lclend->sin_family = AF_INET; 520 lclend->sin_family = AF_INET;
598 remend->sin_family = AF_INET; 521 remend->sin_family = AF_INET;
599 522
600/* if lad/lp, do appropriate binding */ 523 /* if lad/lp, do appropriate binding */
601 if (lad) 524 if (lad)
602 memcpy(&lclend->sin_addr.s_addr, lad, sizeof(struct in_addr)); 525 memcpy(&lclend->sin_addr.s_addr, lad, sizeof(struct in_addr));
603 if (lp) 526 if (lp)
604 lclend->sin_port = htons(lp); 527 lclend->sin_port = htons(lp);
528
605 rr = 0; 529 rr = 0;
606 if (lad || lp) { 530 if (lad || lp) {
607 x = (int) lp; 531 x = (int) lp;
608/* try a few times for the local bind, a la ftp-data-port... */ 532 /* try a few times for the local bind, a la ftp-data-port... */
609 for (y = 4; y > 0; y--) { 533 for (y = 4; y > 0; y--) {
610 rr = bind(nnetfd, (struct sockaddr *) lclend, 534 rr = bind(nnetfd, (struct sockaddr *) lclend,
611 sizeof(struct sockaddr_in)); 535 sizeof(struct sockaddr_in));
@@ -614,14 +538,14 @@ newskt:
614 if (errno != EADDRINUSE) 538 if (errno != EADDRINUSE)
615 break; 539 break;
616 else { 540 else {
617 holler("retrying local %s:%d", inet_ntoa(lclend->sin_addr), lp); 541 warn("retrying local %s:%d", inet_ntoa(lclend->sin_addr), lp);
618 sleep(2); 542 sleep(2);
619 errno = 0; /* clear from sleep */ 543 errno = 0; /* clear from sleep */
620 } /* if EADDRINUSE */ 544 }
621 } /* for y counter */ 545 }
622 } /* if lad or lp */ 546 }
623 if (rr) 547 if (rr)
624 bail("Can't grab %s:%d with bind", 548 errx(1, "Can't grab %s:%d with bind",
625 inet_ntoa(lclend->sin_addr), lp); 549 inet_ntoa(lclend->sin_addr), lp);
626 550
627 if (o_listen) 551 if (o_listen)
@@ -630,95 +554,29 @@ newskt:
630 memcpy(&remend->sin_addr.s_addr, rad, sizeof(struct in_addr)); 554 memcpy(&remend->sin_addr.s_addr, rad, sizeof(struct in_addr));
631 remend->sin_port = htons(rp); 555 remend->sin_port = htons(rp);
632 556
633/* rough format of LSRR option and explanation of weirdness.
634Option comes after IP-hdr dest addr in packet, padded to *4, and ihl > 5.
635IHL is multiples of 4, i.e. real len = ip_hl << 2.
636 type 131 1 ; 0x83: copied, option class 0, number 3
637 len 1 ; of *whole* option!
638 pointer 1 ; nxt-hop-addr; 1-relative, not 0-relative
639 addrlist... var ; 4 bytes per hop-addr
640 pad-to-32 var ; ones, i.e. "NOP"
641
642If we want to route A -> B via hops C and D, we must add C, D, *and* B to the
643options list. Why? Because when we hand the kernel A -> B with list C, D, B
644the "send shuffle" inside the kernel changes it into A -> C with list D, B and
645the outbound packet gets sent to C. If B wasn't also in the hops list, the
646final destination would have been lost at this point.
647
648When C gets the packet, it changes it to A -> D with list C', B where C' is
649the interface address that C used to forward the packet. This "records" the
650route hop from B's point of view, i.e. which address points "toward" B. This
651is to make B better able to return the packets. The pointer gets bumped by 4,
652so that D does the right thing instead of trying to forward back to C.
653
654When B finally gets the packet, it sees that the pointer is at the end of the
655LSRR list and is thus "completed". B will then try to use the packet instead
656of forwarding it, i.e. deliver it up to some application.
657
658Note that by moving the pointer yourself, you could send the traffic directly
659to B but have it return via your preconstructed source-route. Playing with
660this and watching "tcpdump -v" is the best way to understand what's going on.
661
662Only works for TCP in BSD-flavor kernels. UDP is a loss; udp_input calls
663stripoptions() early on, and the code to save the srcrt is notdef'ed.
664Linux is also still a loss at 1.3.x it looks like; the lsrr code is { }...
665*/
666
667/* if any -g arguments were given, set up source-routing. We hit this after
668 the gates are all looked up and ready to rock, any -G pointer is set,
669 and gatesidx is now the *number* of hops */
670 if (gatesidx) { /* if we wanted any srcrt hops ... */
671/* don't even bother compiling if we can't do IP options here! */
672#ifdef IP_OPTIONS
673 if (!optbuf) { /* and don't already *have* a srcrt set */
674 char *opp; /* then do all this setup hair */
675 optbuf = calloc(1, 48);
676 opp = optbuf;
677 *opp++ = IPOPT_LSRR; /* option */
678 *opp++ = (char)
679 (((gatesidx + 1) * sizeof(struct in_addr)) + 3) & 0xff; /* length */
680 *opp++ = gatesptr; /* pointer */
681/* opp now points at first hop addr -- insert the intermediate gateways */
682 for (x = 0; x < gatesidx; x++) {
683 memcpy(opp, gates[x]->iaddrs, sizeof(struct in_addr));
684 opp += sizeof(struct in_addr);
685 }
686/* and tack the final destination on the end [needed!] */
687 memcpy(opp, rad, sizeof(struct in_addr));
688 opp += sizeof(struct in_addr);
689 *opp = IPOPT_NOP; /* alignment filler */
690 } /* if empty optbuf */
691 /* calculate length of whole option mess, which is (3 + [hops]
692 * + [final] + 1), and apply it [have to do this every time
693 * through, of course] */
694 x = ((gatesidx + 1) * sizeof(struct in_addr)) + 4;
695 rr = setsockopt(nnetfd, IPPROTO_IP, IP_OPTIONS, optbuf, x);
696 if (rr == -1)
697 bail("srcrt setsockopt fuxored");
698#else /* IP_OPTIONS */
699 holler("Warning: source routing unavailable on this machine, ignoring");
700#endif /* IP_OPTIONS */
701 } /* if gatesidx */
702 /* wrap connect inside a timer, and hit it */ 557 /* wrap connect inside a timer, and hit it */
703 arm(1, o_wait); 558 arm(1, o_wait);
704 if (setjmp(jbuf) == 0) { 559 if (setjmp(jbuf) == 0) {
705 rr = connect(nnetfd, (struct sockaddr *) remend, sizeof(struct sockaddr)); 560 rr = connect(nnetfd, (struct sockaddr *) remend,
706 } else { /* setjmp: connect failed... */ 561 sizeof(struct sockaddr));
562 } else {
707 rr = -1; 563 rr = -1;
708 errno = ETIMEDOUT; /* fake it */ 564 errno = ETIMEDOUT;
709 } 565 }
710 arm(0, 0); 566 arm(0, 0);
711 if (rr == 0) 567 if (rr == 0)
712 return (nnetfd); 568 return (nnetfd);
713 close(nnetfd); /* clean up junked socket FD!! */ 569 close(nnetfd);
714 return (-1); 570 return (-1);
715} 571}
716 572
717/* dolisten : 573/*
718 just like doconnect, and in fact calls a hunk of doconnect, but listens for 574 * dolisten :
719 incoming and returns an open connection *from* someplace. If we were 575 * just like doconnect, and in fact calls a hunk of doconnect, but listens for
720 given host/port args, any connections from elsewhere are rejected. This 576 * incoming and returns an open connection *from* someplace. If we were
721 in conjunction with local-address binding should limit things nicely... */ 577 * given host/port args, any connections from elsewhere are rejected. This
578 * in conjunction with local-address binding should limit things nicely.
579 */
722int 580int
723dolisten(rad, rp, lad, lp) 581dolisten(rad, rp, lad, lp)
724 struct in_addr *rad; 582 struct in_addr *rad;
@@ -726,41 +584,35 @@ dolisten(rad, rp, lad, lp)
726 struct in_addr *lad; 584 struct in_addr *lad;
727 u_short lp; 585 u_short lp;
728{ 586{
729 register int nnetfd; 587 int nnetfd;
730 register int rr; 588 int rr;
731 struct host_info *whozis = NULL; 589 struct host_info *whozis = NULL;
732 int x; 590 int x;
733 char *cp; 591 char *cp;
734 u_short z; 592 u_short z;
735 errno = 0; 593 errno = 0;
736 594
737/* Pass everything off to doconnect, who in o_listen mode just gets a socket */ 595 /*
596 * Pass everything off to doconnect,
597 * who in o_listen mode just gets a socket
598 */
738 nnetfd = doconnect(rad, rp, lad, lp); 599 nnetfd = doconnect(rad, rp, lad, lp);
739 if (nnetfd <= 0) 600 if (nnetfd <= 0)
740 return (-1); 601 return (-1);
741 if (o_udpmode) { /* apparently UDP can listen ON */ 602 if (o_udpmode) {
742 if (!lp) /* "port 0", but that's not useful */ 603 if (!lp)
743 bail("UDP listen needs -p arg"); 604 errx(1, "UDP listen needs -p arg");
744 } else { 605 } else {
745 rr = listen(nnetfd, 1); /* gotta listen() before we can get */ 606 rr = listen(nnetfd, 1);
746 if (rr < 0) /* our local random port. sheesh. */ 607 if (rr < 0)
747 bail("local listen fuxored"); 608 errx(1, "error listening");
748 } 609 }
749 610
750/* Various things that follow temporarily trash bigbuf_net, which might contain
751 a copy of any recvfrom()ed packet, but we'll read() another copy later. */
752
753/* I can't believe I have to do all this to get my own goddamn bound address
754 and port number. It should just get filled in during bind() or something.
755 All this is only useful if we didn't say -p for listening, since if we
756 struct sockaddr_ind -p we *know* what port we're listening on. At any rate we won't bother
757 with it all unless we wanted to see it, although listening quietly on a
758 random unknown port is probably not very useful without "netstat". */
759 if (o_verbose) { 611 if (o_verbose) {
760 x = sizeof(struct sockaddr); /* how 'bout getsockNUM instead, pinheads?! */ 612 x = sizeof(struct sockaddr);
761 rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x); 613 rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x);
762 if (rr < 0) 614 if (rr < 0)
763 holler("local getsockname failed"); 615 warn("local getsockname failed");
764 strcpy(bigbuf_net, "listening on ["); /* buffer reuse... */ 616 strcpy(bigbuf_net, "listening on ["); /* buffer reuse... */
765 if (lclend->sin_addr.s_addr) 617 if (lclend->sin_addr.s_addr)
766 strcat(bigbuf_net, inet_ntoa(lclend->sin_addr)); 618 strcat(bigbuf_net, inet_ntoa(lclend->sin_addr));
@@ -768,46 +620,37 @@ dolisten(rad, rp, lad, lp)
768 strcat(bigbuf_net, "any"); 620 strcat(bigbuf_net, "any");
769 strcat(bigbuf_net, "] %d ..."); 621 strcat(bigbuf_net, "] %d ...");
770 z = ntohs(lclend->sin_port); 622 z = ntohs(lclend->sin_port);
771 holler(bigbuf_net, z); 623 warn(bigbuf_net, z);
772 } /* verbose -- whew!! */ 624 } /* verbose -- whew!! */
773 /* UDP is a speeeeecial case -- we have to do I/O *and* get the 625 /*
626 * UDP is a speeeeecial case -- we have to do I/O *and* get the
774 * calling party's particulars all at once, listen() and accept() 627 * calling party's particulars all at once, listen() and accept()
775 * don't apply. At least in the BSD universe, however, recvfrom/PEEK 628 * don't apply. At least in the BSD universe, however, recvfrom/PEEK
776 * is enough to tell us something came in, and we can set things up so 629 * is enough to tell us something came in, and we can set things up so
777 * straight read/write actually does work after all. Yow. YMMV on 630 * straight read/write actually does work after all. Yow. YMMV on
778 * strange platforms! */ 631 * strange platforms!
632 */
779 if (o_udpmode) { 633 if (o_udpmode) {
780 x = sizeof(struct sockaddr); /* retval for recvfrom */ 634 x = sizeof(struct sockaddr); /* retval for recvfrom */
781 arm(2, o_wait); /* might as well timeout this, too */ 635 arm(2, o_wait); /* might as well timeout this, too */
782 if (setjmp(jbuf) == 0) { /* do timeout for initial 636 if (setjmp(jbuf) == 0) { /* do timeout for initial
783 * connect */ 637 * connect */
784 rr = recvfrom /* and here we block... */ 638 rr = recvfrom(nnetfd, bigbuf_net, BIGSIZ, MSG_PEEK,
785 (nnetfd, bigbuf_net, BIGSIZ, MSG_PEEK, (struct sockaddr *) remend, &x); 639 (struct sockaddr *)remend, &x);
786 Debug(("dolisten/recvfrom ding, rr = %d, netbuf %s ", rr, bigbuf_net))
787 } else 640 } else
788 goto dol_tmo; /* timeout */ 641 goto dol_tmo;
789 arm(0, 0); 642 arm(0, 0);
790/* I'm not completely clear on how this works -- BSD seems to make UDP 643 rr = connect(nnetfd, (struct sockaddr *)remend,
791 just magically work in a connect()ed context, but we'll undoubtedly run 644 sizeof(struct sockaddr));
792 into systems this deal doesn't work on. For now, we apparently have to
793 issue a connect() on our just-tickled socket so we can write() back.
794 Again, why the fuck doesn't it just get filled in and taken care of?!
795 This hack is anything but optimal. Basically, if you want your listener
796 to also be able to send data back, you need this connect() line, which
797 also has the side effect that now anything from a different source or even a
798 different port on the other end won't show up and will cause ICMP errors.
799 I guess that's what they meant by "connect".
800 Let's try to remember what the "U" is *really* for, eh? */
801 rr = connect(nnetfd, (struct sockaddr *) remend, sizeof(struct sockaddr));
802 goto whoisit; 645 goto whoisit;
803 } /* o_udpmode */ 646 }
804 /* fall here for TCP */ 647 /* fall here for TCP */
805 x = sizeof(struct sockaddr); /* retval for accept */ 648 x = sizeof(struct sockaddr);
806 arm(2, o_wait); /* wrap this in a timer, too; 0 = forever */ 649 arm(2, o_wait);
807 if (setjmp(jbuf) == 0) { 650 if (setjmp(jbuf) == 0) {
808 rr = accept(nnetfd, (struct sockaddr *) remend, &x); 651 rr = accept(nnetfd, (struct sockaddr *) remend, &x);
809 } else 652 } else
810 goto dol_tmo; /* timeout */ 653 goto dol_tmo;
811 arm(0, 0); 654 arm(0, 0);
812 close(nnetfd); /* dump the old socket */ 655 close(nnetfd); /* dump the old socket */
813 nnetfd = rr; /* here's our new one */ 656 nnetfd = rr; /* here's our new one */
@@ -816,139 +659,101 @@ whoisit:
816 if (rr < 0) 659 if (rr < 0)
817 goto dol_err; /* bail out if any errors so far */ 660 goto dol_err; /* bail out if any errors so far */
818 661
819/* If we can, look for any IP options. Useful for testing the receiving end of 662 /*
820 such things, and is a good exercise in dealing with it. We do this before 663 * Find out what address the connection was *to* on
821 the connect message, to ensure that the connect msg is uniformly the LAST 664 * our end, in case we're doing a listen-on-any on
822 thing to emerge after all the intervening crud. Doesn't work for UDP on 665 * a multihomed machine. This allows one to offer
823 any machines I've tested, but feel free to surprise me. */ 666 * different services via different alias addresses,
824#ifdef IP_OPTIONS 667 * such as the "virtual web site" hack.
825 if (!o_verbose) /* if we wont see it, we dont care */ 668 */
826 goto dol_noop;
827 optbuf = calloc(1, 40);
828 x = 40;
829 rr = getsockopt(nnetfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x);
830 if (rr < 0)
831 holler("getsockopt failed");
832 Debug(("ipoptions ret len %d", x))
833 if (x) { /* we've got options, lessee em... */
834 unsigned char *q = (unsigned char *) optbuf;
835 char *p = bigbuf_net; /* local variables, yuk! */
836 char *pp = &bigbuf_net[128]; /* get random space farther
837 * out... */
838 memset(bigbuf_net, 0, 256); /* clear it all first */
839 while (x > 0) {
840 sprintf(pp, "%2.2x ", *q); /* clumsy, but works:
841 * turn into hex */
842 strcat(p, pp); /* and build the final string */
843 q++;
844 p++;
845 x--;
846 }
847 holler("IP options: %s", bigbuf_net);
848 } /* if x, i.e. any options */
849dol_noop:
850#endif /* IP_OPTIONS */
851
852/* find out what address the connection was *to* on our end, in case we're
853 doing a listen-on-any on a multihomed machine. This allows one to
854 offer different services via different alias addresses, such as the
855 "virtual web site" hack. */
856 memset(bigbuf_net, 0, 64); 669 memset(bigbuf_net, 0, 64);
857 cp = &bigbuf_net[32]; 670 cp = &bigbuf_net[32];
858 x = sizeof(struct sockaddr); 671 x = sizeof(struct sockaddr);
859 rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x); 672 rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x);
860 if (rr < 0) 673 if (rr < 0)
861 holler("post-rcv getsockname failed"); 674 warn("post-rcv getsockname failed");
862 strcpy(cp, inet_ntoa(lclend->sin_addr)); 675 strcpy(cp, inet_ntoa(lclend->sin_addr));
863 676
864/* now check out who it is. We don't care about mismatched DNS names here,
865 but any ADDR and PORT we specified had better fucking well match the caller.
866 Converting from addr to inet_ntoa and back again is a bit of a kludge, but
867 gethostpoop wants a string and there's much gnarlier code out there already,
868 so I don't feel bad.
869 The *real* question is why BFD sockets wasn't designed to allow listens for
870 connections *from* specific hosts/ports, instead of requiring the caller to
871 accept the connection and then reject undesireable ones by closing. In
872 other words, we need a TCP MSG_PEEK. */
873 z = ntohs(remend->sin_port); 677 z = ntohs(remend->sin_port);
874 strcpy(bigbuf_net, inet_ntoa(remend->sin_addr)); 678 strcpy(bigbuf_net, inet_ntoa(remend->sin_addr));
875 whozis = gethostpoop(bigbuf_net, o_nflag); 679 whozis = gethinfo(bigbuf_net, o_nflag);
876 errno = 0; 680 errno = 0;
877 x = 0; /* use as a flag... */ 681 x = 0;
878 if (rad) /* xxx: fix to go down the *list* if we have 682 if (rad) /* xxx: fix to go down the *list* if we have
879 * one? */ 683 * one? */
880 if (memcmp(rad, whozis->iaddrs, sizeof(struct sockaddr))) 684 if (memcmp(rad, whozis->iaddrs, sizeof(struct sockaddr)))
881 x = 1; 685 x = 1;
882 if (rp) 686 if (rp) {
883 if (z != rp) 687 if (z != rp)
884 x = 1; 688 x = 1;
885 if (x) /* guilty! */ 689 }
886 bail("invalid connection to [%s] from %s [%s] %d", 690 if (x) {
691 errx(1, "invalid connection to [%s] from %s [%s] %d",
887 cp, whozis->name, whozis->addrs[0], z); 692 cp, whozis->name, whozis->addrs[0], z);
888 holler("connect to [%s] from %s [%s] %d", /* oh, you're okay.. */ 693 }
694 warn("connect to [%s] from %s [%s] %d",
889 cp, whozis->name, whozis->addrs[0], z); 695 cp, whozis->name, whozis->addrs[0], z);
890 return (nnetfd); /* open! */ 696 return (nnetfd);
891 697
892dol_tmo: 698dol_tmo:
893 errno = ETIMEDOUT; /* fake it */ 699 errno = ETIMEDOUT;
894dol_err: 700dol_err:
895 close(nnetfd); 701 close(nnetfd);
896 return (-1); 702 return (-1);
897} 703}
898 704
899/* udptest : 705/*
900 fire a couple of packets at a UDP target port, just to see if it's really 706 * udptest :
901 there. On BSD kernels, ICMP host/port-unreachable errors get delivered to 707 * fire a couple of packets at a UDP target port, just to see if it's really
902 our socket as ECONNREFUSED write errors. On SV kernels, we lose; we'll have 708 * there. On BSD kernels, ICMP host/port-unreachable errors get delivered to
903 to collect and analyze raw ICMP ourselves a la satan's probe_udp_ports 709 * our socket as ECONNREFUSED write errors. On SV kernels, we lose; we'll have
904 backend. Guess where one could swipe the appropriate code from... 710 * to collect and analyze raw ICMP ourselves a la satan's probe_udp_ports
905 711 * backend. Guess where one could swipe the appropriate code from...
906 Use the time delay between writes if given, otherwise use the "tcp ping" 712 *
907 trick for getting the RTT. [I got that idea from pluvius, and warped it.] 713 * Use the time delay between writes if given, otherwise use the "tcp ping"
908 Return either the original fd, or clean up and return -1. */ 714 * trick for getting the RTT. [I got that idea from pluvius, and warped it.]
715 * Return either the original fd, or clean up and return -1.
716 */
909udptest(fd, where) 717udptest(fd, where)
910 int fd; 718 int fd;
911 struct in_addr *where; 719 struct in_addr *where;
912{ 720{
913 register int rr; 721 int rr;
914 722
915 rr = write(fd, bigbuf_in, 1); 723 rr = write(fd, bigbuf_in, 1);
916 if (rr != 1) 724 if (rr != 1)
917 holler("udptest first write failed?! errno %d", errno); 725 warn("udptest first write failed?! errno %d", errno);
918 if (o_wait) 726 if (o_wait)
919 sleep(o_wait); 727 sleep(o_wait);
920 else { 728 else {
921/* use the tcp-ping trick: try connecting to a normally refused port, which 729 o_udpmode = 0;
922 causes us to block for the time that SYN gets there and RST gets back. 730 o_wait = 5;
923 Not completely reliable, but it *does* mostly work. */
924 o_udpmode = 0; /* so doconnect does TCP this time */
925/* Set a temporary connect timeout, so packet filtration doesnt cause
926 us to hang forever, and hit it */
927 o_wait = 5; /* enough that we'll notice?? */
928 rr = doconnect(where, SLEAZE_PORT, 0, 0); 731 rr = doconnect(where, SLEAZE_PORT, 0, 0);
929 if (rr > 0) 732 if (rr > 0)
930 close(rr); /* in case it *did* open */ 733 close(rr);
931 o_wait = 0; /* reset it */ 734 o_wait = 0;
932 o_udpmode++; /* we *are* still doing UDP, right? */ 735 o_udpmode++;
933 } /* if o_wait */ 736 }
934 errno = 0; /* clear from sleep */ 737 errno = 0;
935 rr = write(fd, bigbuf_in, 1); 738 rr = write(fd, bigbuf_in, 1);
936 if (rr == 1) /* if write error, no UDP listener */ 739 if (rr == 1)
937 return (fd); 740 return (fd);
938 close(fd); /* use it or lose it! */ 741 close(fd);
939 return (-1); 742 return (-1);
940} 743}
941 744
942/* oprint : 745/*
943 Hexdump bytes shoveled either way to a running logfile, in the format: 746 * oprint :
944D offset - - - - --- 16 bytes --- - - - - # .... ascii ..... 747 * Hexdump bytes shoveled either way to a running logfile, in the format:
945 where "which" sets the direction indicator, D: 748 * D offset - - - - --- 16 bytes --- - - - - # .... ascii .....
946 0 -- sent to network, or ">" 749 * where "which" sets the direction indicator, D:
947 1 -- rcvd and printed to stdout, or "<" 750 * 0 -- sent to network, or ">"
948 and "buf" and "n" are data-block and length. If the current block generates 751 * 1 -- rcvd and printed to stdout, or "<"
949 a partial line, so be it; we *want* that lockstep indication of who sent 752 * and "buf" and "n" are data-block and length. If the current block generates
950 what when. Adapted from dgaudet's original example -- but must be ripping 753 * a partial line, so be it; we *want* that lockstep indication of who sent
951 *fast*, since we don't want to be too disk-bound... */ 754 * what when. Adapted from dgaudet's original example -- but must be ripping
755 * *fast*, since we don't want to be too disk-bound.
756 */
952void 757void
953oprint(which, buf, n) 758oprint(which, buf, n)
954 int which; 759 int which;
@@ -958,14 +763,14 @@ oprint(which, buf, n)
958 int bc; /* in buffer count */ 763 int bc; /* in buffer count */
959 int obc; /* current "global" offset */ 764 int obc; /* current "global" offset */
960 int soc; /* stage write count */ 765 int soc; /* stage write count */
961 register unsigned char *p; /* main buf ptr; m.b. unsigned here */ 766 unsigned char *p; /* main buf ptr; m.b. unsigned here */
962 register unsigned char *op; /* out hexdump ptr */ 767 unsigned char *op; /* out hexdump ptr */
963 register unsigned char *a; /* out asc-dump ptr */ 768 unsigned char *a; /* out asc-dump ptr */
964 register int x; 769 int x;
965 register unsigned int y; 770 unsigned int y;
966 771
967 if (!ofd) 772 if (!ofd)
968 bail("oprint called with no open fd?!"); 773 errx(1, "oprint called with no open fd?!");
969 if (n == 0) 774 if (n == 0)
970 return; 775 return;
971 776
@@ -1028,27 +833,29 @@ oprint(which, buf, n)
1028 *a = '\n'; /* finish the line */ 833 *a = '\n'; /* finish the line */
1029 x = write(ofd, stage, soc); 834 x = write(ofd, stage, soc);
1030 if (x < 0) 835 if (x < 0)
1031 bail("ofd write err"); 836 errx(1, "ofd write err");
1032 } /* while bc */ 837 }
1033} 838}
1034 839
1035#ifdef TELNET 840#ifdef TELNET
1036u_short o_tn = 0; /* global -t option */ 841u_short o_tn = 0; /* global -t option */
1037 842
1038/* atelnet : 843/*
1039 Answer anything that looks like telnet negotiation with don't/won't. 844 * atelnet :
1040 This doesn't modify any data buffers, update the global output count, 845 * Answer anything that looks like telnet negotiation with don't/won't.
1041 or show up in a hexdump -- it just shits into the outgoing stream. 846 * This doesn't modify any data buffers, update the global output count,
1042 Idea and codebase from Mudge@l0pht.com. */ 847 * or show up in a hexdump -- it just shits into the outgoing stream.
848 * Idea and codebase from Mudge@l0pht.com.
849 */
1043void 850void
1044atelnet(buf, size) 851atelnet(buf, size)
1045 unsigned char *buf; /* has to be unsigned here! */ 852 unsigned char *buf; /* has to be unsigned here! */
1046 unsigned int size; 853 unsigned int size;
1047{ 854{
1048 static unsigned char obuf[4]; /* tiny thing to build responses into */ 855 static unsigned char obuf[4]; /* tiny thing to build responses into */
1049 register int x; 856 int x;
1050 register unsigned char y; 857 unsigned char y;
1051 register unsigned char *p; 858 unsigned char *p;
1052 859
1053 y = 0; 860 y = 0;
1054 p = buf; 861 p = buf;
@@ -1067,42 +874,49 @@ atelnet(buf, size)
1067 obuf[1] = y; 874 obuf[1] = y;
1068 p++; 875 p++;
1069 x--; 876 x--;
1070 obuf[2] = *p; /* copy actual option byte */ 877 obuf[2] = *p;
1071 (void) write(netfd, obuf, 3); 878 (void) write(netfd, obuf, 3);
1072/* if one wanted to bump wrote_net or do a hexdump line, here's the place */ 879 /*
880 * if one wanted to bump wrote_net or do
881 * a hexdump line, here's the place.
882 */
1073 y = 0; 883 y = 0;
1074 } /* if y */ 884 }
1075notiac: 885notiac:
1076 p++; 886 p++;
1077 x--; 887 x--;
1078 } /* while x */ 888 }
1079} 889}
890#endif /* TELNET */
1080 891
1081#endif /* TELNET */ 892/*
1082 893 * readwrite :
1083/* readwrite : 894 * handle stdin/stdout/network I/O. Bwahaha!! -- the select loop from hell.
1084 handle stdin/stdout/network I/O. Bwahaha!! -- the select loop from hell. 895 * In this instance, return what might become our exit status.
1085 In this instance, return what might become our exit status. */ 896 */
1086int 897int
1087readwrite(fd) 898readwrite(fd)
1088 int fd; 899 int fd;
1089{ 900{
1090 register int rr; 901 int rr;
1091 register char *zp; /* stdin buf ptr */ 902 char *zp; /* stdin buf ptr */
1092 register char *np; /* net-in buf ptr */ 903 char *np; /* net-in buf ptr */
1093 unsigned int rzleft; 904 unsigned int rzleft;
1094 unsigned int rnleft; 905 unsigned int rnleft;
1095 u_short netretry; /* net-read retry counter */ 906 u_short netretry; /* net-read retry counter */
1096 u_short wretry; /* net-write sanity counter */ 907 u_short wretry; /* net-write sanity counter */
1097 u_short wfirst; /* one-shot flag to skip first net read */ 908 u_short wfirst; /* one-shot flag to skip first net read */
1098 909
1099/* if you don't have all this FD_* macro hair in sys/types.h, you'll have to 910 /*
1100 either find it or do your own bit-bashing: *fds1 |= (1 << fd), etc... */ 911 * if you don't have all this FD_* macro hair in sys/types.h,
912 * you'll have to either find it or do your own bit-bashing:
913 * *ds1 |= (1 << fd), etc.
914 */
1101 if (fd > FD_SETSIZE) { 915 if (fd > FD_SETSIZE) {
1102 holler("Preposterous fd value %d", fd); 916 warn("Preposterous fd value %d", fd);
1103 return (1); 917 return (1);
1104 } 918 }
1105 FD_SET(fd, &fds1); /* global: the net is open */ 919 FD_SET(fd, &fds1);
1106 netretry = 2; 920 netretry = 2;
1107 wfirst = 0; 921 wfirst = 0;
1108 rzleft = rnleft = 0; 922 rzleft = rnleft = 0;
@@ -1110,25 +924,23 @@ readwrite(fd)
1110 rzleft = insaved; /* preload multi-mode fakeouts */ 924 rzleft = insaved; /* preload multi-mode fakeouts */
1111 zp = bigbuf_in; 925 zp = bigbuf_in;
1112 wfirst = 1; 926 wfirst = 1;
1113 if (Single) /* if not scanning, this is a one-off first */ 927 /* If not scanning, this is a one-off first */
1114 insaved = 0; /* buffer left over from argv 928 if (Single)
1115 * construction, */ 929 insaved = 0;
1116 else { 930 else {
1117 FD_CLR(0, &fds1); /* OR we've already got our 931 FD_CLR(0, &fds1);
1118 * repeat chunk, */ 932 close(0);
1119 close(0); /* so we won't need any more stdin */ 933 }
1120 } /* Single */ 934 }
1121 } /* insaved */
1122 if (o_interval) 935 if (o_interval)
1123 sleep(o_interval); /* pause *before* sending stuff, too */ 936 sleep(o_interval);
1124 errno = 0; /* clear from sleep, close, whatever */ 937 errno = 0;
1125 938
1126/* and now the big ol' select shoveling loop ... */
1127 while (FD_ISSET(fd, &fds1)) { /* i.e. till the *net* closes! */ 939 while (FD_ISSET(fd, &fds1)) { /* i.e. till the *net* closes! */
1128 struct timeval *tv; 940 struct timeval *tv;
1129 941
1130 wretry = 8200; /* more than we'll ever hafta write */ 942 wretry = 8200; /* more than we'll ever hafta write */
1131 if (wfirst) { /* any saved stdin buffer? */ 943 if (wfirst) { /* any saved stdin buffer? */
1132 wfirst = 0; /* clear flag for the duration */ 944 wfirst = 0; /* clear flag for the duration */
1133 goto shovel; /* and go handle it first */ 945 goto shovel; /* and go handle it first */
1134 } 946 }
@@ -1140,13 +952,12 @@ readwrite(fd)
1140 tv = NULL; 952 tv = NULL;
1141 rr = select(getdtablesize(), &fds2, 0, 0, tv); 953 rr = select(getdtablesize(), &fds2, 0, 0, tv);
1142 if (rr < 0) { 954 if (rr < 0) {
1143 if (errno != EINTR) { /* might have gotten ^Zed, etc 955 if (errno != EINTR) {
1144 * ? */ 956 warn("Select Failure");
1145 holler("select fuxored");
1146 close(fd); 957 close(fd);
1147 return (1); 958 return (1);
1148 } 959 }
1149 } /* select fuckup */ 960 }
1150 /* if we have a timeout AND stdin is closed AND we haven't 961 /* if we have a timeout AND stdin is closed AND we haven't
1151 * heard anything from the net during that time, assume it's 962 * heard anything from the net during that time, assume it's
1152 * dead and close it too. */ 963 * dead and close it too. */
@@ -1157,12 +968,12 @@ readwrite(fd)
1157 if (!netretry) { 968 if (!netretry) {
1158 if (o_verbose > 1) /* normally we don't 969 if (o_verbose > 1) /* normally we don't
1159 * care */ 970 * care */
1160 holler("net timeout"); 971 warn("net timeout");
1161 close(fd); 972 close(fd);
1162 return (0); /* not an error! */ 973 return (0); /* not an error! */
1163 } 974 }
1164 } /* select timeout */ 975 } /* select timeout */
1165 /* xxx: should we check the exception fds too? The read fds 976 /* XXX: should we check the exception fds too? The read fds
1166 * seem to give us the right info, and none of the examples I 977 * seem to give us the right info, and none of the examples I
1167 * found bothered. */ 978 * found bothered. */
1168 /* Ding!! Something arrived, go check all the incoming 979 /* Ding!! Something arrived, go check all the incoming
@@ -1180,98 +991,76 @@ readwrite(fd)
1180#ifdef TELNET 991#ifdef TELNET
1181 if (o_tn) 992 if (o_tn)
1182 atelnet(np, rr); /* fake out telnet stuff */ 993 atelnet(np, rr); /* fake out telnet stuff */
1183#endif /* TELNET */ 994#endif /* TELNET */
1184 } /* if rr */ 995 }
1185 Debug(("got %d from the net, errno %d", rr, errno)) 996 }
1186 } /* net:ding */
1187 /* if we're in "slowly" mode there's probably still stuff in 997 /* if we're in "slowly" mode there's probably still stuff in
1188 * the stdin buffer, so don't read unless we really need MORE 998 * the stdin buffer, so don't read unless we really need MORE
1189 * INPUT! MORE INPUT! */ 999 * INPUT! MORE INPUT! */
1190 if (rzleft) 1000 if (rzleft)
1191 goto shovel; 1001 goto shovel;
1192 1002
1193/* okay, suck more stdin */ 1003 if (FD_ISSET(0, &fds2)) {
1194 if (FD_ISSET(0, &fds2)) { /* stdin: ding! */
1195 rr = read(0, bigbuf_in, BIGSIZ); 1004 rr = read(0, bigbuf_in, BIGSIZ);
1196/* Considered making reads here smaller for UDP mode, but 8192-byte 1005 if (rr <= 0) {
1197 mobygrams are kinda fun and exercise the reassembler. */ 1006 FD_CLR(0, &fds1); /* disable and close */
1198 if (rr <= 0) { /* at end, or fukt, or ... */
1199 FD_CLR(0, &fds1); /* disable and close
1200 * stdin */
1201 close(0); 1007 close(0);
1202 } else { 1008 } else {
1203 rzleft = rr; 1009 rzleft = rr;
1204 zp = bigbuf_in; 1010 zp = bigbuf_in;
1205/* special case for multi-mode -- we'll want to send this one buffer to every 1011 if (!Single) {
1206 open TCP port or every UDP attempt, so save its size and clean up stdin */ 1012 insaved = rr;
1207 if (!Single) { /* we might be scanning... */ 1013 FD_CLR(0, &fds1);
1208 insaved = rr; /* save len */ 1014 close(0);
1209 FD_CLR(0, &fds1); /* disable further junk 1015 }
1210 * from stdin */ 1016 }
1211 close(0); /* really, I mean it */ 1017 }
1212 } /* Single */
1213 } /* if rr/read */
1214 } /* stdin:ding */
1215shovel: 1018shovel:
1216/* now that we've dingdonged all our thingdings, send off the results. 1019 /* sanity check. Works because they're both unsigned... */
1217 Geez, why does this look an awful lot like the big loop in "rsh"? ...
1218 not sure if the order of this matters, but write net -> stdout first. */
1219
1220/* sanity check. Works because they're both unsigned... */
1221 if ((rzleft > 8200) || (rnleft > 8200)) { 1020 if ((rzleft > 8200) || (rnleft > 8200)) {
1222 holler("Bogus buffers: %d, %d", rzleft, rnleft); 1021 warn("Bogus buffers: %d, %d", rzleft, rnleft);
1223 rzleft = rnleft = 0; 1022 rzleft = rnleft = 0;
1224 } 1023 }
1225/* net write retries sometimes happen on UDP connections */ 1024 /* net write retries sometimes happen on UDP connections */
1226 if (!wretry) { /* is something hung? */ 1025 if (!wretry) { /* is something hung? */
1227 holler("too many output retries"); 1026 warn("too many output retries");
1228 return (1); 1027 return (1);
1229 } 1028 }
1230 if (rnleft) { 1029 if (rnleft) {
1231 rr = write(1, np, rnleft); 1030 rr = write(1, np, rnleft);
1232 if (rr > 0) { 1031 if (rr > 0) {
1233 if (o_wfile) 1032 if (o_wfile)
1234 oprint(1, np, rr); /* log the stdout */ 1033 oprint(1, np, rr);
1235 np += rr; /* fix up ptrs and whatnot */ 1034 np += rr;
1236 rnleft -= rr; /* will get sanity-checked 1035 rnleft -= rr;
1237 * above */
1238 wrote_out += rr; /* global count */ 1036 wrote_out += rr; /* global count */
1239 } 1037 }
1240 Debug(("wrote %d to stdout, errno %d", rr, errno)) 1038 }
1241 } /* rnleft */
1242 if (rzleft) { 1039 if (rzleft) {
1243 if (o_interval) /* in "slowly" mode ?? */ 1040 if (o_interval)
1244 rr = findline(zp, rzleft); 1041 rr = findline(zp, rzleft);
1245 else 1042 else
1246 rr = rzleft; 1043 rr = rzleft;
1247 rr = write(fd, zp, rr); /* one line, or the whole 1044 rr = write(fd, zp, rr);
1248 * buffer */
1249 if (rr > 0) { 1045 if (rr > 0) {
1250 if (o_wfile) 1046 if (o_wfile)
1251 oprint(0, zp, rr); /* log what got sent */ 1047 oprint(0, zp, rr);
1252 zp += rr; 1048 zp += rr;
1253 rzleft -= rr; 1049 rzleft -= rr;
1254 wrote_net += rr; /* global count */ 1050 wrote_net += rr;
1255 } 1051 }
1256 Debug(("wrote %d to net, errno %d", rr, errno)) 1052 }
1257 } /* rzleft */ 1053 if (o_interval) {
1258 if (o_interval) { /* cycle between slow lines, or ... */
1259 sleep(o_interval); 1054 sleep(o_interval);
1260 errno = 0; /* clear from sleep */ 1055 errno = 0;
1261 continue; /* ...with hairy select loop... */ 1056 continue;
1262 } 1057 }
1263 if ((rzleft) || (rnleft)) { /* shovel that shit till they 1058 if ((rzleft) || (rnleft)) {
1264 * ain't */ 1059 wretry--;
1265 wretry--; /* none left, and get another load */
1266 goto shovel; 1060 goto shovel;
1267 } 1061 }
1268 } /* while fds1:netfd is open */ 1062 }
1269 1063
1270/* XXX: maybe want a more graceful shutdown() here, or screw around with
1271 linger times?? I suspect that I don't need to since I'm always doing
1272 blocking reads and writes and my own manual "last ditch" efforts to read
1273 the net again after a timeout. I haven't seen any screwups yet, but it's
1274 not like my test network is particularly busy... */
1275 close(fd); 1064 close(fd);
1276 return (0); 1065 return (0);
1277} 1066}
@@ -1282,12 +1071,8 @@ main(argc, argv)
1282 int argc; 1071 int argc;
1283 char **argv; 1072 char **argv;
1284{ 1073{
1285#ifndef HAVE_GETOPT 1074 int x, ch;
1286 extern char *optarg; 1075 char *cp;
1287 extern int optind, optopt;
1288#endif
1289 register int x;
1290 register char *cp;
1291 struct host_info *gp; 1076 struct host_info *gp;
1292 struct host_info *whereto = NULL; 1077 struct host_info *whereto = NULL;
1293 struct host_info *wherefrom = NULL; 1078 struct host_info *wherefrom = NULL;
@@ -1301,38 +1086,36 @@ main(argc, argv)
1301 char *randports = NULL; 1086 char *randports = NULL;
1302 1087
1303#ifdef HAVE_BIND 1088#ifdef HAVE_BIND
1304/* can *you* say "cc -yaddayadda netcat.c -lresolv -l44bsd" on SunLOSs? */
1305 res_init(); 1089 res_init();
1306#endif 1090#endif
1307/* I was in this barbershop quartet in Skokie IL ... */
1308/* round up the usual suspects, i.e. malloc up all the stuff we need */
1309 lclend = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr)); 1091 lclend = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr));
1310 remend = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr)); 1092 remend = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr));
1311 bigbuf_in = calloc(1, BIGSIZ); 1093 bigbuf_in = calloc(1, BIGSIZ);
1312 bigbuf_net = calloc(1, BIGSIZ); 1094 bigbuf_net = calloc(1, BIGSIZ);
1313 portpoop = (struct port_info *) calloc(1, sizeof(struct port_info)); 1095 pinfo= (struct port_info *) calloc(1, sizeof(struct port_info));
1314 1096
1315 errno = 0; 1097 errno = 0;
1316 gatesptr = 4; 1098 gatesptr = 4;
1317 h_errno = 0; 1099 h_errno = 0;
1318 1100
1319/* catch a signal or two for cleanup */ 1101 /*
1102 * We want to catch a few of these signals.
1103 * Others we disgard.
1104 */
1320 signal(SIGINT, catch); 1105 signal(SIGINT, catch);
1321 signal(SIGQUIT, catch); 1106 signal(SIGQUIT, catch);
1322 signal(SIGTERM, catch); 1107 signal(SIGTERM, catch);
1323/* and suppress others... */
1324#ifdef SIGURG
1325 signal(SIGURG, SIG_IGN); 1108 signal(SIGURG, SIG_IGN);
1326#endif
1327#ifdef SIGPIPE
1328 signal(SIGPIPE, SIG_IGN); /* important! */ 1109 signal(SIGPIPE, SIG_IGN); /* important! */
1329#endif
1330 1110
1331/* if no args given at all, get 'em from stdin, construct an argv, and hand 1111 /*
1332 anything left over to readwrite(). */ 1112 * If no args given at all, get 'em from stdin, construct an argv,
1113 * and hand anything left over to readwrite().
1114 */
1333 if (argc == 1) { 1115 if (argc == 1) {
1334 cp = argv[0]; 1116 cp = argv[0];
1335 argv = (char **) calloc(1, 128 * sizeof(char *)); /* XXX: 128? */ 1117 /* XXX - 128 ? */
1118 argv = (char **) calloc(1, 128 * sizeof(char *));
1336 argv[0] = cp; /* leave old prog name intact */ 1119 argv[0] = cp; /* leave old prog name intact */
1337 cp = calloc(1, BIGSIZ); 1120 cp = calloc(1, BIGSIZ);
1338 argv[1] = cp; /* head of new arg block */ 1121 argv[1] = cp; /* head of new arg block */
@@ -1342,7 +1125,7 @@ main(argc, argv)
1342 * here */ 1125 * here */
1343 cp[BIGSIZ-1] = '\0'; 1126 cp[BIGSIZ-1] = '\0';
1344 if (insaved <= 0) 1127 if (insaved <= 0)
1345 bail("wrong"); 1128 errx(1, "wrong");
1346 x = findline(cp, insaved); 1129 x = findline(cp, insaved);
1347 if (x) 1130 if (x)
1348 insaved -= x; /* remaining chunk size to be sent */ 1131 insaved -= x; /* remaining chunk size to be sent */
@@ -1355,7 +1138,9 @@ main(argc, argv)
1355 if (cp) 1138 if (cp)
1356 *cp = '\0'; 1139 *cp = '\0';
1357 1140
1358/* find and stash pointers to remaining new "args" */ 1141 /*
1142 * Find and stash pointers to remaining new "args"
1143 */
1359 cp = argv[1]; 1144 cp = argv[1];
1360 cp++; /* skip past first char */ 1145 cp++; /* skip past first char */
1361 x = 2; /* we know argv 0 and 1 already */ 1146 x = 2; /* we know argv 0 and 1 already */
@@ -1371,129 +1156,106 @@ main(argc, argv)
1371 } /* if space */ 1156 } /* if space */
1372 } /* for cp */ 1157 } /* for cp */
1373 argc = x; 1158 argc = x;
1374 } /* if no args given */ 1159 }
1375 /* If your shitbox doesn't have getopt, step into the nineties 1160
1376 * already. */ 1161 while ((ch = getopt(argc, argv, "g:G:hi:lno:p:rs:tuvw:z")) != -1) {
1377 /* optarg, optind = next-argv-component [i.e. flag arg]; optopt = 1162 switch (ch) {
1378 * last-char */ 1163 case 'G': /* srcrt gateways pointer val */
1379 while ((x = getopt(argc, argv, "ae:g:G:hi:lno:p:rs:tuvw:z")) != -1) {
1380/* Debug (("in go: x now %c, optarg %x optind %d", x, optarg, optind)) */
1381 switch (x) {
1382 case 'a':
1383 bail("all-A-records NIY");
1384 o_alla++;
1385 break;
1386#ifdef GAPING_SECURITY_HOLE
1387 case 'e': /* prog to exec */
1388 pr00gie = optarg;
1389 break;
1390#endif
1391 case 'G': /* srcrt gateways pointer val */
1392 x = atoi(optarg); 1164 x = atoi(optarg);
1393 if ((x) && (x == (x & 0x1c))) /* mask off bits of fukt 1165 /* Mask of bits */
1394 * values */ 1166 if ((x) && (x == (x & 0x1c)))
1395 gatesptr = x; 1167 gatesptr = x;
1396 else 1168 else
1397 bail("invalid hop pointer %d, must be multiple of 4 <= 28", x); 1169 errx(1, "invalid hop pointer %d, must be multiple of 4 <= 28", x);
1398 break; 1170 break;
1399 case 'g': /* srcroute hop[s] */ 1171 case 'g': /* srcroute hop[s] */
1400 if (gatesidx > 8) 1172 if (gatesidx > 8)
1401 bail("too many -g hops"); 1173 errx(1, "Too many -g hops!");
1402 if (gates == NULL) /* eat this, Billy-boy */ 1174 if (gates == NULL)
1403 gates = (struct host_info **) calloc(1, sizeof(struct host_info *) * 10); 1175 gates = (struct host_info **) calloc(1,
1404 gp = gethostpoop(optarg, o_nflag); 1176 sizeof(struct host_info *) * 10);
1177 gp = gethinfo(optarg, o_nflag);
1405 if (gp) 1178 if (gp)
1406 gates[gatesidx] = gp; 1179 gates[gatesidx] = gp;
1407 gatesidx++; 1180 gatesidx++;
1408 break; 1181 break;
1409 case 'h': 1182 case 'h':
1410 errno = 0; 1183 help();
1411 helpme(); /* exits by itself */ 1184 break;
1412 case 'i': /* line-interval time */ 1185 case 'i': /* line-interval time */
1413 o_interval = atoi(optarg) & 0xffff; 1186 o_interval = atoi(optarg) & 0xffff;
1414 if (!o_interval) 1187 if (!o_interval)
1415 bail("invalid interval time %s", optarg); 1188 errx(1, "invalid interval time %s", optarg);
1416 break; 1189 break;
1417 case 'l': /* listen mode */ 1190 case 'l': /* listen mode */
1418 o_listen++; 1191 o_listen++;
1419 break; 1192 break;
1420 case 'n': /* numeric-only, no DNS lookups */ 1193 case 'n': /* numeric-only, no DNS lookups */
1421 o_nflag++; 1194 o_nflag++;
1422 break; 1195 break;
1423 case 'o': /* hexdump log */ 1196 case 'o': /* hexdump log */
1424 stage = (unsigned char *) optarg; 1197 stage = (unsigned char *) optarg;
1425 o_wfile++; 1198 o_wfile++;
1426 break; 1199 break;
1427 case 'p': /* local source port */ 1200 case 'p': /* local source port */
1428 o_lport = getportpoop(optarg, 0); 1201 o_lport = getpinfo(optarg, 0);
1429 if (o_lport == 0) 1202 if (o_lport == 0)
1430 bail("invalid local port %s", optarg); 1203 errx(1, "invalid local port %s", optarg);
1431 break; 1204 break;
1432 case 'r': /* randomize various things */ 1205 case 'r': /* randomize various things */
1433 o_random++; 1206 o_random++;
1434 break; 1207 break;
1435 case 's': /* local source address */ 1208 /*
1436/* do a full lookup [since everything else goes through the same mill], 1209 * Do a full lookup [since everything else goes through the same
1437 unless -n was previously specified. In fact, careful placement of -n can 1210 * mill], unless -n was previously specified. In fact, careful
1438 be useful, so we'll still pass o_nflag here instead of forcing numeric. */ 1211 * placement of -n can be useful, so we'll still pass o_nflag
1439 wherefrom = gethostpoop(optarg, o_nflag); 1212 * here instead of forcing numeric.
1213 */
1214 case 's': /* local source address */
1215 wherefrom = gethinfo(optarg, o_nflag);
1440 ouraddr = &wherefrom->iaddrs[0]; 1216 ouraddr = &wherefrom->iaddrs[0];
1441 break; 1217 break;
1442#ifdef TELNET 1218#ifdef TELNET
1443 case 't': /* do telnet fakeout */ 1219 case 't': /* do telnet fakeout */
1444 o_tn++; 1220 o_tn++;
1445 break; 1221 break;
1446#endif /* TELNET */ 1222#endif
1447 case 'u': /* use UDP */ 1223 case 'u': /* use UDP */
1448 o_udpmode++; 1224 o_udpmode++;
1449 break; 1225 break;
1450 case 'v': /* verbose */ 1226 case 'v': /* verbose */
1451 o_verbose++; 1227 o_verbose++;
1452 break; 1228 break;
1453 case 'w': /* wait time */ 1229 case 'w': /* wait time */
1454 o_wait = atoi(optarg); 1230 o_wait = atoi(optarg);
1455 if (o_wait <= 0) 1231 if (o_wait <= 0)
1456 bail("invalid wait-time %s", optarg); 1232 errx(1, "invalid wait-time %s", optarg);
1457 timer1.tv_sec = o_wait; 1233 timer1.tv_sec = o_wait;
1458 timer1.tv_usec = 0; 1234 timer1.tv_usec = 0;
1459 break; 1235 break;
1460 case 'z': /* little or no data xfer */ 1236 case 'z': /* little or no data xfer */
1461 o_zero++; 1237 o_zero++;
1462 break; 1238 break;
1463 default: 1239 default:
1464 errno = 0; 1240 usage(1);
1465 bail("nc -h for help"); 1241 }
1466 } /* switch x */ 1242 }
1467 } /* while getopt */
1468 1243
1469/* other misc initialization */ 1244 /* other misc initialization */
1470 Debug(("fd_set size %d", sizeof(*fds1))) /* how big *is* it? */
1471 FD_SET(0, &fds1); /* stdin *is* initially open */ 1245 FD_SET(0, &fds1); /* stdin *is* initially open */
1472 if (o_random) { 1246 if (o_random) {
1473 SRAND(time(0)); 1247 SRAND(time(0));
1474 randports = calloc(1, 65536); /* big flag array for ports */ 1248 randports = calloc(1, 65536); /* big flag array for ports */
1475 } 1249 }
1476#ifdef GAPING_SECURITY_HOLE
1477 if (pr00gie) {
1478 close(0); /* won't need stdin */
1479 o_wfile = 0; /* -o with -e is meaningless! */
1480 ofd = 0;
1481 }
1482#endif /* G_S_H */
1483 if (o_wfile) { 1250 if (o_wfile) {
1484 ofd = open(stage, O_WRONLY | O_CREAT | O_TRUNC, 0664); 1251 ofd = open(stage, O_WRONLY | O_CREAT | O_TRUNC, 0664);
1485 if (ofd <= 0) /* must be > extant 0/1/2 */ 1252 if (ofd <= 0) /* must be > extant 0/1/2 */
1486 bail("can't open %s", stage); 1253 errx(1, "Can't open %s", stage);
1487 stage = (unsigned char *) calloc(1, 100); 1254 stage = (unsigned char *) calloc(1, 100);
1488 } 1255 }
1489/* optind is now index of first non -x arg */ 1256 /* optind is now index of first non -x arg */
1490 Debug(("after go: x now %c, optarg %x optind %d", x, optarg, optind)) 1257 if (argv[optind])
1491/* Debug (("optind up to %d at host-arg %s", optind, argv[optind])) */ 1258 whereto = gethinfo(argv[optind], o_nflag);
1492/* gonna only use first addr of host-list, like our IQ was normal; if you wanna
1493 get fancy with addresses, look up the list yourself and plug 'em in for now.
1494 unless we finally implement -a, that is. */
1495 if (argv[optind])
1496 whereto = gethostpoop(argv[optind], o_nflag);
1497 if (whereto && whereto->iaddrs) 1259 if (whereto && whereto->iaddrs)
1498 themaddr = &whereto->iaddrs[0]; 1260 themaddr = &whereto->iaddrs[0];
1499 if (themaddr) 1261 if (themaddr)
@@ -1501,160 +1263,139 @@ main(argc, argv)
1501 errno = 0; 1263 errno = 0;
1502 h_errno = 0; 1264 h_errno = 0;
1503 1265
1504/* Handle listen mode here, and exit afterward. Only does one connect; 1266 /*
1505 this is arguably the right thing to do. A "persistent listen-and-fork" 1267 * Handle listen mode here, and exit afterward. Only does one connect;
1506 mode a la inetd has been thought about, but not implemented. A tiny 1268 * this is arguably the right thing to do. A "persistent listen-and-fork"
1507 wrapper script can handle such things... */ 1269 * mode a la inetd has been thought about, but not implemented. A tiny
1270 * wrapper script can handle such things.
1271 */
1508 if (o_listen) { 1272 if (o_listen) {
1509 curport = 0; /* rem port *can* be zero here... */ 1273 curport = 0;
1510 if (argv[optind]) { /* any rem-port-arg? */ 1274 if (argv[optind]) {
1511 curport = getportpoop(argv[optind], 0); 1275 curport = getpinfo(argv[optind], 0);
1512 if (curport == 0) /* if given, demand 1276 if (curport == 0)
1513 * correctness */ 1277 errx(1, "invalid port %s", argv[optind]);
1514 bail("invalid port %s", argv[optind]); 1278 }
1515 } /* if port-arg */
1516 netfd = dolisten(themaddr, curport, ouraddr, o_lport); 1279 netfd = dolisten(themaddr, curport, ouraddr, o_lport);
1517/* dolisten does its own connect reporting, so we don't holler anything here */
1518 if (netfd > 0) { 1280 if (netfd > 0) {
1519#ifdef GAPING_SECURITY_HOLE 1281 x = readwrite(netfd);
1520 if (pr00gie) /* -e given? */ 1282 if (o_verbose > 1)
1521 doexec(netfd); 1283 warn("Sent %i Rcvd %i", wrote_net, wrote_out);
1522#endif /* GAPING_SECURITY_HOLE */ 1284 exit(x);
1523 x = readwrite(netfd); /* it even works with UDP! */ 1285 } else
1524 if (o_verbose > 1) /* normally we don't care */ 1286 errx(1, "no connection");
1525 holler(wrote_txt, wrote_net, wrote_out); 1287 }
1526 exit(x);/* "pack out yer trash" */
1527 } else /* if no netfd */
1528 bail("no connection");
1529 } /* o_listen */
1530 /* fall thru to outbound connects. Now we're more picky about args... */ 1288 /* fall thru to outbound connects. Now we're more picky about args... */
1531 if (!themaddr) 1289 if (!themaddr)
1532 bail("no destination"); 1290 errx(1, "no destination");
1533 if (argv[optind] == NULL) 1291 if (argv[optind] == NULL)
1534 bail("no port[s] to connect to"); 1292 errx(1, "no port[s] to connect to");
1535 if (argv[optind + 1]) /* look ahead: any more port args given? */ 1293 if (argv[optind + 1])
1536 Single = 0; /* multi-mode, case A */ 1294 Single = 0;
1537 ourport = o_lport; /* which can be 0 */ 1295 ourport = o_lport;
1538 1296
1539/* everything from here down is treated as as ports and/or ranges thereof, so
1540 it's all enclosed in this big ol' argv-parsin' loop. Any randomization is
1541 done within each given *range*, but in separate chunks per each succeeding
1542 argument, so we can control the pattern somewhat. */
1543 while (argv[optind]) { 1297 while (argv[optind]) {
1544 hiport = loport = 0; 1298 hiport = loport = 0;
1545 cp = strchr(argv[optind], '-'); /* nn-mm range? */ 1299 cp = strchr(argv[optind], '-');
1546 if (cp) { 1300 if (cp) {
1547 *cp = '\0'; 1301 *cp = '\0';
1548 cp++; 1302 cp++;
1549 hiport = getportpoop(cp, 0); 1303 hiport = getpinfo(cp, 0);
1550 if (hiport == 0) 1304 if (hiport == 0)
1551 bail("invalid port %s", cp); 1305 errx(1, "invalid port %s", cp);
1552 } /* if found a dash */ 1306 } /* if found a dash */
1553 loport = getportpoop(argv[optind], 0); 1307 loport = getpinfo(argv[optind], 0);
1554 if (loport == 0) 1308 if (loport == 0)
1555 bail("invalid port %s", argv[optind]); 1309 errx(1, "invalid port %s", argv[optind]);
1556 if (hiport > loport) { /* was it genuinely a range? */ 1310 if (hiport > loport) { /* was it genuinely a range? */
1557 Single = 0; /* multi-mode, case B */ 1311 Single = 0; /* multi-mode, case B */
1558 curport = hiport; /* start high by default */
1559 if (o_random) { /* maybe populate the random array */ 1312 if (o_random) { /* maybe populate the random array */
1560 loadports(randports, loport, hiport); 1313 loadports(randports, loport, hiport);
1561 curport = nextport(randports); 1314 curport = nextport(randports);
1562 } 1315 } else
1316 curport = hiport;
1563 } else /* not a range, including args like "25-25" */ 1317 } else /* not a range, including args like "25-25" */
1564 curport = loport; 1318 curport = loport;
1565 Debug(("Single %d, curport %d", Single, curport)) 1319 /*
1566/* Now start connecting to these things. curport is already preloaded. */ 1320 * Now start connecting to these things.
1321 * curport is already preloaded.
1322 */
1567 while (loport <= curport) { 1323 while (loport <= curport) {
1568 if ((!o_lport) && (o_random)) { /* -p overrides random 1324 curport = getpinfo(NULL, curport);
1569 * local-port */
1570 ourport = (RAND() & 0xffff); /* random local-bind --
1571 * well above */
1572 if (ourport < 8192) /* resv and any likely
1573 * listeners??? */
1574 ourport += 8192; /* if it *still*
1575 * conflicts, use -s. */
1576 }
1577 curport = getportpoop(NULL, curport);
1578 netfd = doconnect(themaddr, curport, ouraddr, ourport); 1325 netfd = doconnect(themaddr, curport, ouraddr, ourport);
1579 Debug(("netfd %d from port %d to port %d", netfd, ourport, curport)) 1326 if (netfd > 0)
1580 if (netfd > 0) 1327 if (o_zero && o_udpmode)
1581 if (o_zero && o_udpmode) /* if UDP scanning... */
1582 netfd = udptest(netfd, themaddr); 1328 netfd = udptest(netfd, themaddr);
1583 if (netfd > 0) { /* Yow, are we OPEN YET?! */ 1329 if (netfd > 0) {
1584 x = 0; /* pre-exit status */ 1330 x = 0;
1585 holler("%s [%s] %d (%s) open", 1331 if (o_verbose) {
1586 whereto->name, whereto->addrs[0], curport, portpoop->name); 1332 warn("%s [%s] %d (%s) open",
1587#ifdef GAPING_SECURITY_HOLE 1333 whereto->name,
1588 if (pr00gie) /* exec is valid for outbound, 1334 whereto->addrs[0], curport,
1589 * too */ 1335 pinfo->name);
1590 doexec(netfd); 1336 }
1591#endif /* GAPING_SECURITY_HOLE */
1592 if (!o_zero) 1337 if (!o_zero)
1593 x = readwrite(netfd); /* go shovel shit */ 1338 x = readwrite(netfd);
1594 } else {/* no netfd... */ 1339 } else {
1595 x = 1; /* preload exit status for later */ 1340 x = 1;
1596/* if we're scanning at a "one -v" verbosity level, don't print refusals. 1341 if ((Single || (o_verbose > 1))
1597 Give it another -v if you want to see everything. */ 1342 || (errno != ECONNREFUSED)) {
1598 if ((Single || (o_verbose > 1)) || (errno != ECONNREFUSED)) 1343 warn("%s [%s] %d (%s)",
1599 holler("%s [%s] %d (%s)", 1344 whereto->name, whereto->addrs[0],
1600 whereto->name, whereto->addrs[0], curport, portpoop->name); 1345 curport, pinfo->name);
1601 } /* if netfd */ 1346 }
1602 close(netfd); /* just in case we didn't already */ 1347 }
1348 close(netfd);
1603 if (o_interval) 1349 if (o_interval)
1604 sleep(o_interval); /* if -i, delay between 1350 sleep(o_interval);
1605 * ports too */
1606 if (o_random) 1351 if (o_random)
1607 curport = nextport(randports); 1352 curport = nextport(randports);
1608 else 1353 else
1609 curport--; /* just decrement... */ 1354 curport--;
1610 } /* while curport within current range */ 1355 }
1611 optind++; 1356 optind++;
1612 } /* while remaining port-args -- end of big 1357 }
1613 * argv-ports loop */
1614 1358
1615 errno = 0; 1359 errno = 0;
1616 if (o_verbose > 1) /* normally we don't care */ 1360 if (o_verbose > 1)
1617 holler(wrote_txt, wrote_net, wrote_out); 1361 warn("Sent %i Rcvd %i", wrote_net, wrote_out);
1618 if (Single) 1362 if (Single)
1619 exit(x); /* give us status on one connection */ 1363 exit(x);
1620 exit(0); /* otherwise, we're just done */ 1364 exit(0);
1621} 1365}
1622 1366
1623/* helpme : 1367void
1624 the obvious */ 1368usage(doexit)
1625helpme()
1626{ 1369{
1627 o_verbose = 1; 1370 fprintf(stderr, "netcat - [v1.10]\n");
1628 holler("[v1.10]\n\ 1371 fprintf(stderr, "nc [-lnrtuvz] [-e command] [-g intermediates]\n");
1629connect to somewhere: nc [-options] hostname port[s] [ports] ... \n\ 1372 fprintf(stderr, " [-G hopcount] [-i interval] [-o filename] [-p source port]\n");
1630listen for inbound: nc -l -p port [-options] [hostname] [port]\n\ 1373 fprintf(stderr, " [-s ip address] [-w timeout] [hostname] [port[s...]]\n");
1631options:"); 1374 if (doexit)
1632/* sigh, this necessarily gets messy. And the trailing \ characters may be 1375 exit(1);
1633 interpreted oddly by some compilers, generating or not generating extra 1376}
1634 newlines as they bloody please. u-fix... */ 1377
1635#ifdef GAPING_SECURITY_HOLE /* needs to be separate holler() */ 1378void
1636 holler("\ 1379help()
1637 -e prog program to exec after connect [dangerous!!]"); 1380{
1638#endif 1381 usage(0);
1639 holler("\ 1382 fprintf(stderr, "\tCommand Summary:\n\
1640 -g gateway source-routing hop point[s], up to 8\n\ 1383 \t-g gateway source-routing hop point[s], up to 8\n\
1641 -G num source-routing pointer: 4, 8, 12, ...\n\ 1384 \t-G num\t source-routing pointer: 4, 8, 12, ...\n\
1642 -h this cruft\n\ 1385 \t-h this help text\n\
1643 -i secs delay interval for lines sent, ports scanned\n\ 1386 \t-i secs\t delay interval for lines sent, ports scanned\n\
1644 -l listen mode, for inbound connects\n\ 1387 \t-l listen mode, for inbound connects\n\
1645 -n numeric-only IP addresses, no DNS\n\ 1388 \t-n numeric-only IP addresses, no DNS\n\
1646 -o file hex dump of traffic\n\ 1389 \t-o file\t hex dump of traffic\n\
1647 -p port local port number\n\ 1390 \t-r randomize local and remote ports\n\
1648 -r randomize local and remote ports\n\ 1391 \t-s addr\t local source address\n");
1649 -s addr local source address");
1650#ifdef TELNET 1392#ifdef TELNET
1651 holler("\ 1393 fprintf(stderr, "\t\t-t answer TELNET negotiation\n");
1652 -t answer TELNET negotiation");
1653#endif 1394#endif
1654 holler("\ 1395 fprintf(stderr, "\t\t-u UDP mode\n\
1655 -u UDP mode\n\ 1396 \t-v verbose [use twice to be more verbose]\n\
1656 -v verbose [use twice to be more verbose]\n\ 1397 \t-w secs\t timeout for connects and final net reads\n\
1657 -w secs timeout for connects and final net reads\n\ 1398 \t-z zero-I/O mode [used for scanning]\n\
1658 -z zero-I/O mode [used for scanning]"); 1399 Port numbers can be individual or ranges: lo-hi [inclusive]\n");
1659 bail("port numbers can be individual or ranges: lo-hi [inclusive]"); 1400 exit(1);
1660} 1401}