blob: 705b7356a2d7d72029564e252752b2d88974dc9d [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Denys Vlasenkoa02a4e92017-10-05 15:19:25 +02002/*
3 * nc: mini-netcat - built from the ground up for LRP
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00004 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02005 * Copyright (C) 1998, 1999 Charles P. Wright
6 * Copyright (C) 1998 Dave Cinege
Denis Vlasenko9213a9e2006-09-17 16:28:10 +00007 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02008 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Rob Landley1cca9482006-07-10 19:45:20 +00009 */
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020010//config:config NC
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020011//config: bool "nc (11 kb)"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020012//config: default y
13//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020014//config: A simple Unix utility which reads and writes data across network
15//config: connections.
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020016//config:
Denys Vlasenko3c34f682017-09-15 18:55:53 +020017//config:config NETCAT
18//config: bool "netcat (11 kb)"
19//config: default n
20//config: help
21//config: Alias to nc.
22//config:
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020023//config:config NC_SERVER
24//config: bool "Netcat server options (-l)"
25//config: default y
Denys Vlasenko3c34f682017-09-15 18:55:53 +020026//config: depends on NC || NETCAT
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020027//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020028//config: Allow netcat to act as a server.
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020029//config:
30//config:config NC_EXTRA
Denys Vlasenkoa14f3192013-02-28 11:09:14 +010031//config: bool "Netcat extensions (-eiw and -f FILE)"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020032//config: default y
Denys Vlasenko3c34f682017-09-15 18:55:53 +020033//config: depends on NC || NETCAT
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020034//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020035//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).
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020038//config:
39//config:config NC_110_COMPAT
40//config: bool "Netcat 1.10 compatibility (+2.5k)"
Denys Vlasenko3c34f682017-09-15 18:55:53 +020041//config: default y
42//config: depends on NC || NETCAT
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020043//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020044//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.
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020048
Denys Vlasenko47367e12016-11-23 09:05:14 +010049//applet:IF_NC(APPLET(nc, BB_DIR_USR_BIN, BB_SUID_DROP))
Denys Vlasenko3c34f682017-09-15 18:55:53 +020050// APPLET_ODDNAME:name main location suid_type help
51//applet:IF_NETCAT(APPLET_ODDNAME(netcat, nc, BB_DIR_USR_BIN, BB_SUID_DROP, nc))
Denys Vlasenko47367e12016-11-23 09:05:14 +010052
53//kbuild:lib-$(CONFIG_NC) += nc.o
Denys Vlasenko3c34f682017-09-15 18:55:53 +020054//kbuild:lib-$(CONFIG_NETCAT) += nc.o
Denys Vlasenko47367e12016-11-23 09:05:14 +010055
56#include "libbb.h"
57#include "common_bufsiz.h"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020058#if ENABLE_NC_110_COMPAT
59# include "nc_bloaty.c"
Denis Vlasenko29fe7262007-04-05 20:26:28 +000060#else
61
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020062//usage:#if !ENABLE_NC_110_COMPAT
63//usage:
64//usage:#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA
Denys Vlasenko66426762011-06-05 03:58:28 +020065//usage:#define NC_OPTIONS_STR "\n"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020066//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
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020076//usage: IF_NC_SERVER(
77//usage: "\n -l Listen mode, for inbound connects"
78//usage: IF_NC_EXTRA(
Denys Vlasenkoa14f3192013-02-28 11:09:14 +010079//usage: "\n (use -ll with -e for persistent server)"
80//usage: )
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020081//usage: "\n -p PORT Local port"
82//usage: )
Denys Vlasenkoa14f3192013-02-28 11:09:14 +010083//usage: IF_NC_EXTRA(
84//usage: "\n -w SEC Connect timeout"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020085//usage: "\n -i SEC Delay interval for lines sent"
86//usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network"
Denys Vlasenkoa14f3192013-02-28 11:09:14 +010087//usage: "\n -e PROG Run PROG after connect"
Denys Vlasenko77cc2c52010-06-27 04:22:02 +020088//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
Denis Vlasenko5d687242007-01-12 20:59:31 +0000109/* Lots of small differences in features
110 * when compared to "standard" nc
111 */
112
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000113static void timeout(int signum UNUSED_PARAM)
Mike Frysinger60a5c382005-05-06 04:45:38 +0000114{
James Byrne69374872019-07-02 11:35:03 +0200115 bb_simple_error_msg_and_die("timed out");
Mike Frysinger60a5c382005-05-06 04:45:38 +0000116}
117
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000118int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Erik Andersen7ab9c7e2000-05-12 19:41:47 +0000119int nc_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000120{
Denis Vlasenko5d687242007-01-12 20:59:31 +0000121 /* sfd sits _here_ only because of "repeat" option (-l -l). */
122 int sfd = sfd; /* for gcc */
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000123 int cfd = 0;
Denis Vlasenko31635552007-01-20 16:54:19 +0000124 unsigned lport = 0;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000125 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;)
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100130 struct pollfd pfds[2];
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000131 int opt; /* must be signed (getopt returns -1) */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000132
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000133 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000134 /* getopt32 is _almost_ usable:
Denys Vlasenko77cc2c52010-06-27 04:22:02 +0200135 ** it cannot handle "... -e PROG -prog-opt" */
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000136 while ((opt = getopt(argc, argv,
Denys Vlasenko69675782013-01-14 01:34:48 +0100137 "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000138 ) {
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000139 if (ENABLE_NC_SERVER && opt == 'l')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000140 IF_NC_SERVER(do_listen++);
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000141 else if (ENABLE_NC_SERVER && opt == 'p')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000142 IF_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0));
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000143 else if (ENABLE_NC_EXTRA && opt == 'w')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000144 IF_NC_EXTRA( wsecs = xatou(optarg));
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000145 else if (ENABLE_NC_EXTRA && opt == 'i')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000146 IF_NC_EXTRA( delay = xatou(optarg));
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000147 else if (ENABLE_NC_EXTRA && opt == 'f')
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000148 IF_NC_EXTRA( cfd = xopen(optarg, O_RDWR));
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000149 else if (ENABLE_NC_EXTRA && opt == 'e' && optind <= argc) {
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000150 /* 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
Denys Vlasenko77cc2c52010-06-27 04:22:02 +0200153 ** (think "nc -w 60 host port -e PROG"). */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000154 IF_NC_EXTRA(
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000155 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 )
Denys Vlasenkoa14f3192013-02-28 11:09:14 +0100164 /* optind points to argv[argc] (NULL) now.
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000165 ** FIXME: we assume that getopt will not count options
Denys Vlasenko77cc2c52010-06-27 04:22:02 +0200166 ** possibly present on "-e PROG ARGS" and will not
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000167 ** include them into final value of optind
168 ** which is to be used ... */
Rob Landley1cca9482006-07-10 19:45:20 +0000169 } else bb_show_usage();
Matt Kraai1d702672001-02-07 04:09:23 +0000170 }
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000171 argv += optind; /* ... here! */
172 argc -= optind;
173 // -l and -f don't mix
174 if (do_listen && cfd) bb_show_usage();
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000175 // File mode needs need zero arguments, listen mode needs zero or one,
176 // client mode needs one or two
177 if (cfd) {
Denis Vlasenko5d687242007-01-12 20:59:31 +0000178 if (argc) bb_show_usage();
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000179 } else if (do_listen) {
180 if (argc > 1) bb_show_usage();
Denis Vlasenko5d687242007-01-12 20:59:31 +0000181 } else {
182 if (!argc || argc > 2) bb_show_usage();
183 }
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000184 } else {
185 if (argc != 3) bb_show_usage();
186 argc--;
187 argv++;
188 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000189
Mike Frysinger60a5c382005-05-06 04:45:38 +0000190 if (wsecs) {
191 signal(SIGALRM, timeout);
192 alarm(wsecs);
193 }
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000194
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000195 if (!cfd) {
Rob Landley1cca9482006-07-10 19:45:20 +0000196 if (do_listen) {
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000197 sfd = create_and_bind_stream_or_die(argv[0], lport);
Denis Vlasenko5d687242007-01-12 20:59:31 +0000198 xlisten(sfd, do_listen); /* can be > 1 */
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000199#if 0 /* nc-1.10 does not do this (without -v) */
Denis Vlasenko5d687242007-01-12 20:59:31 +0000200 /* If we didn't specify a port number,
201 * query and print it after listen() */
Rob Landley1cca9482006-07-10 19:45:20 +0000202 if (!lport) {
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000203 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);
Denis Vlasenko5d687242007-01-12 20:59:31 +0000207 fdprintf(2, "%d\n", ntohs(lport));
Rob Landley1cca9482006-07-10 19:45:20 +0000208 }
Denis Vlasenkof6b46852009-04-25 13:16:53 +0000209#endif
Denis Vlasenko96e1b382007-09-30 23:50:48 +0000210 close_on_exec_on(sfd);
Denis Vlasenko5d687242007-01-12 20:59:31 +0000211 accept_again:
Denis Vlasenko703e2022007-01-22 14:12:08 +0000212 cfd = accept(sfd, NULL, 0);
Denis Vlasenko13858992006-10-08 12:49:22 +0000213 if (cfd < 0)
James Byrne69374872019-07-02 11:35:03 +0200214 bb_simple_perror_msg_and_die("accept");
Denis Vlasenko5d687242007-01-12 20:59:31 +0000215 if (!execparam)
216 close(sfd);
Rob Landley1cca9482006-07-10 19:45:20 +0000217 } else {
Denis Vlasenko5d687242007-01-12 20:59:31 +0000218 cfd = create_and_connect_stream_or_die(argv[0],
219 argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0);
Rob Landley1cca9482006-07-10 19:45:20 +0000220 }
Matt Kraai1d702672001-02-07 04:09:23 +0000221 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000222
Mike Frysinger60a5c382005-05-06 04:45:38 +0000223 if (wsecs) {
224 alarm(0);
Denys Vlasenko28a105d2009-06-01 11:26:30 +0200225 /* Non-ignored signals revert to SIG_DFL on exec anyway */
Denis Vlasenko3fa36e22008-11-09 00:15:11 +0000226 /*signal(SIGALRM, SIG_DFL);*/
Mike Frysinger60a5c382005-05-06 04:45:38 +0000227 }
228
Eric Andersen1323c942002-04-26 23:59:12 +0000229 /* -e given? */
Denis Vlasenkod0e70af2006-10-16 01:10:28 +0000230 if (execparam) {
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200231 pid_t pid;
232 /* With more than one -l, repeatedly act as server */
Pascal Bellard926031b2010-07-04 15:32:38 +0200233 if (do_listen > 1 && (pid = xvfork()) != 0) {
234 /* parent */
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200235 /* prevent zombies */
236 signal(SIGCHLD, SIG_IGN);
237 close(cfd);
Denis Vlasenko5d687242007-01-12 20:59:31 +0000238 goto accept_again;
Rob Landley1cca9482006-07-10 19:45:20 +0000239 }
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200240 /* child, or main thread if only one -l */
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +0000241 xmove_fd(cfd, 0);
242 xdup2(0, 1);
Denys Vlasenkoa14f3192013-02-28 11:09:14 +0100243 /*xdup2(0, 2); - original nc 1.10 does this, we don't */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000244 IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
Denys Vlasenkoc56d1252013-03-17 22:59:51 +0100245 IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);)
Rob Landley1cca9482006-07-10 19:45:20 +0000246 }
247
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100248 /* loop copying stdin to cfd, and cfd to stdout */
Denis Vlasenko9213a9e2006-09-17 16:28:10 +0000249
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100250 pfds[0].fd = STDIN_FILENO;
251 pfds[0].events = POLLIN;
252 pfds[1].fd = cfd;
253 pfds[1].events = POLLIN;
Eric Andersencc8ed391999-10-05 16:24:54 +0000254
Denys Vlasenko9de2e5a2016-04-21 18:38:51 +0200255#define iobuf bb_common_bufsiz1
256 setup_common_bufsiz();
Rob Landley1cca9482006-07-10 19:45:20 +0000257 for (;;) {
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100258 int fdidx;
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000259 int ofd;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000260 int nread;
Eric Andersencc8ed391999-10-05 16:24:54 +0000261
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100262 if (safe_poll(pfds, 2, -1) < 0)
James Byrne69374872019-07-02 11:35:03 +0200263 bb_simple_perror_msg_and_die("poll");
Eric Andersencc8ed391999-10-05 16:24:54 +0000264
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100265 fdidx = 0;
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200266 while (1) {
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100267 if (pfds[fdidx].revents) {
268 nread = safe_read(pfds[fdidx].fd, iobuf, COMMON_BUFSIZE);
269 if (fdidx != 0) {
Denis Vlasenko5d687242007-01-12 20:59:31 +0000270 if (nread < 1)
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +0000271 exit(EXIT_SUCCESS);
Matt Kraaibfa79672000-12-15 22:34:34 +0000272 ofd = STDOUT_FILENO;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000273 } else {
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200274 if (nread < 1) {
275 /* Close outgoing half-connection so they get EOF,
276 * but leave incoming alone so we can see response */
Denys Vlasenkoca54b662013-07-28 21:08:37 +0200277 shutdown(cfd, SHUT_WR);
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100278 pfds[0].fd = -1;
Paul Fox7b71d742005-07-18 22:23:16 +0000279 }
Rob Landley1cca9482006-07-10 19:45:20 +0000280 ofd = cfd;
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000281 }
Denis Vlasenko74324c82007-06-04 10:16:52 +0000282 xwrite(ofd, iobuf, nread);
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200283 if (delay > 0)
284 sleep(delay);
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000285 }
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100286 if (fdidx == 1)
Tomoya Adachi63416cc2009-08-03 02:59:22 +0200287 break;
Denys Vlasenko5b3b4682017-02-16 17:17:17 +0100288 fdidx++;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000289 }
290 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000291}
Denis Vlasenko29fe7262007-04-05 20:26:28 +0000292#endif