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 | } |
