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