1/* Based on netcat 1.10 RELEASE 960320 written by hobbit@avian.org.
2 * Released into public domain by the author.
3 *
4 * Copyright (C) 2007 Denis Vlasenko.
5 *
6 * Licensed under GPLv2, see file LICENSE in this tarball for details.
7 */
8
9/* Author's comments from nc 1.10:
10 * =====================
11 * Netcat is entirely my own creation, although plenty of other code was used as
12 * examples.  It is freely given away to the Internet community in the hope that
13 * it will be useful, with no restrictions except giving credit where it is due.
14 * No GPLs, Berkeley copyrights or any of that nonsense.  The author assumes NO
15 * responsibility for how anyone uses it.  If netcat makes you rich somehow and
16 * you're feeling generous, mail me a check.  If you are affiliated in any way
17 * with Microsoft Network, get a life.  Always ski in control.  Comments,
18 * questions, and patches to hobbit@avian.org.
19 * ...
20 * Netcat and the associated package is a product of Avian Research, and is freely
21 * available in full source form with no restrictions save an obligation to give
22 * credit where due.
23 * ...
24 * A damn useful little "backend" utility begun 950915 or thereabouts,
25 * as *Hobbit*'s first real stab at some sockets programming.  Something that
26 * should have and indeed may have existed ten years ago, but never became a
27 * standard Unix utility.  IMHO, "nc" could take its place right next to cat,
28 * cp, rm, mv, dd, ls, and all those other cryptic and Unix-like things.
29 * =====================
30 *
31 * Much of author's comments are still retained in the code.
32 *
33 * Functionality removed (rationale):
34 * - miltiple-port ranges, randomized port scanning (use nmap)
35 * - telnet support (use telnet)
36 * - source routing
37 * - multiple DNS checks
38 * Functionalty which is different from nc 1.10:
39 * - Prog in '-e prog' can have prog's parameters and options.
40 *   Because of this -e option must be last.
41 * - nc doesn't redirect stderr to the network socket for the -e prog.
42 * - numeric addresses are printed in (), not [] (IPv6 looks better),
43 *   port numbers are inside (): (1.2.3.4:5678)
44 * - network read errors are reported on verbose levels > 1
45 *   (nc 1.10 treats them as EOF)
46 * - TCP connects from wrong ip/ports (if peer ip:port is specified
47 *   on the command line, but accept() says that it came from different addr)
48 *   are closed, but nc doesn't exit - continues to listen/accept.
49 */
50
51/* done in nc.c: #include "libbb.h" */
52
53enum {
54	SLEAZE_PORT = 31337,               /* for UDP-scan RTT trick, change if ya want */
55	BIGSIZ = 8192,                     /* big buffers */
56
57	netfd = 3,
58	ofd = 4,
59};
60
61struct globals {
62	/* global cmd flags: */
63	unsigned o_verbose;
64	unsigned o_wait;
65#if ENABLE_NC_EXTRA
66	unsigned o_interval;
67#endif
68
69	/*int netfd;*/
70	/*int ofd;*/                     /* hexdump output fd */
71#if ENABLE_LFS
72#define SENT_N_RECV_M "sent %llu, rcvd %llu\n"
73	unsigned long long wrote_out;          /* total stdout bytes */
74	unsigned long long wrote_net;          /* total net bytes */
75#else
76#define SENT_N_RECV_M "sent %u, rcvd %u\n"
77	unsigned wrote_out;          /* total stdout bytes */
78	unsigned wrote_net;          /* total net bytes */
79#endif
80	/* ouraddr is never NULL and goes thru three states as we progress:
81	 1 - local address before bind (IP/port possibly zero)
82	 2 - local address after bind (port is nonzero)
83	 3 - local address after connect??/recv/accept (IP and port are nonzero) */
84	struct len_and_sockaddr *ouraddr;
85	/* themaddr is NULL if no peer hostname[:port] specified on command line */
86	struct len_and_sockaddr *themaddr;
87	/* remend is set after connect/recv/accept to the actual ip:port of peer */
88	struct len_and_sockaddr remend;
89
90	jmp_buf jbuf;                /* timer crud */
91
92	/* will malloc up the following globals: */
93	fd_set ding1;                /* for select loop */
94	fd_set ding2;
95	char bigbuf_in[BIGSIZ];      /* data buffers */
96	char bigbuf_net[BIGSIZ];
97};
98
99#define G (*ptr_to_globals)
100
101#define wrote_out  (G.wrote_out )
102#define wrote_net  (G.wrote_net )
103#define ouraddr    (G.ouraddr   )
104#define themaddr   (G.themaddr  )
105#define remend     (G.remend    )
106#define jbuf       (G.jbuf      )
107#define ding1      (G.ding1     )
108#define ding2      (G.ding2     )
109#define bigbuf_in  (G.bigbuf_in )
110#define bigbuf_net (G.bigbuf_net)
111#define o_verbose  (G.o_verbose )
112#define o_wait     (G.o_wait    )
113#if ENABLE_NC_EXTRA
114#define o_interval (G.o_interval)
115#else
116#define o_interval 0
117#endif
118
119/* Must match getopt32 call! */
120enum {
121	OPT_h = (1 << 0),
122	OPT_n = (1 << 1),
123	OPT_p = (1 << 2),
124	OPT_s = (1 << 3),
125	OPT_u = (1 << 4),
126	OPT_v = (1 << 5),
127	OPT_w = (1 << 6),
128	OPT_l = (1 << 7) * ENABLE_NC_SERVER,
129	OPT_i = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
130	OPT_o = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
131	OPT_z = (1 << (9+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
132};
133
134#define o_nflag   (option_mask32 & OPT_n)
135#define o_udpmode (option_mask32 & OPT_u)
136#if ENABLE_NC_SERVER
137#define o_listen  (option_mask32 & OPT_l)
138#else
139#define o_listen  0
140#endif
141#if ENABLE_NC_EXTRA
142#define o_ofile   (option_mask32 & OPT_o)
143#define o_zero    (option_mask32 & OPT_z)
144#else
145#define o_ofile   0
146#define o_zero    0
147#endif
148
149/* Debug: squirt whatever message and sleep a bit so we can see it go by. */
150/* Beware: writes to stdOUT... */
151#define Debug(...) do { } while (0)
152
153#define holler_error(...)  do { if (o_verbose) bb_error_msg(__VA_ARGS__); } while (0)
154#define holler_perror(...) do { if (o_verbose) bb_perror_msg(__VA_ARGS__); } while (0)
155
156/* catch: no-brainer interrupt handler */
157static void catch(int sig)
158{
159	if (o_verbose > 1)                /* normally we don't care */
160		fprintf(stderr, SENT_N_RECV_M, wrote_net, wrote_out);
161	fprintf(stderr, "punt!\n");
162	exit(1);
163}
164
165/* unarm  */
166static void unarm(void)
167{
168	signal(SIGALRM, SIG_IGN);
169	alarm(0);
170}
171
172/* timeout and other signal handling cruft */
173static void tmtravel(int sig)
174{
175	unarm();
176	longjmp(jbuf, 1);
177}
178
179/* arm: set the timer.  */
180static void arm(unsigned secs)
181{
182	signal(SIGALRM, tmtravel);
183	alarm(secs);
184}
185
186/* findline:
187 find the next newline in a buffer; return inclusive size of that "line",
188 or the entire buffer size, so the caller knows how much to then write().
189 Not distinguishing \n vs \r\n for the nonce; it just works as is... */
190static unsigned findline(char *buf, unsigned siz)
191{
192	char * p;
193	int x;
194	if (!buf)                        /* various sanity checks... */
195		return 0;
196	if (siz > BIGSIZ)
197		return 0;
198	x = siz;
199	for (p = buf; x > 0; x--) {
200		if (*p == '\n') {
201			x = (int) (p - buf);
202			x++;                        /* 'sokay if it points just past the end! */
203Debug("findline returning %d", x);
204			return x;
205		}
206		p++;
207	} /* for */
208Debug("findline returning whole thing: %d", siz);
209	return siz;
210} /* findline */
211
212/* doexec:
213 fiddle all the file descriptors around, and hand off to another prog.  Sort
214 of like a one-off "poor man's inetd".  This is the only section of code
215 that would be security-critical, which is why it's ifdefed out by default.
216 Use at your own hairy risk; if you leave shells lying around behind open
217 listening ports you deserve to lose!! */
218static int doexec(char **proggie) ATTRIBUTE_NORETURN;
219static int doexec(char **proggie)
220{
221	xmove_fd(netfd, 0);
222	dup2(0, 1);
223	/* dup2(0, 2); - do we *really* want this? NO!
224	 * exec'ed prog can do it yourself, if needed */
225	execvp(proggie[0], proggie);
226	bb_perror_msg_and_die("exec");
227}
228
229/* connect_w_timeout:
230 return an fd for one of
231 an open outbound TCP connection, a UDP stub-socket thingie, or
232 an unconnected TCP or UDP socket to listen on.
233 Examines various global o_blah flags to figure out what to do.
234 lad can be NULL, then socket is not bound to any local ip[:port] */
235static int connect_w_timeout(int fd)
236{
237	int rr;
238
239	/* wrap connect inside a timer, and hit it */
240	arm(o_wait);
241	if (setjmp(jbuf) == 0) {
242		rr = connect(fd, &themaddr->sa, themaddr->len);
243		unarm();
244	} else { /* setjmp: connect failed... */
245		rr = -1;
246		errno = ETIMEDOUT; /* fake it */
247	}
248	return rr;
249}
250
251/* dolisten:
252 listens for
253 incoming and returns an open connection *from* someplace.  If we were
254 given host/port args, any connections from elsewhere are rejected.  This
255 in conjunction with local-address binding should limit things nicely... */
256static void dolisten(void)
257{
258	int rr;
259
260	if (!o_udpmode)
261		xlisten(netfd, 1); /* TCP: gotta listen() before we can get */
262
263	/* Various things that follow temporarily trash bigbuf_net, which might contain
264	 a copy of any recvfrom()ed packet, but we'll read() another copy later. */
265
266	/* I can't believe I have to do all this to get my own goddamn bound address
267	 and port number.  It should just get filled in during bind() or something.
268	 All this is only useful if we didn't say -p for listening, since if we
269	 said -p we *know* what port we're listening on.  At any rate we won't bother
270	 with it all unless we wanted to see it, although listening quietly on a
271	 random unknown port is probably not very useful without "netstat". */
272	if (o_verbose) {
273		char *addr;
274		rr = getsockname(netfd, &ouraddr->sa, &ouraddr->len);
275		if (rr < 0)
276			bb_perror_msg_and_die("getsockname after bind");
277		addr = xmalloc_sockaddr2dotted(&ouraddr->sa);
278		fprintf(stderr, "listening on %s ...\n", addr);
279		free(addr);
280	}
281
282	if (o_udpmode) {
283		/* UDP is a speeeeecial case -- we have to do I/O *and* get the calling
284		 party's particulars all at once, listen() and accept() don't apply.
285		 At least in the BSD universe, however, recvfrom/PEEK is enough to tell
286		 us something came in, and we can set things up so straight read/write
287		 actually does work after all.  Yow.  YMMV on strange platforms!  */
288
289		/* I'm not completely clear on how this works -- BSD seems to make UDP
290		 just magically work in a connect()ed context, but we'll undoubtedly run
291		 into systems this deal doesn't work on.  For now, we apparently have to
292		 issue a connect() on our just-tickled socket so we can write() back.
293		 Again, why the fuck doesn't it just get filled in and taken care of?!
294		 This hack is anything but optimal.  Basically, if you want your listener
295		 to also be able to send data back, you need this connect() line, which
296		 also has the side effect that now anything from a different source or even a
297		 different port on the other end won't show up and will cause ICMP errors.
298		 I guess that's what they meant by "connect".
299		 Let's try to remember what the "U" is *really* for, eh? */
300
301		/* If peer address is specified, connect to it */
302		remend.len = LSA_SIZEOF_SA;
303		if (themaddr) {
304			remend = *themaddr;
305			xconnect(netfd, &themaddr->sa, themaddr->len);
306		}
307		/* peek first packet and remember peer addr */
308		arm(o_wait);                /* might as well timeout this, too */
309		if (setjmp(jbuf) == 0) {       /* do timeout for initial connect */
310			/* (*ouraddr) is prefilled with "default" address */
311			/* and here we block... */
312			rr = recv_from_to(netfd, NULL, 0, MSG_PEEK, /*was bigbuf_net, BIGSIZ*/
313				&remend.sa, &ouraddr->sa, ouraddr->len);
314			if (rr < 0)
315				bb_perror_msg_and_die("recvfrom");
316			unarm();
317		} else
318			bb_error_msg_and_die("timeout");
319/* Now we learned *to which IP* peer has connected, and we want to anchor
320our socket on it, so that our outbound packets will have correct local IP.
321Unfortunately, bind() on already bound socket will fail now (EINVAL):
322	xbind(netfd, &ouraddr->sa, ouraddr->len);
323Need to read the packet, save data, close this socket and
324create new one, and bind() it. TODO */
325		if (!themaddr)
326			xconnect(netfd, &remend.sa, ouraddr->len);
327	} else {
328		/* TCP */
329		arm(o_wait); /* wrap this in a timer, too; 0 = forever */
330		if (setjmp(jbuf) == 0) {
331 again:
332			remend.len = LSA_SIZEOF_SA;
333			rr = accept(netfd, &remend.sa, &remend.len);
334			if (rr < 0)
335				bb_perror_msg_and_die("accept");
336			if (themaddr && memcmp(&remend.sa, &themaddr->sa, remend.len) != 0) {
337				/* nc 1.10 bails out instead, and its error message
338				 * is not suppressed by o_verbose */
339				if (o_verbose) {
340					char *remaddr = xmalloc_sockaddr2dotted(&remend.sa);
341					bb_error_msg("connect from wrong ip/port %s ignored", remaddr);
342					free(remaddr);
343				}
344				close(rr);
345				goto again;
346			}
347			unarm();
348		} else
349			bb_error_msg_and_die("timeout");
350		xmove_fd(rr, netfd); /* dump the old socket, here's our new one */
351		/* find out what address the connection was *to* on our end, in case we're
352		 doing a listen-on-any on a multihomed machine.  This allows one to
353		 offer different services via different alias addresses, such as the
354		 "virtual web site" hack. */
355		rr = getsockname(netfd, &ouraddr->sa, &ouraddr->len);
356		if (rr < 0)
357			bb_perror_msg_and_die("getsockname after accept");
358	}
359
360	if (o_verbose) {
361		char *lcladdr, *remaddr, *remhostname;
362
363#if ENABLE_NC_EXTRA && defined(IP_OPTIONS)
364	/* If we can, look for any IP options.  Useful for testing the receiving end of
365	 such things, and is a good exercise in dealing with it.  We do this before
366	 the connect message, to ensure that the connect msg is uniformly the LAST
367	 thing to emerge after all the intervening crud.  Doesn't work for UDP on
368	 any machines I've tested, but feel free to surprise me. */
369		char optbuf[40];
370		int x = sizeof(optbuf);
371
372		rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x);
373		if (rr < 0)
374			bb_perror_msg("getsockopt failed");
375		else if (x) {    /* we've got options, lessee em... */
376			bin2hex(bigbuf_net, optbuf, x);
377			bigbuf_net[2*x] = '\0';
378			fprintf(stderr, "IP options: %s\n", bigbuf_net);
379		}
380#endif
381
382	/* now check out who it is.  We don't care about mismatched DNS names here,
383	 but any ADDR and PORT we specified had better fucking well match the caller.
384	 Converting from addr to inet_ntoa and back again is a bit of a kludge, but
385	 gethostpoop wants a string and there's much gnarlier code out there already,
386	 so I don't feel bad.
387	 The *real* question is why BFD sockets wasn't designed to allow listens for
388	 connections *from* specific hosts/ports, instead of requiring the caller to
389	 accept the connection and then reject undesireable ones by closing.
390	 In other words, we need a TCP MSG_PEEK. */
391	/* bbox: removed most of it */
392		lcladdr = xmalloc_sockaddr2dotted(&ouraddr->sa);
393		remaddr = xmalloc_sockaddr2dotted(&remend.sa);
394		remhostname = o_nflag ? remaddr : xmalloc_sockaddr2host(&remend.sa);
395		fprintf(stderr, "connect to %s from %s (%s)\n",
396				lcladdr, remhostname, remaddr);
397		free(lcladdr);
398		free(remaddr);
399		if (!o_nflag)
400			free(remhostname);
401	}
402}
403
404/* udptest:
405 fire a couple of packets at a UDP target port, just to see if it's really
406 there.  On BSD kernels, ICMP host/port-unreachable errors get delivered to
407 our socket as ECONNREFUSED write errors.  On SV kernels, we lose; we'll have
408 to collect and analyze raw ICMP ourselves a la satan's probe_udp_ports
409 backend.  Guess where one could swipe the appropriate code from...
410
411 Use the time delay between writes if given, otherwise use the "tcp ping"
412 trick for getting the RTT.  [I got that idea from pluvius, and warped it.]
413 Return either the original fd, or clean up and return -1. */
414#if ENABLE_NC_EXTRA
415static int udptest(void)
416{
417	int rr;
418
419	rr = write(netfd, bigbuf_in, 1);
420	if (rr != 1)
421		bb_perror_msg("udptest first write");
422
423	if (o_wait)
424		sleep(o_wait); // can be interrupted! while (t) nanosleep(&t)?
425	else {
426	/* use the tcp-ping trick: try connecting to a normally refused port, which
427	 causes us to block for the time that SYN gets there and RST gets back.
428	 Not completely reliable, but it *does* mostly work. */
429	/* Set a temporary connect timeout, so packet filtration doesnt cause
430	 us to hang forever, and hit it */
431		o_wait = 5;                     /* enough that we'll notice?? */
432		rr = xsocket(ouraddr->sa.sa_family, SOCK_STREAM, 0);
433		set_nport(themaddr, htons(SLEAZE_PORT));
434		connect_w_timeout(rr);
435		/* don't need to restore themaddr's port, it's not used anymore */
436		close(rr);
437		o_wait = 0; /* restore */
438	}
439
440	rr = write(netfd, bigbuf_in, 1);
441	return (rr != 1); /* if rr == 1, return 0 (success) */
442}
443#else
444int udptest(void);
445#endif
446
447/* oprint:
448 Hexdump bytes shoveled either way to a running logfile, in the format:
449 D offset       -  - - - --- 16 bytes --- - - -  -     # .... ascii .....
450 where "which" sets the direction indicator, D:
451 0 -- sent to network, or ">"
452 1 -- rcvd and printed to stdout, or "<"
453 and "buf" and "n" are data-block and length.  If the current block generates
454 a partial line, so be it; we *want* that lockstep indication of who sent
455 what when.  Adapted from dgaudet's original example -- but must be ripping
456 *fast*, since we don't want to be too disk-bound... */
457#if ENABLE_NC_EXTRA
458static void oprint(int direction, unsigned char *p, unsigned bc)
459{
460	unsigned obc;           /* current "global" offset */
461	unsigned x;
462	unsigned char *op;      /* out hexdump ptr */
463	unsigned char *ap;      /* out asc-dump ptr */
464	unsigned char stage[100];
465
466	if (bc == 0)
467		return;
468
469	obc = wrote_net; /* use the globals! */
470	if (direction == '<')
471		obc = wrote_out;
472	stage[0] = direction;
473	stage[59] = '#'; /* preload separator */
474	stage[60] = ' ';
475
476	do {    /* for chunk-o-data ... */
477		x = 16;
478		if (bc < 16) {
479			/* memset(&stage[bc*3 + 11], ' ', 16*3 - bc*3); */
480			memset(&stage[11], ' ', 16*3);
481			x = bc;
482		}
483		sprintf(&stage[1], " %8.8x ", obc);
484		bc -= x;          /* fix current count */
485		obc += x;         /* fix current offset */
486		op = &stage[11];  /* where hex starts */
487		ap = &stage[61];  /* where ascii starts */
488
489		do {  /* for line of dump, however long ... */
490			*op++ = 0x20 | bb_hexdigits_upcase[*p >> 4];
491			*op++ = 0x20 | bb_hexdigits_upcase[*p & 0x0f];
492			*op++ = ' ';
493			if ((*p > 31) && (*p < 127))
494				*ap = *p;   /* printing */
495			else
496				*ap = '.';  /* nonprinting, loose def */
497			ap++;
498			p++;
499		} while (--x);
500		*ap++ = '\n';  /* finish the line */
501		xwrite(ofd, stage, ap - stage);
502	} while (bc);
503}
504#else
505void oprint(int direction, unsigned char *p, unsigned bc);
506#endif
507
508/* readwrite:
509 handle stdin/stdout/network I/O.  Bwahaha!! -- the select loop from hell.
510 In this instance, return what might become our exit status. */
511static int readwrite(void)
512{
513	int rr;
514	char *zp = zp; /* gcc */  /* stdin buf ptr */
515	char *np = np;            /* net-in buf ptr */
516	unsigned rzleft;
517	unsigned rnleft;
518	unsigned netretry;              /* net-read retry counter */
519	unsigned wretry;                /* net-write sanity counter */
520	unsigned wfirst;                /* one-shot flag to skip first net read */
521
522	/* if you don't have all this FD_* macro hair in sys/types.h, you'll have to
523	 either find it or do your own bit-bashing: *ding1 |= (1 << fd), etc... */
524	FD_SET(netfd, &ding1);                /* global: the net is open */
525	netretry = 2;
526	wfirst = 0;
527	rzleft = rnleft = 0;
528	if (o_interval)
529		sleep(o_interval);                /* pause *before* sending stuff, too */
530
531	errno = 0;                        /* clear from sleep, close, whatever */
532	/* and now the big ol' select shoveling loop ... */
533	while (FD_ISSET(netfd, &ding1)) {        /* i.e. till the *net* closes! */
534		wretry = 8200;                        /* more than we'll ever hafta write */
535		if (wfirst) {                        /* any saved stdin buffer? */
536			wfirst = 0;                        /* clear flag for the duration */
537			goto shovel;                        /* and go handle it first */
538		}
539		ding2 = ding1;                        /* FD_COPY ain't portable... */
540	/* some systems, notably linux, crap into their select timers on return, so
541	 we create a expendable copy and give *that* to select.  */
542		if (o_wait) {
543			struct timeval tmp_timer;
544			tmp_timer.tv_sec = o_wait;
545			tmp_timer.tv_usec = 0;
546		/* highest possible fd is netfd (3) */
547			rr = select(netfd+1, &ding2, NULL, NULL, &tmp_timer);
548		} else
549			rr = select(netfd+1, &ding2, NULL, NULL, NULL);
550		if (rr < 0 && errno != EINTR) {                /* might have gotten ^Zed, etc */
551			holler_perror("select");
552			close(netfd);
553			return 1;
554		}
555	/* if we have a timeout AND stdin is closed AND we haven't heard anything
556	 from the net during that time, assume it's dead and close it too. */
557		if (rr == 0) {
558			if (!FD_ISSET(0, &ding1))
559				netretry--;                        /* we actually try a coupla times. */
560			if (!netretry) {
561				if (o_verbose > 1)                /* normally we don't care */
562					fprintf(stderr, "net timeout\n");
563				close(netfd);
564				return 0;                        /* not an error! */
565			}
566		} /* select timeout */
567
568	/* Ding!!  Something arrived, go check all the incoming hoppers, net first */
569		if (FD_ISSET(netfd, &ding2)) {                /* net: ding! */
570			rr = read(netfd, bigbuf_net, BIGSIZ);
571			if (rr <= 0) {
572				if (rr < 0 && o_verbose > 1) {
573					/* nc 1.10 doesn't do this */
574					bb_perror_msg("net read");
575				}
576				FD_CLR(netfd, &ding1);                /* net closed, we'll finish up... */
577				rzleft = 0;                        /* can't write anymore: broken pipe */
578			} else {
579				rnleft = rr;
580				np = bigbuf_net;
581			}
582Debug("got %d from the net, errno %d", rr, errno);
583		} /* net:ding */
584
585	/* if we're in "slowly" mode there's probably still stuff in the stdin
586	 buffer, so don't read unless we really need MORE INPUT!  MORE INPUT! */
587		if (rzleft)
588			goto shovel;
589
590	/* okay, suck more stdin */
591		if (FD_ISSET(0, &ding2)) {                /* stdin: ding! */
592			rr = read(0, bigbuf_in, BIGSIZ);
593	/* Considered making reads here smaller for UDP mode, but 8192-byte
594	 mobygrams are kinda fun and exercise the reassembler. */
595			if (rr <= 0) {                        /* at end, or fukt, or ... */
596				FD_CLR(0, &ding1);                /* disable and close stdin */
597				close(0);
598			} else {
599				rzleft = rr;
600				zp = bigbuf_in;
601			}
602		} /* stdin:ding */
603 shovel:
604	/* now that we've dingdonged all our thingdings, send off the results.
605	 Geez, why does this look an awful lot like the big loop in "rsh"? ...
606	 not sure if the order of this matters, but write net -> stdout first. */
607
608	/* sanity check.  Works because they're both unsigned... */
609		if ((rzleft > 8200) || (rnleft > 8200)) {
610			holler_error("bogus buffers: %u, %u", rzleft, rnleft);
611			rzleft = rnleft = 0;
612		}
613	/* net write retries sometimes happen on UDP connections */
614		if (!wretry) {                        /* is something hung? */
615			holler_error("too many output retries");
616			return 1;
617		}
618		if (rnleft) {
619			rr = write(1, np, rnleft);
620			if (rr > 0) {
621				if (o_ofile)
622					oprint('<', np, rr);                /* log the stdout */
623				np += rr;                        /* fix up ptrs and whatnot */
624				rnleft -= rr;                        /* will get sanity-checked above */
625				wrote_out += rr;                /* global count */
626			}
627Debug("wrote %d to stdout, errno %d", rr, errno);
628		} /* rnleft */
629		if (rzleft) {
630			if (o_interval)                        /* in "slowly" mode ?? */
631				rr = findline(zp, rzleft);
632			else
633				rr = rzleft;
634			rr = write(netfd, zp, rr);        /* one line, or the whole buffer */
635			if (rr > 0) {
636				if (o_ofile)
637					oprint('>', zp, rr);                /* log what got sent */
638				zp += rr;
639				rzleft -= rr;
640				wrote_net += rr;                /* global count */
641			}
642Debug("wrote %d to net, errno %d", rr, errno);
643		} /* rzleft */
644		if (o_interval) {                        /* cycle between slow lines, or ... */
645			sleep(o_interval);
646			errno = 0;                        /* clear from sleep */
647			continue;                        /* ...with hairy select loop... */
648		}
649		if ((rzleft) || (rnleft)) {                /* shovel that shit till they ain't */
650			wretry--;                        /* none left, and get another load */
651			goto shovel;
652		}
653	} /* while ding1:netfd is open */
654
655	close(netfd);
656	return 0;
657} /* readwrite */
658
659/* main: now we pull it all together... */
660int nc_main(int argc, char **argv);
661int nc_main(int argc, char **argv)
662{
663	char *str_p, *str_s, *str_w;
664	USE_NC_EXTRA(char *str_i, *str_o;)
665	char *themdotted = themdotted; /* gcc */
666	char **proggie;
667	int x;
668	unsigned o_lport = 0;
669
670	/* I was in this barbershop quartet in Skokie IL ... */
671	/* round up the usual suspects, i.e. malloc up all the stuff we need */
672	PTR_TO_GLOBALS = xzalloc(sizeof(G));
673
674	/* catch a signal or two for cleanup */
675	signal(SIGINT, catch);
676	signal(SIGQUIT, catch);
677	signal(SIGTERM, catch);
678	/* and suppress others... */
679#ifdef SIGURG
680	signal(SIGURG, SIG_IGN);
681#endif
682	signal(SIGPIPE, SIG_IGN); /* important! */
683
684	proggie = argv;
685	while (*++proggie) {
686		if (strcmp(*proggie, "-e") == 0) {
687			*proggie = NULL;
688			argc = proggie - argv;
689			proggie++;
690			goto e_found;
691		}
692	}
693	proggie = NULL;
694 e_found:
695
696	// -g -G -t -r deleted, unimplemented -a deleted too
697	opt_complementary = "?2:vv"; /* max 2 params, -v is a counter */
698	getopt32(argv, "hnp:s:uvw:" USE_NC_SERVER("l")
699			USE_NC_EXTRA("i:o:z"),
700			&str_p, &str_s, &str_w
701			USE_NC_EXTRA(, &str_i, &str_o, &o_verbose));
702	argv += optind;
703#if ENABLE_NC_EXTRA
704	if (option_mask32 & OPT_i) /* line-interval time */
705		o_interval = xatou_range(str_i, 1, 0xffff);
706#endif
707	//if (option_mask32 & OPT_l) /* listen mode */
708	//if (option_mask32 & OPT_n) /* numeric-only, no DNS lookups */
709	//if (option_mask32 & OPT_o) /* hexdump log */
710	if (option_mask32 & OPT_p) { /* local source port */
711		o_lport = bb_lookup_port(str_p, o_udpmode ? "udp" : "tcp", 0);
712		if (!o_lport)
713			bb_error_msg_and_die("bad local port '%s'", str_p);
714	}
715	//if (option_mask32 & OPT_r) /* randomize various things */
716	//if (option_mask32 & OPT_u) /* use UDP */
717	//if (option_mask32 & OPT_v) /* verbose */
718	if (option_mask32 & OPT_w) { /* wait time */
719		o_wait = xatoi_u(str_w);
720	}
721	//if (option_mask32 & OPT_z) /* little or no data xfer */
722
723	/* We manage our fd's so that they are never 0,1,2 */
724	/*bb_sanitize_stdio(); - not needed */
725
726	if (argv[0]) {
727		themaddr = xhost2sockaddr(argv[0],
728			argv[1]
729			? bb_lookup_port(argv[1], o_udpmode ? "udp" : "tcp", 0)
730			: 0);
731	}
732
733	/* create & bind network socket */
734	x = (o_udpmode ? SOCK_DGRAM : SOCK_STREAM);
735	if (option_mask32 & OPT_s) { /* local address */
736		/* if o_lport is still 0, then we will use random port */
737		ouraddr = xhost2sockaddr(str_s, o_lport);
738		x = xsocket(ouraddr->sa.sa_family, x, 0);
739	} else {
740		/* We try IPv6, then IPv4, unless addr family is
741		 * implicitly set by way of remote addr/port spec */
742		x = xsocket_type(&ouraddr,
743				USE_FEATURE_IPV6((themaddr ? themaddr->sa.sa_family : AF_UNSPEC),)
744				x);
745		if (o_lport)
746			set_nport(ouraddr, htons(o_lport));
747	}
748	xmove_fd(x, netfd);
749	setsockopt_reuseaddr(netfd);
750	if (o_udpmode)
751		socket_want_pktinfo(netfd);
752	xbind(netfd, &ouraddr->sa, ouraddr->len);
753
754	if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) {
755		/* apparently UDP can listen ON "port 0",
756		 but that's not useful */
757		if (!o_lport)
758			bb_error_msg_and_die("UDP listen needs nonzero -p port");
759	}
760
761	FD_SET(0, &ding1);                        /* stdin *is* initially open */
762	if (proggie) {
763		close(0); /* won't need stdin */
764		option_mask32 &= ~OPT_o; /* -o with -e is meaningless! */
765	}
766#if ENABLE_NC_EXTRA
767	if (o_ofile)
768		xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), ofd);
769#endif
770
771	if (o_listen) {
772		dolisten();
773		/* dolisten does its own connect reporting */
774		if (proggie) /* -e given? */
775			doexec(proggie);
776		x = readwrite(); /* it even works with UDP! */
777	} else {
778		/* Outbound connects.  Now we're more picky about args... */
779		if (!themaddr)
780			bb_error_msg_and_die("no destination");
781
782		remend = *themaddr;
783		if (o_verbose)
784			themdotted = xmalloc_sockaddr2dotted(&themaddr->sa);
785
786		x = connect_w_timeout(netfd);
787		if (o_zero && x == 0 && o_udpmode)        /* if UDP scanning... */
788			x = udptest();
789		if (x == 0) {                        /* Yow, are we OPEN YET?! */
790			if (o_verbose)
791				fprintf(stderr, "%s (%s) open\n", argv[0], themdotted);
792			if (proggie)                        /* exec is valid for outbound, too */
793				doexec(proggie);
794			if (!o_zero)
795				x = readwrite();
796		} else { /* connect or udptest wasn't successful */
797			x = 1;                                /* exit status */
798			/* if we're scanning at a "one -v" verbosity level, don't print refusals.
799			 Give it another -v if you want to see everything. */
800			if (o_verbose > 1 || (o_verbose && errno != ECONNREFUSED))
801				bb_perror_msg("%s (%s)", argv[0], themdotted);
802		}
803	}
804	if (o_verbose > 1)                /* normally we don't care */
805		fprintf(stderr, SENT_N_RECV_M, wrote_net, wrote_out);
806	return x;
807}
808