コード例 #1
0
ファイル: netcat.c プロジェクト: NIMk/HDSync
static void got_usr1(int z)
{
  debug_dv(("_____ RECEIVED SIGUSR1 _____ [signal_handler=%s]",
	   BOOL_TO_STR(signal_handler)));
  if (signal_handler)			/* default action */
    netcat_printstats(TRUE);
  else
    got_sigusr1 = TRUE;
}
コード例 #2
0
ファイル: netcat.c プロジェクト: xcodevn/minix3-netcat
static void got_int(int z)
{
  if (!got_sigint)
    ncprint(NCPRINT_VERB1, _("Exiting."));
  debug_v(("_____ RECEIVED SIGINT _____ [signal_handler=%s]",
	  BOOL_TO_STR(signal_handler)));
  got_sigint = TRUE;
  if (signal_handler) {			/* default action */
    if (commandline_need_newline)	/* if we were waiting for input */
      printf("\n");
    netcat_printstats(FALSE);
    exit(EXIT_FAILURE);
  }
}
コード例 #3
0
ファイル: core.c プロジェクト: mattias-ohlsson/netcat
int core_readwrite(nc_sock_t *nc_main, nc_sock_t *nc_slave)
{
  int fd_stdin, fd_stdout, fd_sock, fd_max;
  int read_ret, write_ret;
  #ifdef  __MVS__             /* zosunix01 26.07.2011 */
  unsigned char buf[32768];
  #else
  unsigned char buf[1024]; 
  #endif 
  bool inloop = TRUE;
  fd_set ins, outs;
  struct timeval delayer;
  assert(nc_main && nc_slave);

  debug_v(("core_readwrite(nc_main=%p, nc_slave=%p)", (void *)nc_main,
	  (void *)nc_slave));

  /* set the actual input and output fds and find out the max fd + 1 */
  fd_sock = nc_main->fd;
  assert(fd_sock >= 0);

  /* if the domain is unspecified, it means that this is the standard I/O */
  if (nc_slave->domain == PF_UNSPEC) {
    fd_stdin = STDIN_FILENO;
    fd_stdout = STDOUT_FILENO;
  }
  else {
    fd_stdin = fd_stdout = nc_slave->fd;
    assert(fd_stdin >= 0);
  }
  fd_max = 1 + (fd_stdin > fd_sock ? fd_stdin : fd_sock);
  delayer.tv_sec = 0;
  delayer.tv_usec = 0;

  /* use the internal signal handler */
  signal_handler = FALSE;

  while (inloop) {
    bool call_select = TRUE;
    struct sockaddr_in recv_addr;	/* only used by UDP proto */
    unsigned int recv_len = sizeof(recv_addr);

    /* if we received an interrupt signal break this function */
    if (got_sigint) {
      got_sigint = FALSE;
      break;
    }
    /* if we received a terminating signal we must terminate */
    if (got_sigterm)
      break;

    /* reset the ins and outs events watch because some changes could happen */
    FD_ZERO(&ins);
    FD_ZERO(&outs);

    /* if the receiving queue is not empty it means that something bad is
       happening (for example the target sending queue is delaying the output
       and so requires some more time to free up. */
    if (nc_main->recvq.len == 0) {
      debug_v(("watching main sock for incoming data (recvq is empty)"));
      FD_SET(fd_sock, &ins);
    }
    else
      call_select = FALSE;

    /* same thing for the other socket */
    if (nc_slave->recvq.len == 0) { /* FIXME: call_select = false but could call it
	anyway and one of them could be set.. so what happens? */
      debug_v(("watching slave sock for incoming data (recvq is empty)"));
      if (use_stdin || (netcat_mode == NETCAT_TUNNEL))
        FD_SET(fd_stdin, &ins);
    }
    else
      call_select = FALSE;

    /* now the send queue. There are two cases in which the main sendq is not
       empty.  The first one is when we have a delayed output (-i), in which
       case the delayer is not null, and the socket is writable.  The second
       case is when the socket buffer is full, so the socket is not writable
       and the delayer is either null or set, depending on the opt_interval
       variable. */
    if (nc_main->sendq.len > 0) {
      if ((delayer.tv_sec == 0) && (delayer.tv_usec == 0)) {
	debug_v(("watching main sock for outgoing availability (there is pending data)"));
	FD_SET(fd_sock, &outs);
	call_select = TRUE;
      }
    }

    if (call_select || delayer.tv_sec || delayer.tv_usec) {
      int ret;
#ifndef USE_LINUX_SELECT
      struct timeval dd_saved;

      dd_saved.tv_sec = delayer.tv_sec;
      dd_saved.tv_usec = delayer.tv_usec;
      update_timeval(NULL);
#endif

      debug(("[select] entering with timeout=%d:%d ...", delayer.tv_sec, delayer.tv_usec));
      ret = select(fd_max, &ins, &outs, NULL,
		   (delayer.tv_sec || delayer.tv_usec ? &delayer : NULL));

#ifndef USE_LINUX_SELECT
      delayer.tv_sec = dd_saved.tv_sec;
      delayer.tv_usec = dd_saved.tv_usec;
      update_timeval(&delayer);
#endif

      if (ret < 0) {			/* something went wrong (maybe a legal signal) */
	if (errno == EINTR)
	  goto handle_signal;
	perror("select(core_readwrite)");
	exit(EXIT_FAILURE);
      }
      else if (ret == 0) {		/* timeout expired */
	delayer.tv_sec = 0;
	delayer.tv_usec = 0;
      }

      call_select = TRUE;
      debug(("ret=%d\n", ret));
    }

    /* reading from stdin the incoming data.  The data is currently in the
       kernel's receiving queue, and in this session we move that data to our
       own receiving queue, located in the socket object.  We can be sure that
       this queue is empty now because otherwise this fd wouldn't have been
       watched. */
    if (call_select && FD_ISSET(fd_stdin, &ins)) {
      read_ret = read(fd_stdin, buf, sizeof(buf));
      debug_dv(("read(stdin) = %d", read_ret));

      if (read_ret < 0) {
	perror("read(stdin)");
	exit(EXIT_FAILURE);
      }
      else if (read_ret == 0) {
	/* when we receive EOF and this is a tunnel say goodbye, otherwise
	   it means that stdin has finished its input. */
	if ((netcat_mode == NETCAT_TUNNEL) || opt_eofclose) {
	  debug_v(("EOF Received from stdin! (exiting from loop..)"));
	  inloop = FALSE;
	}
	else {
	  debug_v(("EOF Received from stdin! (removing from lookups..)"));
	  use_stdin = FALSE;
	}
      }
      else {
	/* we can overwrite safely since if the receive queue is busy this fd
	   is not watched at all. */
        nc_slave->recvq.len = read_ret;
        nc_slave->recvq.head = NULL;
        nc_slave->recvq.pos = buf;
      }
    }

    /* for optimization reasons we have a common buffer for both receiving
       queues, because of this, handle the data now so the buffer is available
       for the other socket events. */
    if (nc_slave->recvq.len > 0) {
      nc_buffer_t *my_recvq = &nc_slave->recvq;
      nc_buffer_t *rem_sendq = &nc_main->sendq;
      debug_v(("there are %d data bytes in slave->recvq", my_recvq->len));

      /* if the remote send queue is empty, move there the entire data block */
      if (rem_sendq->len == 0) {
	debug_v(("  moved %d data bytes from slave->recvq to main->sendq", my_recvq->len));
	memcpy(rem_sendq, my_recvq, sizeof(*rem_sendq));
	memset(my_recvq, 0, sizeof(*my_recvq));
      }
      else if (!my_recvq->head) {
	/* move the data block in a dedicated allocated space */
	debug_v(("  reallocating %d data bytes in slave->recvq", my_recvq->len));
	my_recvq->head = malloc(my_recvq->len);
	memcpy(my_recvq->head, my_recvq->pos, my_recvq->len);
	my_recvq->pos = my_recvq->head;
      }
    }

    /* now handle the nc_slave sendq because of the same reason as above. There
       could be a common buffer that moves around the queues, so if this is the case
       handle it so that it can be reused. If we must delay it some more, copy it
       in a dynamically allocated space. */
    if (nc_main->sendq.len > 0) {
      unsigned char *data = nc_main->sendq.pos;
      int data_len = nc_main->sendq.len;
      nc_buffer_t *my_sendq = &nc_main->sendq;

      debug_v(("there are %d data bytes in main->sendq", my_sendq->len));

      /* we have a delayed output, but at this point we might have the
         send queue pointing to a stack buffer.  In this case, allocate a
         new buffer and copy the data there for the buffered output. */
      if (opt_interval) {
	int i = 0;

	if (delayer.tv_sec || delayer.tv_usec)
	  goto skip_sect;		/* the delay is not yet over! */

	/* find the newline character.  We are going to output the first line
	   immediately while we allocate and safe the rest of the data for a
	   later output. */
	while (i < data_len)
	  if (data[i++] == '\n')
	    break;

	data_len = i;
	delayer.tv_sec = opt_interval;
      }

      write_ret = write(fd_sock, data, data_len);
      if (write_ret < 0) {
        #ifdef  __MVS__          /* zosunix01 26.07.2011                   */ 
                                 /* z/OS Unix is Unix V and here the errno */
                                 /* EWOULBBLOCK appears, if the socket is  */
                                 /* blocked.                               */
	if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
        #else
        if (errno == EAGAIN)
        #endif
	  write_ret = 0;	/* write would block, append it to select */
	else {
	  perror("write(net)");
	  exit(EXIT_FAILURE);
	}
      }

      /* FIXME: fix the below unhandled exception, and find a way to delay the
       * tries to call write(2) in case of EAGAIN, i think 100ms would be fine
       * for most systems. A too high value would not use all the bandwidth on
       * bigger installations, while a too small value would eat cpu with
       * kernel overhead. */

      bytes_sent += write_ret;		/* update statistics */
      debug_dv(("write(net) = %d (buf=%p)", write_ret, (void *)data));

      if (write_ret < data_len) {
	debug_v(("Damn! I wanted to send to sock %d bytes but it only sent %d",
		data_len, write_ret));
	data_len = write_ret;
      }

      /* if the option is set, hexdump the sent data */
      if (opt_hexdump) {
#ifndef USE_OLD_HEXDUMP
	fprintf(output_fp, "Sent %u bytes to the socket\n", write_ret);
#endif
	netcat_fhexdump(output_fp, '>', data, data_len);
      }

      /* update the queue */
      my_sendq->len -= data_len;
      my_sendq->pos += data_len;

 skip_sect:
      debug_v(("there are %d data bytes left in the queue", my_sendq->len));
      if (my_sendq->len == 0) {
	free(my_sendq->head);
	memset(my_sendq, 0, sizeof(*my_sendq));
      }
      else if (!my_sendq->head) {
	my_sendq->head = malloc(my_sendq->len);
	memcpy(my_sendq->head, my_sendq->pos, my_sendq->len);
	my_sendq->pos = my_sendq->head;
      }

    }				/* end of reading from stdin section */

    /* reading from the socket (net). */
    if (call_select && FD_ISSET(fd_sock, &ins)) {
      if ((nc_main->proto == NETCAT_PROTO_UDP) && opt_zero) {
	memset(&recv_addr, 0, sizeof(recv_addr));
	/* this allows us to fetch packets from different addresses */
	read_ret = recvfrom(fd_sock, buf, sizeof(buf), 0,
			    (struct sockaddr *)&recv_addr, &recv_len);
	/* when recvfrom() call fails, recv_addr remains untouched */
	debug_dv(("recvfrom(net) = %d (address=%s:%d)", read_ret,
		netcat_inet_ntop(&recv_addr.sin_addr), ntohs(recv_addr.sin_port)));
      }
      else {
	/* common file read fallback */
	read_ret = read(fd_sock, buf, sizeof(buf));
	debug_dv(("read(net) = %d", read_ret));
      }

      if (read_ret < 0) {
	perror("read(net)");
	exit(EXIT_FAILURE);
      }
      else if (read_ret == 0) {
	debug_v(("EOF Received from the net"));
	inloop = FALSE;
      }
      else {
	nc_main->recvq.len = read_ret;
	nc_main->recvq.head = NULL;
	nc_main->recvq.pos = buf;
      }
    }

    /* handle net receiving queue */
    if (nc_main->recvq.len > 0) {
      nc_buffer_t *my_recvq = &nc_main->recvq;
      nc_buffer_t *rem_sendq = &nc_slave->sendq;

      /* check for telnet codes (if enabled).  Note that the buffered output
         interval does NOT apply to telnet code answers */
      if (opt_telnet)
	netcat_telnet_parse(nc_main);

      /* the telnet parsing could have returned 0 chars! */
      if (my_recvq->len > 0) {
	/* if the remote send queue is empty, move there the entire data block */
	if (rem_sendq->len == 0) {
	  memcpy(rem_sendq, my_recvq, sizeof(*rem_sendq));
	  memset(my_recvq, 0, sizeof(*my_recvq));
	}
	else if (!my_recvq->head) {
	  /* move the data block in a dedicated allocated space */
	  my_recvq->head = malloc(my_recvq->len);
	  memcpy(my_recvq->head, my_recvq->pos, my_recvq->len);
	  my_recvq->pos = my_recvq->head;
	}
      }
    }

    if (nc_slave->sendq.len > 0) {
      unsigned char *data = nc_slave->sendq.pos;
      int data_len = nc_slave->sendq.len;
      nc_buffer_t *my_sendq = &nc_slave->sendq;

      write_ret = write(fd_stdout, data, data_len);
      bytes_recv += write_ret;		/* update statistics */
      debug_dv(("write(stdout) = %d", write_ret));

      if (write_ret < 0) {
	perror("write(stdout)");
	exit(EXIT_FAILURE);
      }

      /* FIXME: unhandled exception */
      assert((write_ret > 0) && (write_ret <= data_len));

      if (write_ret < data_len) {
	debug_v(("Damn! I wanted to send to stdout %d bytes but it only sent %d",
		data_len, write_ret));
	data_len = write_ret;
      }

      /* if option is set, hexdump the received data */
      if (opt_hexdump) {
#ifndef USE_OLD_HEXDUMP
	if ((nc_main->proto == NETCAT_PROTO_UDP) && opt_zero)
	  fprintf(output_fp, "Received %d bytes from %s:%d\n", write_ret,
		  netcat_inet_ntop(&recv_addr.sin_addr), ntohs(recv_addr.sin_port));
	else
	  fprintf(output_fp, "Received %d bytes from the socket\n", write_ret);
#endif
	netcat_fhexdump(output_fp, '<', data, write_ret);
      }

      /* update the queue */
      my_sendq->len -= data_len;
      my_sendq->pos += data_len;

      debug_v(("there are %d data bytes left in the queue", my_sendq->len));
      if (my_sendq->len == 0) {
	free(my_sendq->head);
	memset(my_sendq, 0, sizeof(*my_sendq));
      }
      else if (!my_sendq->head) {
	my_sendq->head = malloc(my_sendq->len);
	memcpy(my_sendq->head, my_sendq->pos, my_sendq->len);
	my_sendq->pos = my_sendq->head;
      }
      
    }				/* end of reading from the socket section */

 handle_signal:			/* FIXME: i'm not sure this is the right place */
    if (got_sigusr1) {
      debug_v(("LOCAL printstats!"));
      netcat_printstats(TRUE);
      got_sigusr1 = FALSE;
    }
    continue;
  }				/* end of while (inloop) */

  /* we've got an EOF from the net, close the sockets */
  shutdown(fd_sock, SHUT_RDWR);  
  close(fd_sock);
  nc_main->fd = -1;

  /* close the slave socket only if it wasn't a simulation */
  if (nc_slave->domain != PF_UNSPEC) {
    shutdown(fd_stdin, SHUT_RDWR);
    close(fd_stdin);
    nc_slave->fd = -1;
  }

  /* restore the extarnal signal handler */
  signal_handler = TRUE;

  return 0;
}				/* end of core_readwrite() */
コード例 #4
0
ファイル: netcat.c プロジェクト: xcodevn/minix3-netcat
int main(int argc, char *argv[])
{
  int c, glob_ret = EXIT_FAILURE;
  int total_ports, left_ports, accept_ret = -1, connect_ret = -1;
  struct sigaction sv;
  nc_port_t local_port;		/* local port specified with -p option */
  nc_host_t local_host;		/* local host for bind()ing operations */
  nc_host_t remote_host;
  nc_sock_t listen_sock;
  nc_sock_t connect_sock;
  nc_sock_t stdio_sock;
  nc_ports_t old_flag = NULL;

  memset(&local_port, 0, sizeof(local_port));
  memset(&local_host, 0, sizeof(local_host));
  memset(&remote_host, 0, sizeof(remote_host));
  memset(&listen_sock, 0, sizeof(listen_sock));
  memset(&connect_sock, 0, sizeof(connect_sock));
  memset(&stdio_sock, 0, sizeof(stdio_sock));
  listen_sock.domain = NETCAT_DOMAIN_IPV4;
  connect_sock.domain = NETCAT_DOMAIN_IPV4;

#ifdef ENABLE_NLS
  setlocale(LC_MESSAGES, "");
  bindtextdomain(PACKAGE, LOCALEDIR);
  textdomain(PACKAGE);
#endif

  /* set up the signal handling system */
  sigemptyset(&sv.sa_mask);
  sv.sa_flags = 0;
  sv.sa_handler = got_int;
  sigaction(SIGINT, &sv, NULL);
  sv.sa_handler = got_term;
  sigaction(SIGTERM, &sv, NULL);
  sv.sa_handler = got_usr1;
  sigaction(SIGUSR1, &sv, NULL);
  /* ignore some boring signals */
  sv.sa_handler = SIG_IGN;
  sigaction(SIGPIPE, &sv, NULL);
  sigaction(SIGURG, &sv, NULL);

  /* if no args given at all, take them from stdin and generate argv */
  if (argc == 1)
    netcat_commandline_read(&argc, &argv);

  /* check for command line switches */
  while (TRUE) {
    int option_index = 0;
    static const struct option long_options[] = {
	{ "close",	no_argument,		NULL, 'c' },
	{ "debug",	no_argument,		NULL, 'd' },
	{ "exec",	required_argument,	NULL, 'e' },
	{ "gateway",	required_argument,	NULL, 'g' },
	{ "pointer",	required_argument,	NULL, 'G' },
	{ "help",	no_argument,		NULL, 'h' },
	{ "interval",	required_argument,	NULL, 'i' },
	{ "ipv4",	no_argument,		NULL, '4' },
	{ "ipv6",	no_argument,		NULL, '6' },
	{ "listen",	no_argument,		NULL, 'l' },
	{ "tunnel",	required_argument,	NULL, 'L' },
	{ "dont-resolve", no_argument,		NULL, 'n' },
	{ "convert",	required_argument,	NULL, 'N' }, /* FIXME: proposal: A Ascii? */
	{ "output",	required_argument,	NULL, 'o' },
	{ "local-port",	required_argument,	NULL, 'p' },
	{ "tunnel-port", required_argument,	NULL, 'P' },
	{ "randomize",	no_argument,		NULL, 'r' },
	{ "source",	required_argument,	NULL, 's' },
	{ "tunnel-source", required_argument,	NULL, 'S' },
#ifndef USE_OLD_COMPAT
	{ "tcp",	no_argument,		NULL, 't' },
	{ "telnet",	no_argument,		NULL, 'T' },
#else
	{ "tcp",	no_argument,		NULL, 1 },
	{ "telnet",	no_argument,		NULL, 't' },
#endif
	{ "udp",	no_argument,		NULL, 'u' },
	{ "verbose",	no_argument,		NULL, 'v' },
	{ "version",	no_argument,		NULL, 'V' },
	{ "hexdump",	no_argument,		NULL, 'x' },
	{ "wait",	required_argument,	NULL, 'w' },
	{ "zero",	no_argument,		NULL, 'z' },
	{ 0, 0, 0, 0 }
    };

    c = getopt_long(argc, argv, "46cde:g:G:hi:lL:no:p:P:rs:S:tTuvVxw:z",
		    long_options, &option_index);
    if (c == -1)
      break;

    switch (c) {
    case '4':			/* don't use IPv6 protocol */
      opt_domain = NETCAT_DOMAIN_IPV4;
      break;
    case '6':			/* use IPv6 protocol */
      opt_domain = NETCAT_DOMAIN_IPV6;
      break;
    case 'c':			/* close connection on EOF from stdin */
      opt_eofclose = TRUE;
      break;
    case 'd':			/* enable debugging */
      opt_debug = TRUE;
      break;
    case 'e':			/* prog to exec */
      if (opt_exec)
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("Cannot specify `-e' option double"));
      opt_exec = strdup(optarg);
      break;
    case 'G':			/* srcrt gateways pointer val */
      break;
    case 'g':			/* srcroute hops */
      break;
    case 'h':			/* display help and exit */
      netcat_printhelp(argv[0]);
      exit(EXIT_SUCCESS);
    case 'i':			/* line/ports interval time (seconds) */
      opt_interval = atoi(optarg);
      if (opt_interval < 0)
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("Invalid interval time \"%s\""), optarg);
      break;
    case 'l':			/* mode flag: listen mode */
      if (netcat_mode != NETCAT_UNSPEC)
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("You can specify mode flags (`-l' and `-L') only once"));
      netcat_mode = NETCAT_LISTEN;
      break;
    case 'L':			/* mode flag: tunnel mode */
      if (netcat_mode != NETCAT_UNSPEC)
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("You can specify mode flags (`-l' and `-L') only once"));
      if (opt_zero)
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("`-L' and `-z' options are incompatible"));
      do {
	char *div, *p, *pbuf = strdup(optarg);

	div = p = pbuf;
	/* if the address has '[' unbalanced, threat is as plain address */
	if (div[0] == '[') {
	  div = strchr(div, ']');
	  if (div != NULL) {
	    *div++ = '\0';
	    p++;				/* skip the '[' */
	  }
	}
	div = strchr(div, ':');

	if (div && *(div + 1))
	  *div++ = '\0';
	else {
	  ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		  _("Invalid target string for `-L' option"));
	}

	/* lookup the remote address and the remote port for tunneling */
	if (!netcat_resolvehost(&connect_sock.remote, optarg))
	  ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		  _("Couldn't resolve tunnel target host: %s"), optarg);
	if (!netcat_getport(&connect_sock.port, div, 0))
	  ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		  _("Invalid tunnel target port: %s"), div);

	/* takes the options configured so far as they may change */
	connect_sock.domain = opt_domain;
	connect_sock.proto = opt_proto;
	connect_sock.timeout = opt_wait;
	netcat_mode = NETCAT_TUNNEL;
      } while (FALSE);
      break;
    case 'N':			/* ascii line ends conversion, use with care */
      if (!strcasecmp(optarg, "none"))
	opt_ascii_conversion = NETCAT_CONVERT_NONE;
      else if (!strcasecmp(optarg, "crlf"))
	opt_ascii_conversion = NETCAT_CONVERT_CRLF;
      else if (!strcasecmp(optarg, "cr"))
	opt_ascii_conversion = NETCAT_CONVERT_CR;
      else if (!strcasecmp(optarg, "lf"))
	opt_ascii_conversion = NETCAT_CONVERT_LF;
      else {
	ncprint(NCPRINT_NORMAL, _("Conversion must be one of: none crlf cr lf"));
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("Invalid conversion specified: %s"), optarg);
      }
      break;
    case 'n':			/* numeric-only, no DNS lookups */
      opt_numeric = TRUE;
      break;
    case 'o':			/* output hexdump log to file */
      opt_outputfile = strdup(optarg);
      opt_hexdump = TRUE;	/* implied */
      break;
    case 'p':			/* local source port */
      if (!netcat_getport(&local_port, optarg, 0))
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Invalid local port: %s"),
		optarg);
      break;
    case 'P':			/* used only in tunnel mode (source port) */
      if (!netcat_getport(&connect_sock.local_port, optarg, 0))
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("Invalid tunnel connect port: %s"), optarg);
      break;
    case 'r':			/* randomize various things */
      opt_random = TRUE;
      break;
    case 's':			/* local source address */
      /* lookup the source address and assign it to the connection address */
      if (!netcat_resolvehost(&local_host, optarg))
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("Couldn't resolve local host: %s"), optarg);
      break;
    case 'S':			/* used only in tunnel mode (source ip) */
      if (!netcat_resolvehost(&connect_sock.local, optarg))
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("Couldn't resolve tunnel local host: %s"), optarg);
      break;
    case 1:			/* use TCP protocol (default) */
