netcat.c revision 63c99f9316851ebfab1e6d91ff1807739e55bd5b
/* $OpenBSD: netcat.c,v 1.89 2007/02/20 14:11:17 jmc Exp $ */
/*
* Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Re-written nc(1) for OpenBSD. Original implementation by
* *Hobbit* <hobbit@avian.org>.
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <netinet/in_systm.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <poll.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include "atomicio.h"
#include "strtonum.h"
#ifndef SUN_LEN
#endif
#define PORT_MIN 1
#define PORT_MAX 65535
#define PORT_MAX_LEN 6
/* Command Line Options */
int dflag; /* detached, no stdin */
unsigned int iflag; /* Interval Flag */
int kflag; /* More than one connect */
int lflag; /* Bind to local port */
int nflag; /* Don't do name lookup */
char *Pflag; /* Proxy username */
char *pflag; /* Localport flag */
int rflag; /* Random ports flag */
char *sflag; /* Source Address */
int tflag; /* Telnet Emulation */
int uflag; /* UDP - Default to TCP */
int vflag; /* Verbosity */
int xflag; /* Socks proxy */
int Xflag; /* indicator of Socks version set */
int zflag; /* Port Scan Flag */
int Dflag; /* sodebug */
int timeout = -1;
void atelnet(int, unsigned char *, unsigned int);
void build_ports(char *);
void help(void);
int local_listen(char *, char *, struct addrinfo);
void readwrite(int);
int remote_connect(const char *, const char *, struct addrinfo);
int socks_connect(const char *, const char *,
const char *, const char *, struct addrinfo, int, const char *);
int udptest(int);
int unix_connect(char *);
int unix_listen(char *);
void set_common_sockopts(int);
int parse_iptos(char *);
void usage(int);
int
{
struct sockaddr_storage cliaddr;
struct addrinfo proxyhints;
ret = 1;
s = 0;
socksv = 5;
"46Ddhi:klnP:p:rs:T:tUuvw:X:x:z")) != -1) {
switch (ch) {
case '4':
break;
case '6':
break;
case 'U':
break;
case 'X':
Xflag = 1;
else
break;
case 'd':
dflag = 1;
break;
case 'h':
help();
break;
case 'i':
if (errstr)
break;
case 'k':
kflag = 1;
break;
case 'l':
lflag = 1;
break;
case 'n':
nflag = 1;
break;
case 'P':
break;
case 'p':
break;
case 'r':
rflag = 1;
break;
case 's':
break;
case 't':
tflag = 1;
break;
case 'u':
uflag = 1;
break;
case 'v':
vflag = 1;
break;
case 'w':
if (errstr)
timeout *= 1000;
break;
case 'x':
xflag = 1;
break;
case 'z':
zflag = 1;
break;
case 'D':
Dflag = 1;
break;
case 'T':
break;
default:
usage(1);
}
}
/* Cruft to make sure options are clean, and used properly. */
if (uflag)
if (!lflag)
usage(1);
usage(1);
} else {
usage(1);
}
if (argc > 2)
usage(1);
warnx("-w has no effect with -l");
if (uport)
usage(1);
}
/* Initialize addrinfo structure. */
if (nflag)
}
if (xflag) {
if (uflag)
if (lflag)
if (sflag)
if (nflag)
}
if (lflag) {
int connfd;
ret = 0;
s = unix_listen(host);
/* Allow only one connection at a time, but stay alive. */
for (;;) {
if (s < 0)
/*
* For UDP, we will use recvfrom() initially
* to wait for a caller, then use the regular
* functions to talk to the caller.
*/
if (uflag) {
char buf[8192];
struct sockaddr_storage z;
len = sizeof (z);
plen = 1024;
if (rv < 0)
if (rv < 0)
connfd = s;
} else {
&len);
"Received connection from %s\n",
nflag ? NI_NUMERICHOST : 0));
}
}
(void) close(s);
if (!kflag)
break;
}
ret = 0;
readwrite(s);
(void) close(s);
} else
ret = 1;
} else { /* AF_INET or AF_INET6 */
int i = 0;
/* Construct the portlist[] array. */
/* Cycle through portlist, connecting to each port. */
if (s)
(void) close(s);
if (xflag)
Pflag);
else
if (s < 0)
continue;
ret = 0;
/* For UDP, make sure we are connected. */
if (uflag) {
if (udptest(s) == -1) {
ret = 1;
continue;
}
}
/* Don't look up port if -n. */
if (nflag)
else {
sv = getservbyport(
}
"port [%s/%s] succeeded!\n",
}
if (!zflag)
readwrite(s);
}
}
if (s)
(void) close(s);
return (ret);
}
/*
* print IP address and (optionally) a port
*/
char *
{
char port[NI_MAXSERV];
int e;
/* print port always as number */
return ((char *)gai_strerror(e));
}
return (ntop);
}
/*
* unix_connect()
* Returns a socket connected to a local unix socket. Returns -1 on failure.
*/
int
unix_connect(char *path)
{
struct sockaddr_un sunaddr;
int s;
return (-1);
(void) close(s);
return (-1);
}
(void) close(s);
return (-1);
}
return (s);
}
/*
* unix_listen()
* Create a unix domain socket, and listen on it.
*/
int
unix_listen(char *path)
{
struct sockaddr_un sunaddr;
int s;
/* Create unix domain socket. */
return (-1);
(void) close(s);
return (-1);
}
(void) close(s);
return (-1);
}
if (listen(s, 5) < 0) {
(void) close(s);
return (-1);
}
return (s);
}
/*
* remote_connect()
* Returns a socket connected to a remote host. Properly binds to a local
* port or source address if needed. Returns -1 on failure.
*/
int
{
int s, error;
do {
res0->ai_protocol)) < 0) {
warn("failed to create socket");
continue;
}
/* Bind to a local port or source address if specified. */
ares->ai_addrlen) < 0)
"Using source address: %s\n",
sflag);
"Using source port: %s\n", pflag);
}
}
break;
else if (vflag) {
warn("connect to %s [host %s] (%s) failed",
}
(void) close(s);
s = -1;
return (s);
}
/*
* local_listen()
* Returns a socket listening on a local port, binds to specified source
* address. Returns -1 on failure.
*/
int
{
int s, ret, x = 1;
int error;
/* Allow nodename to be null. */
do {
res0->ai_protocol)) < 0) {
warn("failed to create socket");
continue;
}
if (ret == -1)
res0->ai_addrlen) == 0)
break;
(void) close(s);
s = -1;
if (!uflag && s != -1) {
if (listen(s, 1) < 0)
}
return (s);
}
/*
* readwrite()
* Loop that polls on the network file descriptor and stdin.
*/
void
{
unsigned char buf[8192];
int plen;
plen = 1024;
/* Setup Network FD */
/* Set up STDIN FD. */
if (iflag)
}
if (n == 0)
return;
return;
else if (n == 0) {
} else {
if (tflag)
return;
}
}
/*
* handle the case of disconnected pipe: after pipe
* is closed (indicated by POLLHUP) there may still
* be some data lingering (POLLIN). After we read
* the data, only POLLHUP remains, read() returns 0
* and we are finished.
*/
return;
else if (n == 0) {
} else {
return;
}
}
}
}
void
{
unsigned char *p, *end;
unsigned char obuf[4];
obuf[0] = '\0';
if (*p != IAC)
break;
obuf[1] = 0;
p++;
/* refuse all options */
if (obuf[1]) {
p++;
obuf[2] = *p;
warn("Write Error!");
obuf[0] = '\0';
}
}
}
/*
* build_ports()
* Build an array of ports in portlist[], listing each port
* that we should try to connect to.
*/
void
build_ports(char *p)
{
const char *errstr;
char *n;
int x = 0;
if (lflag)
*n = '\0';
n++;
/* Make sure the ports are in order: lowest->highest. */
if (errstr)
if (errstr)
}
/* Load ports sequentially. */
x++;
}
/* Randomly swap ports. */
if (rflag) {
int y;
char *c;
c = portlist[x];
portlist[y] = c;
}
}
} else {
if (errstr)
portlist[0] = p;
}
}
/*
* udptest()
* Do a few writes to see if the UDP port is there.
* XXX - Better way of doing this? Doesn't work for IPv6.
* Also fails after around 100 ports checked.
*/
int
udptest(int s)
{
int i, ret;
for (i = 0; i <= 3; i++) {
ret = 1;
else
ret = -1;
}
return (ret);
}
void
set_common_sockopts(int s)
{
int x = 1;
if (Dflag) {
}
if (Tflag != -1) {
sizeof (Tflag)) == -1)
}
}
int
parse_iptos(char *s)
{
int tos = -1;
if (strcmp(s, "lowdelay") == 0)
return (IPTOS_LOWDELAY);
if (strcmp(s, "throughput") == 0)
return (IPTOS_THROUGHPUT);
if (strcmp(s, "reliability") == 0)
return (IPTOS_RELIABILITY);
return (tos);
}
void
help(void)
{
usage(0);
\t-4 Use IPv4\n\
\t-6 Use IPv6\n\
\t-D Enable the debug socket option\n\
\t-d Detach from stdin\n\
\t-h This help text\n\
\t-i secs\t Delay interval for lines sent, ports scanned\n\
\t-k Keep inbound sockets open for multiple connects\n\
\t-l Listen mode, for inbound connects\n\
\t-P proxyuser\tUsername for proxy authentication\n\
\t-p port\t Specify local port or listen port\n\
\t-r Randomize remote ports\n\
\t-s addr\t Local source address\n\
\t-T ToS\t Set IP Type of Service\n\
\t-t Answer TELNET negotiation\n\
\t-U Use UNIX domain socket\n\
\t-u UDP mode\n\
\t-v Verbose\n\
\t-w secs\t Timeout for connects and final net reads\n\
\t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
\t-x addr[:port]\tSpecify proxy address and port\n\
\t-z Zero-I/O mode [used for scanning]\n\
Port numbers can be individual or ranges: lo-hi [inclusive]\n");
exit(1);
}
void
{
"usage: nc [-46DdhklnrtUuvz] [-i interval] [-P proxy_username]"
" [-p port]\n");
"\t [-s source_ip_address] [-T ToS] [-w timeout]"
" [-X proxy_protocol]\n");
"\t [-x proxy_address[:port]] [hostname]"
" [port[s]]\n");
if (ret)
exit(1);
}