Upgrade netcat a lot. Make -e able to take the rest of the command line as

what to exec.  Add -f mode and a brief explanation of how to use it to replace
minicom.  Add -l -l mode so you can turn any command into a server.  And group
all of netcat's command line options under two CONFIG entries, so if you
disable both it doesn't use getopt at all.
This commit is contained in:
Rob Landley 2006-07-10 19:45:20 +00:00
parent 5d8843e451
commit 1cca9484db
4 changed files with 146 additions and 117 deletions

View File

@ -19,6 +19,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

View File

@ -2105,23 +2105,41 @@ USE_FEATURE_MDEV_CONFIG( \
" or\n" \
"$ nameif -c /etc/my_mactab_file\n" \
#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
# define USAGE_NC_EXEC(a) a
#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA
#define NC_BR1 "["
#define NC_BR2 "]"
#else
# define USAGE_NC_EXEC(a)
#define NC_BR1
#define NC_BR2
#endif
#define nc_trivial_usage \
"[OPTIONS] [IP] [port]"
"[" \
NC_BR1 USE_NC_SERVER("-lp")USE_NC_EXTRA("iwf") NC_BR2 \
" ["USE_NC_EXTRA("FILENAME|")"{IPADDR PORTNUM}]"USE_NC_EXTRA(" [-e COMMAND]")
#define nc_full_usage \
"Netcat opens a pipe to IP:port\n\n" \
"Options:\n" \
"\t-l\t\tlisten mode, for inbound connects\n" \
"\t-p PORT\t\tlocal port number\n" \
"\t-i SECS\t\tdelay interval for lines sent\n" \
USAGE_NC_EXEC( \
"\t-e PROG\t\tprogram to exec after connect (dangerous!)\n" \
"Netcat opens a pipe, either to IP:port\n\n" \
"Options:" \
USE_NC_EXTRA( \
"\n\t-e\t\texec rest of command line after connect\n" \
"\t-i SECS\t\tdelay interval for lines sent\n" \
"\t-w SECS\t\ttimeout for connect\n" \
"\t-f filename\tuse file (ala /dev/ttyS0) instead of network" \
) \
"\t-w SECS\t\ttimeout for connects and final net reads"
USE_NC_SERVER( \
"\n\t-l\t\tlisten mode, for inbound connects\n" \
USE_NC_EXTRA("\t\t\t(use -l twice with -e for persistent server)\n") \
"\t-p PORT\t\tlocal port number" \
)
#define nc_notes_usage "" \
USE_NC_EXTRA( \
"To use netcat as a terminal emulator on a serial port:\n\n" \
"$ stty 115200 -F /dev/ttyS0\n" \
"$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n" \
) ""
#define nc_example_usage \
"$ nc foobar.somedomain.com 25\n" \
"220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \

View File

@ -446,13 +446,21 @@ config CONFIG_NC
A simple Unix utility which reads and writes data across network
connections.
config CONFIG_NC_GAPING_SECURITY_HOLE
bool "gaping security hole"
config CONFIG_NC_SERVER
bool "Netcat server options (-lp)"
default n
depends on CONFIG_NC
help
Add support for executing a program after making or receiving a
successful connection (-e option).
Allow netcat to act as a server.
config CONFIG_NC_EXTRA
bool "Netcat extensions (-eiw and filename)"
default n
depends on CONFIG_NC
help
Add -e (support for executing the rest of the command line after
making or receiving a successful connection), -i (delay interval for
lines sent), -w (timeout for initial connection).
config CONFIG_NETSTAT
bool "netstat"

View File

@ -1,32 +1,16 @@
/* vi: set sw=4 ts=4: */
/* nc: mini-netcat - built from the ground up for LRP
Copyright (C) 1998 Charles P. Wright
*
* Copyright (C) 1998, 1999 Charles P. Wright
* Copyright (C) 1998 Dave Cinege
*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
0.0.1 6K It works.
0.0.2 5K Smaller and you can also check the exit condition if you wish.
0.0.3 Uses select()
19980918 Busy Boxed! Dave Cinege
19990512 Uses Select. Charles P. Wright
19990513 Fixes stdin stupidity and uses buffers. Charles P. Wright
Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include "busybox.h"
#define xread bb_xread
static void timeout(int signum)
{
bb_error_msg_and_die("Timed out");
@ -34,79 +18,87 @@ static void timeout(int signum)
int nc_main(int argc, char **argv)
{
int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x;
#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
char *pr00gie = NULL;
#endif
int do_listen = 0, lport = 0, delay = 0, wsecs = 0, execflag = 0, opt,
sfd = 0, cfd;
struct sockaddr_in address;
struct hostent *hostinfo;
fd_set readfds, testfds;
char *infile = NULL;
while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) {
switch (opt) {
case 'l':
do_listen++;
break;
case 'p':
memset(&address, 0, sizeof(address));
if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
while ((opt = getopt(argc, argv, "lp:" USE_NC_EXTRA("i:ew:f:"))) > 0) {
if (ENABLE_NC_SERVER && opt=='l') do_listen++;
else if (ENABLE_NC_SERVER && opt=='p')
lport = bb_lookup_port(optarg, "tcp", 0);
else if (ENABLE_NC_EXTRA && opt=='w') wsecs = atoi(optarg);
else if (ENABLE_NC_EXTRA && opt=='i') delay = atoi(optarg);
else if (ENABLE_NC_EXTRA && opt=='f') infile = optarg;
else if (ENABLE_NC_EXTRA && opt=='e' && optind!=argc) {
execflag++;
break;
case 'i':
delay = atoi(optarg);
break;
#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
case 'e':
pr00gie = optarg;
break;
#endif
case 'w':
wsecs = atoi(optarg);
break;
default:
bb_show_usage();
} else bb_show_usage();
}
}
if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
bb_show_usage();
sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
x = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
bb_perror_msg_and_die("reuseaddr");
address.sin_family = AF_INET;
// For listen or file we need zero arguments, dialout is 2.
// For exec we need at least one more argument at the end, more ok
opt = (do_listen || infile) ? 0 : 2 + execflag;
if (execflag ? argc-optind < opt : argc-optind!=opt ||
(infile && do_listen))
bb_show_usage();
if (wsecs) {
signal(SIGALRM, timeout);
alarm(wsecs);
}
if (lport != 0) {
memset(&address.sin_addr, 0, sizeof(address.sin_addr));
address.sin_port = lport;
if (infile) cfd = bb_xopen(infile, O_RDWR);
else {
opt = 1;
sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
fcntl(sfd, F_SETFD, FD_CLOEXEC);
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
address.sin_family = AF_INET;
bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address));
}
// Set local port.
if (do_listen) {
socklen_t addrlen = sizeof(address);
if (lport != 0) {
address.sin_port = lport;
bb_xlisten(sfd, 1);
if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
bb_perror_msg_and_die("accept");
bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address));
}
close(sfd);
sfd = tmpfd;
} else {
hostinfo = xgethostbyname(argv[optind]);
if (do_listen) {
socklen_t addrlen = sizeof(address);
address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
bb_xlisten(sfd, do_listen);
if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
bb_perror_msg_and_die("connect");
// If we didn't specify a port number, query and print it to stderr.
if (!lport) {
socklen_t len = sizeof(address);
getsockname(sfd, &address, &len);
fdprintf(2, "%d\n", SWAP_BE16(address.sin_port));
}
repeatyness:
if ((cfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
bb_perror_msg_and_die("accept");
if (!execflag) close(sfd);
} else {
hostinfo = xgethostbyname(argv[optind]);
address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
bb_perror_msg_and_die("connect");
cfd = sfd;
}
}
if (wsecs) {
@ -114,24 +106,40 @@ int nc_main(int argc, char **argv)
signal(SIGALRM, SIG_DFL);
}
#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
/* -e given? */
if (pr00gie) {
dup2(sfd, 0);
close(sfd);
if (execflag) {
if(cfd) {
signal(SIGCHLD, SIG_IGN);
dup2(cfd, 0);
close(cfd);
}
dup2(0, 1);
dup2(0, 2);
execl(pr00gie, pr00gie, NULL);
// With more than one -l, repeatedly act as server.
if (do_listen>1 && vfork()) {
// This is a bit weird as cleanup goes, since we wind up with no
// stdin/stdout/stderr. But it's small and shouldn't hurt anything.
// We check for cfd == 0 above.
close(0);
close(1);
close(2);
goto repeatyness;
}
execvp(argv[optind], argv+optind);
/* Don't print stuff or it will go over the wire.... */
_exit(-1);
_exit(127);
}
#endif /* CONFIG_NC_GAPING_SECURITY_HOLE */
// Select loop copying stdin to cfd, and cfd to stdout.
FD_ZERO(&readfds);
FD_SET(sfd, &readfds);
FD_SET(cfd, &readfds);
FD_SET(STDIN_FILENO, &readfds);
while (1) {
for (;;) {
int fd;
int ofd;
int nread;
@ -143,30 +151,24 @@ int nc_main(int argc, char **argv)
for (fd = 0; fd < FD_SETSIZE; fd++) {
if (FD_ISSET(fd, &testfds)) {
if ((nread = safe_read(fd, bb_common_bufsiz1,
sizeof(bb_common_bufsiz1))) < 0)
{
bb_perror_msg_and_die(bb_msg_read_error);
}
nread = xread(fd, bb_common_bufsiz1, sizeof(bb_common_bufsiz1));
if (fd == sfd) {
if (nread == 0)
exit(0);
if (fd == cfd) {
if (!nread) exit(0);
ofd = STDOUT_FILENO;
} else {
if (nread <= 0) {
shutdown(sfd, 1 /* send */ );
close(STDIN_FILENO);
if (!nread) {
// Close outgoing half-connection so they get EOF, but
// leave incoming alone so we can see response.
shutdown(cfd, 1);
FD_CLR(STDIN_FILENO, &readfds);
}
ofd = sfd;
ofd = cfd;
}
if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0)
bb_perror_msg_and_die(bb_msg_write_error);
if (delay > 0) {
sleep(delay);
}
if (delay > 0) sleep(delay);
}
}
}