Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/networking/nc.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/networking/nc.c
r821 r1770 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* nc: mini-netcat - built from the ground up for LRP 3 Copyright (C) 1998 Charles P. Wright 4 5 0.0.1 6K It works. 6 0.0.2 5K Smaller and you can also check the exit condition if you wish. 7 0.0.3 Uses select() 8 9 19980918 Busy Boxed! Dave Cinege 10 19990512 Uses Select. Charles P. Wright 11 19990513 Fixes stdin stupidity and uses buffers. Charles P. Wright 12 13 Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 14 */ 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <signal.h> 21 22 #include <sys/types.h> 23 #include <sys/socket.h> 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 #include <netdb.h> 27 #include <sys/ioctl.h> 28 #include "busybox.h" 3 * 4 * Copyright (C) 1998, 1999 Charles P. Wright 5 * Copyright (C) 1998 Dave Cinege 6 * 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 */ 9 10 #include "libbb.h" 11 12 #if ENABLE_DESKTOP 13 #include "nc_bloaty.c" 14 #else 15 16 /* Lots of small differences in features 17 * when compared to "standard" nc 18 */ 29 19 30 20 static void timeout(int signum) 31 21 { 32 bb_error_msg_and_die(" Timed out");22 bb_error_msg_and_die("timed out"); 33 23 } 34 24 25 int nc_main(int argc, char **argv); 35 26 int nc_main(int argc, char **argv) 36 27 { 37 int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x; 38 39 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE 40 char *pr00gie = NULL; 41 #endif 42 43 struct sockaddr_in address; 44 struct hostent *hostinfo; 45 28 /* sfd sits _here_ only because of "repeat" option (-l -l). */ 29 int sfd = sfd; /* for gcc */ 30 int cfd = 0; 31 unsigned lport = 0; 32 SKIP_NC_SERVER(const) unsigned do_listen = 0; 33 SKIP_NC_EXTRA (const) unsigned wsecs = 0; 34 SKIP_NC_EXTRA (const) unsigned delay = 0; 35 SKIP_NC_EXTRA (const int execparam = 0;) 36 USE_NC_EXTRA (char **execparam = NULL;) 37 len_and_sockaddr *lsa; 46 38 fd_set readfds, testfds; 47 48 while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) { 49 switch (opt) { 50 case 'l': 51 do_listen++; 52 break; 53 case 'p': 54 lport = bb_lookup_port(optarg, "tcp", 0); 55 break; 56 case 'i': 57 delay = atoi(optarg); 58 break; 59 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE 60 case 'e': 61 pr00gie = optarg; 62 break; 63 #endif 64 case 'w': 65 wsecs = atoi(optarg); 66 break; 67 default: 68 bb_show_usage(); 69 } 70 } 71 72 if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc)) 73 bb_show_usage(); 74 75 sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0); 76 x = 1; 77 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1) 78 bb_perror_msg_and_die("reuseaddr"); 79 address.sin_family = AF_INET; 39 int opt; /* must be signed (getopt returns -1) */ 40 41 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { 42 /* getopt32 is _almost_ usable: 43 ** it cannot handle "... -e prog -prog-opt" */ 44 while ((opt = getopt(argc, argv, 45 "" USE_NC_SERVER("lp:") USE_NC_EXTRA("w:i:f:e:") )) > 0 46 ) { 47 if (ENABLE_NC_SERVER && opt=='l') USE_NC_SERVER(do_listen++); 48 else if (ENABLE_NC_SERVER && opt=='p') { 49 USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); 50 } 51 else if (ENABLE_NC_EXTRA && opt=='w') USE_NC_EXTRA( wsecs = xatou(optarg)); 52 else if (ENABLE_NC_EXTRA && opt=='i') USE_NC_EXTRA( delay = xatou(optarg)); 53 else if (ENABLE_NC_EXTRA && opt=='f') USE_NC_EXTRA( cfd = xopen(optarg, O_RDWR)); 54 else if (ENABLE_NC_EXTRA && opt=='e' && optind<=argc) { 55 /* We cannot just 'break'. We should let getopt finish. 56 ** Or else we won't be able to find where 57 ** 'host' and 'port' params are 58 ** (think "nc -w 60 host port -e prog"). */ 59 USE_NC_EXTRA( 60 char **p; 61 // +2: one for progname (optarg) and one for NULL 62 execparam = xzalloc(sizeof(char*) * (argc - optind + 2)); 63 p = execparam; 64 *p++ = optarg; 65 while (optind < argc) { 66 *p++ = argv[optind++]; 67 } 68 ) 69 /* optind points to argv[arvc] (NULL) now. 70 ** FIXME: we assume that getopt will not count options 71 ** possibly present on "-e prog args" and will not 72 ** include them into final value of optind 73 ** which is to be used ... */ 74 } else bb_show_usage(); 75 } 76 argv += optind; /* ... here! */ 77 argc -= optind; 78 // -l and -f don't mix 79 if (do_listen && cfd) bb_show_usage(); 80 // Listen or file modes need zero arguments, client mode needs 2 81 if (do_listen || cfd) { 82 if (argc) bb_show_usage(); 83 } else { 84 if (!argc || argc > 2) bb_show_usage(); 85 } 86 } else { 87 if (argc != 3) bb_show_usage(); 88 argc--; 89 argv++; 90 } 80 91 81 92 if (wsecs) { … … 84 95 } 85 96 86 if (lport != 0) { 87 memset(&address.sin_addr, 0, sizeof(address.sin_addr)); 88 address.sin_port = lport; 89 90 bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address)); 91 } 92 93 if (do_listen) { 94 socklen_t addrlen = sizeof(address); 95 96 bb_xlisten(sfd, 1); 97 if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) 98 bb_perror_msg_and_die("accept"); 99 100 close(sfd); 101 sfd = tmpfd; 102 } else { 103 hostinfo = xgethostbyname(argv[optind]); 104 105 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; 106 address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0); 107 108 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) 109 bb_perror_msg_and_die("connect"); 97 if (!cfd) { 98 if (do_listen) { 99 /* create_and_bind_stream_or_die(NULL, lport) 100 * would've work wonderfully, but we need 101 * to know lsa */ 102 sfd = xsocket_stream(&lsa); 103 if (lport) 104 set_nport(lsa, htons(lport)); 105 setsockopt_reuseaddr(sfd); 106 xbind(sfd, &lsa->sa, lsa->len); 107 xlisten(sfd, do_listen); /* can be > 1 */ 108 /* If we didn't specify a port number, 109 * query and print it after listen() */ 110 if (!lport) { 111 socklen_t addrlen = lsa->len; 112 getsockname(sfd, &lsa->sa, &addrlen); 113 lport = get_nport(&lsa->sa); 114 fdprintf(2, "%d\n", ntohs(lport)); 115 } 116 fcntl(sfd, F_SETFD, FD_CLOEXEC); 117 accept_again: 118 cfd = accept(sfd, NULL, 0); 119 if (cfd < 0) 120 bb_perror_msg_and_die("accept"); 121 if (!execparam) 122 close(sfd); 123 } else { 124 cfd = create_and_connect_stream_or_die(argv[0], 125 argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0); 126 } 110 127 } 111 128 … … 115 132 } 116 133 117 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE118 134 /* -e given? */ 119 if (pr00gie) { 120 dup2(sfd, 0); 121 close(sfd); 135 if (execparam) { 136 signal(SIGCHLD, SIG_IGN); 137 // With more than one -l, repeatedly act as server. 138 if (do_listen > 1 && vfork()) { 139 /* parent */ 140 // This is a bit weird as cleanup goes, since we wind up with no 141 // stdin/stdout/stderr. But it's small and shouldn't hurt anything. 142 // We check for cfd == 0 above. 143 logmode = LOGMODE_NONE; 144 close(0); 145 close(1); 146 close(2); 147 goto accept_again; 148 } 149 /* child (or main thread if no multiple -l) */ 150 if (cfd) { 151 dup2(cfd, 0); 152 close(cfd); 153 } 122 154 dup2(0, 1); 123 155 dup2(0, 2); 124 execl(pr00gie, pr00gie, NULL);156 USE_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) 125 157 /* Don't print stuff or it will go over the wire.... */ 126 _exit(-1); 127 } 128 #endif /* CONFIG_NC_GAPING_SECURITY_HOLE */ 158 _exit(127); 159 } 160 161 // Select loop copying stdin to cfd, and cfd to stdout. 129 162 130 163 FD_ZERO(&readfds); 131 FD_SET( sfd, &readfds);164 FD_SET(cfd, &readfds); 132 165 FD_SET(STDIN_FILENO, &readfds); 133 166 134 while (1) {167 for (;;) { 135 168 int fd; 136 169 int ofd; … … 142 175 bb_perror_msg_and_die("select"); 143 176 177 #define iobuf bb_common_bufsiz1 144 178 for (fd = 0; fd < FD_SETSIZE; fd++) { 145 179 if (FD_ISSET(fd, &testfds)) { 146 if ((nread = safe_read(fd, bb_common_bufsiz1, 147 sizeof(bb_common_bufsiz1))) < 0) 148 { 149 bb_perror_msg_and_die(bb_msg_read_error); 150 } 151 152 if (fd == sfd) { 153 if (nread == 0) 180 nread = safe_read(fd, iobuf, sizeof(iobuf)); 181 if (fd == cfd) { 182 if (nread < 1) 154 183 exit(0); 155 184 ofd = STDOUT_FILENO; 156 185 } else { 157 if (nread <= 0) { 158 shutdown(sfd, 1 /* send */ ); 159 close(STDIN_FILENO); 186 if (nread<1) { 187 // Close outgoing half-connection so they get EOF, but 188 // leave incoming alone so we can see response. 189 shutdown(cfd, 1); 160 190 FD_CLR(STDIN_FILENO, &readfds); 161 191 } 162 ofd = sfd;192 ofd = cfd; 163 193 } 164 165 if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0) 166 bb_perror_msg_and_die(bb_msg_write_error); 167 if (delay > 0) { 168 sleep(delay); 169 } 194 xwrite(ofd, iobuf, nread); 195 if (delay > 0) sleep(delay); 170 196 } 171 197 } 172 198 } 173 199 } 200 #endif
Note:
See TracChangeset
for help on using the changeset viewer.