#ifndef USE_OLD_COMPAT
    case 't':
#endif
      opt_proto = NETCAT_PROTO_TCP;
      break;
#ifdef USE_OLD_COMPAT
    case 't':
#endif
    case 'T':			/* answer telnet codes */
      opt_telnet = TRUE;
      break;
    case 'u':			/* use UDP protocol */
      opt_proto = NETCAT_PROTO_UDP;
      break;
    case 'v':			/* be verbose (twice=more verbose) */
      opt_verbose++;
      break;
    case 'V':			/* display version and exit */
      netcat_printversion();
      exit(EXIT_SUCCESS);
    case 'w':			/* wait time (in seconds), 0 means no timeout */
      opt_wait = atoi(optarg);
      if (opt_wait < 0)
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Invalid wait-time: %s"),
		optarg);
      break;
    case 'x':			/* hexdump traffic */
      opt_hexdump = TRUE;
      break;
    case 'z':			/* little or no data xfer */
      if (netcat_mode == NETCAT_TUNNEL)
	ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("`-L' and `-z' options are incompatible"));
      opt_zero = TRUE;
      break;
    default:
      ncprint(NCPRINT_EXIT, _("Try `%s --help' for more information."), argv[0]);
    }
  }

  if (opt_zero && opt_exec)
    ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
		_("`-e' and `-z' options are incompatible"));

  /* initialize the flag buffer to keep track of the specified ports */
  //netcat_flag_init(65535);
  old_flag = netcat_ports_init();

