diff options
Diffstat (limited to '')
-rw-r--r-- | src/usr.bin/nc/generic.h | 377 | ||||
-rw-r--r-- | src/usr.bin/nc/netcat.c | 1401 |
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 | ||
117 | HAVE_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 | ||
138 | randomness 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 | ||
142 | randomness about machine/endian.h, machine/inline.h -- bsdi, net/2 | ||
143 | randomness 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?] | ||
150 | lseek: SEEK_SET vs L_SET and associated lossage [epi-notes, old 386Mach] | ||
151 | bsdi: ioctl_compat.h ? | ||
152 | --- takin' some ifdefs from CNS krb: | ||
153 | F_GETOWN/F_SETOWN | ||
154 | CRAY: long = 8 bytes, etc [class with alpha?] | ||
155 | CGETENT | ||
156 | SIGINFO | ||
157 | SIGTSTP SIGTTOU SIGWINCH | ||
158 | SPX? | ||
159 | SYSV_TERMIO -- covered elsewhere, I hope | ||
160 | TIOCEXT TIOCFLUSH TIOC[GS]WINSIZ | ||
161 | NEWINIT: something about init cleaning up dead login processes [telnet?] | ||
162 | PARENT_DOES_UTMP, too [telnet] | ||
163 | VDISCARD | ||
164 | VEOL/VEOL2/VLNEXT VREPRINT -- termios stuff?, and related... | ||
165 | STREAMSPTY/STREAMSPTYEM | ||
166 | AF_INET/AF_UNSPEC, PF_* | ||
167 | ECHOCTL/ECHOKE | ||
168 | F_ULOCK [?!] | ||
169 | setpgrp/getpgrp() ONEARG business.. | ||
170 | HAVE_ALLOCA | ||
171 | HAVE_GETUTENT | ||
172 | HAVE_SYS_SELECT_H [irix!] | ||
173 | HAVE_DIRENT [old 386mach has *direct.h*!] | ||
174 | HAVE_SIGSET | ||
175 | HAVE_VFORK_H and HAVE_VFORK | ||
176 | HAVE_VHANGUP | ||
177 | HAVE_VSPRINTF | ||
178 | HAVE_IPTOS_* | ||
179 | HAVE_STRCASECMP, STRNCASECMP | ||
180 | HAVE_SYS_FCNTL_H | ||
181 | HAVE_SYS_TIME_H | ||
182 | HAVE_UTIMES | ||
183 | NOTTYENT [?] | ||
184 | HAVE_FCHMOD | ||
185 | HAVE_GETUSERSHELL | ||
186 | HAVE_SIGCONTEXT [stack hair, very machine-specific] | ||
187 | YYLINENO? | ||
188 | POSIX_SIGNALS | ||
189 | POSIX_TERMIOS | ||
190 | SETPROCTITLE -- breaks some places, like fbsd sendmail | ||
191 | SIG* -- actual signal names? some are missing | ||
192 | SIOCGIFCONF | ||
193 | SO_BROADCAST | ||
194 | SHMEM [krb tickets] | ||
195 | VARARGS, or HAVE_VARARGS | ||
196 | CBAUD | ||
197 | ... and B300, B9600, etc etc | ||
198 | HAVE_BZERO vs memset/memcpy | ||
199 | HAVE_SETVBUF | ||
200 | HAVE_STRDUP | ||
201 | HAVE_GETENV | ||
202 | HAVE_STRSAVE | ||
203 | HAVE_STBLKSIZE [stat?] | ||
204 | HAVE_STREAM_H -- in sys/, ref sendmail 8.7 for IP_SRCROUTE | ||
205 | FCHMOD | ||
206 | INITGROUPS -- most machines seem to *have* | ||
207 | SETREUID | ||
208 | SNPRINTF | ||
209 | SETPGRP semantics bsd vs. sys5 style | ||
210 | |||
211 | There's also the issue about WHERE various .h files live, sys/ or otherwise. | ||
212 | There'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 | ||
65 | struct host_info { | 60 | struct 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 | ||
72 | struct port_info { | 66 | struct port_info { |
@@ -76,7 +70,7 @@ struct port_info { | |||
76 | }; | 70 | }; |
77 | 71 | ||
78 | /* globals: */ | 72 | /* globals: */ |
79 | jmp_buf jbuf; /* timer crud */ | 73 | jmp_buf jbuf; /* timer jump buffer*/ |
80 | int jval = 0; /* timer crud */ | 74 | int jval = 0; /* timer crud */ |
81 | int netfd = -1; | 75 | int netfd = -1; |
82 | int ofd = 0; /* hexdump output fd */ | 76 | int ofd = 0; /* hexdump output fd */ |
@@ -84,10 +78,10 @@ int ofd = 0; /* hexdump output fd */ | |||
84 | extern int h_errno; | 78 | extern int h_errno; |
85 | /* stolen almost wholesale from bsd herror.c */ | 79 | /* stolen almost wholesale from bsd herror.c */ |
86 | static char *h_errs[] = { | 80 | static 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 */ | |||
97 | unsigned int insaved = 0; /* stdin-buffer size for multi-mode */ | 91 | unsigned int insaved = 0; /* stdin-buffer size for multi-mode */ |
98 | unsigned int wrote_out = 0; /* total stdout bytes */ | 92 | unsigned int wrote_out = 0; /* total stdout bytes */ |
99 | unsigned int wrote_net = 0; /* total net bytes */ | 93 | unsigned int wrote_net = 0; /* total net bytes */ |
100 | static char wrote_txt[] = " sent %d, rcvd %d"; | ||
101 | static char hexnibs[20] = "0123456789abcdef "; | 94 | static char hexnibs[20] = "0123456789abcdef "; |
102 | 95 | ||
103 | /* will malloc up the following globals: */ | 96 | /* will malloc up the following globals: */ |
104 | struct timeval timer1, timer2; | 97 | struct timeval timer1, timer2; |
105 | struct sockaddr_in *lclend = NULL; /* sockaddr_in structs */ | 98 | struct sockaddr_in *lclend = NULL; /* sockaddr_in structs */ |
106 | struct sockaddr_in *remend = NULL; | 99 | struct sockaddr_in *remend = NULL; |
107 | struct host_info **gates = NULL; /* LSRR hop hostpoop */ | 100 | struct host_info **gates = NULL; /* LSRR hop hinfo */ |
108 | char *optbuf = NULL; /* LSRR or sockopts */ | 101 | char *optbuf = NULL; /* LSRR or sockopts */ |
109 | char *bigbuf_in; /* data buffers */ | 102 | char *bigbuf_in; /* data buffers */ |
110 | char *bigbuf_net; | 103 | char *bigbuf_net; |
111 | fd_set fds1, fds2; | 104 | fd_set fds1, fds2; |
112 | struct port_info *portpoop = NULL; /* for getportpoop / getservby* */ | 105 | struct port_info *pinfo = NULL; /* for getpinfo / getservby* */ |
113 | unsigned char *stage = NULL; /* hexdump line buffer */ | 106 | unsigned char *stage = NULL; /* hexdump line buffer */ |
114 | 107 | ||
115 | /* global cmd flags: */ | 108 | /* global cmd flags: */ |
116 | u_short o_alla = 0; | 109 | u_short o_alla = 0; |
@@ -123,72 +116,27 @@ u_short o_udpmode = 0; | |||
123 | u_short o_verbose = 0; | 116 | u_short o_verbose = 0; |
124 | unsigned int o_wait = 0; | 117 | unsigned int o_wait = 0; |
125 | u_short o_zero = 0; | 118 | u_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 */ | ||
121 | void usage __P((int)); | ||
122 | void 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. */ | ||
145 | void | ||
146 | holler(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 */ | ||
172 | void | ||
173 | bail(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 | */ | ||
185 | void | 133 | void |
186 | catch() | 134 | catch() |
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 | */ | ||
207 | void | 157 | void |
208 | arm(num, secs) | 158 | arm(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 | */ | ||
227 | unsigned int | 179 | unsigned int |
228 | findline(buf, siz) | 180 | findline(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 | */ | ||
257 | int | 209 | int |
258 | comparehosts(poop, hp) | 210 | comparehosts(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 | */ | ||
277 | struct host_info * | 230 | struct host_info * |
278 | gethostpoop(name, numeric) | 231 | gethinfo(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 | */ | ||
377 | u_short | 335 | u_short |
378 | getportpoop(pstring, pnum) | 336 | getpinfo(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 | |||
445 | gp_finish: | 401 | gp_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 | */ | ||
461 | u_short | 421 | u_short |
462 | nextport(block) | 422 | nextport(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 | */ | ||
498 | void | 460 | void |
499 | loadports(block, lo, hi) | 461 | loadports(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 | ||
518 | char *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 |
526 | doexec(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. */ | ||
553 | int | 489 | int |
554 | doconnect(rad, rp, lad, lp) | 490 | doconnect(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 */ |
566 | newskt: | 502 | newskt: |
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. | ||
634 | Option comes after IP-hdr dest addr in packet, padded to *4, and ihl > 5. | ||
635 | IHL 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 | |||
642 | If we want to route A -> B via hops C and D, we must add C, D, *and* B to the | ||
643 | options list. Why? Because when we hand the kernel A -> B with list C, D, B | ||
644 | the "send shuffle" inside the kernel changes it into A -> C with list D, B and | ||
645 | the outbound packet gets sent to C. If B wasn't also in the hops list, the | ||
646 | final destination would have been lost at this point. | ||
647 | |||
648 | When C gets the packet, it changes it to A -> D with list C', B where C' is | ||
649 | the interface address that C used to forward the packet. This "records" the | ||
650 | route hop from B's point of view, i.e. which address points "toward" B. This | ||
651 | is to make B better able to return the packets. The pointer gets bumped by 4, | ||
652 | so that D does the right thing instead of trying to forward back to C. | ||
653 | |||
654 | When B finally gets the packet, it sees that the pointer is at the end of the | ||
655 | LSRR list and is thus "completed". B will then try to use the packet instead | ||
656 | of forwarding it, i.e. deliver it up to some application. | ||
657 | |||
658 | Note that by moving the pointer yourself, you could send the traffic directly | ||
659 | to B but have it return via your preconstructed source-route. Playing with | ||
660 | this and watching "tcpdump -v" is the best way to understand what's going on. | ||
661 | |||
662 | Only works for TCP in BSD-flavor kernels. UDP is a loss; udp_input calls | ||
663 | stripoptions() early on, and the code to save the srcrt is notdef'ed. | ||
664 | Linux 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 | */ | ||
722 | int | 580 | int |
723 | dolisten(rad, rp, lad, lp) | 581 | dolisten(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 */ | ||
849 | dol_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 | ||
892 | dol_tmo: | 698 | dol_tmo: |
893 | errno = ETIMEDOUT; /* fake it */ | 699 | errno = ETIMEDOUT; |
894 | dol_err: | 700 | dol_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 | */ | ||
909 | udptest(fd, where) | 717 | udptest(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 : |
944 | D 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 | */ | ||
952 | void | 757 | void |
953 | oprint(which, buf, n) | 758 | oprint(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 |
1036 | u_short o_tn = 0; /* global -t option */ | 841 | u_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 | */ | ||
1043 | void | 850 | void |
1044 | atelnet(buf, size) | 851 | atelnet(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 | } |
1075 | notiac: | 885 | notiac: |
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 | */ |
1086 | int | 897 | int |
1087 | readwrite(fd) | 898 | readwrite(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 */ | ||
1215 | shovel: | 1018 | shovel: |
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 : | 1367 | void |
1624 | the obvious */ | 1368 | usage(doexit) |
1625 | helpme() | ||
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"); |
1629 | connect to somewhere: nc [-options] hostname port[s] [ports] ... \n\ | 1372 | fprintf(stderr, " [-G hopcount] [-i interval] [-o filename] [-p source port]\n"); |
1630 | listen for inbound: nc -l -p port [-options] [hostname] [port]\n\ | 1373 | fprintf(stderr, " [-s ip address] [-w timeout] [hostname] [port[s...]]\n"); |
1631 | options:"); | 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() */ | 1378 | void |
1636 | holler("\ | 1379 | help() |
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 | } |