blob: f7fc9741fc4aa9a28616f888af7fe2882c055fd8 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02002/* nc: mini-netcat - built from the ground up for LRP
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00003 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02004 * Copyright (C) 1998, 1999 Charles P. Wright
5 * Copyright (C) 1998 Dave Cinege
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00006 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Rob Landley1cca9482006-07-10 19:45:20 +00008 */
Denys Vlasenko77cc2c52010-06-27 04:22:02 +02009//config:config NC
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020010//config: bool "nc (11 kb)"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020011//config: default y
12//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020013//config: A simple Unix utility which reads and writes data across network
14//config: connections.
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020015//config:
Denys Vlasenko3c34f682017-09-15 18:55:53 +020016//config:config NETCAT
17//config: bool "netcat (11 kb)"
18//config: default n
19//config: help
20//config: Alias to nc.
21//config:
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020022//config:config NC_SERVER
23//config: bool "Netcat server options (-l)"
24//config: default y
Denys Vlasenko3c34f682017-09-15 18:55:53 +020025//config: depends on NC || NETCAT
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020026//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020027//config: Allow netcat to act as a server.
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020028//config:
29//config:config NC_EXTRA
Denys Vlasenkoa14f3192013-02-28 11:09:14 +010030//config: bool "Netcat extensions (-eiw and -f FILE)"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020031//config: default y
Denys Vlasenko3c34f682017-09-15 18:55:53 +020032//config: depends on NC || NETCAT
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020033//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020034//config: Add -e (support for executing the rest of the command line after
35//config: making or receiving a successful connection), -i (delay interval for
36//config: lines sent), -w (timeout for initial connection).
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020037//config:
38//config:config NC_110_COMPAT
39//config: bool "Netcat 1.10 compatibility (+2.5k)"
Denys Vlasenko3c34f682017-09-15 18:55:53 +020040//config: default y
41//config: depends on NC || NETCAT
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020042//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020043//config: This option makes nc closely follow original nc-1.10.
44//config: The code is about 2.5k bigger. It enables
45//config: -s ADDR, -n, -u, -v, -o FILE, -z options, but loses
46//config: busybox-specific extensions: -f FILE.
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020047
Denys Vlasenko47367e12016-11-23 09:05:14 +010048//applet:IF_NC(APPLET(nc, BB_DIR_USR_BIN, BB_SUID_DROP))
Denys Vlasenko3c34f682017-09-15 18:55:53 +020049// APPLET_ODDNAME:name main location suid_type help
50//applet:IF_NETCAT(APPLET_ODDNAME(netcat, nc, BB_DIR_USR_BIN, BB_SUID_DROP, nc))
Denys Vlasenko47367e12016-11-23 09:05:14 +010051
52//kbuild:lib-$(CONFIG_NC) += nc.o
Denys Vlasenko3c34f682017-09-15 18:55:53 +020053//kbuild:lib-$(CONFIG_NETCAT) += nc.o
Denys Vlasenko47367e12016-11-23 09:05:14 +010054
55#include "libbb.h"
56#include "common_bufsiz.h"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020057#if ENABLE_NC_110_COMPAT
58# include "nc_bloaty.c"
Denis Vlasenko29fe7262007-04-05 20:26:28 +000059#else
60
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020061//usage:#if !ENABLE_NC_110_COMPAT
62//usage:
63//usage:#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA
Denys Vlasenko66426762011-06-05 03:58:28 +020064//usage:#define NC_OPTIONS_STR "\n"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020065//usage:#else
66//usage:#define NC_OPTIONS_STR
67//usage:#endif
68//usage:
69//usage:#define nc_trivial_usage
70//usage: IF_NC_EXTRA("[-iN] [-wN] ")IF_NC_SERVER("[-l] [-p PORT] ")
71//usage: "["IF_NC_EXTRA("-f FILE|")"IPADDR PORT]"IF_NC_EXTRA(" [-e PROG]")
72//usage:#define nc_full_usage "\n\n"
73//usage: "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE")
74//usage: NC_OPTIONS_STR
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020075//usage: IF_NC_SERVER(
76//usage: "\n -l Listen mode, for inbound connects"
77//usage: IF_NC_EXTRA(
Denys Vlasenkoa14f3192013-02-28 11:09:14 +010078//usage: "\n (use -ll with -e for persistent server)"
79//usage: )
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020080//usage: "\n -p PORT Local port"
81//usage: )
Denys Vlasenkoa14f3192013-02-28 11:09:14 +010082//usage: IF_NC_EXTRA(
83//usage: "\n -w SEC Connect timeout"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020084//usage: "\n -i SEC Delay interval for lines sent"
85//usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network"
Denys Vlasenkoa14f3192013-02-28 11:09:14 +010086//usage: "\n -e PROG Run PROG after connect"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020087//usage: )
88//usage:
89//usage:#define nc_notes_usage ""
90//usage: IF_NC_EXTRA(
91//usage: "To use netcat as a terminal emulator on a serial port:\n\n"
92//usage: "$ stty 115200 -F /dev/ttyS0\n"
93//usage: "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n"
94//usage: )
95//usage:
96//usage:#define nc_example_usage
97//usage: "$ nc foobar.somedomain.com 25\n"
98//usage: "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n"
99//usage: "help\n"
100//usage: "214-Commands supported:\n"
101//usage: "214- HELO EHLO MAIL RCPT DATA AUTH\n"
102//usage: "214 NOOP QUIT RSET HELP\n"
103//usage: "quit\n"
104//usage: "221 foobar closing connection\n"
105//usage:
106//usage:#endif
107
Denis Vlasenko5d687242007-01-12 20:59:31 +0000108/* Lots of small differences in features
109 * when compared to "standard" nc
110 */
111
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000112static void timeout(int signum UNUSED_PARAM)
Mike Frysinger60a5c382005-05-06 04:45:38 +0000113{
Denis Vlasenko13858992006-10-08 12:49:22 +0000114 bb_error_msg_and_die("timed out");
Mike Frysinger60a5c382005-05-06 04:45:38 +0000115}
116
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000117int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Erik Andersen7ab9c7e2000-05-12 19:41:47 +0000118int nc_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000119{
Denis Vlasenko5d687242007-01-12 20:59:31 +0000120 /* sfd sits _here_ only because of "repeat" option (-l -l). */
121 int sfd = sfd; /* for gcc */
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000122 int cfd = 0;
Denis Vlasenko31635552007-01-20 16:54:19 +0000123 unsigned lport = 0;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000124 IF_NOT_NC_SERVER(const) unsigned do_listen = 0;
125 IF_NOT_NC_EXTRA (const) unsigned wsecs = 0;
126 IF_NOT_NC_EXTRA (const) unsigned delay = 0;
127 IF_NOT_NC_EXTRA (const int execparam = 0;)
128 IF_NC_EXTRA (char **execparam = NULL;)
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100129 struct pollfd pfds[2];
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000130 int opt; /* must be signed (getopt returns -1) */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000131
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000132 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000133 /* getopt32 is _almost_ usable:
Denys Vlasenko77cc2c52010-06-27 04:22:02 +0200134 ** it cannot handle "... -e PROG -prog-opt" */
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000135 while ((opt = getopt(argc, argv,
Denys Vlasenko69675782013-01-14 01:34:48 +0100136 "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000137 ) {
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000138 if (ENABLE_NC_SERVER && opt == 'l')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000139 IF_NC_SERVER(do_listen++);
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000140 else if (ENABLE_NC_SERVER && opt == 'p')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000141 IF_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0));
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000142 else if (ENABLE_NC_EXTRA && opt == 'w')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000143 IF_NC_EXTRA( wsecs = xatou(optarg));
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000144 else if (ENABLE_NC_EXTRA && opt == 'i')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000145 IF_NC_EXTRA( delay = xatou(optarg));
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000146 else if (ENABLE_NC_EXTRA && opt == 'f')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000147 IF_NC_EXTRA( cfd = xopen(optarg, O_RDWR));
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000148 else if (ENABLE_NC_EXTRA && opt == 'e' && optind <= argc) {
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000149 /* We cannot just 'break'. We should let getopt finish.
150 ** Or else we won't be able to find where
151 ** 'host' and 'port' params are
Denys Vlasenko77cc2c52010-06-27 04:22:02 +0200152 ** (think "nc -w 60 host port -e PROG"). */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000153 IF_NC_EXTRA(
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000154 char **p;
155 // +2: one for progname (optarg) and one for NULL
156 execparam = xzalloc(sizeof(char*) * (argc - optind + 2));
157 p = execparam;
158 *p++ = optarg;
159 while (optind < argc) {
160 *p++ = argv[optind++];
161 }
162 )
Denys Vlasenkoa14f3192013-02-28 11:09:14 +0100163 /* optind points to argv[argc] (NULL) now.
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000164 ** FIXME: we assume that getopt will not count options
Denys Vlasenko77cc2c52010-06-27 04:22:02 +0200165 ** possibly present on "-e PROG ARGS" and will not
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000166 ** include them into final value of optind
167 ** which is to be used ... */
Rob Landley1cca9482006-07-10 19:45:20 +0000168 } else bb_show_usage();
Matt Kraai1d702672001-02-07 04:09:23 +0000169 }
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000170 argv += optind; /* ... here! */
171 argc -= optind;
172 // -l and -f don't mix
173 if (do_listen && cfd) bb_show_usage();
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000174 // File mode needs need zero arguments, listen mode needs zero or one,
175 // client mode needs one or two
176 if (cfd) {
Denis Vlasenko5d687242007-01-12 20:59:31 +0000177 if (argc) bb_show_usage();
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000178 } else if (do_listen) {
179 if (argc > 1) bb_show_usage();
Denis Vlasenko5d687242007-01-12 20:59:31 +0000180 } else {
181 if (!argc || argc > 2) bb_show_usage();
182 }
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000183 } else {
184 if (argc != 3) bb_show_usage();
185 argc--;
186 argv++;
187 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000188
Mike Frysinger60a5c382005-05-06 04:45:38 +0000189 if (wsecs) {
190 signal(SIGALRM, timeout);
191 alarm(wsecs);
192 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000193
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000194 if (!cfd) {
Rob Landley1cca9482006-07-10 19:45:20 +0000195 if (do_listen) {
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000196 sfd = create_and_bind_stream_or_die(argv[0], lport);
Denis Vlasenko5d687242007-01-12 20:59:31 +0000197 xlisten(sfd, do_listen); /* can be > 1 */
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000198#if 0 /* nc-1.10 does not do this (without -v) */
Denis Vlasenko5d687242007-01-12 20:59:31 +0000199 /* If we didn't specify a port number,
200 * query and print it after listen() */
Rob Landley1cca9482006-07-10 19:45:20 +0000201 if (!lport) {
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000202 len_and_sockaddr lsa;
203 lsa.len = LSA_SIZEOF_SA;
204 getsockname(sfd, &lsa.u.sa, &lsa.len);
205 lport = get_nport(&lsa.u.sa);
Denis Vlasenko5d687242007-01-12 20:59:31 +0000206 fdprintf(2, "%d\n", ntohs(lport));
Rob Landley1cca9482006-07-10 19:45:20 +0000207 }
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000208#endif
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000209 close_on_exec_on(sfd);
Denis Vlasenko5d687242007-01-12 20:59:31 +0000210 accept_again:
Denis Vlasenko703e2022007-01-22 14:12:08 +0000211 cfd = accept(sfd, NULL, 0);
Denis Vlasenko13858992006-10-08 12:49:22 +0000212 if (cfd < 0)
Rob Landley1cca9482006-07-10 19:45:20 +0000213 bb_perror_msg_and_die("accept");
Denis Vlasenko5d687242007-01-12 20:59:31 +0000214 if (!execparam)
215 close(sfd);
Rob Landley1cca9482006-07-10 19:45:20 +0000216 } else {
Denis Vlasenko5d687242007-01-12 20:59:31 +0000217 cfd = create_and_connect_stream_or_die(argv[0],
218 argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0);
Rob Landley1cca9482006-07-10 19:45:20 +0000219 }
Matt Kraai1d702672001-02-07 04:09:23 +0000220 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000221
Mike Frysinger60a5c382005-05-06 04:45:38 +0000222 if (wsecs) {
223 alarm(0);
Denys Vlasenko28a105d2009-06-01 11:26:30 +0200224 /* Non-ignored signals revert to SIG_DFL on exec anyway */
Denis Vlasenko3fa36e22008-11-09 00:15:11 +0000225 /*signal(SIGALRM, SIG_DFL);*/
Mike Frysinger60a5c382005-05-06 04:45:38 +0000226 }
227
Eric Andersen1323c942002-04-26 23:59:12 +0000228 /* -e given? */
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000229 if (execparam) {
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200230 pid_t pid;
231 /* With more than one -l, repeatedly act as server */
Pascal Bellard926031b2010-07-04 15:32:38 +0200232 if (do_listen > 1 && (pid = xvfork()) != 0) {
233 /* parent */
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200234 /* prevent zombies */
235 signal(SIGCHLD, SIG_IGN);
236 close(cfd);
Denis Vlasenko5d687242007-01-12 20:59:31 +0000237 goto accept_again;
Rob Landley1cca9482006-07-10 19:45:20 +0000238 }
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200239 /* child, or main thread if only one -l */
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +0000240 xmove_fd(cfd, 0);
241 xdup2(0, 1);
Denys Vlasenkoa14f3192013-02-28 11:09:14 +0100242 /*xdup2(0, 2); - original nc 1.10 does this, we don't */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000243 IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
Denys Vlasenkoc56d1252013-03-17 22:59:51 +0100244 IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);)
Rob Landley1cca9482006-07-10 19:45:20 +0000245 }
246
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100247 /* loop copying stdin to cfd, and cfd to stdout */
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000248
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100249 pfds[0].fd = STDIN_FILENO;
250 pfds[0].events = POLLIN;
251 pfds[1].fd = cfd;
252 pfds[1].events = POLLIN;
Eric Andersencc8ed391999-10-05 16:24:54 +0000253
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +0200254#define iobuf bb_common_bufsiz1
255 setup_common_bufsiz();
Rob Landley1cca9482006-07-10 19:45:20 +0000256 for (;;) {
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100257 int fdidx;
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000258 int ofd;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000259 int nread;
Eric Andersencc8ed391999-10-05 16:24:54 +0000260
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100261 if (safe_poll(pfds, 2, -1) < 0)
262 bb_perror_msg_and_die("poll");
Eric Andersencc8ed391999-10-05 16:24:54 +0000263
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100264 fdidx = 0;
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200265 while (1) {
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100266 if (pfds[fdidx].revents) {
267 nread = safe_read(pfds[fdidx].fd, iobuf, COMMON_BUFSIZE);
268 if (fdidx != 0) {
Denis Vlasenko5d687242007-01-12 20:59:31 +0000269 if (nread < 1)
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +0000270 exit(EXIT_SUCCESS);
Matt Kraaibfa79672000-12-15 22:34:34 +0000271 ofd = STDOUT_FILENO;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000272 } else {
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200273 if (nread < 1) {
274 /* Close outgoing half-connection so they get EOF,
275 * but leave incoming alone so we can see response */
Denys Vlasenkoca54b662013-07-28 21:08:37 +0200276 shutdown(cfd, SHUT_WR);
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100277 pfds[0].fd = -1;
Paul Fox7b71d742005-07-18 22:23:16 +0000278 }
Rob Landley1cca9482006-07-10 19:45:20 +0000279 ofd = cfd;
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000280 }
Denis Vlasenko74324c82007-06-04 10:16:52 +0000281 xwrite(ofd, iobuf, nread);
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200282 if (delay > 0)
283 sleep(delay);
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000284 }
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100285 if (fdidx == 1)
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200286 break;
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100287 fdidx++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000288 }
289 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000290}
Denis Vlasenko29fe7262007-04-05 20:26:28 +0000291#endif