#ifndef DEBUG
  /* check for debugging support */
  if (opt_debug)
    ncprint(NCPRINT_WARNING,
	    _("Debugging support not compiled, option `-d' discarded. Using maximum verbosity."));
#endif

  /* randomize only if needed */
  if (opt_random)
#ifdef USE_RANDOM
    SRAND(time(0));
#else
    ncprint(NCPRINT_WARNING,
	    _("Randomization support not compiled, option `-r' discarded."));
#endif

  /* handle the -o option. exit on failure */
  if (opt_outputfile) {
    output_fp = fopen(opt_outputfile, "w");
    if (!output_fp)
      ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Failed to open output file: %s (%s)"),
	      opt_outputfile, strerror(errno));
  }
  else
    output_fp = stderr;

  /* FIXME: now we can resolve special hostnames */

  debug_v(("Trying to parse non-args parameters (argc=%d, optind=%d)", argc,
	  optind));

  /* try to get an hostname parameter */
  if (optind < argc) {
    const char *get_host = argv[optind++];
    if (!netcat_resolvehost(&remote_host, get_host))
      ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Couldn't resolve host \"%s\""),
	      get_host);
  }

  /* now loop all the other (maybe optional) parameters for port-ranges */
  while (optind < argc) {
    const char *get_argv = argv[optind++];
    char *q, *parse = strdup(get_argv);
    int port_lo = 0, port_hi = 65535;
    nc_port_t port_tmp;

    if (!(q = strchr(parse, '-')))	/* simple number? */
      q = strchr(parse, ':');		/* try with the other separator */

    if (!q) {
      if (netcat_getport(&port_tmp, parse, 0))
	netcat_ports_insert(old_flag, port_tmp.num, port_tmp.num);
      else
	goto got_err;
    }
    else {		/* could be in the forms: N1-N2, -N2, N1- */
      *q++ = 0;
      if (*parse) {
	if (netcat_getport(&port_tmp, parse, 0))
	  port_lo = port_tmp.num;
	else
	  goto got_err;
      }
      if (*q) {
	if (netcat_getport(&port_tmp, q, 0))
	  port_hi = port_tmp.num;
	else
	  goto got_err;
      }
      if (!*parse && !*q)		/* don't accept the form '-' */
	goto got_err;

      netcat_ports_insert(old_flag, port_lo, port_hi);
    }

    free(parse);
    continue;

 got_err:
    free(parse);
    ncprint(NCPRINT_ERROR, _("Invalid port specification: %s"), get_argv);
    exit(EXIT_FAILURE);
  }

  debug_dv(("Arguments parsing complete! Total ports=%d", netcat_ports_count(old_flag)));
#if 0
  /* pure debugging code */
  c = 0;
  while ((c = netcat_ports_next(old_flag, c))) {
    printf("Got port=%d\n", c);
  }
  exit(0);
#endif

  /* Handle listen mode and tunnel mode (whose index number is higher) */
  if (netcat_mode > NETCAT_CONNECT) {
    /* in tunnel mode the opt_zero flag is illegal, while on listen mode it
       means that no connections should be accepted.  For UDP it means that
       no remote addresses should be used as default endpoint, which means
       that we can't send anything.  In both situations, stdin is no longer
       useful, so close it. */
    if (opt_zero) {
      close(STDIN_FILENO);
      use_stdin = FALSE;
    }

    /* prepare the socket var and start listening */
    listen_sock.proto = opt_proto;
    listen_sock.timeout = opt_wait;
    memcpy(&listen_sock.local, &local_host, sizeof(listen_sock.local));
    memcpy(&listen_sock.local_port, &local_port, sizeof(listen_sock.local_port));
    memcpy(&listen_sock.remote, &remote_host, sizeof(listen_sock.remote));
    accept_ret = core_listen(&listen_sock);

    /* in zero I/O mode the core_tcp_listen() call will always return -1
       (ETIMEDOUT) since no connections are accepted, because of this our job
       is completed now. */
    if (accept_ret < 0) {
      /* since i'm planning to make `-z' compatible with `-L' I need to check
         the exact error that caused this failure. */
      if (opt_zero && (errno == ETIMEDOUT))
	exit(0);

      ncprint(NCPRINT_VERB1 | NCPRINT_EXIT, _("Listen mode failed: %s"),
	      strerror(errno));
    }

    /* if we are in listen mode, run the core loop and exit when it returns.
       otherwise now it's the time to connect to the target host and tunnel
       them together (which means passing to the next section. */
    if (netcat_mode == NETCAT_LISTEN) {
      if (opt_exec) {
	ncprint(NCPRINT_VERB2, _("Passing control to the specified program"));
	ncexec(&listen_sock);		/* this won't return */
      }
      core_readwrite(&listen_sock, &stdio_sock);
      debug_dv(("Listen: EXIT"));
    }
    else {
      /* otherwise we are in tunnel mode.  The connect_sock var was already
         initialized by the command line arguments. */
      assert(netcat_mode == NETCAT_TUNNEL);
      connect_ret = core_connect(&connect_sock);

      /* connection failure? (we cannot get this in UDP mode) */
      if (connect_ret < 0) {
	assert(connect_sock.proto != NETCAT_PROTO_UDP);
	ncprint(NCPRINT_VERB1, "%s: %s",
		netcat_strid(connect_sock.domain, &connect_sock.remote, &connect_sock.port),
		strerror(errno));
      }
      else {
	glob_ret = EXIT_SUCCESS;
	core_readwrite(&listen_sock, &connect_sock);
	debug_dv(("Tunnel: EXIT (ret=%d)", glob_ret));
      }
    }

    /* all jobs should be ok, go to the cleanup */
    goto main_exit;
  }				/* end of listen and tunnel mode handling */

  /* we need to connect outside, this is the connect mode */
  netcat_mode = NETCAT_CONNECT;

  /* first check that a host parameter was given */
  if (!remote_host.host.iaddrs[0].s_addr) {
    /* FIXME: The Networking specifications state that host address "0" is a
       valid host to connect to but this broken check will assume as not
       specified. */
    ncprint(NCPRINT_NORMAL, _("%s: missing hostname argument"), argv[0]);
    ncprint(NCPRINT_EXIT, _("Try `%s --help' for more information."), argv[0]);
  }

  /* since ports are the second argument, checking ports might be enough */
  total_ports = netcat_ports_count(old_flag);
  if (total_ports == 0)
    ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
	    _("No ports specified for connection"));

  c = 0;			/* must be set to 0 for netcat_flag_next() */
  left_ports = total_ports;
  while (left_ports > 0) {
    /* `c' is the port number independently of the sorting method (linear
       or random).  While in linear mode it is also used to fetch the next
       port number */
    if (opt_random)
      c = netcat_ports_rand(old_flag);
    else
      c = netcat_ports_next(old_flag, c);
    left_ports--;		/* decrease the total ports number to try */

    /* since we are nonblocking now, we can start as many connections as we want
       but it's not a great idea connecting more than one host at time */
    connect_sock.proto = opt_proto;
    connect_sock.timeout = opt_wait;
    memcpy(&connect_sock.local, &local_host, sizeof(connect_sock.local));
    memcpy(&connect_sock.local_port, &local_port,
	   sizeof(connect_sock.local_port));
    memcpy(&connect_sock.remote, &remote_host, sizeof(connect_sock.remote));
    netcat_getport(&connect_sock.port, NULL, c);

    /* FIXME: in udp mode and NETCAT_CONNECT, opt_zero is senseless */
    connect_ret = core_connect(&connect_sock);

    /* connection failure? (we cannot get this in UDP mode) */
    if (connect_ret < 0) {
      int ncprint_flags = NCPRINT_VERB1;
      assert(connect_sock.proto != NETCAT_PROTO_UDP);

      /* if we are portscanning or multiple connecting show only open
         ports with verbosity level 1. */
      if (total_ports > 1)
	ncprint_flags = NCPRINT_VERB2;

      ncprint(ncprint_flags, "%s: %s",
	      netcat_strid(connect_sock.domain, &connect_sock.remote, &connect_sock.port),
	      strerror(errno));
      continue;			/* go with next port */
    }

    /* when portscanning (or checking a single port) we are happy if AT LEAST
       ONE port is available. */
    glob_ret = EXIT_SUCCESS;

    if (opt_zero) {
      shutdown(connect_ret, 2);
      close(connect_ret);
    }
    else {
      if (opt_exec) {
	ncprint(NCPRINT_VERB2, _("Passing control to the specified program"));
	ncexec(&connect_sock);		/* this won't return */
      }
      core_readwrite(&connect_sock, &stdio_sock);
      /* FIXME: add a small delay */
      debug_v(("Connect: EXIT"));

      /* both signals are handled inside core_readwrite(), but while the
         SIGINT signal is fully handled, the SIGTERM requires some action
         from outside that function, because of this that flag is not
         cleared. */
      if (got_sigterm)
	break;
    }
  }			/* end of while (left_ports > 0) */

  /* all basic modes should return here for the final cleanup */
 main_exit:
  debug_v(("Main: EXIT (cleaning up)"));

  netcat_printstats(FALSE);
  return glob_ret;
}				/* end of main() */