blob: 117bbe20ea283dcd476ae7da60d1c7f44b00ae0b [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Erik Andersen7ab9c7e2000-05-12 19:41:47 +00002/* nc: mini-netcat - built from the ground up for LRP
Rob Landley1cca9482006-07-10 19:45:20 +00003 *
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 tarball for details.
8 */
Eric Andersencc8ed391999-10-05 16:24:54 +00009
Eric Andersencbe31da2001-02-20 06:14:08 +000010#include "busybox.h"
Eric Andersencc8ed391999-10-05 16:24:54 +000011
Mike Frysinger60a5c382005-05-06 04:45:38 +000012static void timeout(int signum)
13{
14 bb_error_msg_and_die("Timed out");
15}
16
Erik Andersen7ab9c7e2000-05-12 19:41:47 +000017int nc_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +000018{
Rob Landley1cca9482006-07-10 19:45:20 +000019 int do_listen = 0, lport = 0, delay = 0, wsecs = 0, execflag = 0, opt,
20 sfd = 0, cfd;
Erik Andersene49d5ec2000-02-08 19:58:47 +000021 struct sockaddr_in address;
22 struct hostent *hostinfo;
Erik Andersene49d5ec2000-02-08 19:58:47 +000023 fd_set readfds, testfds;
Rob Landley1cca9482006-07-10 19:45:20 +000024 char *infile = NULL;
Erik Andersene49d5ec2000-02-08 19:58:47 +000025
Rob Landley1cca9482006-07-10 19:45:20 +000026 memset(&address, 0, sizeof(address));
27
28 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
29 while ((opt = getopt(argc, argv, "lp:" USE_NC_EXTRA("i:ew:f:"))) > 0) {
30 if (ENABLE_NC_SERVER && opt=='l') do_listen++;
31 else if (ENABLE_NC_SERVER && opt=='p')
Glenn L McGrath036dbaa2004-01-17 05:03:31 +000032 lport = bb_lookup_port(optarg, "tcp", 0);
Rob Landley1cca9482006-07-10 19:45:20 +000033 else if (ENABLE_NC_EXTRA && opt=='w') wsecs = atoi(optarg);
34 else if (ENABLE_NC_EXTRA && opt=='i') delay = atoi(optarg);
35 else if (ENABLE_NC_EXTRA && opt=='f') infile = optarg;
36 else if (ENABLE_NC_EXTRA && opt=='e' && optind!=argc) {
37 execflag++;
Matt Kraai1d702672001-02-07 04:09:23 +000038 break;
Rob Landley1cca9482006-07-10 19:45:20 +000039 } else bb_show_usage();
Matt Kraai1d702672001-02-07 04:09:23 +000040 }
Erik Andersen5e1189e2000-04-15 16:34:54 +000041 }
Eric Andersenb6a44b81999-11-13 04:47:09 +000042
Rob Landley1cca9482006-07-10 19:45:20 +000043
44 // For listen or file we need zero arguments, dialout is 2.
45 // For exec we need at least one more argument at the end, more ok
Matt Kraai1d702672001-02-07 04:09:23 +000046
Rob Landley1cca9482006-07-10 19:45:20 +000047 opt = (do_listen || infile) ? 0 : 2 + execflag;
48 if (execflag ? argc-optind < opt : argc-optind!=opt ||
49 (infile && do_listen))
50 bb_show_usage();
Eric Andersencc8ed391999-10-05 16:24:54 +000051
Mike Frysinger60a5c382005-05-06 04:45:38 +000052 if (wsecs) {
53 signal(SIGALRM, timeout);
54 alarm(wsecs);
55 }
Rob Landley1cca9482006-07-10 19:45:20 +000056
57 if (infile) cfd = bb_xopen(infile, O_RDWR);
58 else {
59 opt = 1;
60 sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
61 fcntl(sfd, F_SETFD, FD_CLOEXEC);
62 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
63 address.sin_family = AF_INET;
Mike Frysinger60a5c382005-05-06 04:45:38 +000064
Rob Landley1cca9482006-07-10 19:45:20 +000065 // Set local port.
Matt Kraai1d702672001-02-07 04:09:23 +000066
Rob Landley1cca9482006-07-10 19:45:20 +000067 if (lport != 0) {
68 address.sin_port = lport;
Matt Kraai1d702672001-02-07 04:09:23 +000069
Rob Landley1cca9482006-07-10 19:45:20 +000070 bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address));
71 }
Matt Kraaibe9f44a2001-05-15 03:05:39 +000072
Rob Landley1cca9482006-07-10 19:45:20 +000073 if (do_listen) {
74 socklen_t addrlen = sizeof(address);
Matt Kraai1d702672001-02-07 04:09:23 +000075
Rob Landley1cca9482006-07-10 19:45:20 +000076 bb_xlisten(sfd, do_listen);
Matt Kraai1d702672001-02-07 04:09:23 +000077
Rob Landley1cca9482006-07-10 19:45:20 +000078 // If we didn't specify a port number, query and print it to stderr.
Matt Kraai1d702672001-02-07 04:09:23 +000079
Rob Landley1cca9482006-07-10 19:45:20 +000080 if (!lport) {
81 socklen_t len = sizeof(address);
82 getsockname(sfd, &address, &len);
83 fdprintf(2, "%d\n", SWAP_BE16(address.sin_port));
84 }
85repeatyness:
86 if ((cfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
87 bb_perror_msg_and_die("accept");
88
89 if (!execflag) close(sfd);
90 } else {
91 hostinfo = xgethostbyname(argv[optind]);
92
93 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
94 address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
95
96 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
97 bb_perror_msg_and_die("connect");
98 cfd = sfd;
99 }
Matt Kraai1d702672001-02-07 04:09:23 +0000100 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000101
Mike Frysinger60a5c382005-05-06 04:45:38 +0000102 if (wsecs) {
103 alarm(0);
104 signal(SIGALRM, SIG_DFL);
105 }
106
Eric Andersen1323c942002-04-26 23:59:12 +0000107 /* -e given? */
Rob Landley1cca9482006-07-10 19:45:20 +0000108 if (execflag) {
109 if(cfd) {
110 signal(SIGCHLD, SIG_IGN);
111 dup2(cfd, 0);
112 close(cfd);
113 }
Mike Frysinger7dc7f402005-05-06 05:00:34 +0000114 dup2(0, 1);
115 dup2(0, 2);
Eric Andersen1323c942002-04-26 23:59:12 +0000116
Rob Landley1cca9482006-07-10 19:45:20 +0000117 // With more than one -l, repeatedly act as server.
118
119 if (do_listen>1 && vfork()) {
120 // This is a bit weird as cleanup goes, since we wind up with no
121 // stdin/stdout/stderr. But it's small and shouldn't hurt anything.
122 // We check for cfd == 0 above.
123 close(0);
124 close(1);
125 close(2);
126
127 goto repeatyness;
128 }
129 execvp(argv[optind], argv+optind);
130 /* Don't print stuff or it will go over the wire.... */
131 _exit(127);
132 }
133
134 // Select loop copying stdin to cfd, and cfd to stdout.
135
Erik Andersene49d5ec2000-02-08 19:58:47 +0000136 FD_ZERO(&readfds);
Rob Landley1cca9482006-07-10 19:45:20 +0000137 FD_SET(cfd, &readfds);
Matt Kraaibfa79672000-12-15 22:34:34 +0000138 FD_SET(STDIN_FILENO, &readfds);
Eric Andersencc8ed391999-10-05 16:24:54 +0000139
Rob Landley1cca9482006-07-10 19:45:20 +0000140 for (;;) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000141 int fd;
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000142 int ofd;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000143 int nread;
Eric Andersencc8ed391999-10-05 16:24:54 +0000144
Erik Andersene49d5ec2000-02-08 19:58:47 +0000145 testfds = readfds;
Eric Andersencc8ed391999-10-05 16:24:54 +0000146
Matt Kraaibfa79672000-12-15 22:34:34 +0000147 if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000148 bb_perror_msg_and_die("select");
Eric Andersencc8ed391999-10-05 16:24:54 +0000149
Erik Andersene49d5ec2000-02-08 19:58:47 +0000150 for (fd = 0; fd < FD_SETSIZE; fd++) {
151 if (FD_ISSET(fd, &testfds)) {
Rob Landley53437472006-07-16 08:14:35 +0000152 nread = safe_read(fd, bb_common_bufsiz1,
153 sizeof(bb_common_bufsiz1));
Eric Andersencc8ed391999-10-05 16:24:54 +0000154
Rob Landley1cca9482006-07-10 19:45:20 +0000155 if (fd == cfd) {
Rob Landley53437472006-07-16 08:14:35 +0000156 if (nread<1) exit(0);
Matt Kraaibfa79672000-12-15 22:34:34 +0000157 ofd = STDOUT_FILENO;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000158 } else {
Rob Landley53437472006-07-16 08:14:35 +0000159 if (nread<1) {
Rob Landley1cca9482006-07-10 19:45:20 +0000160 // Close outgoing half-connection so they get EOF, but
161 // leave incoming alone so we can see response.
162 shutdown(cfd, 1);
Paul Fox7b71d742005-07-18 22:23:16 +0000163 FD_CLR(STDIN_FILENO, &readfds);
164 }
Rob Landley1cca9482006-07-10 19:45:20 +0000165 ofd = cfd;
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000166 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000167
Rob Landley53437472006-07-16 08:14:35 +0000168 xwrite(ofd, bb_common_bufsiz1, nread);
Rob Landley1cca9482006-07-10 19:45:20 +0000169 if (delay > 0) sleep(delay);
Eric Andersen2ce1edc1999-10-12 15:42:48 +0000170 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000171 }
172 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000173}