summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorericj <>2001-06-25 22:17:35 +0000
committerericj <>2001-06-25 22:17:35 +0000
commitabbf925da56bb0d7aac937d8e270af8f025c8fe5 (patch)
treec10aae909652b766aa9a85fa96a1901de7be9b1c
parentde0bea2741dc316bd124830c3b9c8a2d15799319 (diff)
downloadopenbsd-abbf925da56bb0d7aac937d8e270af8f025c8fe5.tar.gz
openbsd-abbf925da56bb0d7aac937d8e270af8f025c8fe5.tar.bz2
openbsd-abbf925da56bb0d7aac937d8e270af8f025c8fe5.zip
Import completely re-written netcat w/ support for IPv6.
very little usage has changed, man page soon to come for it as well. deraadt@ ok
-rw-r--r--src/usr.bin/nc/Makefile5
-rw-r--r--src/usr.bin/nc/atomicio.c58
-rw-r--r--src/usr.bin/nc/netcat.c1741
3 files changed, 523 insertions, 1281 deletions
diff --git a/src/usr.bin/nc/Makefile b/src/usr.bin/nc/Makefile
index 086a9e5ee8..7ae9233f93 100644
--- a/src/usr.bin/nc/Makefile
+++ b/src/usr.bin/nc/Makefile
@@ -1,7 +1,6 @@
1# $OpenBSD: Makefile,v 1.2 1997/09/21 11:50:13 deraadt Exp $ 1# $OpenBSD: Makefile,v 1.3 2001/06/25 22:17:33 ericj Exp $
2 2
3CFLAGS+= -DTELNET
4PROG= nc 3PROG= nc
5SRCS= netcat.c 4SRCS= netcat.c atomicio.c
6 5
7.include <bsd.prog.mk> 6.include <bsd.prog.mk>
diff --git a/src/usr.bin/nc/atomicio.c b/src/usr.bin/nc/atomicio.c
new file mode 100644
index 0000000000..f404eeedd8
--- /dev/null
+++ b/src/usr.bin/nc/atomicio.c
@@ -0,0 +1,58 @@
1/*
2 * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/types.h>
27#include <sys/uio.h>
28
29#include <errno.h>
30#include <unistd.h>
31
32/*
33 * ensure all of data on socket comes through. f==read || f==write
34 */
35ssize_t
36atomicio(f, fd, _s, n)
37 ssize_t (*f) ();
38 int fd;
39 void *_s;
40 size_t n;
41{
42 char *s = _s;
43 ssize_t res, pos = 0;
44
45 while (n > pos) {
46 res = (f) (fd, s + pos, n - pos);
47 switch (res) {
48 case -1:
49 if (errno == EINTR || errno == EAGAIN)
50 continue;
51 case 0:
52 return (res);
53 default:
54 pos += res;
55 }
56 }
57 return (pos);
58}
diff --git a/src/usr.bin/nc/netcat.c b/src/usr.bin/nc/netcat.c
index ac4161cf2c..8370c33c9f 100644
--- a/src/usr.bin/nc/netcat.c
+++ b/src/usr.bin/nc/netcat.c
@@ -1,833 +1,450 @@
1/* $OpenBSD: netcat.c,v 1.20 2001/05/04 01:38:31 millert Exp $ */ 1/* $OpenBSD: netcat.c,v 1.21 2001/06/25 22:17:35 ericj Exp $ */
2 2/*
3/* Netcat 1.10 RELEASE 960320 3 * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
4 *
5 * A damn useful little "backend" utility begun 950915 or thereabouts,
6 * as *Hobbit*'s first real stab at some sockets programming. Something that
7 * should have and indeed may have existed ten years ago, but never became a
8 * standard Unix utility. IMHO, "nc" could take its place right next to cat,
9 * cp, rm, mv, dd, ls, and all those other cryptic and Unix-like things.
10 * 4 *
11 * Read the README for the whole story, doc, applications, etc. 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
12 * 8 *
13 * Layout: 9 * 1. Redistributions of source code must retain the above copyright
14 * conditional includes: 10 * notice, this list of conditions and the following disclaimer.
15 * includes: 11 * 2. Redistributions in binary form must reproduce the above copyright
16 * handy defines: 12 * notice, this list of conditions and the following disclaimer in the
17 * globals: 13 * documentation and/or other materials provided with the distribution.
18 * malloced globals: 14 * 3. The name of the author may not be used to endorse or promote products
19 * cmd-flag globals: 15 * derived from this software without specific prior written permission.
20 * support routines:
21 * readwrite select loop:
22 * main:
23 * 16 *
24 * bluesky: 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * parse ranges of IP address as well as ports, perhaps 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * RAW mode! 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * backend progs to grab a pty and look like a real telnetd?! 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * backend progs to do various encryption modes??!?! 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29*/ 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
30 28
29/*
30 * Re-written nc(1) for OpenBSD. Only code shared with previous version
31 * was the code for telnet emulation. Original implementation by
32 * *Hobbit* <hobbit@avian.org>.
33 */
31 34
32#include <sys/types.h> 35#include <sys/types.h>
33#include <sys/time.h>
34#include <sys/select.h>
35#include <sys/socket.h> 36#include <sys/socket.h>
37#include <sys/time.h>
38
36#include <netinet/in.h> 39#include <netinet/in.h>
37#include <netinet/in_systm.h> 40#include <arpa/telnet.h>
38#include <netinet/ip.h>
39#include <arpa/inet.h>
40#include <arpa/nameser.h>
41#include <netdb.h> /* hostent, gethostby*, getservby* */
42#include <stdio.h>
43#include <string.h>
44#include <err.h> 41#include <err.h>
45#include <errno.h> 42#include <errno.h>
46#include <setjmp.h> 43#include <netdb.h>
47#include <signal.h> 44#include <poll.h>
48#include <fcntl.h>
49#include <resolv.h>
50#include <stdarg.h> 45#include <stdarg.h>
46#include <stdio.h>
51#include <stdlib.h> 47#include <stdlib.h>
48#include <string.h>
52#include <unistd.h> 49#include <unistd.h>
53 50
54#define SLEAZE_PORT 31337 /* for UDP-scan RTT trick, change if ya want */ 51/* Command Line Options */
55#define BIGSIZ 8192 /* big buffers */ 52int iflag; /* Interval Flag */
56 53int kflag; /* More than one connect */
57struct host_info { 54int lflag; /* Bind to local port */
58 char name[MAXHOSTNAMELEN]; /* DNS name */ 55int nflag; /* Dont do name lookup */
59 char addrs[8][24]; /* ascii-format IP addresses */ 56char *pflag; /* Localport flag */
60 struct in_addr iaddrs[8]; /* in_addr.s_addr: ulong */ 57int rflag; /* Random ports flag */
61}; 58char *sflag; /* Source Address */
62 59int tflag; /* Telnet Emulation */
63struct port_info { 60int uflag; /* UDP - Default to TCP */
64 char name[64]; /* name in /etc/services */ 61int vflag; /* Verbosity */
65 char anum[8]; /* ascii-format number */ 62int zflag; /* Port Scan Flag */
66 u_short num; /* real host-order number */ 63
67}; 64int timeout;
68 65int family = AF_UNSPEC;
69/* globals: */ 66char *portlist[65535];
70jmp_buf jbuf; /* timer jump buffer*/ 67
71int jval = 0; /* timer crud */ 68void atelnet __P((int, unsigned char *, unsigned int));
72int netfd = -1; 69void build_ports __P((char *));
73int ofd = 0; /* hexdump output fd */ 70void help __P((void));
74 71int local_listen __P((char *, char *, struct addrinfo));
75int gatesidx = 0; /* LSRR hop count */ 72void readwrite __P((int));
76int gatesptr = 4; /* initial LSRR pointer, settable */ 73int remote_connect __P((char *, char *, struct addrinfo));
77u_short Single = 1; /* zero if scanning */ 74int udptest __P((int));
78unsigned int insaved = 0; /* stdin-buffer size for multi-mode */ 75void usage __P((int));
79unsigned int wrote_out = 0; /* total stdout bytes */
80unsigned int wrote_net = 0; /* total net bytes */
81static char hexnibs[20] = "0123456789abcdef ";
82
83/* will malloc up the following globals: */
84struct timeval timer1, timer2;
85struct sockaddr_in *lclend = NULL; /* sockaddr_in structs */
86struct sockaddr_in *remend = NULL;
87struct host_info **gates = NULL; /* LSRR hop hinfo */
88char *optbuf = NULL; /* LSRR or sockopts */
89char *bigbuf_in; /* data buffers */
90char *bigbuf_net;
91fd_set fds1, fds2;
92struct port_info *pinfo = NULL; /* for getpinfo / getservby* */
93unsigned char *stage = NULL; /* hexdump line buffer */
94
95/* global cmd flags: */
96u_short o_alla = 0;
97unsigned int o_interval = 0;
98u_short o_listen = 0;
99u_short o_nflag = 0;
100u_short o_wfile = 0;
101u_short o_random = 0;
102u_short o_udpmode = 0;
103u_short o_verbose = 0;
104unsigned int o_wait = 0;
105u_short o_zero = 0;
106
107/* Function Prototype's */
108void help __P(());
109void nlog __P((int, char *, ...));
110void usage __P((int));
111
112/*
113 * support routines -- the bulk of this thing. Placed in such an order that
114 * we don't have to forward-declare anything:
115 */
116
117/*
118 * catch :
119 * no-brainer interrupt handler
120 */
121void
122catch()
123{
124 if (o_verbose) /* normally we don't care */
125 nlog(1, "Sent %i Rcvd %i", wrote_net, wrote_out);
126 nlog(1, " punt!");
127}
128
129/* timeout and other signal handling cruft */
130void
131tmtravel()
132{
133 signal(SIGALRM, SIG_IGN);
134 alarm(0);
135 if (jval == 0)
136 nlog(1, "spurious timer interrupt!");
137 longjmp(jbuf, jval);
138}
139
140/*
141 * arm :
142 * set the timer. Zero secs arg means unarm
143 */
144void
145arm(num, secs)
146 unsigned int num;
147 unsigned int secs;
148{
149 if (secs == 0) {
150 signal(SIGALRM, SIG_IGN);
151 alarm(0);
152 jval = 0;
153 } else {
154 signal(SIGALRM, tmtravel);
155 alarm(secs);
156 jval = num;
157 }
158}
159 76
160/* 77int
161 * findline : 78main(argc, argv)
162 * find the next newline in a buffer; return inclusive size of that "line", 79 int argc;
163 * or the entire buffer size, so the caller knows how much to then write(). 80 char *argv[];
164 * Not distinguishing \n vs \r\n for the nonce; it just works as is...
165 */
166unsigned int
167findline(buf, siz)
168 char *buf;
169 unsigned int siz;
170{ 81{
171 char *p; 82 int ch, s, ret = 1;
172 int x; 83 char *host, *uport;
173 if (!buf) /* various sanity checks... */ 84 struct addrinfo hints;
174 return (0); 85 struct servent *sv = 0;
175 if (siz > BIGSIZ) 86 socklen_t len;
176 return (0); 87 struct sockaddr *cliaddr;
177 x = siz; 88
178 for (p = buf; x > 0; x--) { 89 while ((ch = getopt(argc, argv, "46hi:klnp:rs:tuvw:z")) != -1) {
179 if (*p == '\n') { 90 switch (ch) {
180 x = (int) (p - buf); 91 case '4':
181 x++; /* 'sokay if it points just past the end! */ 92 family = AF_INET;
182 return (x); 93 break;
94 case '6':
95 family = AF_INET6;
96 break;
97 case 'h':
98 help();
99 break;
100 case 'i':
101 iflag = atoi(optarg);
102 break;
103 case 'k':
104 kflag = 1;
105 break;
106 case 'l':
107 lflag = 1;
108 break;
109 case 'n':
110 nflag = 1;
111 break;
112 case 'p':
113 pflag = optarg;
114 break;
115 case 'r':
116 rflag = 1;
117 break;
118 case 's':
119 sflag = optarg;
120 break;
121 case 't':
122 tflag = 1;
123 break;
124 case 'u':
125 uflag = 1;
126 break;
127 case 'v':
128 vflag = 1;
129 break;
130 case 'w':
131 timeout = atoi(optarg);
132 break;
133 case 'z':
134 zflag = 1;
135 break;
136 default:
137 usage(1);
183 } 138 }
184 p++;
185 } 139 }
186 return (siz); 140 argc -= optind;
187} 141 argv += optind;
188 142
189/* 143 /* Cruft to make sure options are clean, and used properly. */
190 * comparehosts : 144 if (argv[0] && !argv[1]) {
191 * cross-check the host_info we have so far against new gethostby*() info, 145 if (!lflag)
192 * and holler about mismatches. Perhaps gratuitous, but it can't hurt to 146 usage(1);
193 * point out when someone's DNS is fukt. Returns 1 if mismatch, in case 147 uport = argv[0];
194 * someone else wants to do something about it. 148 host = NULL;
195 */ 149 } else if (argv[0] && argv[1]) {
196int 150 host = argv[0];
197comparehosts(hinfo, hp) 151 uport = argv[1];
198 struct host_info *hinfo; 152 } else
199 struct hostent *hp; 153 usage(1);
200{ 154
201 if (strcasecmp(hinfo->name, hp->h_name) != 0) { 155 if (lflag && sflag)
202 nlog(0, "DNS fwd/rev mismatch: %s != %s", hinfo->name, hp->h_name); 156 errx(1, "cannot use -s and -l");
203 return (1); 157 if (lflag && pflag)
204 } 158 errx(1, "cannot use -p and -l");
205 return (0); 159 if (lflag && zflag)
206} 160 errx(1, "cannot use -p and -l");
161 if (!lflag && kflag)
162 errx(1, "must use -k with -l");
163
164 /* Initialize addrinfo structure */
165 memset(&hints, 0, sizeof(struct addrinfo));
166 hints.ai_family = family;
167 hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
168 hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
169 if (nflag)
170 hints.ai_flags |= AI_NUMERICHOST;
171
172 if (lflag) {
173 int connfd;
174
175 if ((s = local_listen(host, uport, hints)) < 0)
176 errx(1, NULL);
207 177
208/* 178 ret = 0;
209 * gethinfo: 179 /* Allow only one connection at a time, but stay alive */
210 * resolve a host 8 ways from sunday; return a new host_info struct with its 180 for (;;) {
211 * info. The argument can be a name or [ascii] IP address; it will try its 181 /*
212 * damndest to deal with it. "numeric" governs whether we do any DNS at all, 182 * For UDP, we will use recvfrom() initially
213 * and we also check o_verbose for what's appropriate work to do. 183 * to wait for a caller, then use the regular
214 */ 184 * functions to talk to the caller.
215struct host_info * 185 */
216gethinfo(name, numeric) 186 if (uflag) {
217 char *name; 187 int ret;
218 u_short numeric; 188 char buf[1024];
219{ 189 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
220 struct hostent *hostent; 190 struct sockaddr_storage z;
221 struct in_addr iaddr; 191
222 struct host_info *hinfo = NULL; 192 len = sizeof(z);
223 int x; 193 ret = recvfrom(s, buf, sizeof(buf), MSG_PEEK,
224 194 (struct sockaddr *)&z, &len);
225 if (name) 195 if (ret < 0)
226 hinfo = (struct host_info *) calloc(1, sizeof(struct host_info)); 196 errx(1, "%s", strerror(errno));
227 197
228 if (!hinfo) 198 ret = connect(s, (struct sockaddr *)&z,
229 nlog(1, "error obtaining host information"); 199 len);
230 200 if (ret < 0)
231 strlcpy(hinfo->name, "(UNKNOWN)", sizeof(hinfo->name)); 201 errx(1, "%s", strerror(errno));
232 if (inet_aton(name, &iaddr) == 0) { 202
233 if (numeric) 203 connfd = s;
234 nlog(1, "Can't parse %s as an IP address", name); 204 } else {
235 205 connfd = accept(s, (struct sockaddr *)&cliaddr,
236 /* 206 &len);
237 * failure to look up a name is fatal, 207 }
238 * since we can't do anything with it.
239 */
240 hostent = gethostbyname(name);
241 if (!hostent)
242 nlog(1, "%s: forward host lookup failed: ", name);
243
244 strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN);
245 for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) {
246 memcpy(&hinfo->iaddrs[x], hostent->h_addr_list[x],
247 sizeof(struct in_addr));
248 strlcpy(hinfo->addrs[x], inet_ntoa(hinfo->iaddrs[x]),
249 sizeof(hinfo->addrs[0]));
250 }
251 /* Go ahead and return if we don't want to view more */
252 if (!o_verbose)
253 return (hinfo);
254
255 /*
256 * Do inverse lookups in separate loop based on our collected
257 * forward addrs, since gethostby* tends to crap into the same
258 * buffer over and over.
259 */
260 for (x = 0; hinfo->iaddrs[x].s_addr && (x < 8); x++) {
261 hostent = gethostbyaddr((char *) &hinfo->iaddrs[x],
262 sizeof(struct in_addr), AF_INET);
263 if ((!hostent) || (!hostent->h_name))
264 nlog(0, "Warning: inverse host lookup failed for %s: ",
265 hinfo->addrs[x]);
266 else
267 (void) comparehosts(hinfo, hostent);
268 }
269 208
270 } else { /* not INADDR_NONE: numeric addresses... */ 209 readwrite(connfd);
271 memcpy(hinfo->iaddrs, &iaddr, sizeof(struct in_addr)); 210 close(connfd);
272 strlcpy(hinfo->addrs[0], inet_ntoa(iaddr), sizeof(hinfo->addrs)); 211 if (!kflag)
273 /* If all that's wanted is numeric IP, go ahead and leave */ 212 break;
274 if (numeric)
275 return (hinfo);
276
277 /* Go ahead and return if we don't want to view more */
278 if (!o_verbose)
279 return (hinfo);
280
281 hostent = gethostbyaddr((char *) &iaddr,
282 sizeof(struct in_addr), AF_INET);
283
284 /*
285 * numeric or not, failure to look up a PTR is
286 * *not* considered fatal
287 */
288 if (!hostent)
289 nlog(0, "%s: inverse host lookup failed: ", name);
290 else {
291 strlcpy(hinfo->name, hostent->h_name, MAXHOSTNAMELEN);
292 hostent = gethostbyname(hinfo->name);
293 if ((!hostent) || (!hostent->h_addr_list[0]))
294 nlog(0, "Warning: forward host lookup failed for %s: ",
295 hinfo->name);
296 else
297 (void) comparehosts(hinfo, hostent);
298 } 213 }
299 } 214 } else {
300 215 int i = 0;
301 /*
302 * Whatever-all went down previously, we should now have a host_info
303 * struct with at least one IP address in it.
304 */
305 return (hinfo);
306}
307 216
308/* 217 /* construct the portlist[] array */
309 * getpinfo: 218 build_ports(uport);
310 * Same general idea as gethinfo-- look up a port in /etc/services, fill
311 * in global port_info, but return the actual port *number*. Pass ONE of:
312 * pstring to resolve stuff like "23" or "exec";
313 * pnum to reverse-resolve something that's already a number.
314 * If o_nflag is on, fill in what we can but skip the getservby??? stuff.
315 * Might as well have consistent behavior here, and it *is* faster.
316 */
317u_short
318getpinfo(pstring, pnum)
319 char *pstring;
320 unsigned int pnum;
321{
322 struct servent *servent;
323 int x;
324 int y;
325 219
326 pinfo->name[0] = '?';/* fast preload */ 220 /* Cycle through portlist, connecting to each port */
327 pinfo->name[1] = '\0'; 221 for (i = 0; portlist[i] != NULL; i++) {
222
223 if (s)
224 close(s);
225
226 if ((s = remote_connect(host, portlist[i], hints)) < 0)
227 continue;
328 228
329 /* 229 ret = 0;
330 * case 1: reverse-lookup of a number; placed first since this case 230 if (vflag || zflag) {
331 * is much more frequent if we're scanning. 231 /* For UDP, make sure we are connected */
332 */ 232 if (uflag) {
333 if (pnum) { 233 if ((udptest(s)) == -1) {
334 /* Can't be both */ 234 ret = 1;
335 if (pstring) 235 continue;
336 return (0); 236 }
337 237 }
338 x = pnum;
339 if (o_nflag) /* go faster, skip getservbyblah */
340 goto gp_finish;
341 y = htons(x); /* gotta do this -- see Fig.1 below */
342 servent = getservbyport(y, o_udpmode ? "udp" : "tcp");
343 if (servent) {
344 y = ntohs(servent->s_port);
345 if (x != y)
346 nlog(0, "Warning: port-bynum mismatch, %d != %d", x, y);
347 strlcpy(pinfo->name, servent->s_name,
348 sizeof(pinfo->name));
349 }
350 goto gp_finish;
351 }
352 /*
353 * case 2: resolve a string, but we still give preference to numbers
354 * instead of trying to resolve conflicts. None of the entries in *my*
355 * extensive /etc/services begins with a digit, so this should "always
356 * work" unless you're at 3com and have some company-internal services
357 * defined.
358 */
359 if (pstring) {
360 /* Can't be both */
361 if (pnum)
362 return (0);
363
364 x = atoi(pstring);
365 if (x)
366 return (getpinfo(NULL, x)); /* recurse for
367 * numeric-string-arg */
368 if (o_nflag)
369 return (0);
370 servent = getservbyname(pstring, o_udpmode ? "udp" : "tcp");
371 if (servent) {
372 strlcpy(pinfo->name, servent->s_name,
373 sizeof(pinfo->name));
374 x = ntohs(servent->s_port);
375 goto gp_finish;
376 } /* if servent */
377 } /* if pstring */
378 return (0); /* catches any problems so far */
379
380gp_finish:
381 /*
382 * Fall here whether or not we have a valid servent at this point, with
383 * x containing our [host-order and therefore useful, dammit] port number.
384 */
385 sprintf(pinfo->anum, "%d", x); /* always load any numeric
386 * specs! */
387 pinfo->num = (x & 0xffff); /* u_short, remember... */
388 return (pinfo->num);
389}
390 238
391/* 239 /* Don't lookup port if -n */
392 * nextport : 240 if (nflag)
393 * Come up with the next port to try, be it random or whatever. "block" is 241 sv = NULL;
394 * a ptr to randports array, whose bytes [so far] carry these meanings: 242 else {
395 * 0 ignore 243 sv = getservbyport(
396 * 1 to be tested 244 ntohs(atoi(portlist[i])),
397 * 2 tested [which is set as we find them here] 245 uflag ? "udp" : "tcp");
398 * returns a u_short random port, or 0 if all the t-b-t ones are used up. 246 }
399 */ 247
400u_short 248 printf("Connection to %s %s port [%s/%s] succeeded!\n",
401nextport(block) 249 host, portlist[i], uflag ? "udp" : "tcp",
402 char *block; 250 sv ? sv->s_name : "*");
403{ 251 }
404 unsigned int x; 252 if (!zflag)
405 unsigned int y; 253 readwrite(s);
406
407 y = 70000; /* high safety count for rnd-tries */
408 while (y > 0) {
409 x = (arc4random() & 0xffff);
410 if (block[x] == 1) { /* try to find a not-done one... */
411 block[x] = 2;
412 break;
413 } 254 }
414 x = 0;
415 y--;
416 } 255 }
417 if (x)
418 return (x);
419 256
420 y = 65535; /* no random one, try linear downsearch */ 257 if (s)
421 while (y > 0) { /* if they're all used, we *must* be sure! */ 258 close(s);
422 if (block[y] == 1) {
423 block[y] = 2;
424 break;
425 }
426 y--;
427 }
428 if (y)
429 return (y); /* at least one left */
430 259
431 return (0); 260 exit(ret);
432} 261}
433 262
434/* 263/*
435 * loadports : 264 * remote_connect()
436 * set "to be tested" indications in BLOCK, from LO to HI. Almost too small 265 * Return's a socket connected to a remote host. Properly bind's to a local
437 * to be a separate routine, but makes main() a little cleaner. 266 * port or source address if needed. Return's -1 on failure.
438 */ 267 */
439void 268int
440loadports(block, lo, hi) 269remote_connect(host, port, hints)
441 char *block; 270 char *host, *port;
442 u_short lo; 271 struct addrinfo hints;
443 u_short hi;
444{ 272{
445 u_short x; 273 struct addrinfo *res, *res0;
446 274 int s, error;
447 if (!block)
448 nlog(1, "loadports: no block?!");
449 if ((!lo) || (!hi))
450 nlog(1, "loadports: bogus values %d, %d", lo, hi);
451 x = hi;
452 while (lo <= x) {
453 block[x] = 1;
454 x--;
455 }
456}
457 275
276 if ((error = getaddrinfo(host, port, &hints, &res)))
277 errx(1, "%s", gai_strerror(error));
458 278
459/* 279 res0 = res;
460 * doconnect : 280 do {
461 * do all the socket stuff, and return an fd for one of 281 if ((s = socket(res0->ai_family, res0->ai_socktype,
462 * an open outbound TCP connection 282 res0->ai_protocol)) < 0)
463 * a UDP stub-socket thingie 283 continue;
464 * with appropriate socket options set up if we wanted source-routing, or
465 * an unconnected TCP or UDP socket to listen on.
466 * Examines various global o_blah flags to figure out what-all to do.
467 */
468int
469doconnect(rad, rp, lad, lp)
470 struct in_addr *rad;
471 u_short rp;
472 struct in_addr *lad;
473 u_short lp;
474{
475 int nnetfd = 0;
476 int rr;
477 int x, y;
478
479 /* grab a socket; set opts */
480 while (nnetfd == 0) {
481 if (o_udpmode)
482 nnetfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
483 else
484 nnetfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
485 if (nnetfd < 0)
486 nlog(1, "Can't get socket");
487 }
488 284
489 x = 1; 285 /* Bind to a local port or source address if specified */
490 rr = setsockopt(nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 286 if (sflag || pflag) {
491 if (rr == -1) 287 struct addrinfo ahints, *ares;
492 nlog(1, NULL); 288
493 289 if (!(sflag && pflag)) {
494 /* fill in all the right sockaddr crud */ 290 if (!sflag)
495 lclend->sin_family = AF_INET; 291 sflag = NULL;
496 remend->sin_family = AF_INET; 292 else
497 293 pflag = NULL;
498 /* if lad/lp, do appropriate binding */
499 if (lad)
500 memcpy(&lclend->sin_addr.s_addr, lad, sizeof(struct in_addr));
501 if (lp)
502 lclend->sin_port = htons(lp);
503
504 rr = 0;
505 if (lad || lp) {
506 x = (int) lp;
507 /* try a few times for the local bind, a la ftp-data-port... */
508 for (y = 4; y > 0; y--) {
509 rr = bind(nnetfd, (struct sockaddr *) lclend,
510 sizeof(struct sockaddr_in));
511 if (rr == 0)
512 break;
513 if (errno != EADDRINUSE)
514 break;
515 else {
516 nlog(0, "retrying local %s:%d", inet_ntoa(lclend->sin_addr), lp);
517 sleep(2);
518 } 294 }
295
296 memset(&ahints, 0, sizeof(struct addrinfo));
297 ahints.ai_family = res0->ai_family;
298 ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
299 ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
300 if (getaddrinfo(sflag, pflag, &ahints, &ares))
301 errx(1, "%s", gai_strerror(error));
302
303 if (bind(s, (struct sockaddr *)ares->ai_addr,
304 ares->ai_addrlen) < 0) {
305 errx(1, "bind failed: %s", strerror(errno));
306 freeaddrinfo(ares);
307 continue;
308 }
309 freeaddrinfo(ares);
519 } 310 }
520 }
521 if (rr)
522 nlog(1, "Can't grab %s:%d with bind",
523 inet_ntoa(lclend->sin_addr), lp);
524 311
525 if (o_listen) 312 if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
526 return (nnetfd);/* thanks, that's all for today */ 313 break;
314
315 close(s);
316 s = -1;
317 } while ((res0 = res0->ai_next) != NULL);
527 318
528 memcpy(&remend->sin_addr.s_addr, rad, sizeof(struct in_addr)); 319 freeaddrinfo(res);
529 remend->sin_port = htons(rp);
530 320
531 /* wrap connect inside a timer, and hit it */ 321 return (s);
532 arm(1, o_wait);
533 if (setjmp(jbuf) == 0) {
534 rr = connect(nnetfd, (struct sockaddr *) remend,
535 sizeof(struct sockaddr));
536 } else {
537 rr = -1;
538 errno = ETIMEDOUT;
539 }
540 arm(0, 0);
541 if (rr == 0)
542 return (nnetfd);
543 close(nnetfd);
544 return (-1);
545} 322}
546 323
547/* 324/*
548 * dolisten : 325 * local_listen()
549 * just like doconnect, and in fact calls a hunk of doconnect, but listens for 326 * Return's a socket listening on a local port, binds to specified source
550 * incoming and returns an open connection *from* someplace. If we were 327 * address. Return's -1 on failure.
551 * given host/port args, any connections from elsewhere are rejected. This
552 * in conjunction with local-address binding should limit things nicely.
553 */ 328 */
554int 329int
555dolisten(rad, rp, lad, lp) 330local_listen(host, port, hints)
556 struct in_addr *rad; 331 char *host, *port;
557 u_short rp; 332 struct addrinfo hints;
558 struct in_addr *lad;
559 u_short lp;
560{ 333{
561 int nnetfd; 334 struct addrinfo *res, *res0;
562 int rr; 335 int s, ret, x = 1;
563 struct host_info *whozis = NULL; 336 int error;
564 int x;
565 char *cp;
566 u_short z;
567 337
568 /* 338 /* Allow nodename to be null */
569 * Pass everything off to doconnect, 339 hints.ai_flags |= AI_PASSIVE;
570 * who in o_listen mode just gets a socket
571 */
572 nnetfd = doconnect(rad, rp, lad, lp);
573 if (nnetfd <= 0)
574 return (-1);
575 if (o_udpmode) {
576 if (!lp)
577 nlog(1, "UDP listen needs -p arg");
578 } else {
579 rr = listen(nnetfd, 1);
580 if (rr < 0)
581 nlog(1, "error listening");
582 }
583 340
584 if (o_verbose) {
585 x = sizeof(struct sockaddr);
586 rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x);
587 if (rr < 0)
588 nlog(0, "local getsockname failed");
589 strcpy(bigbuf_net, "listening on ["); /* buffer reuse... */
590 if (lclend->sin_addr.s_addr)
591 strcat(bigbuf_net, inet_ntoa(lclend->sin_addr));
592 else
593 strcat(bigbuf_net, "any");
594 strcat(bigbuf_net, "] ...");
595 z = ntohs(lclend->sin_port);
596 nlog(0, "%s %d", bigbuf_net, z);
597 } /* verbose -- whew!! */
598 /* 341 /*
599 * UDP is a speeeeecial case -- we have to do I/O *and* get the 342 * In the case of binding to a wildcard address
600 * calling party's particulars all at once, listen() and accept() 343 * default to binding to an ipv4 address.
601 * don't apply. At least in the BSD universe, however, recvfrom/PEEK
602 * is enough to tell us something came in, and we can set things up so
603 * straight read/write actually does work after all. Yow. YMMV on
604 * strange platforms!
605 */ 344 */
606 if (o_udpmode) { 345 if (host == NULL && hints.ai_family == AF_UNSPEC)
607 x = sizeof(struct sockaddr); /* retval for recvfrom */ 346 hints.ai_family = AF_INET;
608 arm(2, o_wait); /* might as well timeout this, too */
609 if (setjmp(jbuf) == 0) { /* do timeout for initial
610 * connect */
611 rr = recvfrom(nnetfd, bigbuf_net, BIGSIZ, MSG_PEEK,
612 (struct sockaddr *)remend, &x);
613 } else
614 goto dol_tmo;
615 arm(0, 0);
616 rr = connect(nnetfd, (struct sockaddr *)remend,
617 sizeof(struct sockaddr));
618 goto whoisit;
619 }
620 /* fall here for TCP */
621 x = sizeof(struct sockaddr);
622 arm(2, o_wait);
623 if (setjmp(jbuf) == 0) {
624 rr = accept(nnetfd, (struct sockaddr *) remend, &x);
625 } else
626 goto dol_tmo;
627 arm(0, 0);
628 close(nnetfd); /* dump the old socket */
629 nnetfd = rr; /* here's our new one */
630 347
631whoisit: 348 if ((error = getaddrinfo(host, port, &hints, &res)))
632 if (rr < 0) 349 errx(1, "%s", gai_strerror(error));
633 goto dol_err; /* bail out if any errors so far */
634 350
635 /* 351 res0 = res;
636 * Find out what address the connection was *to* on 352 do {
637 * our end, in case we're doing a listen-on-any on 353 if ((s = socket(res0->ai_family, res0->ai_socktype,
638 * a multihomed machine. This allows one to offer 354 res0->ai_protocol)) == 0)
639 * different services via different alias addresses, 355 continue;
640 * such as the "virtual web site" hack.
641 */
642 memset(bigbuf_net, 0, 64);
643 cp = &bigbuf_net[32];
644 x = sizeof(struct sockaddr);
645 rr = getsockname(nnetfd, (struct sockaddr *) lclend, &x);
646 if (rr < 0)
647 nlog(0, "post-rcv getsockname failed");
648 strcpy(cp, inet_ntoa(lclend->sin_addr));
649
650 z = ntohs(remend->sin_port);
651 strcpy(bigbuf_net, inet_ntoa(remend->sin_addr));
652 whozis = gethinfo(bigbuf_net, o_nflag);
653 x = 0;
654 if (rad) /* xxx: fix to go down the *list* if we have
655 * one? */
656 if (memcmp(rad, whozis->iaddrs, sizeof(struct sockaddr)))
657 x = 1;
658 if (rp) {
659 if (z != rp)
660 x = 1;
661 }
662 if (x) {
663 nlog(1, "invalid connection to [%s] from %s [%s] %d",
664 cp, whozis->name, whozis->addrs[0], z);
665 }
666 if (o_verbose) {
667 nlog(0, "connect to [%s] from %s [%s] %d",
668 cp, whozis->name, whozis->addrs[0], z);
669 }
670 return (nnetfd);
671 356
672dol_tmo: 357 ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
673 errno = ETIMEDOUT; 358 if (ret == -1)
674dol_err: 359 errx(1, NULL);
675 close(nnetfd);
676 return (-1);
677}
678 360
679/* 361 if (bind(s, (struct sockaddr *)res0->ai_addr,
680 * udptest : 362 res0->ai_addrlen) == 0)
681 * fire a couple of packets at a UDP target port, just to see if it's really 363 break;
682 * there. On BSD kernels, ICMP host/port-unreachable errors get delivered to 364
683 * our socket as ECONNREFUSED write errors. On SV kernels, we lose; we'll have 365 close(s);
684 * to collect and analyze raw ICMP ourselves a la satan's probe_udp_ports 366 s = -1;
685 * backend. Guess where one could swipe the appropriate code from... 367 } while ((res0 = res0->ai_next) != NULL);
686 * 368
687 * Use the time delay between writes if given, otherwise use the "tcp ping" 369 if (!uflag) {
688 * trick for getting the RTT. [I got that idea from pluvius, and warped it.] 370 if (listen(s, 1) < 0)
689 * Return either the original fd, or clean up and return -1. 371 errx(1, "%s", strerror(errno));
690 */
691int
692udptest(fd, where)
693 int fd;
694 struct in_addr *where;
695{
696 int rr;
697
698 rr = write(fd, bigbuf_in, 1);
699 if (rr != 1)
700 nlog(0, "udptest first write failed: ");
701 if (o_wait)
702 sleep(o_wait);
703 else {
704 o_udpmode = 0;
705 o_wait = 5;
706 rr = doconnect(where, SLEAZE_PORT, 0, 0);
707 if (rr > 0)
708 close(rr);
709 o_wait = 0;
710 o_udpmode++;
711 } 372 }
712 rr = write(fd, bigbuf_in, 1); 373
713 if (rr == 1) 374 freeaddrinfo(res);
714 return (fd); 375
715 close(fd); 376 return (s);
716 return (-1);
717} 377}
718 378
719/* 379/*
720 * oprint : 380 * readwrite()
721 * Hexdump bytes shoveled either way to a running logfile, in the format: 381 * Loop that polls on the network file descriptor and stdin.
722 * D offset - - - - --- 16 bytes --- - - - - # .... ascii .....
723 * where "which" sets the direction indicator, D:
724 * 0 -- sent to network, or ">"
725 * 1 -- rcvd and printed to stdout, or "<"
726 * and "buf" and "n" are data-block and length. If the current block generates
727 * a partial line, so be it; we *want* that lockstep indication of who sent
728 * what when. Adapted from dgaudet's original example -- but must be ripping
729 * *fast*, since we don't want to be too disk-bound.
730 */ 382 */
731void 383void
732oprint(which, buf, n) 384readwrite(nfd)
733 int which; 385 int nfd;
734 char *buf;
735 int n;
736{ 386{
737 int bc; /* in buffer count */ 387 struct pollfd *pfd;
738 int obc; /* current "global" offset */ 388 char buf[BUFSIZ];
739 int soc; /* stage write count */ 389 int wfd = fileno(stdin), n, ret;
740 unsigned char *p; /* main buf ptr; m.b. unsigned here */ 390 int lfd = fileno(stdout);
741 unsigned char *op; /* out hexdump ptr */ 391
742 unsigned char *a; /* out asc-dump ptr */ 392 pfd = malloc(2 * sizeof(struct pollfd));
743 int x; 393
744 unsigned int y; 394 /* Setup Network FD */
745 395 pfd[0].fd = nfd;
746 if (!ofd) 396 pfd[0].events = POLLIN;
747 nlog(1, "oprint called with no open fd?!"); 397
748 if (n == 0) 398 /* Setup STDIN FD */
749 return; 399 pfd[1].fd = wfd;
750 400 pfd[1].events = POLLIN;
751 op = stage; 401
752 if (which) { 402 for (;;) {
753 *op = '<'; 403 if (iflag)
754 obc = wrote_out;/* use the globals! */ 404 sleep(iflag);
755 } else { 405
756 *op = '>'; 406 if (poll(pfd, 2, timeout) < 0) {
757 obc = wrote_net; 407 close(nfd);
758 } 408 close(wfd);
759 op++; /* preload "direction" */ 409 free(pfd);
760 *op = ' '; 410 errx(1, "Polling Error");
761 p = (unsigned char *) buf; 411 }
762 bc = n; 412
763 stage[59] = '#'; /* preload separator */ 413 if (pfd[0].revents & POLLIN) {
764 stage[60] = ' '; 414 if ((n = read(nfd, buf, sizeof(buf))) <= 0) {
765 415 return;
766 while (bc) { /* for chunk-o-data ... */ 416 } else {
767 x = 16; 417 if (tflag)
768 soc = 78; /* len of whole formatted line */ 418 atelnet(nfd, buf, n);
769 if (bc < x) { 419 if ((ret = atomicio(write, lfd, buf, n)) != n)
770 soc = soc - 16 + bc; /* fiddle for however much is 420 return;
771 * left */
772 x = (bc * 3) + 11; /* 2 digits + space per, after
773 * D & offset */
774 op = &stage[x];
775 x = 16 - bc;
776 while (x) {
777 *op++ = ' '; /* preload filler spaces */
778 *op++ = ' ';
779 *op++ = ' ';
780 x--;
781 } 421 }
782 x = bc; /* re-fix current linecount */ 422 }
783 } /* if bc < x */ 423
784 bc -= x; /* fix wrt current line size */ 424 if (pfd[1].revents & POLLIN) {
785 sprintf(&stage[2], "%8.8x ", obc); /* xxx: still slow? */ 425 if ((n = read(wfd, buf, sizeof(buf))) <= 0) {
786 obc += x; /* fix current offset */ 426 return;
787 op = &stage[11];/* where hex starts */ 427 } else
788 a = &stage[61]; /* where ascii starts */ 428 if((ret = atomicio(write, nfd, buf, n)) != n)
789 429 return;
790 while (x) { /* for line of dump, however long ... */ 430 }
791 y = (int) (*p >> 4); /* hi half */
792 *op = hexnibs[y];
793 op++;
794 y = (int) (*p & 0x0f); /* lo half */
795 *op = hexnibs[y];
796 op++;
797 *op = ' ';
798 op++;
799 if ((*p > 31) && (*p < 127))
800 *a = *p; /* printing */
801 else
802 *a = '.'; /* nonprinting, loose def */
803 a++;
804 p++;
805 x--;
806 } /* while x */
807 *a = '\n'; /* finish the line */
808 x = write(ofd, stage, soc);
809 if (x < 0)
810 nlog(1, "ofd write err");
811 } 431 }
812} 432}
813 433
814#ifdef TELNET
815u_short o_tn = 0; /* global -t option */
816
817/* 434/*
818 * atelnet :
819 * Answer anything that looks like telnet negotiation with don't/won't. 435 * Answer anything that looks like telnet negotiation with don't/won't.
820 * This doesn't modify any data buffers, update the global output count, 436 * This doesn't modify any data buffers, update the global output count,
821 * or show up in a hexdump -- it just shits into the outgoing stream. 437 * or show up in a hexdump -- it just shits into the outgoing stream.
822 * Idea and codebase from Mudge@l0pht.com. 438 * Idea and codebase from Mudge@l0pht.com.
823 */ 439 */
824void 440void
825atelnet(buf, size) 441atelnet(nfd, buf, size)
826 unsigned char *buf; /* has to be unsigned here! */ 442 int nfd;
443 unsigned char *buf;
827 unsigned int size; 444 unsigned int size;
828{ 445{
829 static unsigned char obuf[4]; /* tiny thing to build responses into */ 446 static unsigned char obuf[4];
830 int x; 447 int x, ret;
831 unsigned char y; 448 unsigned char y;
832 unsigned char *p; 449 unsigned char *p;
833 450
@@ -835,542 +452,101 @@ atelnet(buf, size)
835 p = buf; 452 p = buf;
836 x = size; 453 x = size;
837 while (x > 0) { 454 while (x > 0) {
838 if (*p != 255) /* IAC? */ 455 if (*p != IAC)
839 goto notiac; 456 goto notiac;
840 obuf[0] = 255; 457 obuf[0] = IAC;
841 p++; 458 p++; x--;
842 x--; 459 if ((*p == WILL) || (*p == WONT))
843 if ((*p == 251) || (*p == 252)) /* WILL or WONT */ 460 y = DONT;
844 y = 254;/* -> DONT */ 461 if ((*p == DO) || (*p == DONT))
845 if ((*p == 253) || (*p == 254)) /* DO or DONT */ 462 y = WONT;
846 y = 252;/* -> WONT */
847 if (y) { 463 if (y) {
848 obuf[1] = y; 464 obuf[1] = y;
849 p++; 465 p++; x--;
850 x--;
851 obuf[2] = *p; 466 obuf[2] = *p;
852 (void) write(netfd, obuf, 3); 467 if ((ret = atomicio(write , nfd, obuf, 3)) != 3)
853 /* 468 warnx("Write Error!");
854 * if one wanted to bump wrote_net or do
855 * a hexdump line, here's the place.
856 */
857 y = 0; 469 y = 0;
858 } 470 }
859notiac: 471notiac:
860 p++; 472 p++; x--;
861 x--;
862 } 473 }
863} 474}
864#endif /* TELNET */
865 475
866/* 476/*
867 * readwrite : 477 * build_ports()
868 * handle stdin/stdout/network I/O. Bwahaha!! -- the select loop from hell. 478 * Build an array or ports in portlist[], listing each port
869 * In this instance, return what might become our exit status. 479 * that we should try to connect too.
870 */ 480 */
871int 481void
872readwrite(fd) 482build_ports(p)
873 int fd; 483 char *p;
874{ 484{
875 int rr; 485 char *n;
876 char *zp; /* stdin buf ptr */ 486 int hi, lo, cp;
877 char *np; /* net-in buf ptr */ 487 int x = 0;
878 unsigned int rzleft;
879 unsigned int rnleft;
880 u_short netretry; /* net-read retry counter */
881 u_short wretry; /* net-write sanity counter */
882 u_short wfirst; /* one-shot flag to skip first net read */
883
884 /*
885 * if you don't have all this FD_* macro hair in sys/types.h,
886 * you'll have to either find it or do your own bit-bashing:
887 * *ds1 |= (1 << fd), etc.
888 */
889 if (fd > FD_SETSIZE) {
890 nlog(0, "Preposterous fd value %d", fd);
891 return (1);
892 }
893 FD_SET(fd, &fds1);
894 netretry = 2;
895 wfirst = 0;
896 rzleft = rnleft = 0;
897 if (insaved) {
898 rzleft = insaved; /* preload multi-mode fakeouts */
899 zp = bigbuf_in;
900 wfirst = 1;
901 /* If not scanning, this is a one-off first */
902 if (Single)
903 insaved = 0;
904 else {
905 FD_CLR(0, &fds1);
906 close(0);
907 }
908 }
909 if (o_interval)
910 sleep(o_interval);
911
912 while (FD_ISSET(fd, &fds1)) { /* i.e. till the *net* closes! */
913 struct timeval *tv;
914
915 wretry = 8200; /* more than we'll ever hafta write */
916 if (wfirst) { /* any saved stdin buffer? */
917 wfirst = 0; /* clear flag for the duration */
918 goto shovel; /* and go handle it first */
919 }
920 fds2 = fds1;
921 if (timer1.tv_sec > 0 || timer1.tv_usec > 0) {
922 memcpy(&timer2, &timer1, sizeof(struct timeval));
923 tv = &timer2;
924 } else
925 tv = NULL;
926 rr = select(getdtablesize(), &fds2, 0, 0, tv);
927 if (rr < 0) {
928 if (errno != EINTR) {
929 nlog(0, "Select Failure");
930 close(fd);
931 return (1);
932 }
933 }
934 /* if we have a timeout AND stdin is closed AND we haven't
935 * heard anything from the net during that time, assume it's
936 * dead and close it too. */
937 if (rr == 0) {
938 if (!FD_ISSET(0, &fds1))
939 netretry--; /* we actually try a coupla
940 * times. */
941 if (!netretry) {
942 if (o_verbose > 1) /* normally we don't
943 * care */
944 nlog(0, "net timeout");
945 close(fd);
946 return (0); /* not an error! */
947 }
948 } /* select timeout */
949 /* XXX: should we check the exception fds too? The read fds
950 * seem to give us the right info, and none of the examples I
951 * found bothered. */
952 /* Ding!! Something arrived, go check all the incoming
953 * hoppers, net first */
954 if (FD_ISSET(fd, &fds2)) { /* net: ding! */
955 rr = read(fd, bigbuf_net, BIGSIZ);
956 if (rr <= 0) {
957 FD_CLR(fd, &fds1); /* net closed, we'll
958 * finish up... */
959 rzleft = 0; /* can't write anymore: broken
960 * pipe */
961 } else {
962 rnleft = rr;
963 np = bigbuf_net;
964#ifdef TELNET
965 if (o_tn)
966 atelnet(np, rr); /* fake out telnet stuff */
967#endif /* TELNET */
968 }
969 }
970 /* if we're in "slowly" mode there's probably still stuff in
971 * the stdin buffer, so don't read unless we really need MORE
972 * INPUT! MORE INPUT! */
973 if (rzleft)
974 goto shovel;
975
976 if (FD_ISSET(0, &fds2)) {
977 rr = read(0, bigbuf_in, BIGSIZ);
978 if (rr <= 0) {
979 FD_CLR(0, &fds1); /* disable and close */
980 close(0);
981 } else {
982 rzleft = rr;
983 zp = bigbuf_in;
984 if (!Single) {
985 insaved = rr;
986 FD_CLR(0, &fds1);
987 close(0);
988 }
989 }
990 }
991shovel:
992 /* sanity check. Works because they're both unsigned... */
993 if ((rzleft > 8200) || (rnleft > 8200)) {
994 rzleft = rnleft = 0;
995 }
996 /* net write retries sometimes happen on UDP connections */
997 if (!wretry) { /* is something hung? */
998 nlog(0, "too many output retries");
999 return (1);
1000 }
1001 if (rnleft) {
1002 rr = write(1, np, rnleft);
1003 if (rr > 0) {
1004 if (o_wfile)
1005 oprint(1, np, rr);
1006 np += rr;
1007 rnleft -= rr;
1008 wrote_out += rr; /* global count */
1009 }
1010 }
1011 if (rzleft) {
1012 if (o_interval)
1013 rr = findline(zp, rzleft);
1014 else
1015 rr = rzleft;
1016 rr = write(fd, zp, rr);
1017 if (rr > 0) {
1018 if (o_wfile)
1019 oprint(0, zp, rr);
1020 zp += rr;
1021 rzleft -= rr;
1022 wrote_net += rr;
1023 }
1024 }
1025 if (o_interval) {
1026 sleep(o_interval);
1027 continue;
1028 }
1029 if ((rzleft) || (rnleft)) {
1030 wretry--;
1031 goto shovel;
1032 }
1033 }
1034 488
1035 close(fd); 489 if ((n = strchr(p, '-')) != NULL) {
1036 return (0); 490 if (lflag)
1037} 491 errx(1, "Cannot use -l with multiple ports!");
1038 492
1039/* main : 493 *n = '\0';
1040 now we pull it all together... */ 494 n++;
1041int
1042main(argc, argv)
1043 int argc;
1044 char **argv;
1045{
1046 int x, ch;
1047 char *cp;
1048 struct host_info *gp;
1049 struct host_info *whereto = NULL;
1050 struct host_info *wherefrom = NULL;
1051 struct in_addr *ouraddr = NULL;
1052 struct in_addr *themaddr = NULL;
1053 u_short o_lport = 0;
1054 u_short ourport = 0;
1055 u_short loport = 0; /* for scanning stuff */
1056 u_short hiport = 0;
1057 u_short curport = 0;
1058 char *randports = NULL;
1059
1060 res_init();
1061
1062 lclend = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr));
1063 remend = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr));
1064 bigbuf_in = calloc(1, BIGSIZ);
1065 bigbuf_net = calloc(1, BIGSIZ);
1066 pinfo= (struct port_info *) calloc(1, sizeof(struct port_info));
1067 495
1068 gatesptr = 4; 496 /* Make sure the ports are in order: lowest->highest */
497 hi = atoi(n);
498 lo = atoi(p);
1069 499
1070 /* 500 if (lo > hi) {
1071 * We want to catch a few of these signals. 501 cp = hi;
1072 * Others we disgard. 502 hi = lo;
1073 */ 503 lo = cp;
1074 signal(SIGINT, catch);
1075 signal(SIGQUIT, catch);
1076 signal(SIGTERM, catch);
1077 signal(SIGURG, SIG_IGN);
1078 signal(SIGPIPE, SIG_IGN); /* important! */
1079
1080 /*
1081 * If no args given at all, get 'em from stdin, construct an argv,
1082 * and hand anything left over to readwrite().
1083 */
1084 if (argc == 1) {
1085 /* Loop until we get a command to try */
1086 for (;;) {
1087 cp = argv[0];
1088 argv = (char **) calloc(1, 128 * sizeof(char *));
1089 argv[0] = cp; /* leave old prog name intact */
1090 cp = calloc(1, BIGSIZ);
1091 argv[1] = cp; /* head of new arg block */
1092 fprintf(stderr, "Cmd line: ");
1093 fflush(stderr); /* I dont care if it's unbuffered or not! */
1094 insaved = read(0, cp, BIGSIZ-1); /* we're gonna fake fgets()
1095 * here */
1096 cp[BIGSIZ-1] = '\0';
1097 if (*cp != '\n' && *cp != '\t')
1098 break;
1099 } 504 }
1100 if (insaved <= 0)
1101 nlog(1, "wrong");
1102 x = findline(cp, insaved);
1103 if (x)
1104 insaved -= x; /* remaining chunk size to be sent */
1105 if (insaved) /* which might be zero... */
1106 memcpy(bigbuf_in, &cp[x], insaved);
1107 cp = strchr(argv[1], '\n');
1108 if (cp)
1109 *cp = '\0';
1110 cp = strchr(argv[1], '\r'); /* look for ^M too */
1111 if (cp)
1112 *cp = '\0';
1113
1114 /*
1115 * Find and stash pointers to remaining new "args"
1116 */
1117 cp = argv[1];
1118 cp++; /* skip past first char */
1119 x = 2; /* we know argv 0 and 1 already */
1120 for (; *cp != '\0'; cp++) {
1121 if (*cp == ' ') {
1122 *cp = '\0'; /* smash all spaces */
1123 continue;
1124 } else {
1125 if (*(cp - 1) == '\0') {
1126 argv[x] = cp;
1127 x++;
1128 }
1129 } /* if space */
1130 } /* for cp */
1131 argc = x;
1132 }
1133 505
1134 while ((ch = getopt(argc, argv, "g:G:hi:lno:p:rs:tuvw:z")) != -1) { 506 /* Load ports sequentially */
1135 switch (ch) { 507 for (cp = lo; cp <= hi; cp++) {
1136 case 'G': /* srcrt gateways pointer val */ 508 portlist[x] = malloc(sizeof(65535));
1137 x = atoi(optarg); 509 sprintf(portlist[x], "%d", cp);
1138 /* Mask of bits */ 510 x++;
1139 if ((x) && (x == (x & 0x1c)))
1140 gatesptr = x;
1141 else
1142 nlog(1, "invalid hop pointer %d, must be multiple of 4 <= 28", x);
1143 break;
1144 case 'g': /* srcroute hop[s] */
1145 if (gatesidx > 8)
1146 nlog(1, "Too many -g hops!");
1147 if (gates == NULL)
1148 gates = (struct host_info **) calloc(1,
1149 sizeof(struct host_info *) * 10);
1150 gp = gethinfo(optarg, o_nflag);
1151 if (gp)
1152 gates[gatesidx] = gp;
1153 gatesidx++;
1154 break;
1155 case 'h':
1156 help();
1157 break;
1158 case 'i': /* line-interval time */
1159 o_interval = atoi(optarg) & 0xffff;
1160 if (!o_interval)
1161 nlog(1, "invalid interval time %s", optarg);
1162 break;
1163 case 'l': /* listen mode */
1164 o_listen++;
1165 break;
1166 case 'n': /* numeric-only, no DNS lookups */
1167 o_nflag++;
1168 break;
1169 case 'o': /* hexdump log */
1170 stage = (unsigned char *) optarg;
1171 o_wfile++;
1172 break;
1173 case 'p': /* local source port */
1174 o_lport = getpinfo(optarg, 0);
1175 if (o_lport == 0)
1176 nlog(1, "invalid local port %s", optarg);
1177 break;
1178 case 'r': /* randomize various things */
1179 o_random++;
1180 break;
1181 /*
1182 * Do a full lookup [since everything else goes through the same
1183 * mill], unless -n was previously specified. In fact, careful
1184 * placement of -n can be useful, so we'll still pass o_nflag
1185 * here instead of forcing numeric.
1186 */
1187 case 's': /* local source address */
1188 wherefrom = gethinfo(optarg, o_nflag);
1189 ouraddr = &wherefrom->iaddrs[0];
1190 break;
1191#ifdef TELNET
1192 case 't': /* do telnet fakeout */
1193 o_tn++;
1194 break;
1195#endif
1196 case 'u': /* use UDP */
1197 o_udpmode++;
1198 break;
1199 case 'v': /* verbose */
1200 o_verbose++;
1201 break;
1202 case 'w': /* wait time */
1203 o_wait = atoi(optarg);
1204 if (o_wait <= 0)
1205 nlog(1, "invalid wait-time %s", optarg);
1206 timer1.tv_sec = o_wait;
1207 timer1.tv_usec = 0;
1208 break;
1209 case 'z': /* little or no data xfer */
1210 o_zero++;
1211 break;
1212 default:
1213 usage(1);
1214 } 511 }
1215 }
1216 512
1217 /* other misc initialization */ 513 /* Randomly swap ports */
1218 FD_SET(0, &fds1); /* stdin *is* initially open */ 514 if (rflag) {
1219 if (o_random) { 515 int y;
1220 randports = calloc(1, 65536); /* big flag array for ports */ 516 char *c;
1221 }
1222 if (o_wfile) {
1223 ofd = open(stage, O_WRONLY | O_CREAT | O_TRUNC, 0664);
1224 if (ofd <= 0) /* must be > extant 0/1/2 */
1225 nlog(1, "%s: ", stage);
1226 stage = (unsigned char *) calloc(1, 100);
1227 }
1228 /* optind is now index of first non -x arg */
1229 if (argv[optind])
1230 whereto = gethinfo(argv[optind], o_nflag);
1231 if (whereto && whereto->iaddrs)
1232 themaddr = &whereto->iaddrs[0];
1233 if (themaddr)
1234 optind++; /* skip past valid host lookup */
1235 517
1236 /* 518 for (x = 0; x <= (hi - lo); x++) {
1237 * Handle listen mode here, and exit afterward. Only does one connect; 519 y = (arc4random() & 0xFFFF) % (hi - lo);
1238 * this is arguably the right thing to do. A "persistent listen-and-fork" 520 c = portlist[x];
1239 * mode a la inetd has been thought about, but not implemented. A tiny 521 portlist[x] = portlist[y];
1240 * wrapper script can handle such things. 522 portlist[y] = c;
1241 */
1242 if (o_listen) {
1243 curport = 0;
1244 if (argv[optind]) {
1245 curport = getpinfo(argv[optind], 0);
1246 if (curport == 0)
1247 nlog(1, "invalid port %s", argv[optind]);
1248 }
1249 netfd = dolisten(themaddr, curport, ouraddr, o_lport);
1250 if (netfd > 0) {
1251 x = readwrite(netfd);
1252 if (o_verbose)
1253 nlog(0, "Sent %i Rcvd %i", wrote_net, wrote_out);
1254 exit(x);
1255 } else
1256 nlog(1, "no connection");
1257 }
1258 /* fall thru to outbound connects. Now we're more picky about args... */
1259 if (!themaddr)
1260 nlog(1, "no destination");
1261 if (argv[optind] == NULL)
1262 nlog(1, "no port[s] to connect to");
1263 if (argv[optind + 1])
1264 Single = 0;
1265 ourport = o_lport;
1266
1267 while (argv[optind]) {
1268 hiport = loport = 0;
1269 if (cp = strchr(argv[optind], '-')) {
1270 *cp = '\0';
1271 cp++;
1272 hiport = getpinfo(cp, 0);
1273 if (hiport == 0)
1274 nlog(1, "invalid port %s", cp);
1275 }
1276 loport = getpinfo(argv[optind], 0);
1277 if (loport == 0)
1278 nlog(1, "invalid port %s", argv[optind]);
1279 if (hiport > loport) {
1280 Single = 0;
1281 if (o_random) {
1282 loadports(randports, loport, hiport);
1283 curport = nextport(randports);
1284 } else
1285 curport = hiport;
1286 } else
1287 curport = loport;
1288 /*
1289 * Now start connecting to these things.
1290 * curport is already preloaded.
1291 */
1292 while (loport <= curport) {
1293 curport = getpinfo(NULL, curport);
1294 netfd = doconnect(themaddr, curport, ouraddr, ourport);
1295 if (netfd > 0)
1296 if (o_zero && o_udpmode)
1297 netfd = udptest(netfd, themaddr);
1298 if (netfd > 0) {
1299 x = errno = 0;
1300 if (o_verbose) {
1301 nlog(0, "%s [%s] %d (%s) open",
1302 whereto->name,
1303 whereto->addrs[0], curport,
1304 pinfo->name);
1305 }
1306 if (!o_zero)
1307 x = readwrite(netfd);
1308 } else {
1309 x = 1;
1310 if ((Single || (o_verbose > 1))
1311 || (errno != ECONNREFUSED)) {
1312 nlog(0, "%s [%s] %d (%s)",
1313 whereto->name, whereto->addrs[0],
1314 curport, pinfo->name);
1315 }
1316 } 523 }
1317 close(netfd); 524 }
1318 if (o_interval) 525 } else {
1319 sleep(o_interval); 526 portlist[0] = malloc(sizeof(65535));
1320 if (o_random) 527 portlist[0] = p;
1321 curport = nextport(randports);
1322 else
1323 curport--;
1324 }
1325 optind++;
1326 } 528 }
1327 errno = 0;
1328 if (o_verbose > 1)
1329 nlog(0, "Sent %i Rcvd %i", wrote_net, wrote_out);
1330 if (Single)
1331 exit(x);
1332 exit(0);
1333} 529}
1334 530
1335/* 531/*
1336 * nlog: 532 * udptest()
1337 * dual purpose function, does both warn() and err() 533 * Do a few writes to see if the UDP port is there.
1338 * and pays attention to o_verbose. 534 * XXX - Better way of doing this? Doesn't work for IPv6
535 * Also fails after around 100 ports checked.
1339 */ 536 */
1340void 537int
1341nlog(doexit, fmt) 538udptest(s)
1342 int doexit; 539 int s;
1343 char *fmt;
1344{ 540{
1345 va_list args; 541 int i, rv, ret;
1346 542
1347 if (o_verbose || doexit) { 543 for (i=0; i <= 3; i++) {
1348 va_start(args, fmt); 544 if ((rv = write(s, "X", 1)) == 1)
1349 vfprintf(stderr, fmt, args); 545 ret = 1;
1350 if (h_errno)
1351 herror(NULL);
1352 else if (errno)
1353 fprintf(stderr, "%s\n", strerror(errno));
1354 else 546 else
1355 putc('\n', stderr); 547 ret = -1;
1356 va_end(args);
1357 } 548 }
1358 549 return (ret);
1359 if (doexit)
1360 exit(1);
1361
1362 h_errno = errno = 0;
1363}
1364
1365void
1366usage(doexit)
1367 int doexit;
1368{
1369 fprintf(stderr, "netcat - [v1.10]\n");
1370 fprintf(stderr, "nc [-lnrtuvz] [-g intermediates] [-G hopcount] [-i interval] [-o filename]\n");
1371 fprintf(stderr, " [-p source port] [-s ip address] [-w timeout] [hostname] [port[s...]]\n");
1372 if (doexit)
1373 exit(1);
1374} 550}
1375 551
1376void 552void
@@ -1378,22 +554,31 @@ help()
1378{ 554{
1379 usage(0); 555 usage(0);
1380 fprintf(stderr, "\tCommand Summary:\n\ 556 fprintf(stderr, "\tCommand Summary:\n\
1381 \t-g gateway source-routing hop point[s], up to 8\n\ 557 \t-4 Use IPv4\n\
1382 \t-G num\t source-routing pointer: 4, 8, 12, ...\n\ 558 \t-6 Use IPv6\n\
1383 \t-h this help text\n\ 559 \t-h This help text\n\
1384 \t-i secs\t delay interval for lines sent, ports scanned\n\ 560 \t-i secs\t Delay interval for lines sent, ports scanned\n\
1385 \t-l listen mode, for inbound connects\n\ 561 \t-k Keep inbound sockets open for multiple connects\n\
1386 \t-n numeric-only IP addresses, no DNS\n\ 562 \t-l Listen mode, for inbound connects\n\
1387 \t-o file\t hex dump of traffic\n\ 563 \t-n Surpress name/port resolutions\n\
1388 \t-r randomize local and remote ports\n\ 564 \t-p Specify local port for remote connects\n\
1389 \t-s addr\t local source address\n"); 565 \t-r Randomize remote ports\n\
1390#ifdef TELNET 566 \t-s addr\t Local source address\n\
1391 fprintf(stderr, "\t\t-t answer TELNET negotiation\n"); 567 \t-t Answer TELNET negotiation\n\
1392#endif 568 \t-u UDP mode\n\
1393 fprintf(stderr, "\t\t-u UDP mode\n\ 569 \t-v Verbose\n\
1394 \t-v verbose [use twice to be more verbose]\n\ 570 \t-w secs\t Timeout for connects and final net reads\n\
1395 \t-w secs\t timeout for connects and final net reads\n\ 571 \t-z Zero-I/O mode [used for scanning]\n\
1396 \t-z zero-I/O mode [used for scanning]\n\ 572 Port numbers can be individual or ranges: lo-hi [inclusive]\n");
1397 Port numbers can be individual or ranges: lo-hi [inclusive]\n");
1398 exit(1); 573 exit(1);
1399} 574}
575
576void
577usage(ret)
578 int ret;
579{
580 fprintf(stderr, "usage: nc [-46hklnrtuvz] [-i interval] [-p source port]\n");
581 fprintf(stderr, "\t [-s ip address] [-w timeout] [hostname] [port[s...]]\n");
582 if (ret)
583 exit(1);
584}