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 <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <netdb.h> #include <netdb.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>

View File

@ -2105,23 +2105,41 @@ USE_FEATURE_MDEV_CONFIG( \
" or\n" \ " or\n" \
"$ nameif -c /etc/my_mactab_file\n" \ "$ nameif -c /etc/my_mactab_file\n" \
#ifdef CONFIG_NC_GAPING_SECURITY_HOLE #if ENABLE_NC_SERVER || ENABLE_NC_EXTRA
# define USAGE_NC_EXEC(a) a #define NC_BR1 "["
#define NC_BR2 "]"
#else #else
# define USAGE_NC_EXEC(a) #define NC_BR1
#define NC_BR2
#endif #endif
#define nc_trivial_usage \ #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 \ #define nc_full_usage \
"Netcat opens a pipe to IP:port\n\n" \ "Netcat opens a pipe, either to IP:port\n\n" \
"Options:\n" \ "Options:" \
"\t-l\t\tlisten mode, for inbound connects\n" \ USE_NC_EXTRA( \
"\t-p PORT\t\tlocal port number\n" \ "\n\t-e\t\texec rest of command line after connect\n" \
"\t-i SECS\t\tdelay interval for lines sent\n" \ "\t-i SECS\t\tdelay interval for lines sent\n" \
USAGE_NC_EXEC( \ "\t-w SECS\t\ttimeout for connect\n" \
"\t-e PROG\t\tprogram to exec after connect (dangerous!)\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 \ #define nc_example_usage \
"$ nc foobar.somedomain.com 25\n" \ "$ nc foobar.somedomain.com 25\n" \
"220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\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 A simple Unix utility which reads and writes data across network
connections. connections.
config CONFIG_NC_GAPING_SECURITY_HOLE config CONFIG_NC_SERVER
bool "gaping security hole" bool "Netcat server options (-lp)"
default n default n
depends on CONFIG_NC depends on CONFIG_NC
help help
Add support for executing a program after making or receiving a Allow netcat to act as a server.
successful connection (-e option).
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 config CONFIG_NETSTAT
bool "netstat" bool "netstat"

View File

@ -1,32 +1,16 @@
/* vi: set sw=4 ts=4: */ /* vi: set sw=4 ts=4: */
/* nc: mini-netcat - built from the ground up for LRP /* 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" #include "busybox.h"
#define xread bb_xread
static void timeout(int signum) static void timeout(int signum)
{ {
bb_error_msg_and_die("Timed out"); bb_error_msg_and_die("Timed out");
@ -34,57 +18,55 @@ static void timeout(int signum)
int nc_main(int argc, char **argv) int nc_main(int argc, char **argv)
{ {
int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x; int do_listen = 0, lport = 0, delay = 0, wsecs = 0, execflag = 0, opt,
sfd = 0, cfd;
#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
char *pr00gie = NULL;
#endif
struct sockaddr_in address; struct sockaddr_in address;
struct hostent *hostinfo; struct hostent *hostinfo;
fd_set readfds, testfds; fd_set readfds, testfds;
char *infile = NULL;
while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) { memset(&address, 0, sizeof(address));
switch (opt) {
case 'l': if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
do_listen++; while ((opt = getopt(argc, argv, "lp:" USE_NC_EXTRA("i:ew:f:"))) > 0) {
break; if (ENABLE_NC_SERVER && opt=='l') do_listen++;
case 'p': else if (ENABLE_NC_SERVER && opt=='p')
lport = bb_lookup_port(optarg, "tcp", 0); 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; break;
case 'i': } else bb_show_usage();
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();
} }
} }
if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
bb_show_usage();
sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0); // For listen or file we need zero arguments, dialout is 2.
x = 1; // For exec we need at least one more argument at the end, more ok
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
bb_perror_msg_and_die("reuseaddr"); opt = (do_listen || infile) ? 0 : 2 + execflag;
address.sin_family = AF_INET; if (execflag ? argc-optind < opt : argc-optind!=opt ||
(infile && do_listen))
bb_show_usage();
if (wsecs) { if (wsecs) {
signal(SIGALRM, timeout); signal(SIGALRM, timeout);
alarm(wsecs); alarm(wsecs);
} }
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;
// Set local port.
if (lport != 0) { if (lport != 0) {
memset(&address.sin_addr, 0, sizeof(address.sin_addr));
address.sin_port = lport; address.sin_port = lport;
bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address)); bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address));
@ -93,12 +75,20 @@ int nc_main(int argc, char **argv)
if (do_listen) { if (do_listen) {
socklen_t addrlen = sizeof(address); socklen_t addrlen = sizeof(address);
bb_xlisten(sfd, 1); bb_xlisten(sfd, do_listen);
if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
// 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"); bb_perror_msg_and_die("accept");
close(sfd); if (!execflag) close(sfd);
sfd = tmpfd;
} else { } else {
hostinfo = xgethostbyname(argv[optind]); hostinfo = xgethostbyname(argv[optind]);
@ -107,6 +97,8 @@ int nc_main(int argc, char **argv)
if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
bb_perror_msg_and_die("connect"); bb_perror_msg_and_die("connect");
cfd = sfd;
}
} }
if (wsecs) { if (wsecs) {
@ -114,24 +106,40 @@ int nc_main(int argc, char **argv)
signal(SIGALRM, SIG_DFL); signal(SIGALRM, SIG_DFL);
} }
#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
/* -e given? */ /* -e given? */
if (pr00gie) { if (execflag) {
dup2(sfd, 0); if(cfd) {
close(sfd); signal(SIGCHLD, SIG_IGN);
dup2(cfd, 0);
close(cfd);
}
dup2(0, 1); dup2(0, 1);
dup2(0, 2); dup2(0, 2);
execl(pr00gie, pr00gie, NULL);
/* Don't print stuff or it will go over the wire.... */ // With more than one -l, repeatedly act as server.
_exit(-1);
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;
} }
#endif /* CONFIG_NC_GAPING_SECURITY_HOLE */ execvp(argv[optind], argv+optind);
/* Don't print stuff or it will go over the wire.... */
_exit(127);
}
// Select loop copying stdin to cfd, and cfd to stdout.
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_SET(sfd, &readfds); FD_SET(cfd, &readfds);
FD_SET(STDIN_FILENO, &readfds); FD_SET(STDIN_FILENO, &readfds);
while (1) { for (;;) {
int fd; int fd;
int ofd; int ofd;
int nread; int nread;
@ -143,30 +151,24 @@ int nc_main(int argc, char **argv)
for (fd = 0; fd < FD_SETSIZE; fd++) { for (fd = 0; fd < FD_SETSIZE; fd++) {
if (FD_ISSET(fd, &testfds)) { if (FD_ISSET(fd, &testfds)) {
if ((nread = safe_read(fd, bb_common_bufsiz1, nread = xread(fd, bb_common_bufsiz1, sizeof(bb_common_bufsiz1));
sizeof(bb_common_bufsiz1))) < 0)
{
bb_perror_msg_and_die(bb_msg_read_error);
}
if (fd == sfd) { if (fd == cfd) {
if (nread == 0) if (!nread) exit(0);
exit(0);
ofd = STDOUT_FILENO; ofd = STDOUT_FILENO;
} else { } else {
if (nread <= 0) { if (!nread) {
shutdown(sfd, 1 /* send */ ); // Close outgoing half-connection so they get EOF, but
close(STDIN_FILENO); // leave incoming alone so we can see response.
shutdown(cfd, 1);
FD_CLR(STDIN_FILENO, &readfds); FD_CLR(STDIN_FILENO, &readfds);
} }
ofd = sfd; ofd = cfd;
} }
if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0) if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0)
bb_perror_msg_and_die(bb_msg_write_error); bb_perror_msg_and_die(bb_msg_write_error);
if (delay > 0) { if (delay > 0) sleep(delay);
sleep(delay);
}
} }
} }
} }