unix/000755 023422 023422 00000000000 10325237241 013536 5ustar00jleplastjleplast000000 000000 unix/Changelog000640 023422 023422 00000010750 10325236647 015360 0ustar00jleplastjleplast000000 000000 Here is sort of an edit history for netcat, in forward cron order. 950915 or so basic gethostpoop and doconnect layout established 950920 or so timeout handlers, improvements to gethostpoop, read-stdin-args, primitive select loop, and later the stdin-to-many saved-count thing 950923 select loop is firm, connect and i/o works nicely added listen mode crocked in UDP and debugged how its back-connect works 950927 unsnarled main a fair amount got "udptest" working right added HELP!! yow. 951003 added exec-a-prog thing cleaned up routine-header comments signal catcher close stdin when we won't need it [-z, etc] 951004 getportpoop inbound options hexdump finally works [forgot to preload "size" int] 951005 or so added random mode, which necessitated more main() logic cleanups 951008 hammered out exit-status stuff, final main() argv loop cleanup massive readme cleanup pre-1.00 release 951010 almost-1.00 release up for FTP, but not announced yet added a couple of wrapper scripts 951012 -- 1.00 nc100 RELEASE, mailing-list spam, etc etc 951021 doc tweak per cgull webproxy/webrelay scripts came together. fuckin' yow. 951023 added indication of *local* address in dolisten() connect handling reset errno before dolisten msgs -- gethostpoop might have munged it 951028 -- 1.01 fixed exit status if -z on a single port -- was -1, is now 0 or 1 like it should be 951029 put "sent/rcvd" typeout more places, still only if -v -v Doc fix: It's *David* Borman, not Paul [aka Mr. Environment Variables, this month...] 951106 -- 1.02 added h_errno strings and updated holler, gethostpoop to find them Still slightly confused if gethostpoop() returns prematurely... 951107 sys/select.h for them what needs it wrote_txt and more calls to print sent/rcvd 951110 try rnd-options, but setsockopt tosses them. Punt... dumped "x.y" microtiming idea; seconds are granular enough for now tweaked help text 951113 -- 1.03 added first-net-read skip to select loop if we have saved stdin, and moved retry-count test ahead of this. Makes multimode work much more sensibly... fleshed out this here edit history 951204 -- 1.04 fixed duplication lameness with printing h_errno stuff 951215 improved data.c; added xfer count and %r 951217 rservice.c, an answer to mudge's k-rad script 951227 port data.c to msloss, it might be useful some doc slogging; particularly the telnet-wrapper idea 960120 -- 1.05 give totals even if we ^C out [that's what sigcatchers are *for*!] cleaned up big LSRR explanation comment 960131 -- 1.06 flushed rndoption stuff report of closing stdin fucking up Solaris. Not tried yet. extra arg to rservice.c documentation updates, added netcat-art and many udder tings added Bela Lubkin's #ifdefs for SIGURG [SCO rel 5] added ignoring SIGPIPE [lesson learned from webs.c] 960201 genned up some more data dumps: pmap-mnt.d, showmount.d, various others; into real tree 960217 -- 1.07 finally fixed stdin-read-args thing to retain and send leftover data added version to help text made ascii-art cuter added "probe" script added Nextstep systype finally fixed data.c to run "forever" created xor.c 960223 -- 1.08 if doconnect skt is 0 grab another one, don't dup(). [stupid solaris..] threw in latest web scripts threw in irc more doc tweaks stuck 1.08 prerelease up for FTP 960227 hexdump in -- it's actually gonna be quite useful! doc adds for hexdump; orig idea from dgaudet@wired 960229 -- 1.09 telnet-opts responder in; left as OPTIONAL chunk since it mucks with the data stream. -e disables -o hexdump; avoid zero-length file turds 960310 -- 1.09a goddamnit-I'm-gonna-release-REAL-soon made -e work outbound, too random final cleanups and doc updates ... pant pant ... 960320 -- 1.10 RELEASE version tested everywhere I could get to, up for FTP 000919 -- jojo@farm9.com -- added twofish encryption, converted cryptix twofish java code to C++, added C interface layer between netcat & twofish Extra -k Option added to set Shared secret key 9/25/00 -Xram_LraK Bill Weiss -- -k change for NT version 9/29/00 jojo -- fixed stupid buffer overflow bug in my code 11/22/04 jleplast -- added -k option to -h list 11/22/04 jleplast -- Added Endian fix provided by Renzo Davoli 11/23/04 jleplast -- Fixed Endian patch for platforms. Tagged as 1-2-1 12/22/04 jleplast -- Added changes to compile under Fedora. Thanks to Jon Asdourian for testing. 10/18/05 jleplast -- Tagged as 1-2-1-RELEASE and released. unix/Credits000644 023422 023422 00000000331 10176317143 015057 0ustar00jleplastjleplast000000 000000 11/22/04 jleplast -- Added Endian fix provided by Renzo Davoli 12/22/04 jleplast -- Added changes to compile under Fedora. Thanks to Jon Asdourian for testing. unix/Makefile000640 023422 023422 00000010034 10325042235 015165 0ustar00jleplastjleplast000000 000000 # makefile for netcat, based off same ol' "generic makefile". # Usually do "make systype" -- if your systype isn't defined, try "generic" # or something else that most closely matches, see where it goes wrong, fix # it, and MAIL THE DIFFS back to Hobbit. ### PREDEFINES # DEFAULTS, possibly overridden by recursive call: # pick gcc if you'd rather , and/or do -g instead of -O if debugging # debugging # DFLAGS = -DTEST -DDEBUG DFLAGS = -DGAPING_SECURITY_HOLE CFLAGS = -O XFLAGS = # xtra cflags, set by systype targets XLIBS = # xtra libs if necessary? # -Bstatic for sunos, -static for gcc, etc. You want this, trust me. STATIC = CC = cc $(CFLAGS) LD = $(CC) -s # linker; defaults to stripped executables o = o # object extension ALL = cryptcat ### BOGON-CATCHERS bogus: @echo "Usage: make [options]" ### HARD TARGETS cryptcat: netcat.c farm9crypt.o twofish2.o $(LD) $(DFLAGS) $(XFLAGS) $(STATIC) -o cryptcat netcat.c farm9crypt.o twofish2.o $(XLIBS) nc-dos: @echo "DOS?! Maybe someday, but not now" ### SYSTYPES -- in the same order as in generic.h, please # designed for msc and nmake, but easy to change for your compiler. # Recursive make may fail if you're short on memory -- u-fix! # Note special hard-target and "quotes" instead of 'quotes' ... dos: $(MAKE) -e $(ALL)-dos $(MFLAGS) CC="cl /nologo" XLIBS= \ XFLAGS="/AS -D__MSDOS__ -DMSDOS" o=obj ultrix: make -e $(ALL) $(MFLAGS) XFLAGS='-DULTRIX' # you may need XLIBS='-lresolv -l44bsd' if you have BIND 4.9.x sunos: make -e $(ALL) $(MFLAGS) XFLAGS='-DSUNOS' STATIC=-Bstatic \ XLIBS='-lresolv' # Pick this one ahead of "solaris" if you actually have the nonshared # libraries [lib*.a] on your machine. By default, the Sun twits don't ship # or install them, forcing you to use shared libs for any network apps. # Kludged for gcc, which many regard as the only thing available. solaris-static: make -e $(ALL) $(MFLAGS) XFLAGS='-DSYSV=4 -D__svr4__ -DSOLARIS' \ CC=gcc STATIC=-static XLIBS='-lnsl -lsocket -lresolv' # the more usual shared-lib version... solaris: make -e $(ALL) $(MFLAGS) XFLAGS='-DSYSV=4 -D__svr4__ -DSOLARIS' \ CC=gcc STATIC= XLIBS='-lnsl -lsocket -lresolv' aix: make -e $(ALL) $(MFLAGS) XFLAGS='-DAIX' linux: make -e $(ALL) $(MFLAGS) XFLAGS='-DLINUX' STATIC=-static \ XLIBS='-lstdc++' # irix 5.2, dunno 'bout earlier versions. If STATIC='-non_shared' doesn't # work for you, null it out and yell at SGI for their STUPID default # of apparently not installing /usr/lib/nonshared/*. Sheesh. irix: make -e $(ALL) $(MFLAGS) XFLAGS='-DIRIX -DSYSV=4 -D__svr4__' \ STATIC=-non_shared osf: make -e $(ALL) $(MFLAGS) XFLAGS='-DOSF' STATIC=-non_shared # virtually the same as netbsd/bsd44lite/whatever freebsd: make -e $(ALL) $(MFLAGS) XFLAGS='-DFREEBSD' STATIC=-static \ XLIBS='-lstdc++' bsdi: make -e $(ALL) $(MFLAGS) XFLAGS='-DBSDI' STATIC=-Bstatic netbsd: make -e $(ALL) $(MFLAGS) XFLAGS='-DNETBSD' STATIC=-static \ XLIBS='-lstdc++' openbsd: @echo "use: make netbsd" # finally got to an hpux box, which turns out to be *really* warped. # STATIC here means "linker subprocess gets args '-a archive'" which causes # /lib/libc.a to be searched ahead of '-a shared', or /lib/libc.sl. hpux: make -e $(ALL) $(MFLAGS) XFLAGS='-DHPUX' STATIC="-Wl,-a,archive" # unixware from bmc@telebase.com; apparently no static because of the # same idiotic lack of link libraries unixware: make -e $(ALL) $(MFLAGS) XFLAGS='-DUNIXWARE -DSYSV=4 -D__svr4__' \ STATIC= XLIBS='-L/usr/lib -lnsl -lsocket -lresolv' # from Declan Rieb at sandia, for a/ux 3.1.1 [also suggests using gcc]: aux: make -e $(ALL) $(MFLAGS) XFLAGS='-DAUX' STATIC=-static CC=gcc # Nexstep from mudge: NeXT cc is really old gcc next: make -e $(ALL) $(MFLAGS) XFLAGS='-DNEXT' STATIC=-Bstatic farm9crypt.o: farm9crypt.cc farm9crypt.h ${CC} -c farm9crypt.cc twofish2.o: twofish2.cc twofish2.h ${CC} -c twofish2.cc # start with this for a new architecture, and see what breaks. generic: make -e $(ALL) $(MFLAGS) XFLAGS='-DGENERIC' STATIC= # Still at large: dgux dynix ??? ### RANDOM clean: rm -f $(ALL) *.o *.obj unix/README000640 023422 023422 00000166642 07162126046 014436 0ustar00jleplastjleplast000000 000000 Netcat 1.10 =========== /\_/\ / 0 0 \ Netcat is a simple Unix utility which reads and writes data ====v==== across network connections, using TCP or UDP protocol. \ W / It is designed to be a reliable "back-end" tool that can | | _ be used directly or easily driven by other programs and / ___ \ / scripts. At the same time, it is a feature-rich network / / \ \ | debugging and exploration tool, since it can create almost (((-----)))-' any kind of connection you would need and has several / interesting built-in capabilities. Netcat, or "nc" as the ( ___ actual program is named, should have been supplied long ago \__.=|___E as another one of those cryptic but standard Unix tools. / In the simplest usage, "nc host port" creates a TCP connection to the given port on the given target host. Your standard input is then sent to the host, and anything that comes back across the connection is sent to your standard output. This continues indefinitely, until the network side of the connection shuts down. Note that this behavior is different from most other applications which shut everything down and exit after an end-of-file on the standard input. Netcat can also function as a server, by listening for inbound connections on arbitrary ports and then doing the same reading and writing. With minor limitations, netcat doesn't really care if it runs in "client" or "server" mode -- it still shovels data back and forth until there isn't any more left. In either mode, shutdown can be forced after a configurable time of inactivity on the network side. And it can do this via UDP too, so netcat is possibly the "udp telnet-like" application you always wanted for testing your UDP-mode servers. UDP, as the "U" implies, gives less reliable data transmission than TCP connections and some systems may have trouble sending large amounts of data that way, but it's still a useful capability to have. You may be asking "why not just use telnet to connect to arbitrary ports?" Valid question, and here are some reasons. Telnet has the "standard input EOF" problem, so one must introduce calculated delays in driving scripts to allow network output to finish. This is the main reason netcat stays running until the *network* side closes. Telnet also will not transfer arbitrary binary data, because certain characters are interpreted as telnet options and are thus removed from the data stream. Telnet also emits some of its diagnostic messages to standard output, where netcat keeps such things religiously separated from its *output* and will never modify any of the real data in transit unless you *really* want it to. And of course telnet is incapable of listening for inbound connections, or using UDP instead. Netcat doesn't have any of these limitations, is much smaller and faster than telnet, and has many other advantages. Some of netcat's major features are: Outbound or inbound connections, TCP or UDP, to or from any ports Full DNS forward/reverse checking, with appropriate warnings Ability to use any local source port Ability to use any locally-configured network source address Built-in port-scanning capabilities, with randomizer Built-in loose source-routing capability Can read command line arguments from standard input Slow-send mode, one line every N seconds Hex dump of transmitted and received data Optional ability to let another program service established connections Optional telnet-options responder Efforts have been made to have netcat "do the right thing" in all its various modes. If you believe that it is doing the wrong thing under whatever circumstances, please notify me and tell me how you think it should behave. If netcat is not able to do some task you think up, minor tweaks to the code will probably fix that. It provides a basic and easily-modified template for writing other network applications, and I certainly encourage people to make custom mods and send in any improvements they make to it. This is the second release; the overall differences from 1.00 are relatively minor and have mostly to do with portability and bugfixes. Many people provided greatly appreciated fixes and comments on the 1.00 release. Continued feedback from the Internet community is always welcome! Netcat is entirely my own creation, although plenty of other code was used as examples. It is freely given away to the Internet community in the hope that it will be useful, with no restrictions except giving credit where it is due. No GPLs, Berkeley copyrights or any of that nonsense. The author assumes NO responsibility for how anyone uses it. If netcat makes you rich somehow and you're feeling generous, mail me a check. If you are affiliated in any way with Microsoft Network, get a life. Always ski in control. Comments, questions, and patches to hobbit@avian.org. Building ======== Compiling is fairly straightforward. Examine the Makefile for a SYSTYPE that matches yours, and do "make ". The executable "nc" should appear. If there is no relevant SYSTYPE section, try "generic". If you create new sections for generic.h and Makefile to support another platform, please follow the given format and mail back the diffs. There are a couple of other settable #defines in netcat.c, which you can include as DFLAGS="-DTHIS -DTHAT" to your "make" invocation without having to edit the Makefile. See the following discussions for what they are and do. If you want to link against the resolver library on SunOS [recommended] and you have BIND 4.9.x, you may need to change XLIBS=-lresolv in the Makefile to XLIBS="-lresolv -l44bsd". Linux sys/time.h does not really support presetting of FD_SETSIZE; a harmless warning is issued. Some systems may warn about pointer types for signal(). No problem, though. Exploration of features ======================= Where to begin? Netcat is at the same time so simple and versatile, it's like trying to describe everything you can do with your Swiss Army knife. This will go over the basics; you should also read the usage examples and notes later on which may give you even more ideas about what this sort of tool is good for. If no command arguments are given at all, netcat asks for them, reads a line from standard input, and breaks it up into arguments internally. This can be useful when driving netcat from certain types of scripts, with the side effect of hiding your command line arguments from "ps" displays. The host argument can be a name or IP address. If -n is specified, netcat will only accept numeric IP addresses and do no DNS lookups for anything. If -n is not given and -v is turned on, netcat will do a full forward and reverse name and address lookup for the host, and warn you about the all-too-common problem of mismatched names in the DNS. This often takes a little longer for connection setup, but is useful to know about. There are circumstances under which this can *save* time, such as when you want to know the name for some IP address and also connect there. Netcat will just tell you all about it, saving the manual steps of looking up the hostname yourself. Normally mismatch- checking is case-insensitive per the DNS spec, but you can define ANAL at compile time to make it case-sensitive -- sometimes useful for uncovering minor errors in your own DNS files while poking around your networks. A port argument is required for outbound connections, and can be numeric or a name as listed in /etc/services. If -n is specified, only numeric arguments are valid. Special syntax and/or more than one port argument cause different behavior -- see details below about port-scanning. The -v switch controls the verbosity level of messages sent to standard error. You will probably want to run netcat most of the time with -v turned on, so you can see info about the connections it is trying to make. You will probably also want to give a smallish -w argument, which limits the time spent trying to make a connection. I usually alias "nc" to "nc -v -w 3", which makes it function just about the same for things I would otherwise use telnet to do. The timeout is easily changed by a subsequent -w argument which overrides the earlier one. Specifying -v more than once makes diagnostic output MORE verbose. If -v is not specified at all, netcat silently does its work unless some error happens, whereupon it describes the error and exits with a nonzero status. Refused network connections are generally NOT considered to be errors, unless you only asked for a single TCP port and it was refused. Note that -w also sets the network inactivity timeout. This does not have any effect until standard input closes, but then if nothing further arrives from the network in the next seconds, netcat tries to read the net once more for good measure, and then closes and exits. There are a lot of network services now that accept a small amount of input and return a large amount of output, such as Gopher and Web servers, which is the main reason netcat was written to "block" on the network staying open rather than standard input. Handling the timeout this way gives uniform behavior with network servers that *don't* close by themselves until told to. UDP connections are opened instead of TCP when -u is specified. These aren't really "connections" per se since UDP is a connectionless protocol, although netcat does internally use the "connected UDP socket" mechanism that most kernels support. Although netcat claims that an outgoing UDP connection is "open" immediately, no data is sent until something is read from standard input. Only thereafter is it possible to determine whether there really is a UDP server on the other end, and often you just can't tell. Most UDP protocols use timeouts and retries to do their thing and in many cases won't bother answering at all, so you should specify a timeout and hope for the best. You will get more out of UDP connections if standard input is fed from a source of data that looks like various kinds of server requests. To obtain a hex dump file of the data sent either way, use "-o logfile". The dump lines begin with "<" or ">" to respectively indicate "from the net" or "to the net", and contain the total count per direction, and hex and ascii representations of the traffic. Capturing a hex dump naturally slows netcat down a bit, so don't use it where speed is critical. Netcat can bind to any local port, subject to privilege restrictions and ports that are already in use. It is also possible to use a specific local network source address if it is that of a network interface on your machine. [Note: this does not work correctly on all platforms.] Use "-p portarg" to grab a specific local port, and "-s ip-addr" or "-s name" to have that be your source IP address. This is often referred to as "anchoring the socket". Root users can grab any unused source port including the "reserved" ones less than 1024. Absence of -p will bind to whatever unused port the system gives you, just like any other normal client connection, unless you use -r [see below]. Listen mode will cause netcat to wait for an inbound connection, and then the same data transfer happens. Thus, you can do "nc -l -p 1234 < filename" and when someone else connects to your port 1234, the file is sent to them whether they wanted it or not. Listen mode is generally used along with a local port argument -- this is required for UDP mode, while TCP mode can have the system assign one and tell you what it is if -v is turned on. If you specify a target host and optional port in listen mode, netcat will accept an inbound connection only from that host and if you specify one, only from that foreign source port. In verbose mode you'll be informed about the inbound connection, including what address and port it came from, and since listening on "any" applies to several possibilities, which address it came *to* on your end. If the system supports IP socket options, netcat will attempt to retrieve any such options from an inbound connection and print them out in hex. If netcat is compiled with -DGAPING_SECURITY_HOLE, the -e argument specifies a program to exec after making or receiving a successful connection. In the listening mode, this works similarly to "inetd" but only for a single instance. Use with GREAT CARE. This piece of the code is normally not enabled; if you know what you're doing, have fun. This hack also works in UDP mode. Note that you can only supply -e with the name of the program, but no arguments. If you want to launch something with an argument list, write a two-line wrapper script or just use inetd like always. If netcat is compiled with -DTELNET, the -t argument enables it to respond to telnet option negotiation [always in the negative, i.e. DONT or WONT]. This allows it to connect to a telnetd and get past the initial negotiation far enough to get a login prompt from the server. Since this feature has the potential to modify the data stream, it is not enabled by default. You have to understand why you might need this and turn on the #define yourself. Data from the network connection is always delivered to standard output as efficiently as possible, using large 8K reads and writes. Standard input is normally sent to the net the same way, but the -i switch specifies an "interval time" which slows this down considerably. Standard input is still read in large batches, but netcat then tries to find where line breaks exist and sends one line every interval time. Note that if standard input is a terminal, data is already read line by line, so unless you make the -i interval rather long, what you type will go out at a fairly normal rate. -i is really designed for use when you want to "measure out" what is read from files or pipes. Port-scanning is a popular method for exploring what's out there. Netcat accepts its commands with options first, then the target host, and everything thereafter is interpreted as port names or numbers, or ranges of ports in M-N syntax. CAVEAT: some port names in /etc/services contain hyphens -- netcat currently will not correctly parse those, so specify ranges using numbers if you can. If more than one port is thus specified, netcat connects to *all* of them, sending the same batch of data from standard input [up to 8K worth] to each one that is successfully connected to. Specifying multiple ports also suppresses diagnostic messages about refused connections, unless -v is specified twice for "more verbosity". This way you normally get notified only about genuinely open connections. Example: "nc -v -w 2 -z target 20-30" will try connecting to every port between 20 and 30 [inclusive] at the target, and will likely inform you about an FTP server, telnet server, and mailer along the way. The -z switch prevents sending any data to a TCP connection and very limited probe data to a UDP connection, and is thus useful as a fast scanning mode just to see what ports the target is listening on. To limit scanning speed if desired, -i will insert a delay between each port probe. There are some pitfalls with regard to UDP scanning, described later, but in general it works well. For each range of ports specified, scanning is normally done downward within that range. If the -r switch is used, scanning hops randomly around within that range and reports open ports as it finds them. [If you want them listed in order regardless, pipe standard error through "sort"...] In addition, if random mode is in effect, the local source ports are also randomized. This prevents netcat from exhibiting any kind of regular pattern in its scanning. You can exert fairly fine control over your scan by judicious use of -r and selected port ranges to cover. If you use -r for a single connection, the source port will have a random value above 8192, rather than the next one the kernel would have assigned you. Note that selecting a specific local port with -p overrides any local-port randomization. Many people are interested in testing network connectivity using IP source routing, even if it's only to make sure their own firewalls are blocking source-routed packets. On systems that support it, the -g switch can be used multiple times [up to 8] to construct a loose-source-routed path for your connection, and the -G argument positions the "hop pointer" within the list. If your network allows source-routed traffic in and out, you can test connectivity to your own services via remote points in the internet. Note that although newer BSD-flavor telnets also have source-routing capability, it isn't clearly documented and the command syntax is somewhat clumsy. Netcat's handling of "-g" is modeled after "traceroute". Netcat tries its best to behave just like "cat". It currently does nothing to terminal input modes, and does no end-of-line conversion. Standard input from a terminal is read line by line with normal editing characters in effect. You can freely suspend out of an interactive connection and resume. ^C or whatever your interrupt character is will make netcat close the network connection and exit. A switch to place the terminal in raw mode has been considered, but so far has not been necessary. You can send raw binary data by reading it out of a file or piping from another program, so more meaningful effort would be spent writing an appropriate front-end driver. Netcat is not an "arbitrary packet generator", but the ability to talk to raw sockets and/or nit/bpf/dlpi may appear at some point. Such things are clearly useful; I refer you to Darren Reed's excellent ip_filter package, which now includes a tool to construct and send raw packets with any contents you want. Example uses -- the light side ============================== Again, this is a very partial list of possibilities, but it may get you to think up more applications for netcat. Driving netcat with simple shell or expect scripts is an easy and flexible way to do fairly complex tasks, especially if you're not into coding network tools in C. My coding isn't particularly strong either [although undoubtedly better after writing this thing!], so I tend to construct bare-metal tools like this that I can trivially plug into other applications. Netcat doubles as a teaching tool -- one can learn a great deal about more complex network protocols by trying to simulate them through raw connections! An example of netcat as a backend for something else is the shell-script Web browser, which simply asks for the relevant parts of a URL and pipes "GET /what/ever" into a netcat connection to the server. I used to do this with telnet, and had to use calculated sleep times and other stupidity to kludge around telnet's limitations. Netcat guarantees that I get the whole page, and since it transfers all the data unmodified, I can even pull down binary image files and display them elsewhere later. Some folks may find the idea of a shell-script web browser silly and strange, but it starts up and gets me my info a hell of a lot faster than a GUI browser and doesn't hide any contents of links and forms and such. This is included, as scripts/web, along with several other web-related examples. Netcat is an obvious replacement for telnet as a tool for talking to daemons. For example, it is easier to type "nc host 25", talk to someone's mailer, and just ^C out than having to type ^]c or QUIT as telnet would require you to do. You can quickly catalog the services on your network by telling netcat to connect to well-known services and collect greetings, or at least scan for open ports. You'll probably want to collect netcat's diagnostic messages in your output files, so be sure to include standard error in the output using `>& file' in *csh or `> file 2>&1' in bourne shell. A scanning example: "echo QUIT | nc -v -w 5 target 20-250 500-600 5990-7000" will inform you about a target's various well-known TCP servers, including r-services, X, IRC, and maybe a few you didn't expect. Sending in QUIT and using the timeout will almost guarantee that you see some kind of greeting or error from each service, which usually indicates what it is and what version. [Beware of the "chargen" port, though...] SATAN uses exactly this technique to collect host information, and indeed some of the ideas herein were taken from the SATAN backend tools. If you script this up to try every host in your subnet space and just let it run, you will not only see all the services, you'll find out about hosts that aren't correctly listed in your DNS. Then you can compare new snapshots against old snapshots to see changes. For going after particular services, a more intrusive example is in scripts/probe. Netcat can be used as a simple data transfer agent, and it doesn't really matter which end is the listener and which end is the client -- input at one side arrives at the other side as output. It is helpful to start the listener at the receiving side with no timeout specified, and then give the sending side a small timeout. That way the listener stays listening until you contact it, and after data stops flowing the client will time out, shut down, and take the listener with it. Unless the intervening network is fraught with problems, this should be completely reliable, and you can always increase the timeout. A typical example of something "rsh" is often used for: on one side, nc -l -p 1234 | uncompress -c | tar xvfp - and then on the other side tar cfp - /some/dir | compress -c | nc -w 3 othermachine 1234 will transfer the contents of a directory from one machine to another, without having to worry about .rhosts files, user accounts, or inetd configurations at either end. Again, it matters not which is the listener or receiver; the "tarring" machine could just as easily be running the listener instead. One could conceivably use a scheme like this for backups, by having cron-jobs fire up listeners and backup handlers [which can be restricted to specific addresses and ports between each other] and pipe "dump" or "tar" on one machine to "dd of=/dev/tapedrive" on another as usual. Since netcat returns a nonzero exit status for a denied listener connection, scripts to handle such tasks could easily log and reject connect attempts from third parties, and then retry. Another simple data-transfer example: shipping things to a PC that doesn't have any network applications yet except a TCP stack and a web browser. Point the browser at an arbitrary port on a Unix server by telling it to download something like http://unixbox:4444/foo, and have a listener on the Unix side ready to ship out a file when the connect comes in. The browser may pervert binary data when told to save the URL, but you can dig the raw data out of the on-disk cache. If you build netcat with GAPING_SECURITY_HOLE defined, you can use it as an "inetd" substitute to test experimental network servers that would otherwise run under "inetd". A script or program will have its input and output hooked to the network the same way, perhaps sans some fancier signal handling. Given that most network services do not bind to a particular local address, whether they are under "inetd" or not, it is possible for netcat avoid the "address already in use" error by binding to a specific address. This lets you [as root, for low ports] place netcat "in the way" of a standard service, since inbound connections are generally sent to such specifically-bound listeners first and fall back to the ones bound to "any". This allows for a one-off experimental simulation of some service, without having to screw around with inetd.conf. Running with -v turned on and collecting a connection log from standard error is recommended. Netcat as well can make an outbound connection and then run a program or script on the originating end, with input and output connected to the same network port. This "inverse inetd" capability could enhance the backup-server concept described above or help facilitate things such as a "network dialback" concept. The possibilities are many and varied here; if such things are intended as security mechanisms, it may be best to modify netcat specifically for the purpose instead of wrapping such functions in scripts. Speaking of inetd, netcat will function perfectly well *under* inetd as a TCP connection redirector for inbound services, like a "plug-gw" without the authentication step. This is very useful for doing stuff like redirecting traffic through your firewall out to other places like web servers and mail hubs, while posing no risk to the firewall machine itself. Put netcat behind inetd and tcp_wrappers, perhaps thusly: www stream tcp nowait nobody /etc/tcpd /bin/nc -w 3 realwww 80 and you have a simple and effective "application relay" with access control and logging. Note use of the wait time as a "safety" in case realwww isn't reachable or the calling user aborts the connection -- otherwise the relay may hang there forever. You can use netcat to generate huge amounts of useless network data for various performance testing. For example, doing yes AAAAAAAAAAAAAAAAAAAAAA | nc -v -v -l -p 2222 > /dev/null on one side and then hitting it with yes BBBBBBBBBBBBBBBBBBBBBB | nc othermachine 2222 > /dev/null from another host will saturate your wires with A's and B's. The "very verbose" switch usage will tell you how many of each were sent and received after you interrupt either side. Using UDP mode produces tremendously MORE trash per unit time in the form of fragmented 8 Kbyte mobygrams -- enough to stress-test kernels and network interfaces. Firing random binary data into various network servers may help expose bugs in their input handling, which nowadays is a popular thing to explore. A simple example data-generator is given in data/data.c included in this package, along with a small collection of canned input files to generate various packet contents. This program is documented in its beginning comments, but of interest here is using "%r" to generate random bytes at well-chosen points in a data stream. If you can crash your daemon, you likely have a security problem. The hex dump feature may be useful for debugging odd network protocols, especially if you don't have any network monitoring equipment handy or aren't root where you'd need to run "tcpdump" or something. Bind a listening netcat to a local port, and have it run a script which in turn runs another netcat to the real service and captures the hex dump to a log file. This sets up a transparent relay between your local port and wherever the real service is. Be sure that the script-run netcat does *not* use -v, or the extra info it sends to standard error may confuse the protocol. Note also that you cannot have the "listen/exec" netcat do the data capture, since once the connection arrives it is no longer netcat that is running. Binding to an arbitrary local port allows you to simulate things like r-service clients, if you are root locally. For example, feeding "^@root^@joe^@pwd^@" [where ^@ is a null, and root/joe could be any other local/remote username pair] into a "rsh" or "rlogin" server, FROM your port 1023 for example, duplicates what the server expects to receive. Thus, you can test for insecure .rhosts files around your network without having to create new user accounts on your client machine. The program data/rservice.c can aid this process by constructing the "rcmd" protocol bytes. Doing this also prevents "rshd" from trying to create that separate standard-error socket and still gives you an input path, as opposed to the usual action of "rsh -n". Using netcat for things like this can be really useful sometimes, because rsh and rlogin generally want a host *name* as an argument and won't accept IP addresses. If your client-end DNS is hosed, as may be true when you're trying to extract backup sets on to a dumb client, "netcat -n" wins where normal rsh/rlogin is useless. If you are unsure that a remote syslogger is working, test it with netcat. Make a UDP connection to port 514 and type in "<0>message", which should correspond to "kern.emerg" and cause syslogd to scream into every file it has open [and possibly all over users' terminals]. You can tame this down by using a different number and use netcat inside routine scripts to send syslog messages to places that aren't configured in syslog.conf. For example, "echo '<38>message' | nc -w 1 -u loggerhost 514" should send to auth.notice on loggerhost. The exact number may vary; check against your syslog.h first. Netcat provides several ways for you to test your own packet filters. If you bind to a port normally protected against outside access and make a connection to somewhere outside your own network, the return traffic will be coming to your chosen port from the "outside" and should be blocked. TCP may get through if your filter passes all "ack syn", but it shouldn't be even doing that to low ports on your network. Remember to test with UDP traffic as well! If your filter passes at least outbound source-routed IP packets, bouncing a connection back to yourself via some gateway outside your network will create "incoming" traffic with your source address, which should get dropped by a correctly configured anti-spoofing filter. This is a "non-test" if you're also dropping source-routing, but it's good to be able to test for that too. Any packet filter worth its salt will be blocking source-routed packets in both directions, but you never know what interesting quirks you might turn up by playing around with source ports and addresses and watching the wires with a network monitor. You can use netcat to protect your own workstation's X server against outside access. X is stupid enough to listen for connections on "any" and never tell you when new connections arrive, which is one reason it is so vulnerable. Once you have all your various X windows up and running you can use netcat to bind just to your ethernet address and listen to port 6000. Any new connections from outside the machine will hit netcat instead your X server, and you get a log of who's trying. You can either tell netcat to drop the connection, or perhaps run another copy of itself to relay to your actual X server on "localhost". This may not work for dedicated X terminals, but it may be possible to authorize your X terminal only for its boot server, and run a relay netcat over on the server that will in turn talk to your X terminal. Since netcat only handles one listening connection per run, make sure that whatever way you rig it causes another one to run and listen on 6000 soon afterward, or your real X server will be reachable once again. A very minimal script just to protect yourself could be while true ; do nc -v -l -s -p 6000 localhost 2 done which causes netcat to accept and then close any inbound connection to your workstation's normal ethernet address, and another copy is immediately run by the script. Send standard error to a file for a log of connection attempts. If your system can't do the "specific bind" thing all is not lost; run your X server on display ":1" or port 6001, and netcat can still function as a probe alarm by listening on 6000. Does your shell-account provider allow personal Web pages, but not CGI scripts? You can have netcat listen on a particular port to execute a program or script of your choosing, and then just point to the port with a URL in your homepage. The listener could even exist on a completely different machine, avoiding the potential ire of the homepage-host administrators. Since the script will get the raw browser query as input it won't look like a typical CGI script, and since it's running under your UID you need to write it carefully. You may want to write a netcat-based script as a wrapper that reads a query and sets up environment variables for a regular CGI script. The possibilities for using netcat and scripts to handle Web stuff are almost endless. Again, see the examples under scripts/. Example uses -- the dark side ============================= Equal time is deserved here, since a versatile tool like this can be useful to any Shade of Hat. I could use my Victorinox to either fix your car or disassemble it, right? You can clearly use something like netcat to attack or defend -- I don't try to govern anyone's social outlook, I just build tools. Regardless of your intentions, you should still be aware of these threats to your own systems. The first obvious thing is scanning someone *else's* network for vulnerable services. Files containing preconstructed data, be it exploratory or exploitive, can be fed in as standard input, including command-line arguments to netcat itself to keep "ps" ignorant of your doings. The more random the scanning, the less likelihood of detection by humans, scan-detectors, or dynamic filtering, and with -i you'll wait longer but avoid loading down the target's network. Some examples for crafting various standard UDP probes are given in data/*.d. Some configurations of packet filters attempt to solve the FTP-data problem by just allowing such connections from the outside. These come FROM port 20, TO high TCP ports inside -- if you locally bind to port 20, you may find yourself able to bypass filtering in some cases. Maybe not to low ports "inside", but perhaps to TCP NFS servers, X servers, Prospero, ciscos that listen on 200x and 400x... Similar bypassing may be possible for UDP [and maybe TCP too] if a connection comes from port 53; a filter may assume it's a nameserver response. Using -e in conjunction with binding to a specific address can enable "server takeover" by getting in ahead of the real ones, whereupon you can snarf data sent in and feed your own back out. At the very least you can log a hex dump of someone else's session. If you are root, you can certainly use -s and -e to run various hacked daemons without having to touch inetd.conf or the real daemons themselves. You may not always have the root access to deal with low ports, but what if you are on a machine that also happens to be an NFS server? You might be able to collect some interesting things from port 2049, including local file handles. There are several other servers that run on high ports that are likely candidates for takeover, including many of the RPC services on some platforms [yppasswdd, anyone?]. Kerberos tickets, X cookies, and IRC traffic also come to mind. RADIUS-based terminal servers connect incoming users to shell-account machines on a high port, usually 1642 or thereabouts. SOCKS servers run on 1080. Do "netstat -a" and get creative. There are some daemons that are well-written enough to bind separately to all the local interfaces, possibly with an eye toward heading off this sort of problem. Named from recent BIND releases, and NTP, are two that come to mind. Netstat will show these listening on address.53 instead of *.53. You won't be able to get in front of these on any of the real interface addresses, which of course is especially interesting in the case of named, but these servers sometimes forget about things like "alias" interface addresses or interfaces that appear later on such as dynamic PPP links. There are some hacked web servers and versions of "inetd" floating around that specifically bind as well, based on a configuration file -- these generally *are* bound to alias addresses to offer several different address-based services from one machine. Using -e to start a remote backdoor shell is another obvious sort of thing, easier than constructing a file for inetd to listen on "ingreslock" or something, and you can access-control it against other people by specifying a client host and port. Experience with this truly demonstrates how fragile the barrier between being "logged in" or not really is, and is further expressed by scripts/bsh. If you're already behind a firewall, it may be easier to make an *outbound* connection and then run a shell; a small wrapper script can periodically try connecting to a known place and port, you can later listen there until the inbound connection arrives, and there's your shell. Running a shell via UDP has several interesting features, although be aware that once "connected", the UDP stub sockets tend to show up in "netstat" just like TCP connections and may not be quite as subtle as you wanted. Packets may also be lost, so use TCP if you need reliable connections. But since UDP is connectionless, a hookup of this sort will stick around almost forever, even if you ^C out of netcat or do a reboot on your side, and you only need to remember the ports you used on both ends to reestablish. And outbound UDP-plus-exec connection creates the connected socket and starts the program immediately. On a listening UDP connection, the socket is created once a first packet is received. In either case, though, such a "connection" has the interesting side effect that only your client-side IP address and [chosen?] source port will thereafter be able to talk to it. Instant access control! A non-local third party would have to do ALL of the following to take over such a session: forge UDP with your source address [trivial to do; see below] guess the port numbers of BOTH ends, or sniff the wire for them arrange to block ICMP or UDP return traffic between it and your real source, so the session doesn't die with a network write error. The companion program data/rservice.c is helpful in scripting up any sort of r-service username or password guessing attack. The arguments to "rservice" are simply the strings that get null-terminated and passed over an "rcmd"-style connection, with the assumption that the client does not need a separate standard-error port. Brute-force password banging is best done via "rexec" if it is available since it is less likely to log failed attempts. Thus, doing "rservice joe joespass pwd | nc target exec" should return joe's home dir if the password is right, or "Permission denied." Plug in a dictionary and go to town. If you're attacking rsh/rlogin, remember to be root and bind to a port between 512 and 1023 on your end, and pipe in "rservice joe joe pwd" and such. Netcat can prevent inadvertently sending extra information over a telnet connection. Use "nc -t" in place of telnet, and daemons that try to ask for things like USER and TERM environment variables will get no useful answers, as they otherwise would from a more recent telnet program. Some telnetds actually try to collect this stuff and then plug the USER variable into "login" so that the caller is then just asked for a password! This mechanism could cause a login attempt as YOUR real username to be logged over there if you use a Borman-based telnet instead of "nc -t". Got an unused network interface configured in your kernel [e.g. SLIP], or support for alias addresses? Ifconfig one to be any address you like, and bind to it with -s to enable all sorts of shenanigans with bogus source addresses. The interface probably has to be UP before this works; some SLIP versions need a far-end address before this is true. Hammering on UDP services is then a no-brainer. What you can do to an unfiltered syslog daemon should be fairly obvious; trimming the conf file can help protect against it. Many routers out there still blindly believe what they receive via RIP and other routing protocols. Although most UDP echo and chargen servers check if an incoming packet was sent from *another* "internal" UDP server, there are many that still do not, any two of which [or many, for that matter] could keep each other entertained for hours at the expense of bandwidth. And you can always make someone wonder why she's being probed by nsa.gov. Your TCP spoofing possibilities are mostly limited to destinations you can source-route to while locally bound to your phony address. Many sites block source-routed packets these days for precisely this reason. If your kernel does oddball things when sending source-routed packets, try moving the pointer around with -G. You may also have to fiddle with the routing on your own machine before you start receiving packets back. Warning: some machines still send out traffic using the source address of the outbound interface, regardless of your binding, especially in the case of localhost. Check first. If you can open a connection but then get no data back from it, the target host is probably killing the IP options on its end [this is an option inside TCP wrappers and several other packages], which happens after the 3-way handshake is completed. If you send some data and observe the "send-q" side of "netstat" for that connection increasing but never getting sent, that's another symptom. Beware: if Sendmail 8.7.x detects a source-routed SMTP connection, it extracts the hop list and sticks it in the Received: header! SYN bombing [sometimes called "hosing"] can disable many TCP servers, and if you hit one often enough, you can keep it unreachable for days. As is true of many other denial-of-service attacks, there is currently no defense against it except maybe at the human level. Making kernel SOMAXCONN considerably larger than the default and the half-open timeout smaller can help, and indeed some people running large high-performance web servers have *had* to do that just to handle normal traffic. Taking out mailers and web servers is sociopathic, but on the other hand it is sometimes useful to be able to, say, disable a site's identd daemon for a few minutes. If someone realizes what is going on, backtracing will still be difficult since the packets have a phony source address, but calls to enough ISP NOCs might eventually pinpoint the source. It is also trivial for a clueful ISP to watch for or even block outgoing packets with obviously fake source addresses, but as we know many of them are not clueful or willing to get involved in such hassles. Besides, outbound packets with an [otherwise unreachable] source address in one of their net blocks would look fairly legitimate. Notes ===== A discussion of various caveats, subtleties, and the design of the innards. As of version 1.07 you can construct a single file containing command arguments and then some data to transfer. Netcat is now smart enough to pick out the first line and build the argument list, and send any remaining data across the net to one or multiple ports. The first release of netcat had trouble with this -- it called fgets() for the command line argument, which behind the scenes does a large read() from standard input, perhaps 4096 bytes or so, and feeds that out to the fgets() library routine. By the time netcat 1.00 started directly read()ing stdin for more data, 4096 bytes of it were gone. It now uses raw read() everywhere and does the right thing whether reading from files, pipes, or ttys. If you use this for multiple-port connections, the single block of data will now be a maximum of 8K minus the first line. Improvements have been made to the logic in sending the saved chunk to each new port. Note that any command-line arguments hidden using this mechanism could still be extracted from a core dump. When netcat receives an inbound UDP connection, it creates a "connected socket" back to the source of the connection so that it can also send out data using normal write(). Using this mechanism instead of recvfrom/sendto has several advantages -- the read/write select loop is simplified, and ICMP errors can in effect be received by non-root users. However, it has the subtle side effect that if further UDP packets arrive from the caller but from different source ports, the listener will not receive them. UDP listen mode on a multihomed machine may have similar quirks unless you specifically bind to one of its addresses. It is not clear that kernel support for UDP connected sockets and/or my understanding of it is entirely complete here, so experiment... You should be aware of some subtleties concerning UDP scanning. If -z is on, netcat attempts to send a single null byte to the target port, twice, with a small time in between. You can either use the -w timeout, or netcat will try to make a "sideline" TCP connection to the target to introduce a small time delay equal to the round-trip time between you and the target. Note that if you have a -w timeout and -i timeout set, BOTH take effect and you wait twice as long. The TCP connection is to a normally refused port to minimize traffic, but if you notice a UDP fast-scan taking somewhat longer than it should, it could be that the target is actually listening on the TCP port. Either way, any ICMP port-unreachable messages from the target should have arrived in the meantime. The second single-byte UDP probe is then sent. Under BSD kernels, the ICMP error is delivered to the "connected socket" and the second write returns an error, which tells netcat that there is NOT a UDP service there. While Linux seems to be a fortunate exception, under many SYSV derived kernels the ICMP is not delivered, and netcat starts reporting that *all* the ports are "open" -- clearly wrong. [Some systems may not even *have* the "udp connected socket" concept, and netcat in its current form will not work for UDP at all.] If -z is specified and only one UDP port is probed, netcat's exit status reflects whether the connection was "open" or "refused" as with TCP. It may also be that UDP packets are being blocked by filters with no ICMP error returns, in which case everything will time out and return "open". This all sounds backwards, but that's how UDP works. If you're not sure, try "echo w00gumz | nc -u -w 2 target 7" to see if you can reach its UDP echo port at all. You should have no trouble using a BSD-flavor system to scan for UDP around your own network, although flooding a target with the high activity that -z generates will cause it to occasionally drop packets and indicate false "opens". A more "correct" way to do this is collect and analyze the ICMP errors, as does SATAN's "udp_scan" backend, but then again there's no guarantee that the ICMP gets back to you either. Udp_scan also does the zero-byte probes but is excruciatingly careful to calculate its own round-trip timing average and dynamically set its own response timeouts along with decoding any ICMP received. Netcat uses a much sleazier method which is nonetheless quite effective. Cisco routers are known to have a "dead time" in between ICMP responses about unreachable UDP ports, so a fast scan of a cisco will show almost everything "open". If you are looking for a specific UDP service, you can construct a file containing the right bytes to trigger a response from the other end and send that as standard input. Netcat will read up to 8K of the file and send the same data to every UDP port given. Note that you must use a timeout in this case [as would any other UDP client application] since the two-write probe only happens if -z is specified. Many telnet servers insist on a specific set of option negotiations before presenting a login banner. On a raw connection you will see this as small amount of binary gook. My attempts to create fixed input bytes to make a telnetd happy worked some places but failed against newer BSD-flavor ones, possibly due to timing problems, but there are a couple of much better workarounds. First, compile with -DTELNET and use -t if you just want to get past the option negotiation and talk to something on a telnet port. You will still see the binary gook -- in fact you'll see a lot more of it as the options are responded to behind the scenes. The telnet responder does NOT update the total byte count, or show up in the hex dump -- it just responds negatively to any options read from the incoming data stream. If you want to use a normal full-blown telnet to get to something but also want some of netcat's features involved like settable ports or timeouts, construct a tiny "foo" script: #! /bin/sh exec nc -otheroptions targethost 23 and then do nc -l -p someport -e foo localhost & telnet localhost someport and your telnet should connect transparently through the exec'ed netcat to the target, using whatever options you supplied in the "foo" script. Don't use -t inside the script, or you'll wind up sending *two* option responses. I've observed inconsistent behavior under some Linuxes [perhaps just older ones?] when binding in listen mode. Sometimes netcat binds only to "localhost" if invoked with no address or port arguments, and sometimes it is unable to bind to a specific address for listening if something else is already listening on "any". The former problem can be worked around by specifying "-s 0.0.0.0", which will do the right thing despite netcat claiming that it's listening on [127.0.0.1]. This is a known problem -- for example, there's a mention of it in the makefile for SOCKS. On the flip side, binding to localhost and sending packets to some other machine doesn't work as you'd expect -- they go out with the source address of the sending interface instead. The Linux kernel contains a specific check to ensure that packets from 127.0.0.1 are never sent to the wire; other kernels may contain similar code. Linux, of course, *still* doesn't support source-routing, but they claim that it and many other network improvements are at least breathing hard. There are several possible errors associated with making TCP connections, but to specifically see anything other than "refused", one must wait the full kernel-defined timeout for a connection to fail. Netcat's mechanism of wrapping an alarm timer around the connect prevents the *real* network error from being returned -- "errno" at that point indicates "interrupted system call" since the connect attempt was interrupted. Some old 4.3 BSD kernels would actually return things like "host unreachable" immediately if that was the case, but most newer kernels seem to wait the full timeout and *then* pass back the real error. Go figure. In this case, I'd argue that the old way was better, despite those same kernels generally being the ones that tear down *established* TCP connections when ICMP-bombed. Incoming socket options are passed to applications by the kernel in the kernel's own internal format. The socket-options structure for source-routing contains the "first-hop" IP address first, followed by the rest of the real options list. The kernel uses this as is when sending reply packets -- the structure is therefore designed to be more useful to the kernel than to humans, but the hex dump of it that netcat produces is still useful to have. Kernels treat source-routing options somewhat oddly, but it sort of makes sense once one understands what's going on internally. The options list of addresses must contain hop1, hop2, ..., destination. When a source-routed packet is sent by the kernel [at least BSD], the actual destination address becomes irrelevant because it is replaced with "hop1", "hop1" is removed from the options list, and all the other addresses in the list are shifted up to fill the hole. Thus the outbound packet is sent from your chosen source address to the first *gateway*, and the options list now contains hop2, ..., destination. During all this address shuffling, the kernel does NOT change the pointer value, which is why it is useful to be able to set the pointer yourself -- you can construct some really bizarre return paths, and send your traffic fairly directly to the target but around some larger loop on the way back. Some Sun kernels seem to never flip the source-route around if it contains less than three hops, never reset the pointer anyway, and tries to send the packet [with options containing a "completed" source route!!] directly back to the source. This is way broken, of course. [Maybe ipforwarding has to be on? I haven't had an opportunity to beat on it thoroughly yet.] "Credits" section: The original idea for netcat fell out of a long-standing desire and fruitless search for a tool resembling it and having the same features. After reading some other network code and realizing just how many cool things about sockets could be controlled by the calling user, I started on the basics and the rest fell together pretty quickly. Some port-scanning ideas were taken from Venema/Farmer's SATAN tool kit, and Pluvius' "pscan" utility. Healthy amounts of BSD kernel source were perused in an attempt to dope out socket options and source-route handling; additional help was obtained from Dave Borman's telnet sources. The select loop is loosely based on fairly well-known code from "rsh" and Richard Stevens' "sock" program [which itself is sort of a "netcat" with more obscure features], with some more paranoid sanity-checking thrown in to guard against the distinct likelihood that there are subtleties about such things I still don't understand. I found the argument-hiding method cleanly implemented in Barrett's "deslogin"; reading the line as input allows greater versatility and is much less prone to cause bizarre problems than the more common trick of overwriting the argv array. After the first release, several people contributed portability fixes; they are credited in generic.h and the Makefile. Lauren Burka inspired the ascii art for this revised document. Dean Gaudet at Wired supplied a precursor to the hex-dump code, and mudge@l0pht.com originally experimented with and supplied code for the telnet-options responder. Outbound "-e " resulted from a need to quietly bypass a firewall installation. Other suggestions and patches have rolled in for which I am always grateful, but there are only 26 hours per day and a discussion of feature creep near the end of this document. Netcat was written with the Russian railroad in mind -- conservatively built and solid, but it *will* get you there. While the coding style is fairly "tight", I have attempted to present it cleanly [keeping *my* lines under 80 characters, dammit] and put in plenty of comments as to why certain things are done. Items I know to be questionable are clearly marked with "XXX". Source code was made to be modified, but determining where to start is difficult with some of the tangles of spaghetti code that are out there. Here are some of the major points I feel are worth mentioning about netcat's internal design, whether or not you agree with my approach. Except for generic.h, which changes to adapt more platforms, netcat is a single source file. This has the distinct advantage of only having to include headers once and not having to re-declare all my functions in a billion different places. I have attempted to contain all the gross who's-got-what-.h-file things in one small dumping ground. Functions are placed "dependencies-first", such that when the compiler runs into the calls later, it already knows the type and arguments and won't complain. No function prototyping -- not even the __P(()) crock -- is used, since it is more portable and a file of this size is easy enough to check manually. Each function has a standard-format comment ahead of it, which is easily found using the regexp " :$". I freely use gotos. Loops and if-clauses are made as small and non-nested as possible, and the ends of same *marked* for clarity [I wish everyone would do this!!]. Large structures and buffers are all malloc()ed up on the fly, slightly larger than the size asked for and zeroed out. This reduces the chances of damage from those "end of the buffer" fencepost errors or runaway pointers escaping off the end. These things are permanent per run, so nothing needs to be freed until the program exits. File descriptor zero is always expected to be standard input, even if it is closed. If a new network descriptor winds up being zero, a different one is asked for which will be nonzero, and fd zero is simply left kicking around for the rest of the run. Why? Because everything else assumes that stdin is always zero and "netfd" is always positive. This may seem silly, but it was a lot easier to code. The new fd is obtained directly as a new socket, because trying to simply dup() a new fd broke subsequent socket-style use of the new fd under Solaris' stupid streams handling in the socket library. The catch-all message and error handlers are implemented with an ample list of phoney arguments to get around various problems with varargs. Varargs seems like deliberate obfuscation in the first place, and using it would also require use of vfprintf() which not all platforms support. The trailing sleep in bail() is to allow output to flush, which is sometimes needed if netcat is already on the other end of a network connection. The reader may notice that the section that does DNS lookups seems much gnarlier and more confusing than other parts. This is NOT MY FAULT. The sockaddr and hostent abstractions are an abortion that forces the coder to deal with it. Then again, a lot of BSD kernel code looks like similar struct-pointer hell. I try to straighten it out somewhat by defining my own HINF structure, containing names, ascii-format IP addresses, and binary IP addresses. I fill this structure exactly once per host argument, and squirrel everything safely away and handy for whatever wants to reference it later. Where many other network apps use the FIONBIO ioctl to set non-blocking I/O on network sockets, netcat uses straightforward blocking I/O everywhere. This makes everything very lock-step, relying on the network and filesystem layers to feed in data when needed. Data read in is completely written out before any more is fetched. This may not be quite the right thing to do under some OSes that don't do timed select() right, but this remains to be seen. The hexdump routine is written to be as fast as possible, which is why it does so much work itself instead of just sprintf()ing everything together. Each dump line is built into a single buffer and atomically written out using the lowest level I/O calls. Further improvements could undoubtedly be made by using writev() and eliminating all sprintf()s, but it seems to fly right along as is. If both exec-a-prog mode and a hexdump file is asked for, the hexdump flag is deliberately turned off to avoid creating random zero-length files. Files are opened in "truncate" mode; if you want "append" mode instead, change the open flags in main(). main() may look a bit hairy, but that's only because it has to go down the argv list and handle multiple ports, random mode, and exit status. Efforts have been made to place a minimum of code inside the getopt() loop. Any real work is sent off to functions in what is hopefully a straightforward way. Obligatory vendor-bash: If "nc" had become a standard utility years ago, the commercial vendors would have likely packaged it setuid root and with -DGAPING_SECURITY_HOLE turned on but not documented. It is hoped that netcat will aid people in finding and fixing the no-brainer holes of this sort that keep appearing, by allowing easier experimentation with the "bare metal" of the network layer. It could be argued that netcat already has too many features. I have tried to avoid "feature creep" by limiting netcat's base functionality only to those things which are truly relevant to making network connections and the everyday associated DNS lossage we're used to. Option switches already have slightly overloaded functionality. Random port mode is sort of pushing it. The hex-dump feature went in later because it *is* genuinely useful. The telnet-responder code *almost* verges on the gratuitous, especially since it mucks with the data stream, and is left as an optional piece. Many people have asked for example "how 'bout adding encryption?" and my response is that such things should be separate entities that could pipe their data *through* netcat instead of having their own networking code. I am therefore not completely enthusiastic about adding any more features to this thing, although you are still free to send along any mods you think are useful. Nonetheless, at this point I think of netcat as my tcp/ip swiss army knife, and the numerous companion programs and scripts to go with it as duct tape. Duct tape of course has a light side and a dark side and binds the universe together, and if I wrap enough of it around what I'm trying to accomplish, it *will* work. Alternatively, if netcat is a large hammer, there are many network protocols that are increasingly looking like nails by now... _H* 960320 v1.10 RELEASE -- happy spring! unix/README.cryptcat000640 023422 023422 00000003565 10176317426 016263 0ustar00jleplastjleplast000000 000000 cryptcat = netcat + encryption Cryptcat is the standard netcat enhanced with twofish encryption. Twofish is courtesy of counterpane, and cryptix. We started with the Java version of twofish from cryptix, converted it to C++ (don't ask why), and enhanced it by adding CBC mode and the ciphertext stealing technique from Applied Cryptography (pg. 196) How do you use it? Machine A: cryptcat -l -p 1234 < testfile Machine B: cryptcat 1234 This is identical to the normal netcat options for doing exactly the same thing. However, in this case the data transferred is encrypted. Known issues: It is known that linux will throw errors like: /tmp/ccF9UdJx.o(.text+0x6d0): In function `getportpoop': : warning: Using 'getservbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /tmp/ccF9UdJx.o(.text+0x61f): In function getportpoop': : warning: Using 'getservbyport' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking This is due to using -static which either Hobbit or someone else insists in the Makefile is The Right Thing(tm). The compiled code still seems to run without an issue and according to ldd it is a static binary. Changes -- been putting these in Changelog file... Since release alot of people have been submitting changes (many times for the same thing). I've been doing my best to keep up, we are trying to get this up on sourceforge, but there seems to be some sort of "approval" process that makes it unclear if that will actually happen. So, if you have submitted something, and its not here, let me know. If you've submitted a change, and its here with someone else's name, that just means someone else got the same change in before you. If you have a change, let me know what name if any to include with the change. unix/farm9crypt.cc000640 023422 023422 00000007732 10160731523 016151 0ustar00jleplastjleplast000000 000000 /* * farm9crypt.cpp * * C interface between netcat and twofish. * * Intended for direct replacement of system "read" and "write" calls. * * Design is like a "C" version of an object. * * Static variables, initialized with farm9crypt_init creates a * "readDecryptor" and "writeEncryptor" object, both of which are based * on the assumption that text lines are being transferred between * the two sides. * * jojo@farm9.com -- 29 Sept 2000, fixed buffer size (really it should have crashed!) * jojo@farm9.com -- 2 Oct 2000, yet another bug fix...(thanks to Jimmy for reporting this!) * jojo@farm9.com -- 2 Oct 2000, no more printf of key cuz its stupid (yet another Dragos suggestion) * jeff@wwti.com -- 9 Feb 2001, added string.h include for yet more linux brokenness */ #ifndef WIN32 #include #include // suggested by several people -- for OpenBSD, FreeBSD compiles #include /* basics, SO_ and AF_ defs, sockaddr, ... */ #include #else #include #include #include #include #include #endif extern "C" { #include "farm9crypt.h" } #include "twofish2.h" static int debug = false; static int initialized = false; static TwoFish* decryptor = NULL; static TwoFish* encryptor = NULL; extern "C" void farm9crypt_debug() { debug = true; } /* * farm9crypt_initialized * * Return Value: * true if this module has been initialized, otherwise false */ extern "C" int farm9crypt_initialized() { return( initialized ); } /* * farm9crypt_init * * Input Parameters: * keystr -- used to generate Twofish key for encryption and decryption * * Return Value: * none */ extern "C" void farm9crypt_init( char* keystr ) { // printf( "farm9crypt_init: %s\n", keystr ); encryptor = new TwoFish( generateKey( keystr ), false, NULL, NULL ); decryptor = new TwoFish( generateKey( keystr ), true, NULL, NULL ); initialized = true; srand( 1000 ); } /* * farm9crypt_read * * Susbstitute for socket read (one line replacement in netcat) * * Handles decryption * * Parameters same as "recv" */ static char outBuffer[8193]; static char inBuffer[8193]; extern "C" int farm9crypt_read( int sockfd, char* buf, int size ) { int total = 0; char outbuf[16]; char outbuf2[16]; if ( size > 8192 ) { size = 8192; } while (total < 32) { int result = recv( sockfd, buf + total, 32 - total, 0 ); if ( result > 0 ) { total += result; } else { return(0); } } decryptor->resetCBC(); decryptor->setOutputBuffer( (unsigned char*)&outBuffer[0] ); decryptor->blockCrypt( buf, outbuf, 16 ); decryptor->flush(); decryptor->setOutputBuffer( (unsigned char*)&outBuffer[0] ); decryptor->blockCrypt( buf + 16, outbuf2, 16 ); int limit = atoi( outbuf ); total = 0; char* inbuf = &inBuffer[0]; while ( total < limit ) { int result = recv( sockfd, inbuf + total, limit - total, 0 ); if ( result > 0 ) { total += result; } else { break; } } int loc = 0; char* obuf = &outBuffer[0]; while ( total > 0 ) { int amount = 16; if ( total < amount ) { amount = total; } decryptor->blockCrypt( inbuf + loc, outbuf, amount ); total -= amount; loc += 16; } decryptor->flush(); memcpy( buf, obuf + 32, limit ); *(buf + limit) = 0; // in case return( limit ); } static char localBuf[2000]; extern "C" int farm9crypt_write( int sockfd, char* buf, int size ) { char tempbuf[16]; char outbuf[16]; sprintf( tempbuf, "%d %d", size, rand() ); tempbuf[strlen(tempbuf)] = 'x'; encryptor->setSocket( sockfd ); encryptor->setOutputBuffer( (unsigned char*)&outBuffer[0] ); encryptor->resetCBC(); encryptor->blockCrypt( tempbuf, outbuf, 16 ); encryptor->blockCrypt( tempbuf, outbuf, 16 ); int loc = 0; int totalsize = size; while ( size > 0 ) { int amount = 16; if ( size < amount ) { amount = size; } encryptor->blockCrypt( buf + loc, &outBuffer[loc+32], amount ); size -= amount; loc += amount; } encryptor->flush(); return( totalsize ); } unix/farm9crypt.h000640 023422 023422 00000000665 10161121431 016001 0ustar00jleplastjleplast000000 000000 /* * farm9crypt.h * * C interface between netcat and twofish. * * Intended for direct replacement of system "read" and "write" calls. * * NOTE: This file must be included within "extern C {...}" when included in C++ */ void farm9crypt_init( char* inkey ); void farm9crypt_debug(); int farm9crypt_initialized(); int farm9crypt_read( int sockfd, char* buf, int size ); int farm9crypt_write( int sockfd, char* buf, int size ); unix/generic.h000640 023422 023422 00000026412 10150736513 015326 0ustar00jleplastjleplast000000 000000 /* generic.h -- anything you don't #undef at the end remains in effect. The ONLY things that go in here are generic indicator flags; it's up to your programs to declare and call things based on those flags. You should only need to make changes via a minimal system-specific section at the end of this file. To build a new section, rip through this and check everything it mentions on your platform, and #undef that which needs it. If you generate a system-specific section you didn't find in here, please mail me a copy so I can update the "master". I realize I'm probably inventing another pseudo-standard here, but goddamnit, everybody ELSE has already, and I can't include all of their hairball schemes too. HAVE_xx conforms to the gnu/autoconf usage and seems to be the most common format. In fact, I dug a lot of these out of autoconf and tried to common them all together using "stupidh" to collect data from platforms. In disgust... _H* 940910, 941115, 950511. Pseudo-version: 1.3 Updated 951104 with many patches from netcat feedback, and properly closed a lot of slop in open-ended comments: version 1.4 960217 + nextstep: version 1.5 */ #ifndef GENERIC_H /* only run through this once */ #define GENERIC_H /* =============================== */ /* System calls, lib routines, etc */ /* =============================== */ /* How does your system declare malloc, void or char? Usually void, but go ask the SunOS people why they had to be different... */ #define VOID_MALLOC /* notably from fwtk/firewall.h: posix locking? */ #define HAVE_FLOCK /* otherwise it's lockf() */ /* if you don't have setsid(), you might have setpgrp(). */ #define HAVE_SETSID /* random() is generally considered better than rand() */ #define HAVE_RANDOM /* the srand48/lrand48/etc family is s'posedly even better */ #define HAVE_RAND48 /* bmc@telebase and others have suggested these macros if a box *does* have rand48. Will consider for later if we're doing something that really requires stronger random numbers, but netcat and such certainly doesn't. #define srandom(seed) srand48((long) seed) #define random() lrand48() */ /* if your machine doesn't have lstat(), it should have stat() [dos...] */ #define HAVE_LSTAT /* different kinds of term ioctls. How to recognize them, very roughly: sysv/POSIX_ME_HARDER: termio[s].h, struct termio[s], tty.c_*[] bsd/old stuff: sgtty.h, ioctl(TIOCSETP), sgttyb.sg_*, tchars.t_* */ #define HAVE_TERMIOS /* dbm vs ndbm */ #define HAVE_NDBM /* extended utmp/wtmp stuff. MOST machines still do NOT have this SV-ism */ #define UTMPX /* some systems have nice() which takes *relative* values... [resource.h] */ #define HAVE_SETPRIORITY /* a sysvism, I think, but ... */ #define HAVE_SYSINFO /* ============= */ /* Include files */ /* ============= */ /* Presence of these can be determined via a script that sniffs them out if you aren't sure. See "stupidh"... */ /* stdlib comes with most modern compilers, but ya never know */ #define HAVE_STDLIB_H /* not on a DOS box! */ #define HAVE_UNISTD_H /* stdarg is a weird one */ #define HAVE_STDARG_H /* dir.h or maybe ndir.h otherwise. */ #define HAVE_DIRENT_H /* string or strings */ #define HAVE_STRINGS_H /* if you don't have lastlog.h, what you want might be in login.h */ #define HAVE_LASTLOG_H /* predefines for _PATH_various */ #define HAVE_PATHS_H /* some SV-flavors break select stuff out separately */ #define HAVE_SELECT_H /* assorted others */ #define HAVE_PARAM_H /* in sys/ */ #define HAVE_SYSMACROS_H /* in sys/ */ #define HAVE_TTYENT_H /* securetty et al */ /* ==================== */ /* Still maybe have to do something about the following, if it's even worth it. I just grepped a lot of these out of various code, without looking them up yet: #define HAVE_EINPROGRESS #define HAVE_F_SETOWN HAVE_FILIO_H ... fionbio, fiosetown, etc... will need for hairier select loops. #define HAVE_SETENV ... now *there's* a hairy one; **environ is portable #define HAVE_GETUSERSHELL ... you could always pull it out of getpwent() #define HAVE_SETE[UG]ID ... lib or syscall, it varies on diff platforms #define HAVE_STRCHR ... should actually be handled by string/strings #define HAVE_PSTAT #define HAVE_ST_BLKSIZE ... a stat() thing? #define HAVE_IP_TOS #define HAVE_STRFTIME ... screw this, we'll just INCLUDE one for lame old boxes that don't have it [sunos 3.x, early 4.x?] #define HAVE_VFPRINTF #define HAVE_SHADOW_PASSWD ... in its multitudinous schemes?? ... how about sumpin' like #define SHADOW_PASSWD_TYPE ... could get grody. ... looks like sysv /etc/shadow, getspent() family is common. #define SIG* ... what a swamp, punt for now; should all be in signal.h #define HAVE_STRCSPN ... see larry wall's comment in the fwtk regex code #define ULTRIX_AUTH ... bwahaha. #define HAVE_YP or NIS or whatever you wanna call it this week randomness about VARARGS?? --- later stuff to be considered --- #define UINT4 ... u-int on alpha/osf, i.e. __alpha/__osf__, ulong elsewhere? dont name it that, though, it'll conflict with extant .h files like md5 randomness about machine/endian.h, machine/inline.h -- bsdi, net/2 randomness about _PATH_WTMP vs WTMP_FILE and where they even live!! #define HAVE_SYS_ERRLIST ... whether it's in stdio.h or not [bsd 4.4] --- still more stuff #define HAVE_SETENV #define _PATH_UTMP vs UTMP_FILE, a la deslogind?! #define HAVE_DAEMON #define HAVE_INETADDR [vixie bind?] lseek: SEEK_SET vs L_SET and associated lossage [epi-notes, old 386Mach] bsdi: ioctl_compat.h ? --- takin' some ifdefs from CNS krb: F_GETOWN/F_SETOWN CRAY: long = 8 bytes, etc [class with alpha?] CGETENT SIGINFO SIGTSTP SIGTTOU SIGWINCH SPX? SYSV_TERMIO -- covered elsewhere, I hope TIOCEXT TIOCFLUSH TIOC[GS]WINSIZ NEWINIT: something about init cleaning up dead login processes [telnet?] PARENT_DOES_UTMP, too [telnet] VDISCARD VEOL/VEOL2/VLNEXT VREPRINT -- termios stuff?, and related... STREAMSPTY/STREAMSPTYEM AF_INET/AF_UNSPEC, PF_* ECHOCTL/ECHOKE F_ULOCK [?!] setpgrp/getpgrp() ONEARG business.. HAVE_ALLOCA HAVE_GETUTENT HAVE_SYS_SELECT_H [irix!] HAVE_DIRENT [old 386mach has *direct.h*!] HAVE_SIGSET HAVE_VFORK_H and HAVE_VFORK HAVE_VHANGUP HAVE_VSPRINTF HAVE_IPTOS_* HAVE_STRCASECMP, STRNCASECMP HAVE_SYS_FCNTL_H HAVE_SYS_TIME_H HAVE_UTIMES NOTTYENT [?] HAVE_FCHMOD HAVE_GETUSERSHELL HAVE_SIGCONTEXT [stack hair, very machine-specific] YYLINENO? POSIX_SIGNALS POSIX_TERMIOS SETPROCTITLE -- breaks some places, like fbsd sendmail SIG* -- actual signal names? some are missing SIOCGIFCONF SO_BROADCAST SHMEM [krb tickets] VARARGS, or HAVE_VARARGS CBAUD ... and B300, B9600, etc etc HAVE_BZERO vs memset/memcpy HAVE_SETVBUF HAVE_STRDUP HAVE_GETENV HAVE_STRSAVE HAVE_STBLKSIZE [stat?] HAVE_STREAM_H -- in sys/, ref sendmail 8.7 for IP_SRCROUTE FCHMOD INITGROUPS -- most machines seem to *have* SETREUID SNPRINTF SETPGRP semantics bsd vs. sys5 style There's also the issue about WHERE various .h files live, sys/ or otherwise. There's a BIG swamp lurking where network code of any sort lives. */ /* ======================== */ /* System-specific sections */ /* ======================== */ /* By turning OFF various bits of the above, you can customize for a given platform. Yes, we're ignoring the stock compiler predefines and using our own plugged in via the Makefile. */ /* DOS boxes, with MSC; you may need to adapt to a different compiler. */ /* looks like later ones *do* have dirent.h, for example */ #ifdef MSDOS #undef HAVE_FLOCK #undef HAVE_RANDOM #undef HAVE_LSTAT #undef HAVE_TERMIOS #undef UTMPX #undef HAVE_SYSINFO #undef HAVE_UNISTD_H #undef HAVE_DIRENT_H /* unless you have the k00l little wrapper from L5!! */ #undef HAVE_STRINGS_H #undef HAVE_LASTLOG_H #undef HAVE_PATHS_H #undef HAVE_PARAM_H #undef HAVE_SYSMACROS_H #undef HAVE_SELECT_H #undef HAVE_TTYENT_H #endif /* MSDOS */ /* buglix 4.x; dunno about 3.x on down. should be bsd4.2 */ #ifdef ULTRIX #undef UTMPX #undef HAVE_PATHS_H #undef HAVE_SYSMACROS_H #undef HAVE_SELECT_H #endif /* buglix */ /* some of this might still be broken on older sunoses */ #ifdef SUNOS #undef VOID_MALLOC #undef UTMPX #undef HAVE_PATHS_H #undef HAVE_SELECT_H #endif /* sunos */ /* "contact your vendor for a fix" */ #ifdef SOLARIS /* has UTMPX */ #undef HAVE_RANDOM #undef HAVE_SETPRIORITY #undef HAVE_STRINGS_H /* this is genuinely the case, go figure */ #undef HAVE_PATHS_H #undef HAVE_SELECT_H #undef HAVE_TTYENT_H #endif /* SOLARIS */ /* whatever aix variant MIT had at the time; 3.2.x?? */ #ifdef AIX #undef UTMPX #undef HAVE_LASTLOG_H #define HAVE_LOGIN_H /* "special", in the educational sense */ #endif /* aix */ /* linux, which is trying as desperately as the gnu folks can to be POSIXLY_CORRECT. I think I'm gonna hurl... */ #ifdef LINUX #undef UTMPX #undef HAVE_SYSINFO #undef HAVE_SELECT_H #undef HAVE_TTYENT_H #endif /* linux */ /* irix 5.x; may not be correct for earlier ones */ #ifdef IRIX /* wow, does irix really have everything?! */ #endif /* irix */ /* osf on alphas */ #ifdef OSF #undef UTMPX #undef HAVE_SELECT_H #endif /* osf */ /* they's some FUCKED UP paths in this one! */ #ifdef FREEBSD #undef UTMPX #undef HAVE_SYSINFO #undef HAVE_LASTLOG_H #undef HAVE_SYSMACROS_H #undef HAVE_SELECT_H /* actually a lie, but only for kernel */ #endif /* freebsd */ /* Originally from the sidewinder site, of all places, but subsequently checked further under a more normal bsdi 2.0 */ #ifdef BSDI #undef UTMPX #undef HAVE_LASTLOG_H #undef HAVE_SYSMACROS_H /* and their malloc.h was in sys/ ?! */ #undef HAVE_SELECT_H #endif /* bsdi */ /* netbsd/44lite, jives with amiga-netbsd from cactus */ #ifdef NETBSD #undef UTMPX #undef HAVE_SYSINFO #undef HAVE_LASTLOG_H #undef HAVE_SELECT_H #endif /* netbsd */ /* Hpux 9.0x, from BBN and various patches sent in */ #ifdef HPUX #undef HAVE_RANDOM /* but *does* have ?rand48 -- need to consider.. */ #undef HAVE_UTMPX #undef HAVE_LASTLOG_H /* has utmp/wtmp/btmp nonsense, and pututline() */ #undef HAVE_PATHS_H #undef HAVE_SELECT_H #undef HAVE_TTYENT_H #endif /* hockeypux */ /* Unixware [a loose definition of "unix", to be sure], 1.1.2 [at least] from Brian Clapper. He wasn't sure about 2.0... */ #ifdef UNIXWARE /* has UTMPX */ #undef HAVE_SETPRIORITY /* NOTE: UnixWare does provide the BSD stuff, in "/usr/ucbinclude" (headers) and "/usr/ucblib" (libraries). However, I've run into problems linking stuff out of that version of the C library, when objects are also coming out of the "regular" C library. My advice: Avoid the BSD compatibility stuff wherever possible. Brian Clapper */ #undef HAVE_STRINGS_H #undef HAVE_PATHS_H #undef HAVE_TTYENT_H #endif /* UNIXWARE */ /* A/UX 3.1.x from darieb@sandia.gov */ #ifdef AUX #undef HAVE_RANDOM #undef HAVE_SELECT_H /* xxx: untested */ #endif /* a/ux */ /* NeXTSTEP 3.2 motorola mudge@l0pht.com xxx should also work with white hardware and Sparc/HPPA. Should work with 3.3 too as it's 4.3 / 4.4 bsd wrapped around mach */ #ifdef NEXT #undef UTMPX #undef HAVE_SELECT_H #endif /* NeXTSTEP 3.2 motorola */ /* Make some "generic" assumptions if all else fails */ #ifdef GENERIC #undef HAVE_FLOCK #if defined(SYSV) && (SYSV < 4) /* TW leftover: old SV doesnt have symlinks */ #undef HAVE_LSTAT #endif /* old SYSV */ #undef HAVE_TERMIOS #undef UTMPX #undef HAVE_PATHS_H #undef HAVE_SELECT_H #endif /* generic */ /* ================ */ #endif /* GENERIC_H */ unix/netcat.blurb000640 023422 023422 00000005125 07162126046 016050 0ustar00jleplastjleplast000000 000000 Netcat 1.10 is an updated release of Netcat, a simple Unix utility which reads and writes data across network connections using TCP or UDP protocol. It is designed to be a reliable "back-end" tool that can be used directly or easily driven by other programs and scripts. At the same time it is a feature-rich network debugging and exploration tool, since it can create almost any kind of connection you would need and has several interesting built-in capabilities. Some of netcat's major features are: Outbound or inbound connections, TCP or UDP, to or from any ports Full DNS forward/reverse checking, with appropriate warnings Ability to use any local source port Ability to use any locally-configured network source address Built-in port-scanning capabilities, with randomizer Built-in loose source-routing capability Can read command line arguments from standard input Slow-send mode, one line every N seconds Hex dump of transmitted and received data Optional ability to let another program service established connections Optional telnet-options responder A very short list of potential uses: Script backends Scanning ports and inventorying services, automated probes Backup handlers File transfers Server testing, simulation, debugging, and hijacking Firewall testing Proxy gatewaying Network performance testing Address spoofing tests Protecting X servers 1001 other uses you'll likely come up with Changes between the 1.00 release and this release: Better portability -- updated generic.h and Makefile [thanx folks!] Indication of local-end interface address on inbound connections That's *Dave* Borman's telnet, not Paul Borman... Better indication of DNS errors Total byte counts printed if -v -v is used A bunch of front-end driver companion programs and scripts Better handling of stdin arguments-plus-data Hex-dump feature Telnet responder Program exec works inbound or outbound now Netcat and the associated package is a product of Avian Research, and is freely available in full source form with no restrictions save an obligation to give credit where due. Get it via anonymous FTP at avian.org:/src/hacks/nc110.tgz which is a gzipped tar file and not to be confused with its version 1.00 precursor, nc100.tgz. Other distribution formats can be accomodated upon request. Netcat is also mirrored at the following [faster] sites: zippy.telcom.arizona.edu:/pub/mirrors/avian.org/hacks/nc110.tgz ftp.sterling.com:/mirrors/avian.org/src/hacks/nc110.tgz coast.cs.purdue.edu:/pub/tools/unix/netcat/nc110.tgz ftp.rge.com:/pub/security/coast/mirrors/avian.org/netcat/nc110.tgz _H* 960320 unix/netcat.c000640 023422 023422 00000164063 10325231755 015172 0ustar00jleplastjleplast000000 000000 /* Shared secret TwoFish Encryption added 9/20/00 -JoJo Extra -k Option added to set Shared secret key 9/25/00 -Xram_LraK wrap user-supplied string to farm9crypt_init with memcpy() and ... #ifdef resolv.h for broken linux distros 2/9/2001 -Jeff Nathan */ /* Netcat 1.10 RELEASE 960320 A damn useful little "backend" utility begun 950915 or thereabouts, as *Hobbit*'s first real stab at some sockets programming. Something that should have and indeed may have existed ten years ago, but never became a standard Unix utility. IMHO, "nc" could take its place right next to cat, cp, rm, mv, dd, ls, and all those other cryptic and Unix-like things. Read the README for the whole story, doc, applications, etc. Layout: conditional includes: includes: handy defines: globals: malloced globals: cmd-flag globals: support routines: readwrite select loop: main: bluesky: parse ranges of IP address as well as ports, perhaps RAW mode! backend progs to grab a pty and look like a real telnetd?! backend progs to do various encryption modes??!?! */ #include "generic.h" /* same as with L5, skey, etc */ /* conditional includes -- a very messy section which you may have to dink for your own architecture [and please send diffs...]: */ /* #undef _POSIX_SOURCE /* might need this for something? */ #define HAVE_BIND /* ASSUMPTION -- seems to work everywhere! */ #define HAVE_HELP /* undefine if you dont want the help text */ /* #define ANAL /* if you want case-sensitive DNS matching */ #ifdef HAVE_STDLIB_H #include #else #include #endif #ifdef HAVE_SELECT_H /* random SV variants need this */ #include #endif /* have to do this *before* including types.h. xxx: Linux still has it wrong */ #ifdef FD_SETSIZE /* should be in types.h, butcha never know. */ #undef FD_SETSIZE /* if we ever need more than 16 active */ #endif /* fd's, something is horribly wrong! */ #define FD_SETSIZE 16 /* <-- this'll give us a long anyways, wtf */ #include /* *now* do it. Sigh, this is broken */ #ifdef HAVE_RANDOM /* aficionados of ?rand48() should realize */ #define SRAND srandom /* that this doesn't need *strong* random */ #define RAND random /* numbers just to mix up port numbers!! */ #else #define SRAND srand #define RAND rand #endif /* HAVE_RANDOM */ /* includes: */ #include /* timeval, time_t */ #include /* jmp_buf et al */ #include /* basics, SO_ and AF_ defs, sockaddr, ... */ #include /* sockaddr_in, htons, in_addr */ #include /* misc crud that netinet/ip.h references */ #include /* IPOPT_LSRR, header stuff */ #include /* hostent, gethostby*, getservby* */ #include /* inet_ntoa */ #include #include /* strcpy, strchr, yadda yadda */ #include #include #include /* O_WRONLY et al */ #ifdef LINUX #include #endif /* handy stuff: */ #define SA struct sockaddr /* socket overgeneralization braindeath */ #define SAI struct sockaddr_in /* ... whoever came up with this model */ #define IA struct in_addr /* ... should be taken out and shot, */ /* ... not that TLI is any better. sigh.. */ #define SLEAZE_PORT 31337 /* for UDP-scan RTT trick, change if ya want */ #define USHORT unsigned short /* use these for options an' stuff */ #define BIGSIZ 8192 /* big buffers */ #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif #ifdef MAXHOSTNAMELEN #undef MAXHOSTNAMELEN /* might be too small on aix, so fix it */ #endif #define MAXHOSTNAMELEN 256 #define MAXKEYSIZE 32 struct host_poop { char name[MAXHOSTNAMELEN]; /* dns name */ char addrs[8][24]; /* ascii-format IP addresses */ struct in_addr iaddrs[8]; /* real addresses: in_addr.s_addr: ulong */ }; #define HINF struct host_poop struct port_poop { char name [64]; /* name in /etc/services */ char anum [8]; /* ascii-format number */ USHORT num; /* real host-order number */ }; #define PINF struct port_poop /* globals: */ jmp_buf jbuf; /* timer crud */ int jval = 0; /* timer crud */ int netfd = -1; int ofd = 0; /* hexdump output fd */ static char unknown[] = "(UNKNOWN)"; static char p_tcp[] = "tcp"; /* for getservby* */ static char p_udp[] = "udp"; #ifdef HAVE_BIND extern int h_errno; /* stolen almost wholesale from bsd herror.c */ static char * h_errs[] = { "Error 0", /* but we *don't* use this */ "Unknown host", /* 1 HOST_NOT_FOUND */ "Host name lookup failure", /* 2 TRY_AGAIN */ "Unknown server error", /* 3 NO_RECOVERY */ "No address associated with name", /* 4 NO_ADDRESS */ }; #else int h_errno; /* just so we *do* have it available */ #endif /* HAVE_BIND */ int gatesidx = 0; /* LSRR hop count */ int gatesptr = 4; /* initial LSRR pointer, settable */ USHORT Single = 1; /* zero if scanning */ unsigned int insaved = 0; /* stdin-buffer size for multi-mode */ unsigned int wrote_out = 0; /* total stdout bytes */ unsigned int wrote_net = 0; /* total net bytes */ static char wrote_txt[] = " sent %d, rcvd %d"; static char hexnibs[20] = "0123456789abcdef "; /* will malloc up the following globals: */ struct timeval * timer1 = NULL; struct timeval * timer2 = NULL; SAI * lclend = NULL; /* sockaddr_in structs */ SAI * remend = NULL; HINF ** gates = NULL; /* LSRR hop hostpoop */ char * optbuf = NULL; /* LSRR or sockopts */ char * bigbuf_in; /* data buffers */ char * bigbuf_net; fd_set * ding1; /* for select loop */ fd_set * ding2; PINF * portpoop = NULL; /* for getportpoop / getservby* */ unsigned char * stage = NULL; /* hexdump line buffer */ /* global cmd flags: */ USHORT o_alla = 0; unsigned int o_interval = 0; USHORT o_listen = 0; USHORT o_nflag = 0; USHORT o_wfile = 0; USHORT o_random = 0; USHORT o_udpmode = 0; USHORT o_verbose = 0; unsigned int o_wait = 0; USHORT o_zero = 0; /* o_tn in optional section */ /* Debug macro: squirt whatever message and sleep a bit so we can see it go by. need to call like Debug ((stuff)) [with no ; ] so macro args match! Beware: writes to stdOUT... */ #ifdef DEBUG #define Debug(x) printf x; printf ("\n"); fflush (stdout); sleep (1); #else #define Debug(x) /* nil... */ #endif /* support routines -- the bulk of this thing. Placed in such an order that we don't have to forward-declare anything: */ /* holler : fake varargs -- need to do this way because we wind up calling through more levels of indirection than vanilla varargs can handle, and not all machines have vfprintf/vsyslog/whatever! 6 params oughta be enough. */ void holler (str, p1, p2, p3, p4, p5, p6) char * str; char * p1, * p2, * p3, * p4, * p5, * p6; { if (o_verbose) { fprintf (stderr, str, p1, p2, p3, p4, p5, p6); #ifdef HAVE_BIND if (h_errno) { /* if host-lookup variety of error ... */ if (h_errno > 4) /* oh no you don't, either */ fprintf (stderr, "preposterous h_errno: %d", h_errno); else fprintf (stderr, h_errs[h_errno]); /* handle it here */ h_errno = 0; /* and reset for next call */ } #endif if (errno) { /* this gives funny-looking messages, but */ perror (" "); /* it's more portable than sys_errlist[]... */ } else /* xxx: do something better? */ fprintf (stderr, "\n"); fflush (stderr); } } /* holler */ /* bail : error-exit handler, callable from anywhere */ void bail (str, p1, p2, p3, p4, p5, p6) char * str; char * p1, * p2, * p3, * p4, * p5, * p6; { o_verbose = 1; holler (str, p1, p2, p3, p4, p5, p6); close (netfd); sleep (1); exit (1); } /* bail */ /* catch : no-brainer interrupt handler */ void catch () { errno = 0; if (o_verbose > 1) /* normally we don't care */ bail (wrote_txt, wrote_net, wrote_out); bail (" punt!"); } /* timeout and other signal handling cruft */ void tmtravel () { signal (SIGALRM, SIG_IGN); alarm (0); if (jval == 0) bail ("spurious timer interrupt!"); longjmp (jbuf, jval); } /* arm : set the timer. Zero secs arg means unarm */ void arm (num, secs) unsigned int num; unsigned int secs; { if (secs == 0) { /* reset */ signal (SIGALRM, SIG_IGN); alarm (0); jval = 0; } else { /* set */ signal (SIGALRM, tmtravel); alarm (secs); jval = num; } /* if secs */ } /* arm */ /* Hmalloc : malloc up what I want, rounded up to *4, and pre-zeroed. Either succeeds or bails out on its own, so that callers don't have to worry about it. */ char * Hmalloc (size) unsigned int size; { unsigned int s = (size + 4) & 0xfffffffc; /* 4GB?! */ char * p = malloc (s); if (p != NULL) memset (p, 0, s); else bail ("Hmalloc %d failed", s); return (p); } /* Hmalloc */ /* findline : find the next newline in a buffer; return inclusive size of that "line", or the entire buffer size, so the caller knows how much to then write(). Not distinguishing \n vs \r\n for the nonce; it just works as is... */ unsigned int findline (buf, siz) char * buf; unsigned int siz; { register char * p; register int x; if (! buf) /* various sanity checks... */ return (0); if (siz > BIGSIZ) return (0); x = siz; for (p = buf; x > 0; x--) { if (*p == '\n') { x = (int) (p - buf); x++; /* 'sokay if it points just past the end! */ Debug (("findline returning %d", x)) return (x); } p++; } /* for */ Debug (("findline returning whole thing: %d", siz)) return (siz); } /* findline */ /* comparehosts : cross-check the host_poop we have so far against new gethostby*() info, and holler about mismatches. Perhaps gratuitous, but it can't hurt to point out when someone's DNS is fukt. Returns 1 if mismatch, in case someone else wants to do something about it. */ int comparehosts (poop, hp) HINF * poop; struct hostent * hp; { errno = 0; h_errno = 0; /* The DNS spec is officially case-insensitive, but for those times when you *really* wanna see any and all discrepancies, by all means define this. */ #ifdef ANAL if (strcmp (poop->name, hp->h_name) != 0) { /* case-sensitive */ #else if (strcasecmp (poop->name, hp->h_name) != 0) { /* normal */ #endif holler ("DNS fwd/rev mismatch: %s != %s", poop->name, hp->h_name); return (1); } return (0); /* ... do we need to do anything over and above that?? */ } /* comparehosts */ /* gethostpoop : resolve a host 8 ways from sunday; return a new host_poop struct with its info. The argument can be a name or [ascii] IP address; it will try its damndest to deal with it. "numeric" governs whether we do any DNS at all, and we also check o_verbose for what's appropriate work to do. */ HINF * gethostpoop (name, numeric) char * name; USHORT numeric; { struct hostent * hostent; struct in_addr iaddr; register HINF * poop = NULL; register int x; /* I really want to strangle the twit who dreamed up all these sockaddr and hostent abstractions, and then forced them all to be incompatible with each other so you *HAVE* to do all this ridiculous casting back and forth. If that wasn't bad enough, all the doc insists on referring to local ports and addresses as "names", which makes NO sense down at the bare metal. What an absolutely horrid paradigm, and to think of all the people who have been wasting significant amounts of time fighting with this stupid deliberate obfuscation over the last 10 years... then again, I like languages wherein a pointer is a pointer, what you put there is your own business, the compiler stays out of your face, and sheep are nervous. Maybe that's why my C code reads like assembler half the time... */ /* If we want to see all the DNS stuff, do the following hair -- if inet_addr, do reverse and forward with any warnings; otherwise try to do forward and reverse with any warnings. In other words, as long as we're here, do a complete DNS check on these clowns. Yes, it slows things down a bit for a first run, but once it's cached, who cares? */ errno = 0; h_errno = 0; if (name) poop = (HINF *) Hmalloc (sizeof (HINF)); if (! poop) bail ("gethostpoop fuxored"); strcpy (poop->name, unknown); /* preload it */ /* see wzv:workarounds.c for dg/ux return-a-struct inet_addr lossage */ iaddr.s_addr = inet_addr (name); if (iaddr.s_addr == INADDR_NONE) { /* here's the great split: names... */ if (numeric) bail ("Can't parse %s as an IP address", name); hostent = gethostbyname (name); if (! hostent) /* failure to look up a name is fatal, since we can't do anything with it */ bail ("%s: forward host lookup failed: ", name); strncpy (poop->name, hostent->h_name, MAXHOSTNAMELEN - 2); for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) { memcpy (&poop->iaddrs[x], hostent->h_addr_list[x], sizeof (IA)); strncpy (poop->addrs[x], inet_ntoa (poop->iaddrs[x]), sizeof (poop->addrs[0])); } /* for x -> addrs, part A */ if (! o_verbose) /* if we didn't want to see the */ return (poop); /* inverse stuff, we're done. */ /* do inverse lookups in separate loop based on our collected forward addrs, since gethostby* tends to crap into the same buffer over and over */ for (x = 0; poop->iaddrs[x].s_addr && (x < 8); x++) { hostent = gethostbyaddr ((char *)&poop->iaddrs[x], sizeof (IA), AF_INET); if ((! hostent) || (! hostent-> h_name)) holler ("Warning: inverse host lookup failed for %s: ", poop->addrs[x]); else (void) comparehosts (poop, hostent); } /* for x -> addrs, part B */ } else { /* not INADDR_NONE: numeric addresses... */ memcpy (poop->iaddrs, &iaddr, sizeof (IA)); strncpy (poop->addrs[0], inet_ntoa (iaddr), sizeof (poop->addrs)); if (numeric) /* if numeric-only, we're done */ return (poop); if (! o_verbose) /* likewise if we don't want */ return (poop); /* the full DNS hair */ hostent = gethostbyaddr ((char *) &iaddr, sizeof (IA), AF_INET); /* numeric or not, failure to look up a PTR is *not* considered fatal */ if (! hostent) holler ("%s: inverse host lookup failed: ", name); else { strncpy (poop->name, hostent->h_name, MAXHOSTNAMELEN - 2); hostent = gethostbyname (poop->name); if ((! hostent) || (! hostent->h_addr_list[0])) holler ("Warning: forward host lookup failed for %s: ", poop->name); else (void) comparehosts (poop, hostent); } /* if hostent */ } /* INADDR_NONE Great Split */ /* whatever-all went down previously, we should now have a host_poop struct with at least one IP address in it. */ h_errno = 0; return (poop); } /* gethostpoop */ /* getportpoop : Same general idea as gethostpoop -- look up a port in /etc/services, fill in global port_poop, but return the actual port *number*. Pass ONE of: pstring to resolve stuff like "23" or "exec"; pnum to reverse-resolve something that's already a number. If o_nflag is on, fill in what we can but skip the getservby??? stuff. Might as well have consistent behavior here, and it *is* faster. */ USHORT getportpoop (pstring, pnum) char * pstring; unsigned int pnum; { struct servent * servent; register int x; register int y; char * whichp = p_tcp; if (o_udpmode) whichp = p_udp; portpoop->name[0] = '?'; /* fast preload */ portpoop->name[1] = '\0'; /* case 1: reverse-lookup of a number; placed first since this case is much more frequent if we're scanning */ if (pnum) { if (pstring) /* one or the other, pleeze */ return (0); x = pnum; if (o_nflag) /* go faster, skip getservbyblah */ goto gp_finish; y = htons (x); /* gotta do this -- see Fig.1 below */ servent = getservbyport (y, whichp); if (servent) { y = ntohs (servent->s_port); if (x != y) /* "never happen" */ holler ("Warning: port-bynum mismatch, %d != %d", x, y); strncpy (portpoop->name, servent->s_name, sizeof (portpoop->name)); } /* if servent */ goto gp_finish; } /* if pnum */ /* case 2: resolve a string, but we still give preference to numbers instead of trying to resolve conflicts. None of the entries in *my* extensive /etc/services begins with a digit, so this should "always work" unless you're at 3com and have some company-internal services defined... */ if (pstring) { if (pnum) /* one or the other, pleeze */ return (0); x = atoi (pstring); if (x) return (getportpoop (NULL, x)); /* recurse for numeric-string-arg */ if (o_nflag) /* can't use names! */ return (0); servent = getservbyname (pstring, whichp); if (servent) { strncpy (portpoop->name, servent->s_name, sizeof (portpoop->name)); x = ntohs (servent->s_port); goto gp_finish; } /* if servent */ } /* if pstring */ return (0); /* catches any problems so far */ /* Obligatory netdb.h-inspired rant: servent.s_port is supposed to be an int. Despite this, we still have to treat it as a short when copying it around. Not only that, but we have to convert it *back* into net order for getservbyport to work. Manpages generally aren't clear on all this, but there are plenty of examples in which it is just quietly done. More BSD lossage... since everything getserv* ever deals with is local to our own host, why bother with all this network-order/host-order crap at all?! That should be saved for when we want to actually plug the port[s] into some real network calls -- and guess what, we have to *re*-convert at that point as well. Fuckheads. */ gp_finish: /* Fall here whether or not we have a valid servent at this point, with x containing our [host-order and therefore useful, dammit] port number */ sprintf (portpoop->anum, "%d", x); /* always load any numeric specs! */ portpoop->num = (x & 0xffff); /* ushort, remember... */ return (portpoop->num); } /* getportpoop */ /* nextport : Come up with the next port to try, be it random or whatever. "block" is a ptr to randports array, whose bytes [so far] carry these meanings: 0 ignore 1 to be tested 2 tested [which is set as we find them here] returns a USHORT random port, or 0 if all the t-b-t ones are used up. */ USHORT nextport (block) char * block; { register unsigned int x; register unsigned int y; y = 70000; /* high safety count for rnd-tries */ while (y > 0) { x = (RAND() & 0xffff); if (block[x] == 1) { /* try to find a not-done one... */ block[x] = 2; break; } x = 0; /* bummer. */ y--; } /* while y */ if (x) return (x); y = 65535; /* no random one, try linear downsearch */ while (y > 0) { /* if they're all used, we *must* be sure! */ if (block[y] == 1) { block[y] = 2; break; } y--; } /* while y */ if (y) return (y); /* at least one left */ return (0); /* no more left! */ } /* nextport */ /* loadports : set "to be tested" indications in BLOCK, from LO to HI. Almost too small to be a separate routine, but makes main() a little cleaner... */ void loadports (block, lo, hi) char * block; USHORT lo; USHORT hi; { USHORT x; if (! block) bail ("loadports: no block?!"); if ((! lo) || (! hi)) bail ("loadports: bogus values %d, %d", lo, hi); x = hi; while (lo <= x) { block[x] = 1; x--; } } /* loadports */ #ifdef GAPING_SECURITY_HOLE char * pr00gie = NULL; /* global ptr to -e arg */ /* doexec : fiddle all the file descriptors around, and hand off to another prog. Sort of like a one-off "poor man's inetd". This is the only section of code that would be security-critical, which is why it's ifdefed out by default. Use at your own hairy risk; if you leave shells lying around behind open listening ports you deserve to lose!! */ doexec (fd) int fd; { register char * p; dup2 (fd, 0); /* the precise order of fiddlage */ close (fd); /* is apparently crucial; this is */ dup2 (0, 1); /* swiped directly out of "inetd". */ dup2 (0, 2); p = strrchr (pr00gie, '/'); /* shorter argv[0] */ if (p) p++; else p = pr00gie; Debug (("gonna exec %s as %s...", pr00gie, p)) execl (pr00gie, p, NULL); bail ("exec %s failed", pr00gie); /* this gets sent out. Hmm... */ } /* doexec */ #endif /* GAPING_SECURITY_HOLE */ /* doconnect : do all the socket stuff, and return an fd for one of an open outbound TCP connection a UDP stub-socket thingie with appropriate socket options set up if we wanted source-routing, or an unconnected TCP or UDP socket to listen on. Examines various global o_blah flags to figure out what-all to do. */ int doconnect (rad, rp, lad, lp) IA * rad; USHORT rp; IA * lad; USHORT lp; { register int nnetfd; register int rr; int x, y; errno = 0; /* grab a socket; set opts */ newskt: if (o_udpmode) nnetfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); else nnetfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (nnetfd < 0) bail ("Can't get socket"); if (nnetfd == 0) /* if stdin was closed this might *be* 0, */ goto newskt; /* so grab another. See text for why... */ x = 1; rr = setsockopt (nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)); if (rr == -1) holler ("nnetfd reuseaddr failed"); /* ??? */ #ifdef SO_REUSEPORT /* doesnt exist everywhere... */ rr = setsockopt (nnetfd, SOL_SOCKET, SO_REUSEPORT, &x, sizeof (x)); if (rr == -1) holler ("nnetfd reuseport failed"); /* ??? */ #endif #if 0 /* If you want to screw with RCVBUF/SNDBUF, do it here. Liudvikas Bukys at Rochester sent this example, which would involve YET MORE options and is just archived here in case you want to mess with it. o_xxxbuf are global integers set in main() getopt loop, and check for rr == 0 afterward. */ rr = setsockopt(nnetfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf); rr = setsockopt(nnetfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf); #endif /* fill in all the right sockaddr crud */ lclend->sin_family = AF_INET; /* fill in all the right sockaddr crud */ lclend->sin_family = AF_INET; remend->sin_family = AF_INET; /* if lad/lp, do appropriate binding */ if (lad) memcpy (&lclend->sin_addr.s_addr, lad, sizeof (IA)); if (lp) lclend->sin_port = htons (lp); rr = 0; if (lad || lp) { x = (int) lp; /* try a few times for the local bind, a la ftp-data-port... */ for (y = 4; y > 0; y--) { rr = bind (nnetfd, (SA *)lclend, sizeof (SA)); if (rr == 0) break; if (errno != EADDRINUSE) break; else { holler ("retrying local %s:%d", inet_ntoa (lclend->sin_addr), lp); sleep (2); errno = 0; /* clear from sleep */ } /* if EADDRINUSE */ } /* for y counter */ } /* if lad or lp */ if (rr) bail ("Can't grab %s:%d with bind", inet_ntoa(lclend->sin_addr), lp); if (o_listen) return (nnetfd); /* thanks, that's all for today */ memcpy (&remend->sin_addr.s_addr, rad, sizeof (IA)); remend->sin_port = htons (rp); /* rough format of LSRR option and explanation of weirdness. Option comes after IP-hdr dest addr in packet, padded to *4, and ihl > 5. IHL is multiples of 4, i.e. real len = ip_hl << 2. type 131 1 ; 0x83: copied, option class 0, number 3 len 1 ; of *whole* option! pointer 1 ; nxt-hop-addr; 1-relative, not 0-relative addrlist... var ; 4 bytes per hop-addr pad-to-32 var ; ones, i.e. "NOP" If we want to route A -> B via hops C and D, we must add C, D, *and* B to the options list. Why? Because when we hand the kernel A -> B with list C, D, B the "send shuffle" inside the kernel changes it into A -> C with list D, B and the outbound packet gets sent to C. If B wasn't also in the hops list, the final destination would have been lost at this point. When C gets the packet, it changes it to A -> D with list C', B where C' is the interface address that C used to forward the packet. This "records" the route hop from B's point of view, i.e. which address points "toward" B. This is to make B better able to return the packets. The pointer gets bumped by 4, so that D does the right thing instead of trying to forward back to C. When B finally gets the packet, it sees that the pointer is at the end of the LSRR list and is thus "completed". B will then try to use the packet instead of forwarding it, i.e. deliver it up to some application. Note that by moving the pointer yourself, you could send the traffic directly to B but have it return via your preconstructed source-route. Playing with this and watching "tcpdump -v" is the best way to understand what's going on. Only works for TCP in BSD-flavor kernels. UDP is a loss; udp_input calls stripoptions() early on, and the code to save the srcrt is notdef'ed. Linux is also still a loss at 1.3.x it looks like; the lsrr code is { }... */ /* if any -g arguments were given, set up source-routing. We hit this after the gates are all looked up and ready to rock, any -G pointer is set, and gatesidx is now the *number* of hops */ if (gatesidx) { /* if we wanted any srcrt hops ... */ /* don't even bother compiling if we can't do IP options here! */ #ifdef IP_OPTIONS if (! optbuf) { /* and don't already *have* a srcrt set */ char * opp; /* then do all this setup hair */ optbuf = Hmalloc (48); opp = optbuf; *opp++ = IPOPT_LSRR; /* option */ *opp++ = (char) (((gatesidx + 1) * sizeof (IA)) + 3) & 0xff; /* length */ *opp++ = gatesptr; /* pointer */ /* opp now points at first hop addr -- insert the intermediate gateways */ for ( x = 0; x < gatesidx; x++) { memcpy (opp, gates[x]->iaddrs, sizeof (IA)); opp += sizeof (IA); } /* and tack the final destination on the end [needed!] */ memcpy (opp, rad, sizeof (IA)); opp += sizeof (IA); *opp = IPOPT_NOP; /* alignment filler */ } /* if empty optbuf */ /* calculate length of whole option mess, which is (3 + [hops] + [final] + 1), and apply it [have to do this every time through, of course] */ x = ((gatesidx + 1) * sizeof (IA)) + 4; rr = setsockopt (nnetfd, IPPROTO_IP, IP_OPTIONS, optbuf, x); if (rr == -1) bail ("srcrt setsockopt fuxored"); #else /* IP_OPTIONS */ holler ("Warning: source routing unavailable on this machine, ignoring"); #endif /* IP_OPTIONS*/ } /* if gatesidx */ /* wrap connect inside a timer, and hit it */ arm (1, o_wait); if (setjmp (jbuf) == 0) { rr = connect (nnetfd, (SA *)remend, sizeof (SA)); } else { /* setjmp: connect failed... */ rr = -1; errno = ETIMEDOUT; /* fake it */ } arm (0, 0); if (rr == 0) return (nnetfd); close (nnetfd); /* clean up junked socket FD!! */ return (-1); } /* doconnect */ /* dolisten : just like doconnect, and in fact calls a hunk of doconnect, but listens for incoming and returns an open connection *from* someplace. If we were given host/port args, any connections from elsewhere are rejected. This in conjunction with local-address binding should limit things nicely... */ int dolisten (rad, rp, lad, lp) IA * rad; USHORT rp; IA * lad; USHORT lp; { register int nnetfd; register int rr; HINF * whozis = NULL; int x; char * cp; USHORT z; errno = 0; /* Pass everything off to doconnect, who in o_listen mode just gets a socket */ nnetfd = doconnect (rad, rp, lad, lp); if (nnetfd <= 0) return (-1); if (o_udpmode) { /* apparently UDP can listen ON */ if (! lp) /* "port 0", but that's not useful */ bail ("UDP listen needs -p arg"); } else { rr = listen (nnetfd, 1); /* gotta listen() before we can get */ if (rr < 0) /* our local random port. sheesh. */ bail ("local listen fuxored"); } /* Various things that follow temporarily trash bigbuf_net, which might contain a copy of any recvfrom()ed packet, but we'll read() another copy later. */ /* I can't believe I have to do all this to get my own goddamn bound address and port number. It should just get filled in during bind() or something. All this is only useful if we didn't say -p for listening, since if we said -p we *know* what port we're listening on. At any rate we won't bother with it all unless we wanted to see it, although listening quietly on a random unknown port is probably not very useful without "netstat". */ if (o_verbose) { x = sizeof (SA); /* how 'bout getsockNUM instead, pinheads?! */ rr = getsockname (nnetfd, (SA *) lclend, &x); if (rr < 0) holler ("local getsockname failed"); strcpy (bigbuf_net, "listening on ["); /* buffer reuse... */ if (lclend->sin_addr.s_addr) strcat (bigbuf_net, inet_ntoa (lclend->sin_addr)); else strcat (bigbuf_net, "any"); strcat (bigbuf_net, "] %d ..."); z = ntohs (lclend->sin_port); holler (bigbuf_net, z); } /* verbose -- whew!! */ /* UDP is a speeeeecial case -- we have to do I/O *and* get the calling party's particulars all at once, listen() and accept() don't apply. At least in the BSD universe, however, recvfrom/PEEK is enough to tell us something came in, and we can set things up so straight read/write actually does work after all. Yow. YMMV on strange platforms! */ if (o_udpmode) { x = sizeof (SA); /* retval for recvfrom */ arm (2, o_wait); /* might as well timeout this, too */ if (setjmp (jbuf) == 0) { /* do timeout for initial connect */ rr = recvfrom /* and here we block... */ (nnetfd, bigbuf_net, BIGSIZ, MSG_PEEK, (SA *) remend, &x); Debug (("dolisten/recvfrom ding, rr = %d, netbuf %s ", rr, bigbuf_net)) } else goto dol_tmo; /* timeout */ arm (0, 0); /* I'm not completely clear on how this works -- BSD seems to make UDP just magically work in a connect()ed context, but we'll undoubtedly run into systems this deal doesn't work on. For now, we apparently have to issue a connect() on our just-tickled socket so we can write() back. Again, why the fuck doesn't it just get filled in and taken care of?! This hack is anything but optimal. Basically, if you want your listener to also be able to send data back, you need this connect() line, which also has the side effect that now anything from a different source or even a different port on the other end won't show up and will cause ICMP errors. I guess that's what they meant by "connect". Let's try to remember what the "U" is *really* for, eh? */ rr = connect (nnetfd, (SA *)remend, sizeof (SA)); goto whoisit; } /* o_udpmode */ /* fall here for TCP */ x = sizeof (SA); /* retval for accept */ arm (2, o_wait); /* wrap this in a timer, too; 0 = forever */ if (setjmp (jbuf) == 0) { rr = accept (nnetfd, (SA *)remend, &x); } else goto dol_tmo; /* timeout */ arm (0, 0); close (nnetfd); /* dump the old socket */ nnetfd = rr; /* here's our new one */ whoisit: if (rr < 0) goto dol_err; /* bail out if any errors so far */ /* If we can, look for any IP options. Useful for testing the receiving end of such things, and is a good exercise in dealing with it. We do this before the connect message, to ensure that the connect msg is uniformly the LAST thing to emerge after all the intervening crud. Doesn't work for UDP on any machines I've tested, but feel free to surprise me. */ #ifdef IP_OPTIONS if (! o_verbose) /* if we wont see it, we dont care */ goto dol_noop; optbuf = Hmalloc (40); x = 40; rr = getsockopt (nnetfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x); if (rr < 0) holler ("getsockopt failed"); Debug (("ipoptions ret len %d", x)) if (x) { /* we've got options, lessee em... */ unsigned char * q = (unsigned char *) optbuf; char * p = bigbuf_net; /* local variables, yuk! */ char * pp = &bigbuf_net[128]; /* get random space farther out... */ memset (bigbuf_net, 0, 256); /* clear it all first */ while (x > 0) { sprintf (pp, "%2.2x ", *q); /* clumsy, but works: turn into hex */ strcat (p, pp); /* and build the final string */ q++; p++; x--; } holler ("IP options: %s", bigbuf_net); } /* if x, i.e. any options */ dol_noop: #endif /* IP_OPTIONS */ /* find out what address the connection was *to* on our end, in case we're doing a listen-on-any on a multihomed machine. This allows one to offer different services via different alias addresses, such as the "virtual web site" hack. */ memset (bigbuf_net, 0, 64); cp = &bigbuf_net[32]; x = sizeof (SA); rr = getsockname (nnetfd, (SA *) lclend, &x); if (rr < 0) holler ("post-rcv getsockname failed"); strcpy (cp, inet_ntoa (lclend->sin_addr)); /* now check out who it is. We don't care about mismatched DNS names here, but any ADDR and PORT we specified had better fucking well match the caller. Converting from addr to inet_ntoa and back again is a bit of a kludge, but gethostpoop wants a string and there's much gnarlier code out there already, so I don't feel bad. The *real* question is why BFD sockets wasn't designed to allow listens for connections *from* specific hosts/ports, instead of requiring the caller to accept the connection and then reject undesireable ones by closing. In other words, we need a TCP MSG_PEEK. */ z = ntohs (remend->sin_port); strcpy (bigbuf_net, inet_ntoa (remend->sin_addr)); whozis = gethostpoop (bigbuf_net, o_nflag); errno = 0; x = 0; /* use as a flag... */ if (rad) /* xxx: fix to go down the *list* if we have one? */ if (memcmp (rad, whozis->iaddrs, sizeof (SA))) x = 1; if (rp) if (z != rp) x = 1; if (x) /* guilty! */ bail ("invalid connection to [%s] from %s [%s] %d", cp, whozis->name, whozis->addrs[0], z); holler ("connect to [%s] from %s [%s] %d", /* oh, you're okay.. */ cp, whozis->name, whozis->addrs[0], z); return (nnetfd); /* open! */ dol_tmo: errno = ETIMEDOUT; /* fake it */ dol_err: close (nnetfd); return (-1); } /* dolisten */ /* udptest : fire a couple of packets at a UDP target port, just to see if it's really there. On BSD kernels, ICMP host/port-unreachable errors get delivered to our socket as ECONNREFUSED write errors. On SV kernels, we lose; we'll have to collect and analyze raw ICMP ourselves a la satan's probe_udp_ports backend. Guess where one could swipe the appropriate code from... Use the time delay between writes if given, otherwise use the "tcp ping" trick for getting the RTT. [I got that idea from pluvius, and warped it.] Return either the original fd, or clean up and return -1. */ udptest (fd, where) int fd; IA * where; { register int rr; rr = write (fd, bigbuf_in, 1); if (rr != 1) holler ("udptest first write failed?! errno %d", errno); if (o_wait) sleep (o_wait); else { /* use the tcp-ping trick: try connecting to a normally refused port, which causes us to block for the time that SYN gets there and RST gets back. Not completely reliable, but it *does* mostly work. */ o_udpmode = 0; /* so doconnect does TCP this time */ /* Set a temporary connect timeout, so packet filtration doesnt cause us to hang forever, and hit it */ o_wait = 5; /* enough that we'll notice?? */ rr = doconnect (where, SLEAZE_PORT, 0, 0); if (rr > 0) close (rr); /* in case it *did* open */ o_wait = 0; /* reset it */ o_udpmode++; /* we *are* still doing UDP, right? */ } /* if o_wait */ errno = 0; /* clear from sleep */ rr = write (fd, bigbuf_in, 1); if (rr == 1) /* if write error, no UDP listener */ return (fd); close (fd); /* use it or lose it! */ return (-1); } /* udptest */ /* oprint : Hexdump bytes shoveled either way to a running logfile, in the format: D offset - - - - --- 16 bytes --- - - - - # .... ascii ..... where "which" sets the direction indicator, D: 0 -- sent to network, or ">" 1 -- rcvd and printed to stdout, or "<" and "buf" and "n" are data-block and length. If the current block generates a partial line, so be it; we *want* that lockstep indication of who sent what when. Adapted from dgaudet's original example -- but must be ripping *fast*, since we don't want to be too disk-bound... */ void oprint (which, buf, n) int which; char * buf; int n; { int bc; /* in buffer count */ int obc; /* current "global" offset */ int soc; /* stage write count */ register unsigned char * p; /* main buf ptr; m.b. unsigned here */ register unsigned char * op; /* out hexdump ptr */ register unsigned char * a; /* out asc-dump ptr */ register int x; register unsigned int y; if (! ofd) bail ("oprint called with no open fd?!"); if (n == 0) return; op = stage; if (which) { *op = '<'; obc = wrote_out; /* use the globals! */ } else { *op = '>'; obc = wrote_net; } op++; /* preload "direction" */ *op = ' '; p = (unsigned char *) buf; bc = n; stage[59] = '#'; /* preload separator */ stage[60] = ' '; while (bc) { /* for chunk-o-data ... */ x = 16; soc = 78; /* len of whole formatted line */ if (bc < x) { soc = soc - 16 + bc; /* fiddle for however much is left */ x = (bc * 3) + 11; /* 2 digits + space per, after D & offset */ op = &stage[x]; x = 16 - bc; while (x) { *op++ = ' '; /* preload filler spaces */ *op++ = ' '; *op++ = ' '; x--; } x = bc; /* re-fix current linecount */ } /* if bc < x */ bc -= x; /* fix wrt current line size */ sprintf (&stage[2], "%8.8x ", obc); /* xxx: still slow? */ obc += x; /* fix current offset */ op = &stage[11]; /* where hex starts */ a = &stage[61]; /* where ascii starts */ while (x) { /* for line of dump, however long ... */ y = (int)(*p >> 4); /* hi half */ *op = hexnibs[y]; op++; y = (int)(*p & 0x0f); /* lo half */ *op = hexnibs[y]; op++; *op = ' '; op++; if ((*p > 31) && (*p < 127)) *a = *p; /* printing */ else *a = '.'; /* nonprinting, loose def */ a++; p++; x--; } /* while x */ *a = '\n'; /* finish the line */ x = write (ofd, stage, soc); if (x < 0) bail ("ofd write err"); } /* while bc */ } /* oprint */ #ifdef TELNET USHORT o_tn = 0; /* global -t option */ /* atelnet : Answer anything that looks like telnet negotiation with don't/won't. This doesn't modify any data buffers, update the global output count, or show up in a hexdump -- it just shits into the outgoing stream. Idea and codebase from Mudge@l0pht.com. */ void atelnet (buf, size) unsigned char * buf; /* has to be unsigned here! */ unsigned int size; { static unsigned char obuf [4]; /* tiny thing to build responses into */ register int x; register unsigned char y; register unsigned char * p; y = 0; p = buf; x = size; while (x > 0) { if (*p != 255) /* IAC? */ goto notiac; obuf[0] = 255; p++; x--; if ((*p == 251) || (*p == 252)) /* WILL or WONT */ y = 254; /* -> DONT */ if ((*p == 253) || (*p == 254)) /* DO or DONT */ y = 252; /* -> WONT */ if (y) { obuf[1] = y; p++; x--; obuf[2] = *p; /* copy actual option byte */ (void) write (netfd, obuf, 3); /* if one wanted to bump wrote_net or do a hexdump line, here's the place */ y = 0; } /* if y */ notiac: p++; x--; } /* while x */ } /* atelnet */ #endif /* TELNET */ /* readwrite : handle stdin/stdout/network I/O. Bwahaha!! -- the select loop from hell. In this instance, return what might become our exit status. */ int readwrite (fd) int fd; { register int rr; register char * zp; /* stdin buf ptr */ register char * np; /* net-in buf ptr */ unsigned int rzleft; unsigned int rnleft; USHORT netretry; /* net-read retry counter */ USHORT wretry; /* net-write sanity counter */ USHORT wfirst; /* one-shot flag to skip first net read */ /* if you don't have all this FD_* macro hair in sys/types.h, you'll have to either find it or do your own bit-bashing: *ding1 |= (1 << fd), etc... */ if (fd > FD_SETSIZE) { holler ("Preposterous fd value %d", fd); return (1); } FD_SET (fd, ding1); /* global: the net is open */ netretry = 2; wfirst = 0; rzleft = rnleft = 0; if (insaved) { rzleft = insaved; /* preload multi-mode fakeouts */ zp = bigbuf_in; wfirst = 1; if (Single) /* if not scanning, this is a one-off first */ insaved = 0; /* buffer left over from argv construction, */ else { FD_CLR (0, ding1); /* OR we've already got our repeat chunk, */ close (0); /* so we won't need any more stdin */ } /* Single */ } /* insaved */ if (o_interval) sleep (o_interval); /* pause *before* sending stuff, too */ errno = 0; /* clear from sleep, close, whatever */ /* and now the big ol' select shoveling loop ... */ while (FD_ISSET (fd, ding1)) { /* i.e. till the *net* closes! */ wretry = 8200; /* more than we'll ever hafta write */ if (wfirst) { /* any saved stdin buffer? */ wfirst = 0; /* clear flag for the duration */ goto shovel; /* and go handle it first */ } *ding2 = *ding1; /* FD_COPY ain't portable... */ /* some systems, notably linux, crap into their select timers on return, so we create a expendable copy and give *that* to select. *Fuck* me ... */ if (timer1) memcpy (timer2, timer1, sizeof (struct timeval)); rr = select (16, ding2, 0, 0, timer2); /* here it is, kiddies */ if (rr < 0) { if (errno != EINTR) { /* might have gotten ^Zed, etc ?*/ holler ("select fuxored"); close (fd); return (1); } } /* select fuckup */ /* if we have a timeout AND stdin is closed AND we haven't heard anything from the net during that time, assume it's dead and close it too. */ if (rr == 0) { if (! FD_ISSET (0, ding1)) netretry--; /* we actually try a coupla times. */ if (! netretry) { if (o_verbose > 1) /* normally we don't care */ holler ("net timeout"); close (fd); return (0); /* not an error! */ } } /* select timeout */ /* xxx: should we check the exception fds too? The read fds seem to give us the right info, and none of the examples I found bothered. */ /* Ding!! Something arrived, go check all the incoming hoppers, net first */ if (FD_ISSET (fd, ding2)) { /* net: ding! */ /*rr = read (fd, bigbuf_net, BIGSIZ);*/ rr = farm9crypt_read (fd, bigbuf_net, BIGSIZ); if (rr <= 0) { FD_CLR (fd, ding1); /* net closed, we'll finish up... */ rzleft = 0; /* can't write anymore: broken pipe */ } else { rnleft = rr; np = bigbuf_net; #ifdef TELNET if (o_tn) atelnet (np, rr); /* fake out telnet stuff */ #endif /* TELNET */ } /* if rr */ Debug (("got %d from the net, errno %d", rr, errno)) } /* net:ding */ /* if we're in "slowly" mode there's probably still stuff in the stdin buffer, so don't read unless we really need MORE INPUT! MORE INPUT! */ if (rzleft) goto shovel; /* okay, suck more stdin */ if (FD_ISSET (0, ding2)) { /* stdin: ding! */ rr = read (0, bigbuf_in, BIGSIZ); /* Considered making reads here smaller for UDP mode, but 8192-byte mobygrams are kinda fun and exercise the reassembler. */ if (rr <= 0) { /* at end, or fukt, or ... */ FD_CLR (0, ding1); /* disable and close stdin */ close (0); } else { rzleft = rr; zp = bigbuf_in; /* special case for multi-mode -- we'll want to send this one buffer to every open TCP port or every UDP attempt, so save its size and clean up stdin */ if (! Single) { /* we might be scanning... */ insaved = rr; /* save len */ FD_CLR (0, ding1); /* disable further junk from stdin */ close (0); /* really, I mean it */ } /* Single */ } /* if rr/read */ } /* stdin:ding */ shovel: /* now that we've dingdonged all our thingdings, send off the results. Geez, why does this look an awful lot like the big loop in "rsh"? ... not sure if the order of this matters, but write net -> stdout first. */ /* sanity check. Works because they're both unsigned... */ if ((rzleft > 8200) || (rnleft > 8200)) { holler ("Bogus buffers: %d, %d", rzleft, rnleft); rzleft = rnleft = 0; } /* net write retries sometimes happen on UDP connections */ if (! wretry) { /* is something hung? */ holler ("too many output retries"); return (1); } if (rnleft) { rr = write (1, np, rnleft); if (rr > 0) { if (o_wfile) oprint (1, np, rr); /* log the stdout */ np += rr; /* fix up ptrs and whatnot */ rnleft -= rr; /* will get sanity-checked above */ wrote_out += rr; /* global count */ } Debug (("wrote %d to stdout, errno %d", rr, errno)) } /* rnleft */ if (rzleft) { if (o_interval) /* in "slowly" mode ?? */ rr = findline (zp, rzleft); else rr = rzleft; /*rr = write (fd, zp, rr);*/ /* one line, or the whole buffer */ rr = farm9crypt_write (fd, zp, rr); /* one line, or the whole buffer */ if (rr > 0) { if (o_wfile) oprint (0, zp, rr); /* log what got sent */ zp += rr; rzleft -= rr; wrote_net += rr; /* global count */ } Debug (("wrote %d to net, errno %d", rr, errno)) } /* rzleft */ if (o_interval) { /* cycle between slow lines, or ... */ sleep (o_interval); errno = 0; /* clear from sleep */ continue; /* ...with hairy select loop... */ } if ((rzleft) || (rnleft)) { /* shovel that shit till they ain't */ wretry--; /* none left, and get another load */ goto shovel; } } /* while ding1:netfd is open */ /* XXX: maybe want a more graceful shutdown() here, or screw around with linger times?? I suspect that I don't need to since I'm always doing blocking reads and writes and my own manual "last ditch" efforts to read the net again after a timeout. I haven't seen any screwups yet, but it's not like my test network is particularly busy... */ close (fd); return (0); } /* readwrite */ /* main : now we pull it all together... */ main (argc, argv) int argc; char ** argv; { #ifndef HAVE_GETOPT extern char * optarg; extern int optind, optopt; #endif register int x; register char *cp; HINF * gp; HINF * whereto = NULL; HINF * wherefrom = NULL; IA * ouraddr = NULL; IA * themaddr = NULL; USHORT o_lport = 0; USHORT ourport = 0; USHORT loport = 0; /* for scanning stuff */ USHORT hiport = 0; USHORT curport = 0; char * randports = NULL; char * crypt_key_f9 = "metallica"; char keystr[32]; /* if(farm9crypt_initialized() == 0) { farm9crypt_init(crypt_key_f9); } */ #ifdef HAVE_BIND /* can *you* say "cc -yaddayadda netcat.c -lresolv -l44bsd" on SunLOSs? */ res_init(); #endif /* I was in this barbershop quartet in Skokie IL ... */ /* round up the usual suspects, i.e. malloc up all the stuff we need */ lclend = (SAI *) Hmalloc (sizeof (SA)); remend = (SAI *) Hmalloc (sizeof (SA)); bigbuf_in = Hmalloc (BIGSIZ); bigbuf_net = Hmalloc (BIGSIZ); ding1 = (fd_set *) Hmalloc (sizeof (fd_set)); ding2 = (fd_set *) Hmalloc (sizeof (fd_set)); portpoop = (PINF *) Hmalloc (sizeof (PINF)); errno = 0; gatesptr = 4; h_errno = 0; /* catch a signal or two for cleanup */ signal (SIGINT, catch); signal (SIGQUIT, catch); signal (SIGTERM, catch); /* and suppress others... */ #ifdef SIGURG signal (SIGURG, SIG_IGN); #endif #ifdef SIGPIPE signal (SIGPIPE, SIG_IGN); /* important! */ #endif /* if no args given at all, get 'em from stdin, construct an argv, and hand anything left over to readwrite(). */ if (argc == 1) { cp = argv[0]; argv = (char **) Hmalloc (128 * sizeof (char *)); /* XXX: 128? */ argv[0] = cp; /* leave old prog name intact */ cp = Hmalloc (BIGSIZ); argv[1] = cp; /* head of new arg block */ if (farm9crypt_initialized() == 0) { farm9crypt_init(crypt_key_f9); } fprintf (stderr, "Cmd line: "); fflush (stderr); /* I dont care if it's unbuffered or not! */ insaved = read (0, cp, BIGSIZ); /* we're gonna fake fgets() here */ if (insaved <= 0) bail ("wrong"); x = findline (cp, insaved); if (x) insaved -= x; /* remaining chunk size to be sent */ if (insaved) /* which might be zero... */ memcpy (bigbuf_in, &cp[x], insaved); cp = strchr (argv[1], '\n'); if (cp) *cp = '\0'; cp = strchr (argv[1], '\r'); /* look for ^M too */ if (cp) *cp = '\0'; /* find and stash pointers to remaining new "args" */ cp = argv[1]; cp++; /* skip past first char */ x = 2; /* we know argv 0 and 1 already */ for (; *cp != '\0'; cp++) { if (*cp == ' ') { *cp = '\0'; /* smash all spaces */ continue; } else { if (*(cp-1) == '\0') { argv[x] = cp; x++; } } /* if space */ } /* for cp */ argc = x; } /* if no args given */ /* If your shitbox doesn't have getopt, step into the nineties already. */ /* optarg, optind = next-argv-component [i.e. flag arg]; optopt = last-char */ while ((x = getopt (argc, argv, "ae:g:G:hi:k:lno:p:rs:tuvw:z")) != EOF) { /* Debug (("in go: x now %c, optarg %x optind %d", x, optarg, optind)) */ switch (x) { case 'a': bail ("all-A-records NIY"); o_alla++; break; #ifdef GAPING_SECURITY_HOLE case 'e': /* prog to exec */ pr00gie = optarg; break; #endif case 'k': farm9crypt_init(memcpy(keystr, optarg, MAXKEYSIZE)); break; case 'G': /* srcrt gateways pointer val */ x = atoi (optarg); if ((x) && (x == (x & 0x1c))) /* mask off bits of fukt values */ gatesptr = x; else bail ("invalid hop pointer %d, must be multiple of 4 <= 28", x); break; case 'g': /* srcroute hop[s] */ if (gatesidx > 8) bail ("too many -g hops"); if (gates == NULL) /* eat this, Billy-boy */ gates = (HINF **) Hmalloc (sizeof (HINF *) * 10); gp = gethostpoop (optarg, o_nflag); if (gp) gates[gatesidx] = gp; gatesidx++; break; case 'h': errno = 0; #ifdef HAVE_HELP helpme(); /* exits by itself */ #else bail ("no help available, dork -- RTFS"); #endif case 'i': /* line-interval time */ o_interval = atoi (optarg) & 0xffff; if (! o_interval) bail ("invalid interval time %s", optarg); break; case 'l': /* listen mode */ o_listen++; break; case 'n': /* numeric-only, no DNS lookups */ o_nflag++; break; case 'o': /* hexdump log */ stage = (unsigned char *) optarg; o_wfile++; break; case 'p': /* local source port */ o_lport = getportpoop (optarg, 0); if (o_lport == 0) bail ("invalid local port %s", optarg); break; case 'r': /* randomize various things */ o_random++; break; case 's': /* local source address */ /* do a full lookup [since everything else goes through the same mill], unless -n was previously specified. In fact, careful placement of -n can be useful, so we'll still pass o_nflag here instead of forcing numeric. */ wherefrom = gethostpoop (optarg, o_nflag); ouraddr = &wherefrom->iaddrs[0]; break; #ifdef TELNET case 't': /* do telnet fakeout */ o_tn++; break; #endif /* TELNET */ case 'u': /* use UDP */ o_udpmode++; break; case 'v': /* verbose */ o_verbose++; break; case 'w': /* wait time */ o_wait = atoi (optarg); if (o_wait <= 0) bail ("invalid wait-time %s", optarg); timer1 = (struct timeval *) Hmalloc (sizeof (struct timeval)); timer2 = (struct timeval *) Hmalloc (sizeof (struct timeval)); timer1->tv_sec = o_wait; /* we need two. see readwrite()... */ break; case 'z': /* little or no data xfer */ o_zero++; break; default: errno = 0; bail ("nc -h for help"); } /* switch x */ } /* while getopt */ /* other misc initialization */ if (farm9crypt_initialized() == 0) { farm9crypt_init(crypt_key_f9); } Debug (("fd_set size %d", sizeof (*ding1))) /* how big *is* it? */ FD_SET (0, ding1); /* stdin *is* initially open */ if (o_random) { SRAND (time (0)); randports = Hmalloc (65536); /* big flag array for ports */ } #ifdef GAPING_SECURITY_HOLE if (pr00gie) { close (0); /* won't need stdin */ o_wfile = 0; /* -o with -e is meaningless! */ ofd = 0; } #endif /* G_S_H */ if (o_wfile) { ofd = open (stage, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (ofd <= 0) /* must be > extant 0/1/2 */ bail ("can't open %s", stage); stage = (unsigned char *) Hmalloc (100); } /* optind is now index of first non -x arg */ Debug (("after go: x now %c, optarg %x optind %d", x, optarg, optind)) /* Debug (("optind up to %d at host-arg %s", optind, argv[optind])) */ /* gonna only use first addr of host-list, like our IQ was normal; if you wanna get fancy with addresses, look up the list yourself and plug 'em in for now. unless we finally implement -a, that is. */ if (argv[optind]) whereto = gethostpoop (argv[optind], o_nflag); if (whereto && whereto->iaddrs) themaddr = &whereto->iaddrs[0]; if (themaddr) optind++; /* skip past valid host lookup */ errno = 0; h_errno = 0; /* Handle listen mode here, and exit afterward. Only does one connect; this is arguably the right thing to do. A "persistent listen-and-fork" mode a la inetd has been thought about, but not implemented. A tiny wrapper script can handle such things... */ if (o_listen) { curport = 0; /* rem port *can* be zero here... */ if (argv[optind]) { /* any rem-port-arg? */ curport = getportpoop (argv[optind], 0); if (curport == 0) /* if given, demand correctness */ bail ("invalid port %s", argv[optind]); } /* if port-arg */ netfd = dolisten (themaddr, curport, ouraddr, o_lport); /* dolisten does its own connect reporting, so we don't holler anything here */ if (netfd > 0) { #ifdef GAPING_SECURITY_HOLE if (pr00gie) /* -e given? */ doexec (netfd); #endif /* GAPING_SECURITY_HOLE */ x = readwrite (netfd); /* it even works with UDP! */ if (o_verbose > 1) /* normally we don't care */ holler (wrote_txt, wrote_net, wrote_out); exit (x); /* "pack out yer trash" */ } else /* if no netfd */ bail ("no connection"); } /* o_listen */ /* fall thru to outbound connects. Now we're more picky about args... */ if (! themaddr) bail ("no destination"); if (argv[optind] == NULL) bail ("no port[s] to connect to"); if (argv[optind + 1]) /* look ahead: any more port args given? */ Single = 0; /* multi-mode, case A */ ourport = o_lport; /* which can be 0 */ /* everything from here down is treated as as ports and/or ranges thereof, so it's all enclosed in this big ol' argv-parsin' loop. Any randomization is done within each given *range*, but in separate chunks per each succeeding argument, so we can control the pattern somewhat. */ while (argv[optind]) { hiport = loport = 0; cp = strchr (argv[optind], '-'); /* nn-mm range? */ if (cp) { *cp = '\0'; cp++; hiport = getportpoop (cp, 0); if (hiport == 0) bail ("invalid port %s", cp); } /* if found a dash */ loport = getportpoop (argv[optind], 0); if (loport == 0) bail ("invalid port %s", argv[optind]); if (hiport > loport) { /* was it genuinely a range? */ Single = 0; /* multi-mode, case B */ curport = hiport; /* start high by default */ if (o_random) { /* maybe populate the random array */ loadports (randports, loport, hiport); curport = nextport (randports); } } else /* not a range, including args like "25-25" */ curport = loport; Debug (("Single %d, curport %d", Single, curport)) /* Now start connecting to these things. curport is already preloaded. */ while (loport <= curport) { if ((! o_lport) && (o_random)) { /* -p overrides random local-port */ ourport = (RAND() & 0xffff); /* random local-bind -- well above */ if (ourport < 8192) /* resv and any likely listeners??? */ ourport += 8192; /* if it *still* conflicts, use -s. */ } curport = getportpoop (NULL, curport); netfd = doconnect (themaddr, curport, ouraddr, ourport); Debug (("netfd %d from port %d to port %d", netfd, ourport, curport)) if (netfd > 0) if (o_zero && o_udpmode) /* if UDP scanning... */ netfd = udptest (netfd, themaddr); if (netfd > 0) { /* Yow, are we OPEN YET?! */ x = 0; /* pre-exit status */ holler ("%s [%s] %d (%s) open", whereto->name, whereto->addrs[0], curport, portpoop->name); #ifdef GAPING_SECURITY_HOLE if (pr00gie) /* exec is valid for outbound, too */ doexec (netfd); #endif /* GAPING_SECURITY_HOLE */ if (! o_zero) x = readwrite (netfd); /* go shovel shit */ } else { /* no netfd... */ x = 1; /* preload exit status for later */ /* if we're scanning at a "one -v" verbosity level, don't print refusals. Give it another -v if you want to see everything. */ if ((Single || (o_verbose > 1)) || (errno != ECONNREFUSED)) holler ("%s [%s] %d (%s)", whereto->name, whereto->addrs[0], curport, portpoop->name); } /* if netfd */ close (netfd); /* just in case we didn't already */ if (o_interval) sleep (o_interval); /* if -i, delay between ports too */ if (o_random) curport = nextport (randports); else curport--; /* just decrement... */ } /* while curport within current range */ optind++; } /* while remaining port-args -- end of big argv-ports loop*/ errno = 0; if (o_verbose > 1) /* normally we don't care */ holler (wrote_txt, wrote_net, wrote_out); if (Single) exit (x); /* give us status on one connection */ exit (0); /* otherwise, we're just done */ } /* main */ #ifdef HAVE_HELP /* unless we wanna be *really* cryptic */ /* helpme : the obvious */ helpme() { o_verbose = 1; holler ("[v1.10]\n\ connect to somewhere: nc [-options] hostname port[s] [ports] ... \n\ listen for inbound: nc -l -p port [-options] [hostname] [port]\n\ options:"); /* sigh, this necessarily gets messy. And the trailing \ characters may be interpreted oddly by some compilers, generating or not generating extra newlines as they bloody please. u-fix... */ #ifdef GAPING_SECURITY_HOLE /* needs to be separate holler() */ holler ("\ -e prog program to exec after connect [dangerous!!]"); #endif holler ("\ -g gateway source-routing hop point[s], up to 8\n\ -G num source-routing pointer: 4, 8, 12, ...\n\ -h this cruft\n\ -k secret set the shared secret\n\ -i secs delay interval for lines sent, ports scanned\n\ -l listen mode, for inbound connects\n\ -n numeric-only IP addresses, no DNS\n\ -o file hex dump of traffic\n\ -p port local port number\n\ -r randomize local and remote ports\n\ -s addr local source address"); #ifdef TELNET holler ("\ -t answer TELNET negotiation"); #endif holler ("\ -u UDP mode\n\ -v verbose [use twice to be more verbose]\n\ -w secs timeout for connects and final net reads\n\ -z zero-I/O mode [used for scanning]"); bail ("port numbers can be individual or ranges: lo-hi [inclusive]"); } /* helpme */ #endif /* HAVE_HELP */ /* None genuine without this seal! _H*/ unix/twofish2.cc000640 023422 023422 00000064704 10160731523 015620 0ustar00jleplastjleplast000000 000000 #include #include /* include param.h for the [__]BYTE_ORDER/ENDIAN definitions */ #include typedef unsigned char BYTE; typedef unsigned long DWORD; /* 32-bit unsigned quantity */ /* $Id: twofish2.cc,v 1.3 2004/12/18 04:34:27 jleplast Exp $ * * Copyright (C) 1997-2000 The Cryptix Foundation Limited. * All rights reserved. * * Use, modification, copying and distribution of this software is subject * the terms and conditions of the Cryptix General Licence. You should have * received a copy of the Cryptix General Licence along with this library; * if not, you can download a copy from http://www.cryptix.org/ . */ /** Fixed 8x8 permutation S-boxes */ static unsigned char P[2][256] = { { // p0 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0 }, { // p1 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 } }; /** MDS matrix */ static int MDS[4][256]; // blank final #include "twofish2.h" //////////////////////////////////////////////////////////////////// ////////////////////// DEFINES ///////////////////////////////////// //////////////////////////////////////////////////////////////////// #define LFSR1(x) ( ((x) >> 1) ^ (((x) & 0x01) ? MDS_GF_FDBK/2 : 0)) #define LFSR2(x) ( ((x) >> 2) ^ (((x) & 0x02) ? MDS_GF_FDBK/2 : 0) ^ (((x) & 0x01) ? MDS_GF_FDBK/4 : 0)) #define Mx_1(x) ((DWORD) (x)) /* force result to dword so << will work */ #define Mx_X(x) ((DWORD) ((x) ^ LFSR2(x))) /* 5B */ #define Mx_Y(x) ((DWORD) ((x) ^ LFSR1(x) ^ LFSR2(x))) /* EF */ #define RS_rem(x) { BYTE b = (BYTE) (x >> 24); DWORD g2 = ((b << 1) ^ ((b & 0x80) ? RS_GF_FDBK : 0 )) & 0xFF; DWORD g3 = ((b >> 1) & 0x7F) ^ ((b & 1) ? RS_GF_FDBK >> 1 : 0 ) ^ g2 ; x = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; } //#define _b(x,N) (((BYTE *)&x)[((N) & 3) ^ ADDR_XOR]) /* pick bytes out of a dword */ #define _b(x,N) (((BYTE *)&x)[((N) & 3)]) /* pick bytes out of a dword */ /* Initial endian patch provided by Renzo Davoli */ #if defined(__BYTE_ORDER) #define BYTE_ORDER __BYTE_ORDER #define BIG_ENDIAN __BIG_ENDIAN #define LITTLE_ENDIAN __LITTLE_ENDIAN #elif !defined(BYTE_ORDER) #error "BYTE_ORDER (or variants) not defined!" #endif #ifdef BYTE_ORDER #if BYTE_ORDER == BIG_ENDIAN #define b0(x) _b(x,3) /* extract LSB of DWORD */ #define b1(x) _b(x,2) #define b2(x) _b(x,1) #define b3(x) _b(x,0) /* extract MSB of DWORD */ #elif BYTE_ORDER == LITTLE_ENDIAN #define b0(x) _b(x,0) /* extract LSB of DWORD */ #define b1(x) _b(x,1) #define b2(x) _b(x,2) #define b3(x) _b(x,3) /* extract MSB of DWORD */ #endif #endif //////////////////////////////////////////////////////////////////// ////////////////////// METHODS ///////////////////////////////////// //////////////////////////////////////////////////////////////////// void TwoFish::precomputeMDSmatrix() { // precompute the MDS matrix int m1[2]; int mX[2]; int mY[2]; int i, j; for (i = 0; i < 256; i++) { j = P[0][i] & 0xFF; // compute all the matrix elements m1[0] = j; mX[0] = Mx_X( j ) & 0xFF; mY[0] = Mx_Y( j ) & 0xFF; j = P[1][i] & 0xFF; m1[1] = j; mX[1] = Mx_X( j ) & 0xFF; mY[1] = Mx_Y( j ) & 0xFF; MDS[0][i] = m1[P_00] << 0 | // fill matrix w/ above elements mX[P_00] << 8 | mY[P_00] << 16 | mY[P_00] << 24; MDS[1][i] = mY[P_10] << 0 | mY[P_10] << 8 | mX[P_10] << 16 | m1[P_10] << 24; MDS[2][i] = mX[P_20] << 0 | mY[P_20] << 8 | m1[P_20] << 16 | mY[P_20] << 24; MDS[3][i] = mX[P_30] << 0 | m1[P_30] << 8 | mY[P_30] << 16 | mX[P_30] << 24; } } // Constructor //........................................................................... TwoFish::TwoFish(char* userkey, bool _decrypt, FILE* _fpout, unsigned char* _outputBuffer ) { decrypt = _decrypt; fpout = _fpout; if ( fpout == NULL ) { outputIsFile = false; } else { outputIsFile = true; } outputBuffer = _outputBuffer; if ( outputBuffer == NULL ) { outputIsBuffer = false; } else { outputIsBuffer = true; } precomputeMDSmatrix(); makeSubKeys(userkey); qBlockDefined = false; } // Private methods //........................................................................... /** * Expand a user-supplied key material into a session key. * * @param key The 64/128/192/256-bit user-key to use. * @return This cipher's round keys. * @exception InvalidKeyException If the key is invalid. */ void TwoFish::makeSubKeys( char* k ) { int length = 32; int k64Cnt = length / 8; int k32e[4]; // even 32-bit entities int k32o[4]; // odd 32-bit entities int sBoxKey[4]; // split user key material into even and odd 32-bit entities and // compute S-box keys using (12, 8) Reed-Solomon code over GF(256) int i, j, offset = 0; for (i = 0, j = k64Cnt-1; i < 4 && offset < length; i++, j--) { k32e[i] = (k[offset] & 0xFF) | (k[offset+1] & 0xFF) << 8 | (k[offset+2] & 0xFF) << 16 | (k[offset+3] & 0xFF) << 24; offset += 4; k32o[i] = (k[offset] & 0xFF) | (k[offset+1] & 0xFF) << 8 | (k[offset+2] & 0xFF) << 16 | (k[offset+3] & 0xFF) << 24; offset += 4; sBoxKey[j] = RS_MDS_Encode( k32e[i], k32o[i] ); // reverse order } // compute the round decryption subkeys for PHT. these same subkeys // will be used in encryption but will be applied in reverse order. unsigned int A, B, q=0; i=0; while(i < TOTAL_SUBKEYS) { A = F32( k64Cnt, q, k32e ); // A uses even key entities q += SK_BUMP; B = F32( k64Cnt, q, k32o ); // B uses odd key entities q += SK_BUMP; B = B << 8 | B >> 24; A += B; subKeys[i++] = A; // combine with a PHT A += B; subKeys[i++] = A << SK_ROTL | A >> (32-SK_ROTL); } // fully expand the table for speed int k0 = sBoxKey[0]; int k1 = sBoxKey[1]; int k2 = sBoxKey[2]; int k3 = sBoxKey[3]; int b0, b1, b2, b3; for (i = 0; i < 256; i++) { b0 = b1 = b2 = b3 = i; switch (k64Cnt & 3) { case 1: sBox[ 2*i ] = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)]; sBox[ 2*i+1] = MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)]; sBox[0x200+2*i ] = MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)]; sBox[0x200+2*i+1] = MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; break; case 0: // same as 4 b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); case 3: b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); case 2: // 128-bit keys sBox[ 2*i ] = MDS[0][ (P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) ^ b0(k0)]; sBox[ 2*i+1] = MDS[1][ (P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) ^ b1(k0)]; sBox[0x200+2*i ] = MDS[2][ (P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) ^ b2(k0)]; sBox[0x200+2*i+1] = MDS[3][ (P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) ^ b3(k0)]; } } // swap input and output whitening keys when decrypting if(decrypt) { for(i=0; i<4; i++) { int t = subKeys[i]; subKeys[i] = subKeys[i+4]; subKeys[i+4] = t; } } } static void bzero( char* ptr, int size ) { for ( int i = 0; i < size; i++ ) { *ptr++ = 0; } } // // write output to all active output areas // void TwoFish::flushOutput( char* b, int len ) { if ( outputIsSocket ) { int wret = write( sockfd, b, len ); } for ( int i = 0; i < len; i++, b++ ) { if ( outputIsFile ) { fputc( *b, fpout ); } if ( outputIsBuffer ) { *outputBuffer = *b; outputBuffer++; } } } /** * Encrypt or decrypt exactly one block of plaintext in CBC mode. * Use "ciphertext stealing" technique described on pg. 196 * of "Applied Cryptography" to encrypt the final partial * (i.e. <16 byte) block if necessary. * * Note: the "ciphertext stealing" requires we read ahead and have * special handling for the last two blocks. Because of this, the * output from the TwoFish algorithm is handled internally here. * It would be better to have a higher level handle this as well as * CBC mode. Unfortunately, I've mixed the two together, which is * pretty crappy... The Java version separates these out correctly. * * @param in The plaintext. * @param out The ciphertext * @param size how much to encrypt * @return none */ void TwoFish::blockCrypt( char* in, char* out, int size ) { // here is where we implement CBC mode and cipher block stealing if ( size == 16 ) { // if we are encrypting, CBC means we XOR the plain text block with the // previous cipher text block before encrypting if ( !decrypt && qBlockDefined ) { char* scanner = in; for ( int i = 0; i < 16; i++, scanner++ ) { *scanner = *scanner ^ qBlockCrypt[i]; } } // TwoFish block level encryption or decryption blockCrypt16( in, out ); // if we are decrypting, CBC means we XOR the result of the decryption // with the previous ciper text block to get the resulting plain text if ( decrypt && qBlockDefined ) { char* scanner = out; for ( int i = 0; i < 16; i++, scanner++ ) { *scanner = *scanner ^ qBlockPlain[i]; } } // save the input and output blocks, since CBC needs these for XOR // operations qBlockPush( in, out ); } else { // cipher block stealing, we are at Pn, // but since Cn-1 must now be replaced with CnC' // we pop it off, and recalculate Cn-1 // char PnMinusOne[16]; char CnMinusOne[16]; if ( decrypt ) { // We are on an odd block, and had to do cipher block stealing, // so the PnMinusOne has to be derived differently. qBlockPop( &CnMinusOne[0], &PnMinusOne[0] ); // First we decrypt it into CBC and C' char CBCplusCprime[16]; blockCrypt16( &CnMinusOne[0], &CBCplusCprime[0] ); // we then xor the first few bytes with the "in" bytes (Cn) // to recover Pn, which we put in out char* scanner = in; char* outScanner = out; for ( int i = 0; i < size; i++, scanner++, outScanner++ ) { *outScanner = *scanner ^ CBCplusCprime[i]; } // We now recover the original CnMinusOne, which consists of // the first "size" bytes of "in" data, followed by the // "Cprime" portion of CBCplusCprime scanner = in; for ( int i = 0; i < size; i++, scanner++ ) { CnMinusOne[i] = *scanner; } for ( int i = size; i < 16; i++ ) { CnMinusOne[i] = CBCplusCprime[i]; } // we now decrypt CnMinusOne to get PnMinusOne xored with Cn-2 blockCrypt16( &CnMinusOne[0], &PnMinusOne[0] ); for ( int i = 0; i < 16; i++ ) { PnMinusOne[i] = PnMinusOne[i] ^ prevCipher[i]; } // So at this point, out has PnMinusOne qBlockPush( &CnMinusOne[0], &PnMinusOne[0] ); qBlockFlush(); flushOutput( out, size ); } else { qBlockPop( &PnMinusOne[0], &CnMinusOne[0] ); char Pn[16]; bzero( &Pn[0], 16 ); memcpy( &Pn[0], in, size ); for ( int i = 0; i < 16; i++ ) { Pn[i] = CnMinusOne[i] ^ Pn[i]; } blockCrypt16( &Pn[0], out ); qBlockPush( &Pn[0], out ); // now we officially have Cn-1 qBlockFlush(); // write them all out flushOutput( &CnMinusOne[0], size ); // old Cn-1 becomes new partial Cn } qBlockDefined = false; } } void TwoFish::qBlockPush( char* p, char* c ) { if ( qBlockDefined ) { qBlockFlush(); } memcpy( &prevCipher[0], &qBlockPlain[0], 16 ); memcpy( &qBlockPlain[0], p, 16 ); memcpy( &qBlockCrypt[0], c, 16 ); qBlockDefined = true; } void TwoFish::qBlockPop( char* p, char* c ) { memcpy( p, &qBlockPlain[0], 16 ); memcpy( c, &qBlockCrypt[0], 16 ); qBlockDefined = false; } // // flush a complete block to all active output areas // this occurs when we know the block does not need to be // re-encrypted or re-decrypted. The redoing of encryption // and decryption is necessary for cipher text stealing technique // and is done on the last complete block. // void TwoFish::qBlockFlush() { flushOutput( &qBlockCrypt[0], 16 ); } void TwoFish::flush() { if ( qBlockDefined ) { qBlockFlush(); } } void TwoFish::blockCrypt16( char* in, char* out ) { int inOffset = 0; int outOffset = 0; unsigned int x0 = (in[inOffset] & 0xFF) | (in[inOffset+1] & 0xFF) << 8 | (in[inOffset+2] & 0xFF) << 16 | (in[inOffset+3] & 0xFF) << 24; inOffset += 4; unsigned int x1 = (in[inOffset] & 0xFF) | (in[inOffset+1] & 0xFF) << 8 | (in[inOffset+2] & 0xFF) << 16 | (in[inOffset+3] & 0xFF) << 24; inOffset += 4; unsigned int x2 = (in[inOffset] & 0xFF) | (in[inOffset+1] & 0xFF) << 8 | (in[inOffset+2] & 0xFF) << 16 | (in[inOffset+3] & 0xFF) << 24; inOffset += 4; unsigned int x3 = (in[inOffset] & 0xFF) | (in[inOffset+1] & 0xFF) << 8 | (in[inOffset+2] & 0xFF) << 16 | (in[inOffset+3] & 0xFF) << 24; /* unsigned int x0; unsigned int x1; unsigned int x2; unsigned int x3; in += inOffset; memcpy( &x0, in, 4 ); in += 4; memcpy( &x1, in, 4 ); in += 4; memcpy( &x2, in, 4 ); in += 4; memcpy( &x3, in, 4 );*/ x0 ^= subKeys[0]; x1 ^= subKeys[1]; x2 ^= subKeys[2]; x3 ^= subKeys[3]; int k, t0, t1; if ( decrypt ) { k = 39; for (int R = 0; R < ROUNDS; R += 2) { t0 = Fe320( sBox, x0 ); t1 = Fe323( sBox, x1 ); x3 ^= t0 + (t1<<1) + subKeys[k--]; x3 = x3 >> 1 | x3 << 31; x2 = x2 << 1 | x2 >> 31; x2 ^= t0 + t1 + subKeys[k--]; t0 = Fe320( sBox, x2 ); t1 = Fe323( sBox, x3 ); x1 ^= t0 + (t1<<1) + subKeys[k--]; x1 = x1 >> 1 | x1 << 31; x0 = x0 << 1 | x0 >> 31; x0 ^= t0 + t1 + subKeys[k--]; } } else { k = 8; for (int R = 0; R < ROUNDS; R += 2) { t0 = Fe320( sBox, x0 ); t1 = Fe323( sBox, x1 ); x2 ^= t0 + t1 + subKeys[k++]; x2 = x2 >> 1 | x2 << 31; x3 = x3 << 1 | x3 >> 31; x3 ^= t0 + (t1<<1) + subKeys[k++]; t0 = Fe320( sBox, x2 ); t1 = Fe323( sBox, x3 ); x0 ^= t0 + t1 + subKeys[k++]; x0 = x0 >> 1 | x0 << 31; x1 = x1 << 1 | x1 >> 31; x1 ^= t0 + (t1<<1) + subKeys[k++]; } } x2 ^= subKeys[4]; x3 ^= subKeys[5]; x0 ^= subKeys[6]; x1 ^= subKeys[7]; out += outOffset; /*memcpy( out, &x2, 4 ); out += 4; memcpy( out, &x3, 4 ); out += 4; memcpy( out, &x0, 4 ); out += 4; memcpy( out, &x1, 4 );*/ *out++ = (x2 ); *out++ = (x2 >> 8); *out++ = (x2 >> 16); *out++ = (x2 >> 24); *out++ = (x3 ); *out++ = (x3 >> 8); *out++ = (x3 >> 16); *out++ = (x3 >> 24); *out++ = (x0 ); *out++ = (x0 >> 8); *out++ = (x0 >> 16); *out++ = (x0 >> 24); *out++ = (x1 ); *out++ = (x1 >> 8); *out++ = (x1 >> 16); *out++ = (x1 >> 24); } /** * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box * 32-bit entity from two key material 32-bit entities. * * @param k0 1st 32-bit entity. * @param k1 2nd 32-bit entity. * @return Remainder polynomial generated using RS code */ int TwoFish::RS_MDS_Encode( int k0, int k1 ) { int r = k1; for (int i = 0; i < 4; i++) // shift 1 byte at a time RS_rem( r ); r ^= k0; for (int i = 0; i < 4; i++) RS_rem( r ); return r; } int TwoFish::F32( int k64Cnt, int x, int* k32 ) { int b0 = b0(x); int b1 = b1(x); int b2 = b2(x); int b3 = b3(x); int k0 = k32[0]; int k1 = k32[1]; int k2 = k32[2]; int k3 = k32[3]; int result = 0; switch (k64Cnt & 3) { case 1: result = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)] ^ MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)] ^ MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)] ^ MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; break; case 0: // same as 4 b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); case 3: b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); case 2: // 128-bit keys (optimize for this case) result = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) ^ b0(k0)] ^ MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) ^ b1(k0)] ^ MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) ^ b2(k0)] ^ MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) ^ b3(k0)]; break; } return result; } int TwoFish::Fe320( int* sBox, int x ) { return sBox[ b0(x) << 1 ] ^ sBox[ (b1(x) << 1) | 1] ^ sBox[0x200 + (b2(x) << 1) ] ^ sBox[0x200 + (b3(x) << 1) | 1]; } int TwoFish::Fe323( int* sBox, int x ) { return sBox[ (b3(x) << 1) ] ^ sBox[ (b0(x) << 1) | 1] ^ sBox[0x200 + (b1(x) << 1) ] ^ sBox[0x200 + (b2(x) << 1) | 1]; } int TwoFish::Fe32( int* sBox, int x, int R ) { return sBox[ 2*_b(x, R ) ] ^ sBox[ 2*_b(x, R+1) + 1] ^ sBox[0x200 + 2*_b(x, R+2) ] ^ sBox[0x200 + 2*_b(x, R+3) + 1]; } static char key[32]; char* generateKey( char* s ) { int sIdx = 0; for ( int i = 0; i < 32; i++ ) { char sval = *( s + sIdx ); if (( sval >= '0' ) && ( sval <= '9' )) { key[i] = sval; } else if (( sval >= 'a' ) && ( sval <= 'f' )) { key[i] = sval; } else { int q = sval%16; if ( q < 10 ) { key[i] = ('0' + q); } else { key[i] = ('a' + q - 10); } } sIdx++; if ( *( s + sIdx ) == 0 ) { sIdx = 0; } } return( &key[0] ); } AsciiTwofish::AsciiTwofish( TwoFish* e ) { engine = e; } void AsciiTwofish::encryptAscii( char* in, char* out, int outBufferSize ) { engine->setDecrypt( false ); engine->resetCBC(); unsigned char byteBuf[200]; char* originalOut = out; // encrypt one block at a time with twofish char inList[16]; unsigned char outList[16]; engine->setOutputBuffer( byteBuf ); int remaining = strlen( in ); int len = remaining; int bidx = 0; while ( remaining > 0 ) { if ( remaining > 16 ) { memcpy( inList, in + bidx, 16 ); engine->blockCrypt( inList, (char*)outList, 16 ); } else { memcpy( inList, in + bidx, remaining ); engine->blockCrypt( inList, (char*)outList, remaining ); } bidx += 16; remaining -= 16; } engine->flush(); // now do totally stupid ascii encoding of bytes if ( outBufferSize < len*3 ) { printf( "Hey, outBufferSize is %d, but len*3 is %d\n", outBufferSize, len*3 ); } else { for ( int i = 0; i < len; i++ ) { sprintf( out, "%03d", byteBuf[i] ); out += 3; } } engine->setOutputBuffer( NULL ); } void AsciiTwofish::decryptAscii( char* in, char* out ) { engine->setDecrypt( true ); engine->resetCBC(); engine->setOutputBuffer( (unsigned char*)out ); int inLen = strlen( in ); if (( *( in + inLen - 1 ) == '\n' ) || ( *( in + inLen - 1 ) == '\r' )) { *( in + inLen - 1 ) = 0; inLen = strlen( in ); } unsigned char byteBuf[200]; int byteBufIdx = 0; // first convert ascii to bytes, placing in another buffer for ( int i = 0; i < inLen; i += 3 ) { unsigned int x = 0; x = x * 10 + ( *in++ - '0' ); x = x * 10 + ( *in++ - '0' ); x = x * 10 + ( *in++ - '0' ); byteBuf[ byteBufIdx++ ] = x; byteBuf[ byteBufIdx ] = 0; } // then run it through twofish placing result into command buffer char inList[16]; unsigned char outList[16]; int remaining = byteBufIdx; *( out + byteBufIdx ) = 0; int bidx = 0; while ( remaining > 0 ) { if ( remaining > 16 ) { memcpy( inList, &byteBuf[bidx], 16 ); engine->blockCrypt( inList, (char*)outList, 16 ); } else { memcpy( inList, &byteBuf[bidx], remaining ); engine->blockCrypt( inList, (char*)outList, remaining ); } bidx += 16; remaining -= 16; } engine->flush(); engine->setOutputBuffer( NULL ); *( out + byteBufIdx ) = 0; } unix/twofish2.h000640 023422 023422 00000006212 10160731523 015450 0ustar00jleplastjleplast000000 000000 #include class TwoFish { // Constants //........................................................................... enum { BLOCK_SIZE = 16, // bytes in a data-block ROUNDS = 16, TOTAL_SUBKEYS = 4 + 4 + 2*ROUNDS, SK_BUMP = 0x01010101, SK_ROTL = 9, P_00 = 1, P_01 = 0, P_02 = 0, P_03 = P_01 ^ 1, P_04 = 1, P_10 = 0, P_11 = 0, P_12 = 1, P_13 = P_11 ^ 1, P_14 = 0, P_20 = 1, P_21 = 1, P_22 = 0, P_23 = P_21 ^ 1, P_24 = 0, P_30 = 0, P_31 = 1, P_32 = 1, P_33 = P_31 ^ 1, P_34 = 1, GF256_FDBK = 0x169, GF256_FDBK_2 = 0x169 / 2, GF256_FDBK_4 = 0x169 / 4, RS_GF_FDBK = 0x14D, // field generator MDS_GF_FDBK = 0x169 /* primitive polynomial for GF(256)*/ }; // Static code - to intialise the MDS matrix //........................................................................... private: void precomputeMDSmatrix(); // Instance variables //........................................................................... /** Encrypt (false) or decrypt mode (true) */ bool decrypt; bool outputIsFile; bool outputIsBuffer; bool outputIsSocket; /** Key dependent S-box */ int sBox[4 * 256]; /** Subkeys */ int subKeys[TOTAL_SUBKEYS]; // output areas FILE* fpout; unsigned char* outputBuffer; int sockfd; public: // Constructor //........................................................................... TwoFish( char* userkey, bool _decrypt, FILE* fpout, unsigned char* outbuf ); void setDecrypt( bool d ) { decrypt = d; } void setFp( FILE* fp ) { fpout = fp; if ( fp != NULL ) outputIsFile = true; else outputIsFile = false; } void setOutputBuffer( unsigned char* obuf ) { outputBuffer = obuf; if ( outputBuffer != NULL ) outputIsBuffer = true; else outputIsBuffer = false; } void setSocket( int sfd ) { sockfd = sfd; if ( sfd != -1 ) outputIsSocket = true; else outputIsSocket = false; } void blockCrypt( char* in, char* out, int size ); void blockCrypt16( char* in, char* out ); void flush(); void resetCBC() { qBlockDefined = false; } private: void flushOutput( char* output, int size ); void qBlockPush( char* p, char* c ); void qBlockPop( char* p, char* c ); void qBlockFlush(); char qBlockPlain[16]; char qBlockCrypt[16]; char prevCipher[16]; bool qBlockDefined; // Private methods //........................................................................... void makeSubKeys( char* k ); // own methods //........................................................................... int RS_MDS_Encode( int k0, int k1 ); int F32( int k64Cnt, int x, int* k32 ); int Fe32( int* sBox, int x, int R ); int Fe320( int* sBox, int x ); int Fe323( int* sBox, int x ); }; char* generateKey( char* kstr ); class AsciiTwofish { public: AsciiTwofish( TwoFish* engine ); void encryptAscii( char* in, char* out, int outBufferSize ); void decryptAscii( char* in, char* out ); private: TwoFish* engine; };