1 /*
2 * netcat.c -- main project file
3 * Part of the GNU netcat project
4 *
5 * Author: Giovanni Giacobbi <giovanni@giacobbi.net>
6 * Copyright (C) 2002 - 2003 Giovanni Giacobbi
7 *
8 * $Id: netcat.c,v 1.63 2003/08/21 15:27:18 themnemonic Exp $
9 */
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 * This program is distributed in the hope that it will be useful, *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21 * GNU General Public License for more details. *
22 * *
23 ***************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "netcat.h"
30 #include <signal.h>
31 #include <getopt.h>
32 #include <time.h> /* time(2) used as random seed */
33
34 /* int gatesidx = 0; */ /* LSRR hop count */
35 /* int gatesptr = 4; */ /* initial LSRR pointer, settable */
36 /* nc_host_t **gates = NULL; */ /* LSRR hop hostpoop */
37 /* char *optbuf = NULL; */ /* LSRR or sockopts */
38 FILE *output_fp = NULL; /* output fd (FIXME: i don't like this) */
39 bool use_stdin = TRUE; /* tells wether stdin was closed or not */
40 bool signal_handler = TRUE; /* handle the signals externally */
41 bool got_sigterm = FALSE; /* when this TRUE the application must exit */
42 bool got_sigint = FALSE; /* when this TRUE the application should exit */
43 bool got_sigusr1 = FALSE; /* when set, the application should print stats */
44 bool commandline_need_newline = FALSE; /* fancy output handling */
45
46 /* global options flags */
47 nc_mode_t netcat_mode = 0; /* Netcat working modality */
48 bool opt_eofclose = FALSE; /* close connection on EOF from stdin */
49 bool opt_debug = FALSE; /* debugging output */
50 bool opt_numeric = FALSE; /* don't resolve hostnames */
51 bool opt_random = FALSE; /* use random ports */
52 bool opt_udpmode = FALSE; /* use udp protocol instead of tcp */
53 bool opt_telnet = FALSE; /* answer in telnet mode */
54 bool opt_hexdump = FALSE; /* hexdump traffic */
55 bool opt_zero = FALSE; /* zero I/O mode (don't expect anything) */
56 int opt_interval = 0; /* delay (in seconds) between lines/ports */
57 int opt_verbose = 0; /* be verbose (> 1 to be MORE verbose) */
58 int opt_wait = 0; /* wait time */
59 char *opt_outputfile = NULL; /* hexdump output file */
60 char *opt_exec = NULL; /* program to exec after connecting */
61 nc_proto_t opt_proto = NETCAT_PROTO_TCP; /* protocol to use for connections */
62
63
64 /* signal handling */
65
got_term(int z)66 static void got_term(int z)
67 {
68 if (!got_sigterm)
69 ncprint(NCPRINT_VERB1, _("Terminated."));
70 debug_v(("_____ RECEIVED SIGTERM _____ [signal_handler=%s]",
71 BOOL_TO_STR(signal_handler)));
72 got_sigterm = TRUE;
73 if (signal_handler) /* default action */
74 exit(EXIT_FAILURE);
75 }
76
got_int(int z)77 static void got_int(int z)
78 {
79 if (!got_sigint)
80 ncprint(NCPRINT_VERB1, _("Exiting."));
81 debug_v(("_____ RECEIVED SIGINT _____ [signal_handler=%s]",
82 BOOL_TO_STR(signal_handler)));
83 got_sigint = TRUE;
84 if (signal_handler) { /* default action */
85 if (commandline_need_newline) /* if we were waiting for input */
86 printf("\n");
87 netcat_printstats(FALSE);
88 exit(EXIT_FAILURE);
89 }
90 }
91
got_usr1(int z)92 static void got_usr1(int z)
93 {
94 debug_dv(("_____ RECEIVED SIGUSR1 _____ [signal_handler=%s]",
95 BOOL_TO_STR(signal_handler)));
96 if (signal_handler) /* default action */
97 netcat_printstats(TRUE);
98 else
99 got_sigusr1 = TRUE;
100 }
101
102 /* Execute an external file making its stdin/stdout/stderr the actual socket */
103
ncexec(nc_sock_t * ncsock)104 static void ncexec(nc_sock_t *ncsock)
105 {
106 int saved_stderr;
107 char *p;
108 assert(ncsock && (ncsock->fd >= 0));
109
110 /* save the stderr fd because we may need it later */
111 saved_stderr = dup(STDERR_FILENO);
112
113 /* duplicate the socket for the child program */
114 dup2(ncsock->fd, STDIN_FILENO); /* the precise order of fiddlage */
115 close(ncsock->fd); /* is apparently crucial; this is */
116 dup2(STDIN_FILENO, STDOUT_FILENO); /* swiped directly out of "inetd". */
117 dup2(STDIN_FILENO, STDERR_FILENO); /* also duplicate the stderr channel */
118
119 /* change the label for the executed program */
120 if ((p = strrchr(opt_exec, '/')))
121 p++; /* shorter argv[0] */
122 else
123 p = opt_exec;
124
125 /* replace this process with the new one */
126 #ifndef USE_OLD_COMPAT
127 execl("/bin/sh", p, "-c", opt_exec, NULL);
128 #else
129 execl(opt_exec, p, NULL);
130 #endif
131 dup2(saved_stderr, STDERR_FILENO);
132 ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Couldn't execute %s: %s"),
133 opt_exec, strerror(errno));
134 } /* end of ncexec() */
135
136 /* main: handle command line arguments and listening status */
137
main(int argc,char * argv[])138 int main(int argc, char *argv[])
139 {
140 int c, glob_ret = EXIT_FAILURE;
141 int total_ports, left_ports, accept_ret = -1, connect_ret = -1;
142 struct sigaction sv;
143 nc_port_t local_port; /* local port specified with -p option */
144 nc_host_t local_host; /* local host for bind()ing operations */
145 nc_host_t remote_host;
146 nc_sock_t listen_sock;
147 nc_sock_t connect_sock;
148 nc_sock_t stdio_sock;
149
150 memset(&local_port, 0, sizeof(local_port));
151 memset(&local_host, 0, sizeof(local_host));
152 memset(&remote_host, 0, sizeof(remote_host));
153 memset(&listen_sock, 0, sizeof(listen_sock));
154 memset(&connect_sock, 0, sizeof(listen_sock));
155 memset(&stdio_sock, 0, sizeof(stdio_sock));
156 listen_sock.domain = PF_INET;
157 connect_sock.domain = PF_INET;
158
159 #ifdef ENABLE_NLS
160 setlocale(LC_MESSAGES, "");
161 bindtextdomain(PACKAGE, LOCALEDIR);
162 textdomain(PACKAGE);
163 #endif
164
165 /* set up the signal handling system */
166 sigemptyset(&sv.sa_mask);
167 sv.sa_flags = 0;
168 sv.sa_handler = got_int;
169 sigaction(SIGINT, &sv, NULL);
170 sv.sa_handler = got_term;
171 sigaction(SIGTERM, &sv, NULL);
172 sv.sa_handler = got_usr1;
173 sigaction(SIGUSR1, &sv, NULL);
174 /* ignore some boring signals */
175 sv.sa_handler = SIG_IGN;
176 sigaction(SIGPIPE, &sv, NULL);
177 sigaction(SIGURG, &sv, NULL);
178
179 /* if no args given at all, take them from stdin and generate argv */
180 if (argc == 1)
181 netcat_commandline_read(&argc, &argv);
182
183 /* check for command line switches */
184 while (TRUE) {
185 int option_index = 0;
186 static const struct option long_options[] = {
187 { "close", no_argument, NULL, 'c' },
188 { "debug", no_argument, NULL, 'd' },
189 { "exec", required_argument, NULL, 'e' },
190 { "gateway", required_argument, NULL, 'g' },
191 { "pointer", required_argument, NULL, 'G' },
192 { "help", no_argument, NULL, 'h' },
193 { "interval", required_argument, NULL, 'i' },
194 { "listen", no_argument, NULL, 'l' },
195 { "tunnel", required_argument, NULL, 'L' },
196 { "dont-resolve", no_argument, NULL, 'n' },
197 { "output", required_argument, NULL, 'o' },
198 { "local-port", required_argument, NULL, 'p' },
199 { "tunnel-port", required_argument, NULL, 'P' },
200 { "randomize", no_argument, NULL, 'r' },
201 { "source", required_argument, NULL, 's' },
202 { "tunnel-source", required_argument, NULL, 'S' },
203 #ifndef USE_OLD_COMPAT
204 { "tcp", no_argument, NULL, 't' },
205 { "telnet", no_argument, NULL, 'T' },
206 #else
207 { "tcp", no_argument, NULL, 1 },
208 { "telnet", no_argument, NULL, 't' },
209 #endif
210 { "udp", no_argument, NULL, 'u' },
211 { "verbose", no_argument, NULL, 'v' },
212 { "version", no_argument, NULL, 'V' },
213 { "hexdump", no_argument, NULL, 'x' },
214 { "wait", required_argument, NULL, 'w' },
215 { "zero", no_argument, NULL, 'z' },
216 { 0, 0, 0, 0 }
217 };
218
219 c = getopt_long(argc, argv, "cde:g:G:hi:lL:no:p:P:rs:S:tTuvVxw:z",
220 long_options, &option_index);
221 if (c == -1)
222 break;
223
224 switch (c) {
225 case 'c': /* close connection on EOF from stdin */
226 opt_eofclose = TRUE;
227 break;
228 case 'd': /* enable debugging */
229 opt_debug = TRUE;
230 break;
231 case 'e': /* prog to exec */
232 if (opt_exec)
233 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
234 _("Cannot specify `-e' option double"));
235 opt_exec = strdup(optarg);
236 break;
237 case 'G': /* srcrt gateways pointer val */
238 break;
239 case 'g': /* srcroute hop[s] */
240 break;
241 case 'h': /* display help and exit */
242 netcat_printhelp(argv[0]);
243 exit(EXIT_SUCCESS);
244 case 'i': /* line/ports interval time (seconds) */
245 opt_interval = atoi(optarg);
246 if (opt_interval <= 0)
247 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
248 _("Invalid interval time \"%s\""), optarg);
249 break;
250 case 'l': /* mode flag: listen mode */
251 if (netcat_mode != NETCAT_UNSPEC)
252 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
253 _("You can specify mode flags (`-l' and `-L') only once"));
254 netcat_mode = NETCAT_LISTEN;
255 break;
256 case 'L': /* mode flag: tunnel mode */
257 if (netcat_mode != NETCAT_UNSPEC)
258 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
259 _("You can specify mode flags (`-l' and `-L') only once"));
260 if (opt_zero)
261 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
262 _("`-L' and `-z' options are incompatible"));
263 do {
264 char *div = strchr(optarg, ':');
265
266 if (div && *(div + 1))
267 *div++ = '\0';
268 else
269 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
270 _("Invalid target string for `-L' option"));
271
272 /* lookup the remote address and the remote port for tunneling */
273 if (!netcat_resolvehost(&connect_sock.host, optarg))
274 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
275 _("Couldn't resolve tunnel target host: %s"), optarg);
276 if (!netcat_getport(&connect_sock.port, div, 0))
277 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
278 _("Invalid tunnel target port: %s"), div);
279
280 connect_sock.proto = opt_proto;
281 connect_sock.timeout = opt_wait;
282 netcat_mode = NETCAT_TUNNEL;
283 } while (FALSE);
284 break;
285 case 'n': /* numeric-only, no DNS lookups */
286 opt_numeric = TRUE;
287 break;
288 case 'o': /* output hexdump log to file */
289 opt_outputfile = strdup(optarg);
290 opt_hexdump = TRUE; /* implied */
291 break;
292 case 'p': /* local source port */
293 if (!netcat_getport(&local_port, optarg, 0))
294 ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Invalid local port: %s"),
295 optarg);
296 break;
297 case 'P': /* used only in tunnel mode (source port) */
298 if (!netcat_getport(&connect_sock.local_port, optarg, 0))
299 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
300 _("Invalid tunnel connect port: %s"), optarg);
301 break;
302 case 'r': /* randomize various things */
303 opt_random = TRUE;
304 break;
305 case 's': /* local source address */
306 /* lookup the source address and assign it to the connection address */
307 if (!netcat_resolvehost(&local_host, optarg))
308 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
309 _("Couldn't resolve local host: %s"), optarg);
310 break;
311 case 'S': /* used only in tunnel mode (source ip) */
312 if (!netcat_resolvehost(&connect_sock.local_host, optarg))
313 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
314 _("Couldn't resolve tunnel local host: %s"), optarg);
315 break;
316 case 1: /* use TCP protocol (default) */
317 #ifndef USE_OLD_COMPAT
318 case 't':
319 #endif
320 opt_proto = NETCAT_PROTO_TCP;
321 break;
322 #ifdef USE_OLD_COMPAT
323 case 't':
324 #endif
325 case 'T': /* answer telnet codes */
326 opt_telnet = TRUE;
327 break;
328 case 'u': /* use UDP protocol */
329 opt_proto = NETCAT_PROTO_UDP;
330 break;
331 case 'v': /* be verbose (twice=more verbose) */
332 opt_verbose++;
333 break;
334 case 'V': /* display version and exit */
335 netcat_printversion();
336 exit(EXIT_SUCCESS);
337 case 'w': /* wait time (in seconds) */
338 opt_wait = atoi(optarg);
339 if (opt_wait <= 0)
340 ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Invalid wait-time: %s"),
341 optarg);
342 break;
343 case 'x': /* hexdump traffic */
344 opt_hexdump = TRUE;
345 break;
346 case 'z': /* little or no data xfer */
347 if (netcat_mode == NETCAT_TUNNEL)
348 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
349 _("`-L' and `-z' options are incompatible"));
350 opt_zero = TRUE;
351 break;
352 default:
353 ncprint(NCPRINT_EXIT, _("Try `%s --help' for more information."), argv[0]);
354 }
355 }
356
357 if (opt_zero && opt_exec)
358 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
359 _("`-e' and `-z' options are incompatible"));
360
361 /* initialize the flag buffer to keep track of the specified ports */
362 netcat_flag_init(65535);
363
364 #ifndef DEBUG
365 /* check for debugging support */
366 if (opt_debug)
367 ncprint(NCPRINT_WARNING,
368 _("Debugging support not compiled, option `-d' discarded. Using maximum verbosity."));
369 #endif
370
371 /* randomize only if needed */
372 if (opt_random)
373 #ifdef USE_RANDOM
374 SRAND(time(0));
375 #else
376 ncprint(NCPRINT_WARNING,
377 _("Randomization support not compiled, option `-r' discarded."));
378 #endif
379
380 /* handle the -o option. exit on failure */
381 if (opt_outputfile) {
382 output_fp = fopen(opt_outputfile, "w");
383 if (!output_fp)
384 ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Failed to open output file: %s"),
385 strerror(errno));
386 }
387 else
388 output_fp = stderr;
389
390 debug_v(("Trying to parse non-args parameters (argc=%d, optind=%d)", argc,
391 optind));
392
393 /* try to get an hostname parameter */
394 if (optind < argc) {
395 char *myhost = argv[optind++];
396 if (!netcat_resolvehost(&remote_host, myhost))
397 ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Couldn't resolve host \"%s\""),
398 myhost);
399 }
400
401 /* now loop all the other (maybe optional) parameters for port-ranges */
402 while (optind < argc) {
403 const char *get_argv = argv[optind++];
404 char *q, *parse = strdup(get_argv);
405 int port_lo = 0, port_hi = 65535;
406 nc_port_t port_tmp;
407
408 if (!(q = strchr(parse, '-'))) /* simple number? */
409 q = strchr(parse, ':'); /* try with the other separator */
410
411 if (!q) {
412 if (netcat_getport(&port_tmp, parse, 0))
413 netcat_flag_set(port_tmp.num, TRUE);
414 else
415 goto got_err;
416 }
417 else { /* could be in the forms: N1-N2, -N2, N1- */
418 *q++ = 0;
419 if (*parse) {
420 if (netcat_getport(&port_tmp, parse, 0))
421 port_lo = port_tmp.num;
422 else
423 goto got_err;
424 }
425 if (*q) {
426 if (netcat_getport(&port_tmp, q, 0))
427 port_hi = port_tmp.num;
428 else
429 goto got_err;
430 }
431 if (!*parse && !*q) /* don't accept the form '-' */
432 goto got_err;
433
434 /* now update the flagset (this is int, so it's ok even if hi == 65535) */
435 while (port_lo <= port_hi)
436 netcat_flag_set(port_lo++, TRUE);
437 }
438
439 free(parse);
440 continue;
441
442 got_err:
443 free(parse);
444 ncprint(NCPRINT_ERROR, _("Invalid port specification: %s"), get_argv);
445 exit(EXIT_FAILURE);
446 }
447
448 debug_dv(("Arguments parsing complete! Total ports=%d", netcat_flag_count()));
449 #if 0
450 /* pure debugging code */
451 c = 0;
452 while ((c = netcat_flag_next(c))) {
453 printf("Got port=%d\n", c);
454 }
455 exit(0);
456 #endif
457
458 /* Handle listen mode and tunnel mode (whose index number is higher) */
459 if (netcat_mode > NETCAT_CONNECT) {
460 /* in tunnel mode the opt_zero flag is illegal, while on listen mode it
461 means that no connections should be accepted. For UDP it means that
462 no remote addresses should be used as default endpoint, which means
463 that we can't send anything. In both situations, stdin is no longer
464 useful, so close it. */
465 if (opt_zero) {
466 close(STDIN_FILENO);
467 use_stdin = FALSE;
468 }
469
470 /* prepare the socket var and start listening */
471 listen_sock.proto = opt_proto;
472 listen_sock.timeout = opt_wait;
473 memcpy(&listen_sock.local_host, &local_host, sizeof(listen_sock.local_host));
474 memcpy(&listen_sock.local_port, &local_port, sizeof(listen_sock.local_port));
475 memcpy(&listen_sock.host, &remote_host, sizeof(listen_sock.host));
476 accept_ret = core_listen(&listen_sock);
477
478 /* in zero I/O mode the core_tcp_listen() call will always return -1
479 (ETIMEDOUT) since no connections are accepted, because of this our job
480 is completed now. */
481 if (accept_ret < 0) {
482 /* since i'm planning to make `-z' compatible with `-L' I need to check
483 the exact error that caused this failure. */
484 if (opt_zero && (errno == ETIMEDOUT))
485 exit(0);
486
487 ncprint(NCPRINT_VERB1 | NCPRINT_EXIT, _("Listen mode failed: %s"),
488 strerror(errno));
489 }
490
491 /* if we are in listen mode, run the core loop and exit when it returns.
492 otherwise now it's the time to connect to the target host and tunnel
493 them together (which means passing to the next section. */
494 if (netcat_mode == NETCAT_LISTEN) {
495 if (opt_exec) {
496 ncprint(NCPRINT_VERB2, _("Passing control to the specified program"));
497 ncexec(&listen_sock); /* this won't return */
498 }
499 core_readwrite(&listen_sock, &stdio_sock);
500 debug_dv(("Listen: EXIT"));
501 }
502 else {
503 /* otherwise we are in tunnel mode. The connect_sock var was already
504 initialized by the command line arguments. */
505 assert(netcat_mode == NETCAT_TUNNEL);
506 connect_ret = core_connect(&connect_sock);
507
508 /* connection failure? (we cannot get this in UDP mode) */
509 if (connect_ret < 0) {
510 assert(opt_proto != NETCAT_PROTO_UDP);
511 ncprint(NCPRINT_VERB1, "%s: %s",
512 netcat_strid(&connect_sock.host, &connect_sock.port),
513 strerror(errno));
514 }
515 else {
516 glob_ret = EXIT_SUCCESS;
517 core_readwrite(&listen_sock, &connect_sock);
518 debug_dv(("Tunnel: EXIT (ret=%d)", glob_ret));
519 }
520 }
521
522 /* all jobs should be ok, go to the cleanup */
523 goto main_exit;
524 } /* end of listen and tunnel mode handling */
525
526 /* we need to connect outside, this is the connect mode */
527 netcat_mode = NETCAT_CONNECT;
528
529 /* first check that a host parameter was given */
530 if (!remote_host.iaddrs[0].s_addr) {
531 /* FIXME: The Networking specifications state that host address "0" is a
532 valid host to connect to but this broken check will assume as not
533 specified. */
534 ncprint(NCPRINT_NORMAL, _("%s: missing hostname argument"), argv[0]);
535 ncprint(NCPRINT_EXIT, _("Try `%s --help' for more information."), argv[0]);
536 }
537
538 /* since ports are the second argument, checking ports might be enough */
539 total_ports = netcat_flag_count();
540 if (total_ports == 0)
541 ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
542 _("No ports specified for connection"));
543
544 c = 0; /* must be set to 0 for netcat_flag_next() */
545 left_ports = total_ports;
546 while (left_ports > 0) {
547 /* `c' is the port number independently of the sorting method (linear
548 or random). While in linear mode it is also used to fetch the next
549 port number */
550 if (opt_random)
551 c = netcat_flag_rand();
552 else
553 c = netcat_flag_next(c);
554 left_ports--; /* decrease the total ports number to try */
555
556 /* since we are nonblocking now, we can start as many connections as we want
557 but it's not a great idea connecting more than one host at time */
558 connect_sock.proto = opt_proto;
559 connect_sock.timeout = opt_wait;
560 memcpy(&connect_sock.local_host, &local_host,
561 sizeof(connect_sock.local_host));
562 memcpy(&connect_sock.local_port, &local_port,
563 sizeof(connect_sock.local_port));
564 memcpy(&connect_sock.host, &remote_host, sizeof(connect_sock.host));
565 netcat_getport(&connect_sock.port, NULL, c);
566
567 /* FIXME: in udp mode and NETCAT_CONNECT, opt_zero is senseless */
568 connect_ret = core_connect(&connect_sock);
569
570 /* connection failure? (we cannot get this in UDP mode) */
571 if (connect_ret < 0) {
572 int ncprint_flags = NCPRINT_VERB1;
573 assert(connect_sock.proto != NETCAT_PROTO_UDP);
574
575 /* if we are portscanning or multiple connecting show only open
576 ports with verbosity level 1. */
577 if (total_ports > 1)
578 ncprint_flags = NCPRINT_VERB2;
579
580 ncprint(ncprint_flags, "%s: %s",
581 netcat_strid(&connect_sock.host, &connect_sock.port),
582 strerror(errno));
583 continue; /* go with next port */
584 }
585
586 /* when portscanning (or checking a single port) we are happy if AT LEAST
587 ONE port is available. */
588 glob_ret = EXIT_SUCCESS;
589
590 if (opt_zero) {
591 shutdown(connect_ret, 2);
592 close(connect_ret);
593 }
594 else {
595 if (opt_exec) {
596 ncprint(NCPRINT_VERB2, _("Passing control to the specified program"));
597 ncexec(&connect_sock); /* this won't return */
598 }
599 core_readwrite(&connect_sock, &stdio_sock);
600 /* FIXME: add a small delay */
601 debug_v(("Connect: EXIT"));
602
603 /* both signals are handled inside core_readwrite(), but while the
604 SIGINT signal is fully handled, the SIGTERM requires some action
605 from outside that function, because of this that flag is not
606 cleared. */
607 if (got_sigterm)
608 break;
609 }
610 } /* end of while (left_ports > 0) */
611
612 /* all basic modes should return here for the final cleanup */
613 main_exit:
614 debug_v(("Main: EXIT (cleaning up)"));
615
616 netcat_printstats(FALSE);
617 return glob_ret;
618 } /* end of main() */
619