diff options
author | Rob Landley <rob@landley.net> | 2006-07-10 19:45:20 +0000 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2006-07-10 19:45:20 +0000 |
commit | 1cca9484db69971f652dfef48778da0dc56dad12 (patch) | |
tree | 71cb84ae857702f57bdced4a1e99b877499bfd4a /networking/nc.c | |
parent | 5d8843e451c01d8abfe6b5be772637310e9e581e (diff) | |
download | busybox-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.c | 202 |
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 | |||
30 | static void timeout(int signum) | 14 | static 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 | ||
35 | int nc_main(int argc, char **argv) | 19 | int 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 | } | ||
87 | repeatyness: | ||
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 | } |