📄 netcat.c
字号:
/* 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 <stdlib.h>#else#include <malloc.h>#endif#ifdef HAVE_SELECT_H /* random SV variants need this */#include <sys/select.h>#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 <sys/types.h> /* *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 <sys/time.h> /* timeval, time_t */#include <setjmp.h> /* jmp_buf et al */#include <sys/socket.h> /* basics, SO_ and AF_ defs, sockaddr, ... */#include <netinet/in.h> /* sockaddr_in, htons, in_addr */#include <netinet/in_systm.h> /* misc crud that netinet/ip.h references */#include <netinet/ip.h> /* IPOPT_LSRR, header stuff */#include <netdb.h> /* hostent, gethostby*, getservby* */#include <arpa/inet.h> /* inet_ntoa */#include <stdio.h>#include <string.h> /* strcpy, strchr, yadda yadda */#include <errno.h>#include <signal.h>#include <fcntl.h> /* O_WRONLY et al *//* 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 256struct 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_poopstruct 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_BINDextern 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 */};#elseint 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -