Exemple #1
0
static int core_tcp_listen(nc_sock_t *ncsock)
{
  int sock_listen, sock_accept, timeout = ncsock->timeout;
  debug_v(("core_tcp_listen(ncsock=%p)", (void *)ncsock));

  sock_listen = netcat_socket_new_listen(PF_INET, &ncsock->local_host.iaddrs[0],
			ncsock->local_port.netnum);
  if (sock_listen < 0)
    ncprint(NCPRINT_ERROR | NCPRINT_EXIT,
	    _("Couldn't setup listening socket (err=%d)"), sock_listen);

  /* if the port was set to 0 this means that it is assigned randomly by the
     OS.  Find out which port they assigned to us. */
  if (ncsock->local_port.num == 0) {
    int ret;
    struct sockaddr_in myaddr;
    unsigned int myaddr_len = sizeof(myaddr);

    ret = getsockname(sock_listen, (struct sockaddr *)&myaddr, &myaddr_len);
    if (ret < 0) {
      close(sock_listen);
      return -1;
    }
    netcat_getport(&ncsock->local_port, NULL, ntohs(myaddr.sin_port));
  }

  ncprint(NCPRINT_VERB2, _("Listening on %s"),
	netcat_strid(&ncsock->local_host, &ncsock->local_port));
  while (TRUE) {
    struct sockaddr_in my_addr;
    unsigned int my_len = sizeof(my_addr);	/* this *IS* socklen_t */

    sock_accept = netcat_socket_accept(sock_listen, timeout);
    /* reset the timeout to the "use remaining time" value (see network.c file)
       if it exited with timeout we also return this function, so losing the
       original value is not a bad thing. */
    timeout = -1;

    /* failures in netcat_socket_accept() cause this function to return */
    if (sock_accept < 0)
      return -1;

    /* FIXME: i want a library function like netcat_peername() that fetches it
       and resolves with netcat_resolvehost(). */
    getpeername(sock_accept, (struct sockaddr *)&my_addr, &my_len);

    /* if a remote address (and optionally some ports) have been specified we
       assume it as the only ip and port that it is allowed to connect to
       this socket */

    if ((ncsock->host.iaddrs[0].s_addr && memcmp(&ncsock->host.iaddrs[0],
	 &my_addr.sin_addr, sizeof(ncsock->host.iaddrs[0]))) ||
	(netcat_flag_count() && !netcat_flag_get(ntohs(my_addr.sin_port)))) {
      ncprint(NCPRINT_VERB2, _("Unwanted connection from %s:%hu (refused)"),
	      netcat_inet_ntop(&my_addr.sin_addr), ntohs(my_addr.sin_port));
      goto refuse;
    }
    ncprint(NCPRINT_VERB1, _("Connection from %s:%hu"),
	    netcat_inet_ntop(&my_addr.sin_addr), ntohs(my_addr.sin_port));

    /* with zero I/O mode we don't really accept any connection */
    if (opt_zero)
      goto refuse;

    /* we have got our socket, now exit the loop */
    break;

 refuse:
    shutdown(sock_accept, 2);
    close(sock_accept);
    continue;
  }			/* end of infinite accepting loop */

  /* we don't need a listening socket anymore */
  close(sock_listen);
  return sock_accept;
}				/* end of core_tcp_listen() */
Exemple #2
0
static int core_udp_listen(nc_sock_t *ncsock)
{
  int ret, *sockbuf, sock, sock_max, timeout = ncsock->timeout;
  bool need_udphelper = TRUE;
#ifdef USE_PKTINFO
  int sockopt = 1;
#endif
  struct sockaddr_in myaddr;
  struct timeval tt;		/* needed by the select() call */
  debug_v(("core_udp_listen(ncsock=%p)", (void *)ncsock));

#ifdef USE_PKTINFO
  need_udphelper = FALSE;
#else
  /* if we need a specified source address then go straight to it */
  if (ncsock->local_host.iaddrs[0].s_addr)
    need_udphelper = FALSE;
#endif

  if (!need_udphelper) {
    /* simulates a udphelper_sockets_open() call */
    sockbuf = calloc(2, sizeof(int));
    sockbuf[0] = 1;
    sockbuf[1] = sock = netcat_socket_new(PF_INET, SOCK_DGRAM);
  }
#ifndef USE_PKTINFO
  else
    sock = udphelper_sockets_open(&sockbuf, ncsock->local_port.netnum);
#endif
  if (sock < 0)
    goto err;

  /* we know that udphelper_sockets_open() returns the highest socket, and
     if we didn't call it we have just one socket */
  sock_max = sock + 1;

  if (!need_udphelper) {
    /* prepare myaddr for the bind() call */
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = ncsock->local_port.netnum;
    memcpy(&myaddr.sin_addr, &ncsock->local_host.iaddrs[0],
	   sizeof(myaddr.sin_addr));
    /* bind() MUST be called in this function, since it's the final call for
       this type of socket. FIXME: I heard that UDP port 0 is illegal. true? */
    ret = bind(sock, (struct sockaddr *)&myaddr, sizeof(myaddr));
    if (ret < 0)
      goto err;
  }

#ifdef USE_PKTINFO
  /* set the right flag in order to obtain the ancillary data */
  ret = setsockopt(sock, SOL_IP, IP_PKTINFO, &sockopt, sizeof(sockopt));
  if (ret < 0)
    goto err;
#endif

  /* if the port was set to 0 this means that it is assigned randomly by the
     OS.  Find out which port they assigned to us. */
  if (ncsock->local_port.num == 0) {
    struct sockaddr_in get_myaddr;
    unsigned int get_myaddr_len = sizeof(get_myaddr);

    ret = getsockname(sock, (struct sockaddr *)&get_myaddr, &get_myaddr_len);
    if (ret < 0)
      goto err;
    netcat_getport(&ncsock->local_port, NULL, ntohs(get_myaddr.sin_port));
    assert(ncsock->local_port.num != 0);
  }

  if (!need_udphelper)
    ncprint(NCPRINT_VERB2, _("Listening on %s"),
	    netcat_strid(&ncsock->local_host, &ncsock->local_port));
  else
    ncprint(NCPRINT_VERB2, _("Listening on %s (using %d sockets)"),
	    netcat_strid(&ncsock->local_host, &ncsock->local_port), sockbuf[0]);

  /* since this protocol is connectionless, we need a special handling here.
     We want to simulate a two-ends connection but in order to do this we need
     a remote address and a local address (in case we bound to INADDR_ANY).
     Wait here until a packet is received, and use its source and destination
     addresses as default endpoints.  If we have the zero-I/O option set, we
     just eat the packet and return when timeout is elapsed (maybe never). */
  tt.tv_sec = timeout;
  tt.tv_usec = 0;

  while (TRUE) {
    int socks_loop;
    fd_set ins;

    FD_ZERO(&ins);
    for (socks_loop = 1; socks_loop <= sockbuf[0]; socks_loop++) {
      debug_v(("Setting sock %d on ins", sockbuf[socks_loop]));
      FD_SET(sockbuf[socks_loop], &ins);
    }

    /* automatically use remaining timeout time if in zero-I/O mode */
    ret = select(sock_max, &ins, NULL, NULL, (timeout > 0 ? &tt : NULL));
    if (ret == 0)
      break;

    /* loop all the open sockets to find the active one */
    for (socks_loop = 1; socks_loop <= sockbuf[0]; socks_loop++) {
      int recv_ret, write_ret;
      struct msghdr my_hdr;
      #ifdef  __MVS__             /* zosunix01 26.07.2011 */
      unsigned char buf[32768];
      #else
      unsigned char buf[1024]; 
      #endif 
      struct iovec my_hdr_vec;
      struct sockaddr_in rem_addr;
      struct sockaddr_in local_addr;
#ifdef USE_PKTINFO
      unsigned char anc_buf[512];
#endif

      sock = sockbuf[socks_loop];

      if (!FD_ISSET(sock, &ins))
	continue;

      /* I've looked for this code for a lot of hours, and finally found the
         RFC 2292 which provides a socket API for fetching the destination
         interface of the incoming packet. */
      memset(&my_hdr, 0, sizeof(my_hdr));
      memset(&rem_addr, 0, sizeof(rem_addr));
      memset(&local_addr, 0, sizeof(local_addr));
      my_hdr.msg_name = (void *)&rem_addr;
      my_hdr.msg_namelen = sizeof(rem_addr);
      /* initialize the vector struct and then the vectory member of the header */
      my_hdr_vec.iov_base = buf;
      my_hdr_vec.iov_len = sizeof(buf);
      my_hdr.msg_iov = &my_hdr_vec;
      my_hdr.msg_iovlen = 1;
#ifdef USE_PKTINFO
      /* now the core part for the IP_PKTINFO support: the ancillary data */
      my_hdr.msg_control = anc_buf;
      my_hdr.msg_controllen = sizeof(anc_buf);
#endif

      /* now check the remote address.  If we are simulating a routing then
         use the MSG_PEEK flag, which leaves the received packet untouched */
      recv_ret = recvmsg(sock, &my_hdr, (opt_zero ? 0 : MSG_PEEK));

      debug_v(("received packet from %s:%d%s", netcat_inet_ntop(&rem_addr.sin_addr),
		ntohs(rem_addr.sin_port), (opt_zero ? "" : ", using as default dest")));

#ifdef USE_PKTINFO
      ret = udphelper_ancillary_read(&my_hdr, &local_addr);
      local_addr.sin_port = myaddr.sin_port;
      local_addr.sin_family = myaddr.sin_family;
#else
      ret = sizeof(local_addr);
      ret = getsockname(sock, (struct sockaddr *)&local_addr, &ret);
#endif

      if (ret == 0) {
	char tmpbuf[127];

	strncpy(tmpbuf, netcat_inet_ntop(&rem_addr.sin_addr), sizeof(tmpbuf));
	ncprint(NCPRINT_VERB1, _("Received packet from %s:%d -> %s:%d (local)"),
		tmpbuf, ntohs(rem_addr.sin_port),
		netcat_inet_ntop(&local_addr.sin_addr),
		ntohs(local_addr.sin_port));
      }
      else
	ncprint(NCPRINT_VERB1, _("Received packet from %s:%d"),
		netcat_inet_ntop(&rem_addr.sin_addr), ntohs(rem_addr.sin_port));

      if (opt_zero) {		/* output the packet right here right now */
	write_ret = write(STDOUT_FILENO, buf, recv_ret);
	bytes_recv += write_ret;
	debug_dv(("write_u(stdout) = %d", write_ret));

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

	/* FIXME: unhandled exception */
	assert(write_ret == recv_ret);

	/* if the hexdump option is set, hexdump the received data */
	if (opt_hexdump) {
#ifndef USE_OLD_HEXDUMP
	  fprintf(output_fp, "Received %d bytes from %s:%d\n", recv_ret,
		netcat_inet_ntop(&rem_addr.sin_addr), ntohs(rem_addr.sin_port));
#endif
	  netcat_fhexdump(output_fp, '<', buf, write_ret);
	}
      }
      else {
#ifdef USE_PKTINFO
	nc_sock_t dup_socket;

	memset(&dup_socket, 0, sizeof(dup_socket));
	dup_socket.domain = ncsock->domain;
	dup_socket.proto = ncsock->proto;
	memcpy(&dup_socket.local_host.iaddrs[0], &local_addr.sin_addr,
	       sizeof(local_addr));
	memcpy(&dup_socket.host.iaddrs[0], &rem_addr.sin_addr,
	       sizeof(local_addr));
	dup_socket.local_port.netnum = local_addr.sin_port;
	dup_socket.local_port.num = ntohs(local_addr.sin_port);
	dup_socket.port.netnum = rem_addr.sin_port;
	dup_socket.port.num = ntohs(rem_addr.sin_port);
	/* copy the received data in the socket's queue */
	ncsock->recvq.len = recv_ret;
	ncsock->recvq.head = ncsock->recvq.pos = malloc(recv_ret);
	memcpy(ncsock->recvq.head, my_hdr_vec.iov_base, recv_ret);
	/* FIXME: this ONLY saves the first 1024 bytes! and the others? */
#else
	ret = connect(sock, (struct sockaddr *)&rem_addr, sizeof(rem_addr));
	if (ret < 0)
	  goto err;

	/* remove this socket from the array in order not to get it closed */
	sockbuf[socks_loop] = -1;
#endif
	udphelper_sockets_close(sockbuf);

#ifdef USE_PKTINFO
	/* this is all we want from this function */
	debug_dv(("calling the udp_connect() function..."));
	return core_udp_connect(&dup_socket);
#else
	return sock;
#endif
      }
    }				/* end of foreach (sock, sockbuf) */
  }				/* end of packet receiving loop */

  /* no packets until timeout, set errno and proceed to general error handling */
  errno = ETIMEDOUT;

 err:
  udphelper_sockets_close(sockbuf);
  return -1;
}				/* end of core_udp_listen() */
Exemple #3
0
static int core_tcp_connect(nc_sock_t *ncsock)
{
  int ret, sock, timeout = ncsock->timeout;
  struct timeval timest;
  fd_set outs;
  debug_v(("core_tcp_connect(ncsock=%p)", (void *)ncsock));

  /* since we are nonblocking now, we could start as many connections as we
     want but it's not a great idea connecting more than one host at time.
     Also don't specify the local address if it's not really needed, so we can
     avoid one bind(2) call. */
  sock = netcat_socket_new_connect(PF_INET, SOCK_STREAM,
	&ncsock->host.iaddrs[0], ncsock->port.netnum,
	(ncsock->local_host.iaddrs[0].s_addr ? &ncsock->local_host.iaddrs[0] :
	NULL), ncsock->local_port.netnum);

  #ifdef __MVS__   /* 01.08.2011 zosunix01                                */
                   /* The new retcode shows, that the destination host has*/
                   /* rejected the connect. The function doesn't finish   */
                   /* the main program, but ends with the retcode -1 to   */ 
                   /* indicate a failure.                                 */
  if (sock == -6) {
   return -1;
  }
  #endif

  if (sock < 0)
    ncprint(NCPRINT_ERROR | NCPRINT_EXIT, "Couldn't create connection (err=%d): %s",
	    sock, strerror(errno)); 

  /* initialize select()'s variables */
  FD_ZERO(&outs);
  FD_SET(sock, &outs);
  timest.tv_sec = timeout;
  timest.tv_usec = 0;

  ret = select(sock + 1, NULL, &outs, NULL, (timeout > 0 ? &timest : NULL));
  if (ret > 0) {
    int ret, get_ret;
    unsigned int get_len = sizeof(get_ret);	/* socklen_t */

    /* ok, select([single]), so sock must have triggered this */
    assert(FD_ISSET(sock, &outs));

    /* fetch the errors of the socket and handle system request errors */
    ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, &get_ret, &get_len);
    if (ret < 0)
      ncprint(NCPRINT_ERROR | NCPRINT_EXIT, "Critical system request failed: %s",
	      strerror(errno));

    /* POSIX says that SO_ERROR expects an int, so my_len must be untouched */
    assert(get_len == sizeof(get_ret));

    /* FIXME: the error Broken Pipe should probably not stop here */
    debug_v(("Connection returned errcode=%d (%s)", get_ret, strerror(get_ret)));
    if (get_ret > 0) {
      char tmp;

      /* Ok, select() returned a write event for this socket AND getsockopt()
         said that some error happened.  This mean that EOF is expected. */
      ret = read(sock, &tmp, 1);
      #ifdef __MVS__  /* zosunix01 27.07.2011                          */
                      /* In z/OS Unix the socket is closed in the case */
                      /* of a connection error                         */
      if(!((ret == -1) && ((errno == EAGAIN) || (errno == ENOTCONN)))) {
       assert(ret == 0);
      }
      #else
      assert(ret == 0); /* for systems other than z/OS Unix */
      #endif
      /* FIXME: see the TODO entry about false error detection */

      shutdown(sock, 2);
      close(sock);
      ncsock->fd = -1;
      errno = get_ret;		/* value returned by getsockopt(SO_ERROR) */
      return -1;
    }

    /* everything went fine, we have the socket */
    ncprint(NCPRINT_VERB1, _("%s open"), netcat_strid(&ncsock->host,
						      &ncsock->port));
    return sock;
  }
  else if (ret) {
    /* Terminated by a signal. Silently exit */
    if (errno == EINTR)
      exit(EXIT_FAILURE);
    /* The error seems to be a little worse */
    ncprint(NCPRINT_ERROR | NCPRINT_EXIT, "Critical system request failed: %s",
	    strerror(errno));
  }

  /* select returned 0, this means connection timed out for our timing
     directives (in fact the socket has a longer timeout usually, so we need
     to abort the connection try, set the proper errno and return */
  shutdown(sock, 2);
  close(sock);
  errno = ETIMEDOUT;
  return -1;
}				/* end of core_tcp_connect() */
Exemple #4
0
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() */