X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Fnc.c;h=3f4149e14289bfdb866408cf534b09b151f23bcc;hb=59fe8b90890a07c87ec9c2943bae515d5c6d959d;hp=63d8c5b19db9b70b8f16527ac4a3f6e8ed7b5104;hpb=f63a20ad7baf5471f2691e8347bf243eb5935d86;p=oweals%2Fbusybox.git diff --git a/networking/nc.c b/networking/nc.c index 63d8c5b19..3f4149e14 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -1,147 +1,143 @@ /* vi: set sw=4 ts=4: */ /* nc: mini-netcat - built from the ground up for LRP - Copyright (C) 1998 Charles P. Wright - - 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 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include + * + * 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. + */ + #include "busybox.h" -#define GAPING_SECURITY_HOLE +static void timeout(int signum) +{ + bb_error_msg_and_die("Timed out"); +} int nc_main(int argc, char **argv) { - int do_listen = 0, lport = 0, delay = 0, tmpfd, opt, sfd, x; - char buf[BUFSIZ]; -#ifdef 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; - - while ((opt = getopt(argc, argv, "lp:i:e:")) > 0) { - switch (opt) { - case 'l': - do_listen++; + char *infile = NULL; + + 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 'p': - lport = atoi(optarg); - break; - case 'i': - delay = atoi(optarg); - break; -#ifdef GAPING_SECURITY_HOLE - case 'e': - pr00gie = optarg; - break; -#endif - default: - show_usage(); + } else bb_show_usage(); } } -#ifdef GAPING_SECURITY_HOLE - if (pr00gie) { - /* won't need stdin */ - close (fileno(stdin)); + + // 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); } -#endif /* GAPING_SECURITY_HOLE */ + + if (infile) cfd = xopen(infile, O_RDWR); + else { + opt = 1; + sfd = 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 ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc)) - show_usage(); + if (lport != 0) { + address.sin_port = lport; - if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - perror_msg_and_die("socket"); - x = 1; - if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1) - perror_msg_and_die ("reuseaddr failed"); - address.sin_family = AF_INET; + xbind(sfd, (struct sockaddr *) &address, sizeof(address)); + } - if (lport != 0) { - memset(&address.sin_addr, 0, sizeof(address.sin_addr)); - address.sin_port = htons(lport); + if (do_listen) { + socklen_t addrlen = sizeof(address); - if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) - perror_msg_and_die("bind"); - } + xlisten(sfd, do_listen); - if (do_listen) { - socklen_t addrlen = sizeof(address); + // If we didn't specify a port number, query and print it to stderr. - if (listen(sfd, 1) < 0) - perror_msg_and_die("listen"); + 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 ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) - perror_msg_and_die("accept"); + if (!execflag) close(sfd); + } else { + hostinfo = xgethostbyname(argv[optind]); - close(sfd); - sfd = tmpfd; - } 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); - address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; - address.sin_port = htons(atoi(argv[optind+1])); + if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) + bb_perror_msg_and_die("connect"); + cfd = sfd; + } + } - if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) - perror_msg_and_die("connect"); + if (wsecs) { + alarm(0); + signal(SIGALRM, SIG_DFL); } -#ifdef GAPING_SECURITY_HOLE /* -e given? */ - if (pr00gie) { - dup2(sfd, 0); - close(sfd); - dup2 (0, 1); - dup2 (0, 2); - execl (pr00gie, pr00gie, NULL); + if (execflag) { + if(cfd) { + signal(SIGCHLD, SIG_IGN); + dup2(cfd, 0); + close(cfd); + } + dup2(0, 1); + dup2(0, 2); + + // 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 /* 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; @@ -149,28 +145,28 @@ int nc_main(int argc, char **argv) testfds = readfds; if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0) - perror_msg_and_die("select"); + bb_perror_msg_and_die("select"); for (fd = 0; fd < FD_SETSIZE; fd++) { if (FD_ISSET(fd, &testfds)) { - if ((nread = safe_read(fd, buf, sizeof(buf))) < 0) - perror_msg_and_die("read"); + nread = safe_read(fd, bb_common_bufsiz1, + sizeof(bb_common_bufsiz1)); - if (fd == sfd) { - if (nread == 0) - exit(0); + if (fd == cfd) { + if (nread<1) exit(0); ofd = STDOUT_FILENO; } else { - if (nread == 0) - shutdown(sfd, 1); - ofd = sfd; + if (nread<1) { + // 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 = cfd; } - if (full_write(ofd, buf, nread) < 0) - perror_msg_and_die("write"); - if (delay > 0) { - sleep(delay); - } + xwrite(ofd, bb_common_bufsiz1, nread); + if (delay > 0) sleep(delay); } } }