source: MondoRescue/branches/3.3/mindi-busybox/networking/nc.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

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