1/* vi: set sw=4 ts=4: */ 2/* nc: mini-netcat - built from the ground up for LRP 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 source tree. 8 */ 9//config:config NC 10//config: bool "nc" 11//config: default y 12//config: help 13//config: A simple Unix utility which reads and writes data across network 14//config: connections. 15//config: 16//config:config NC_SERVER 17//config: bool "Netcat server options (-l)" 18//config: default y 19//config: depends on NC 20//config: help 21//config: Allow netcat to act as a server. 22//config: 23//config:config NC_EXTRA 24//config: bool "Netcat extensions (-eiw and -f FILE)" 25//config: default y 26//config: depends on NC 27//config: help 28//config: Add -e (support for executing the rest of the command line after 29//config: making or receiving a successful connection), -i (delay interval for 30//config: lines sent), -w (timeout for initial connection). 31//config: 32//config:config NC_110_COMPAT 33//config: bool "Netcat 1.10 compatibility (+2.5k)" 34//config: default n # off specially for Rob 35//config: depends on NC 36//config: help 37//config: This option makes nc closely follow original nc-1.10. 38//config: The code is about 2.5k bigger. It enables 39//config: -s ADDR, -n, -u, -v, -o FILE, -z options, but loses 40//config: busybox-specific extensions: -f FILE. 41 42//applet:IF_NC(APPLET(nc, BB_DIR_USR_BIN, BB_SUID_DROP)) 43 44//kbuild:lib-$(CONFIG_NC) += nc.o 45 46#include "libbb.h" 47#include "common_bufsiz.h" 48#if ENABLE_NC_110_COMPAT 49# include "nc_bloaty.c" 50#else 51 52//usage:#if !ENABLE_NC_110_COMPAT 53//usage: 54//usage:#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA 55//usage:#define NC_OPTIONS_STR "\n" 56//usage:#else 57//usage:#define NC_OPTIONS_STR 58//usage:#endif 59//usage: 60//usage:#define nc_trivial_usage 61//usage: IF_NC_EXTRA("[-iN] [-wN] ")IF_NC_SERVER("[-l] [-p PORT] ") 62//usage: "["IF_NC_EXTRA("-f FILE|")"IPADDR PORT]"IF_NC_EXTRA(" [-e PROG]") 63//usage:#define nc_full_usage "\n\n" 64//usage: "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE") 65//usage: NC_OPTIONS_STR 66//usage: IF_NC_SERVER( 67//usage: "\n -l Listen mode, for inbound connects" 68//usage: IF_NC_EXTRA( 69//usage: "\n (use -ll with -e for persistent server)" 70//usage: ) 71//usage: "\n -p PORT Local port" 72//usage: ) 73//usage: IF_NC_EXTRA( 74//usage: "\n -w SEC Connect timeout" 75//usage: "\n -i SEC Delay interval for lines sent" 76//usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network" 77//usage: "\n -e PROG Run PROG after connect" 78//usage: ) 79//usage: 80//usage:#define nc_notes_usage "" 81//usage: IF_NC_EXTRA( 82//usage: "To use netcat as a terminal emulator on a serial port:\n\n" 83//usage: "$ stty 115200 -F /dev/ttyS0\n" 84//usage: "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n" 85//usage: ) 86//usage: 87//usage:#define nc_example_usage 88//usage: "$ nc foobar.somedomain.com 25\n" 89//usage: "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" 90//usage: "help\n" 91//usage: "214-Commands supported:\n" 92//usage: "214- HELO EHLO MAIL RCPT DATA AUTH\n" 93//usage: "214 NOOP QUIT RSET HELP\n" 94//usage: "quit\n" 95//usage: "221 foobar closing connection\n" 96//usage: 97//usage:#endif 98 99/* Lots of small differences in features 100 * when compared to "standard" nc 101 */ 102 103static void timeout(int signum UNUSED_PARAM) 104{ 105 bb_error_msg_and_die("timed out"); 106} 107 108int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 109int nc_main(int argc, char **argv) 110{ 111 /* sfd sits _here_ only because of "repeat" option (-l -l). */ 112 int sfd = sfd; /* for gcc */ 113 int cfd = 0; 114 unsigned lport = 0; 115 IF_NOT_NC_SERVER(const) unsigned do_listen = 0; 116 IF_NOT_NC_EXTRA (const) unsigned wsecs = 0; 117 IF_NOT_NC_EXTRA (const) unsigned delay = 0; 118 IF_NOT_NC_EXTRA (const int execparam = 0;) 119 IF_NC_EXTRA (char **execparam = NULL;) 120 struct pollfd pfds[2]; 121 int opt; /* must be signed (getopt returns -1) */ 122 123 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { 124 /* getopt32 is _almost_ usable: 125 ** it cannot handle "... -e PROG -prog-opt" */ 126 while ((opt = getopt(argc, argv, 127 "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0 128 ) { 129 if (ENABLE_NC_SERVER && opt == 'l') 130 IF_NC_SERVER(do_listen++); 131 else if (ENABLE_NC_SERVER && opt == 'p') 132 IF_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); 133 else if (ENABLE_NC_EXTRA && opt == 'w') 134 IF_NC_EXTRA( wsecs = xatou(optarg)); 135 else if (ENABLE_NC_EXTRA && opt == 'i') 136 IF_NC_EXTRA( delay = xatou(optarg)); 137 else if (ENABLE_NC_EXTRA && opt == 'f') 138 IF_NC_EXTRA( cfd = xopen(optarg, O_RDWR)); 139 else if (ENABLE_NC_EXTRA && opt == 'e' && optind <= argc) { 140 /* We cannot just 'break'. We should let getopt finish. 141 ** Or else we won't be able to find where 142 ** 'host' and 'port' params are 143 ** (think "nc -w 60 host port -e PROG"). */ 144 IF_NC_EXTRA( 145 char **p; 146 // +2: one for progname (optarg) and one for NULL 147 execparam = xzalloc(sizeof(char*) * (argc - optind + 2)); 148 p = execparam; 149 *p++ = optarg; 150 while (optind < argc) { 151 *p++ = argv[optind++]; 152 } 153 ) 154 /* optind points to argv[argc] (NULL) now. 155 ** FIXME: we assume that getopt will not count options 156 ** possibly present on "-e PROG ARGS" and will not 157 ** include them into final value of optind 158 ** which is to be used ... */ 159 } else bb_show_usage(); 160 } 161 argv += optind; /* ... here! */ 162 argc -= optind; 163 // -l and -f don't mix 164 if (do_listen && cfd) bb_show_usage(); 165 // File mode needs need zero arguments, listen mode needs zero or one, 166 // client mode needs one or two 167 if (cfd) { 168 if (argc) bb_show_usage(); 169 } else if (do_listen) { 170 if (argc > 1) bb_show_usage(); 171 } else { 172 if (!argc || argc > 2) bb_show_usage(); 173 } 174 } else { 175 if (argc != 3) bb_show_usage(); 176 argc--; 177 argv++; 178 } 179 180 if (wsecs) { 181 signal(SIGALRM, timeout); 182 alarm(wsecs); 183 } 184 185 if (!cfd) { 186 if (do_listen) { 187 sfd = create_and_bind_stream_or_die(argv[0], lport); 188 xlisten(sfd, do_listen); /* can be > 1 */ 189#if 0 /* nc-1.10 does not do this (without -v) */ 190 /* If we didn't specify a port number, 191 * query and print it after listen() */ 192 if (!lport) { 193 len_and_sockaddr lsa; 194 lsa.len = LSA_SIZEOF_SA; 195 getsockname(sfd, &lsa.u.sa, &lsa.len); 196 lport = get_nport(&lsa.u.sa); 197 fdprintf(2, "%d\n", ntohs(lport)); 198 } 199#endif 200 close_on_exec_on(sfd); 201 accept_again: 202 cfd = accept(sfd, NULL, 0); 203 if (cfd < 0) 204 bb_perror_msg_and_die("accept"); 205 if (!execparam) 206 close(sfd); 207 } else { 208 cfd = create_and_connect_stream_or_die(argv[0], 209 argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0); 210 } 211 } 212 213 if (wsecs) { 214 alarm(0); 215 /* Non-ignored signals revert to SIG_DFL on exec anyway */ 216 /*signal(SIGALRM, SIG_DFL);*/ 217 } 218 219 /* -e given? */ 220 if (execparam) { 221 pid_t pid; 222 /* With more than one -l, repeatedly act as server */ 223 if (do_listen > 1 && (pid = xvfork()) != 0) { 224 /* parent */ 225 /* prevent zombies */ 226 signal(SIGCHLD, SIG_IGN); 227 close(cfd); 228 goto accept_again; 229 } 230 /* child, or main thread if only one -l */ 231 xmove_fd(cfd, 0); 232 xdup2(0, 1); 233 /*xdup2(0, 2); - original nc 1.10 does this, we don't */ 234 IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) 235 IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);) 236 } 237 238 /* loop copying stdin to cfd, and cfd to stdout */ 239 240 pfds[0].fd = STDIN_FILENO; 241 pfds[0].events = POLLIN; 242 pfds[1].fd = cfd; 243 pfds[1].events = POLLIN; 244 245#define iobuf bb_common_bufsiz1 246 setup_common_bufsiz(); 247 for (;;) { 248 int fdidx; 249 int ofd; 250 int nread; 251 252 if (safe_poll(pfds, 2, -1) < 0) 253 bb_perror_msg_and_die("poll"); 254 255 fdidx = 0; 256 while (1) { 257 if (pfds[fdidx].revents) { 258 nread = safe_read(pfds[fdidx].fd, iobuf, COMMON_BUFSIZE); 259 if (fdidx != 0) { 260 if (nread < 1) 261 exit(EXIT_SUCCESS); 262 ofd = STDOUT_FILENO; 263 } else { 264 if (nread < 1) { 265 /* Close outgoing half-connection so they get EOF, 266 * but leave incoming alone so we can see response */ 267 shutdown(cfd, SHUT_WR); 268 pfds[0].fd = -1; 269 } 270 ofd = cfd; 271 } 272 xwrite(ofd, iobuf, nread); 273 if (delay > 0) 274 sleep(delay); 275 } 276 if (fdidx == 1) 277 break; 278 fdidx++; 279 } 280 } 281} 282#endif 283