summaryrefslogtreecommitdiff
path: root/networking/nc.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2006-07-10 19:45:20 +0000
committerRob Landley <rob@landley.net>2006-07-10 19:45:20 +0000
commit1cca9484db69971f652dfef48778da0dc56dad12 (patch)
tree71cb84ae857702f57bdced4a1e99b877499bfd4a /networking/nc.c
parent5d8843e451c01d8abfe6b5be772637310e9e581e (diff)
downloadbusybox-w32-1cca9484db69971f652dfef48778da0dc56dad12.tar.gz
busybox-w32-1cca9484db69971f652dfef48778da0dc56dad12.tar.bz2
busybox-w32-1cca9484db69971f652dfef48778da0dc56dad12.zip
Upgrade netcat a lot. Make -e able to take the rest of the command line as
what to exec. Add -f mode and a brief explanation of how to use it to replace minicom. Add -l -l mode so you can turn any command into a server. And group all of netcat's command line options under two CONFIG entries, so if you disable both it doesn't use getopt at all.
Diffstat (limited to 'networking/nc.c')
-rw-r--r--networking/nc.c202
1 files changed, 102 insertions, 100 deletions
diff --git a/networking/nc.c b/networking/nc.c
index 24f1aa5a5..bda0c407b 100644
--- a/networking/nc.c
+++ b/networking/nc.c
@@ -1,32 +1,16 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* nc: mini-netcat - built from the ground up for LRP 2/* nc: mini-netcat - built from the ground up for LRP
3 Copyright (C) 1998 Charles P. Wright 3 *
4 4 * Copyright (C) 1998, 1999 Charles P. Wright
5 0.0.1 6K It works. 5 * Copyright (C) 1998 Dave Cinege
6 0.0.2 5K Smaller and you can also check the exit condition if you wish. 6 *
7 0.0.3 Uses select() 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 8 */
9 19980918 Busy Boxed! Dave Cinege 9
10 19990512 Uses Select. Charles P. Wright
11 19990513 Fixes stdin stupidity and uses buffers. Charles P. Wright
12
13 Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
14*/
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20#include <signal.h>
21
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
26#include <netdb.h>
27#include <sys/ioctl.h>
28#include "busybox.h" 10#include "busybox.h"
29 11
12#define xread bb_xread
13
30static void timeout(int signum) 14static void timeout(int signum)
31{ 15{
32 bb_error_msg_and_die("Timed out"); 16 bb_error_msg_and_die("Timed out");
@@ -34,79 +18,87 @@ static void timeout(int signum)
34 18
35int nc_main(int argc, char **argv) 19int nc_main(int argc, char **argv)
36{ 20{
37 int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x; 21 int do_listen = 0, lport = 0, delay = 0, wsecs = 0, execflag = 0, opt,
38 22 sfd = 0, cfd;
39#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
40 char *pr00gie = NULL;
41#endif
42
43 struct sockaddr_in address; 23 struct sockaddr_in address;
44 struct hostent *hostinfo; 24 struct hostent *hostinfo;
45
46 fd_set readfds, testfds; 25 fd_set readfds, testfds;
26 char *infile = NULL;
47 27
48 while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) { 28 memset(&address, 0, sizeof(address));
49 switch (opt) { 29
50 case 'l': 30 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
51 do_listen++; 31 while ((opt = getopt(argc, argv, "lp:" USE_NC_EXTRA("i:ew:f:"))) > 0) {
52 break; 32 if (ENABLE_NC_SERVER && opt=='l') do_listen++;
53 case 'p': 33 else if (ENABLE_NC_SERVER && opt=='p')
54 lport = bb_lookup_port(optarg, "tcp", 0); 34 lport = bb_lookup_port(optarg, "tcp", 0);
35 else if (ENABLE_NC_EXTRA && opt=='w') wsecs = atoi(optarg);
36 else if (ENABLE_NC_EXTRA && opt=='i') delay = atoi(optarg);
37 else if (ENABLE_NC_EXTRA && opt=='f') infile = optarg;
38 else if (ENABLE_NC_EXTRA && opt=='e' && optind!=argc) {
39 execflag++;
55 break; 40 break;
56 case 'i': 41 } else bb_show_usage();
57 delay = atoi(optarg);
58 break;
59#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
60 case 'e':
61 pr00gie = optarg;
62 break;
63#endif
64 case 'w':
65 wsecs = atoi(optarg);
66 break;
67 default:
68 bb_show_usage();
69 } 42 }
70 } 43 }
71 44
72 if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc)) 45
73 bb_show_usage(); 46 // For listen or file we need zero arguments, dialout is 2.
47 // For exec we need at least one more argument at the end, more ok
74 48
75 sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0); 49 opt = (do_listen || infile) ? 0 : 2 + execflag;
76 x = 1; 50 if (execflag ? argc-optind < opt : argc-optind!=opt ||
77 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1) 51 (infile && do_listen))
78 bb_perror_msg_and_die("reuseaddr"); 52 bb_show_usage();
79 address.sin_family = AF_INET;
80 53
81 if (wsecs) { 54 if (wsecs) {
82 signal(SIGALRM, timeout); 55 signal(SIGALRM, timeout);
83 alarm(wsecs); 56 alarm(wsecs);
84 } 57 }
58
59 if (infile) cfd = bb_xopen(infile, O_RDWR);
60 else {
61 opt = 1;
62 sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
63 fcntl(sfd, F_SETFD, FD_CLOEXEC);
64 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
65 address.sin_family = AF_INET;
85 66
86 if (lport != 0) { 67 // Set local port.
87 memset(&address.sin_addr, 0, sizeof(address.sin_addr));
88 address.sin_port = lport;
89 68
90 bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address)); 69 if (lport != 0) {
91 } 70 address.sin_port = lport;
71
72 bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address));
73 }
74
75 if (do_listen) {
76 socklen_t addrlen = sizeof(address);
77
78 bb_xlisten(sfd, do_listen);
92 79
93 if (do_listen) { 80 // If we didn't specify a port number, query and print it to stderr.
94 socklen_t addrlen = sizeof(address);
95 81
96 bb_xlisten(sfd, 1); 82 if (!lport) {
97 if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) 83 socklen_t len = sizeof(address);
98 bb_perror_msg_and_die("accept"); 84 getsockname(sfd, &address, &len);
85 fdprintf(2, "%d\n", SWAP_BE16(address.sin_port));
86 }
87repeatyness:
88 if ((cfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
89 bb_perror_msg_and_die("accept");
99 90
100 close(sfd); 91 if (!execflag) close(sfd);
101 sfd = tmpfd; 92 } else {
102 } else { 93 hostinfo = xgethostbyname(argv[optind]);
103 hostinfo = xgethostbyname(argv[optind]);
104 94
105 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; 95 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
106 address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0); 96 address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
107 97
108 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) 98 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
109 bb_perror_msg_and_die("connect"); 99 bb_perror_msg_and_die("connect");
100 cfd = sfd;
101 }
110 } 102 }
111 103
112 if (wsecs) { 104 if (wsecs) {
@@ -114,24 +106,40 @@ int nc_main(int argc, char **argv)
114 signal(SIGALRM, SIG_DFL); 106 signal(SIGALRM, SIG_DFL);
115 } 107 }
116 108
117#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
118 /* -e given? */ 109 /* -e given? */
119 if (pr00gie) { 110 if (execflag) {
120 dup2(sfd, 0); 111 if(cfd) {
121 close(sfd); 112 signal(SIGCHLD, SIG_IGN);
113 dup2(cfd, 0);
114 close(cfd);
115 }
122 dup2(0, 1); 116 dup2(0, 1);
123 dup2(0, 2); 117 dup2(0, 2);
124 execl(pr00gie, pr00gie, NULL); 118
119 // With more than one -l, repeatedly act as server.
120
121 if (do_listen>1 && vfork()) {
122 // This is a bit weird as cleanup goes, since we wind up with no
123 // stdin/stdout/stderr. But it's small and shouldn't hurt anything.
124 // We check for cfd == 0 above.
125 close(0);
126 close(1);
127 close(2);
128
129 goto repeatyness;
130 }
131 execvp(argv[optind], argv+optind);
125 /* Don't print stuff or it will go over the wire.... */ 132 /* Don't print stuff or it will go over the wire.... */
126 _exit(-1); 133 _exit(127);
127 } 134 }
128#endif /* CONFIG_NC_GAPING_SECURITY_HOLE */
129 135
136 // Select loop copying stdin to cfd, and cfd to stdout.
137
130 FD_ZERO(&readfds); 138 FD_ZERO(&readfds);
131 FD_SET(sfd, &readfds); 139 FD_SET(cfd, &readfds);
132 FD_SET(STDIN_FILENO, &readfds); 140 FD_SET(STDIN_FILENO, &readfds);
133 141
134 while (1) { 142 for (;;) {
135 int fd; 143 int fd;
136 int ofd; 144 int ofd;
137 int nread; 145 int nread;
@@ -143,30 +151,24 @@ int nc_main(int argc, char **argv)
143 151
144 for (fd = 0; fd < FD_SETSIZE; fd++) { 152 for (fd = 0; fd < FD_SETSIZE; fd++) {
145 if (FD_ISSET(fd, &testfds)) { 153 if (FD_ISSET(fd, &testfds)) {
146 if ((nread = safe_read(fd, bb_common_bufsiz1, 154 nread = xread(fd, bb_common_bufsiz1, sizeof(bb_common_bufsiz1));
147 sizeof(bb_common_bufsiz1))) < 0)
148 {
149 bb_perror_msg_and_die(bb_msg_read_error);
150 }
151 155
152 if (fd == sfd) { 156 if (fd == cfd) {
153 if (nread == 0) 157 if (!nread) exit(0);
154 exit(0);
155 ofd = STDOUT_FILENO; 158 ofd = STDOUT_FILENO;
156 } else { 159 } else {
157 if (nread <= 0) { 160 if (!nread) {
158 shutdown(sfd, 1 /* send */ ); 161 // Close outgoing half-connection so they get EOF, but
159 close(STDIN_FILENO); 162 // leave incoming alone so we can see response.
163 shutdown(cfd, 1);
160 FD_CLR(STDIN_FILENO, &readfds); 164 FD_CLR(STDIN_FILENO, &readfds);
161 } 165 }
162 ofd = sfd; 166 ofd = cfd;
163 } 167 }
164 168
165 if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0) 169 if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0)
166 bb_perror_msg_and_die(bb_msg_write_error); 170 bb_perror_msg_and_die(bb_msg_write_error);
167 if (delay > 0) { 171 if (delay > 0) sleep(delay);
168 sleep(delay);
169 }
170 } 172 }
171 } 173 }
172 } 174 }