Mercurial > hg > toybox
comparison toys/other/netcat.c @ 694:786841fdb1e0
Reindent to two spaces per level. Remove vi: directives that haven't worked right in years (ubuntu broke its' vim implementation). Remove trailing spaces. Add/remove blank lines. Re-wordwrap in places. Update documentation with new coding style.
The actual code should be the same afterward, this is just cosmetic refactoring.
author | Rob Landley <rob@landley.net> |
---|---|
date | Tue, 13 Nov 2012 17:14:08 -0600 |
parents | 7e846e281e38 |
children | b4faf2ae39e8 |
comparison
equal
deleted
inserted
replaced
693:4a5a250e0633 | 694:786841fdb1e0 |
---|---|
1 /* vi: set sw=4 ts=4: | 1 /* netcat.c - Forward stdin/stdout to a file or network connection. |
2 * | |
3 * netcat.c - Forward stdin/stdout to a file or network connection. | |
4 * | 2 * |
5 * Copyright 2007 Rob Landley <rob@landley.net> | 3 * Copyright 2007 Rob Landley <rob@landley.net> |
6 * | 4 * |
7 * TODO: udp, ipv6, genericize for telnet/microcom/tail-f | 5 * TODO: udp, ipv6, genericize for telnet/microcom/tail-f |
8 | 6 |
9 | |
10 USE_NETCAT(OLDTOY(nc, netcat, USE_NETCAT_LISTEN("tl^L^")"w#p#s:q#f:", TOYFLAG_BIN)) | 7 USE_NETCAT(OLDTOY(nc, netcat, USE_NETCAT_LISTEN("tl^L^")"w#p#s:q#f:", TOYFLAG_BIN)) |
11 USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("tl^L^")"w#p#s:q#f:", TOYFLAG_BIN)) | 8 USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("tl^L^")"w#p#s:q#f:", TOYFLAG_BIN)) |
12 | 9 |
13 config NETCAT | 10 config NETCAT |
14 bool "netcat" | 11 bool "netcat" |
15 default y | 12 default y |
16 help | 13 help |
17 usage: netcat [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME|-let} [-e COMMAND] | 14 usage: netcat [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME|-let} [-e COMMAND] |
18 | 15 |
19 -w SECONDS timeout for connection | 16 -w SECONDS timeout for connection |
20 -p local port number | 17 -p local port number |
21 -s local ipv4 address | 18 -s local ipv4 address |
22 -q SECONDS quit this many seconds after EOF on stdin. | 19 -q SECONDS quit this many seconds after EOF on stdin. |
23 -f use FILENAME (ala /dev/ttyS0) instead of network | 20 -f use FILENAME (ala /dev/ttyS0) instead of network |
24 | 21 |
25 Use "stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho" with | 22 Use "stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho" with |
26 netcat -f to connect to a serial port. | 23 netcat -f to connect to a serial port. |
27 | |
28 | 24 |
29 config NETCAT_LISTEN | 25 config NETCAT_LISTEN |
30 bool "netcat server options (-let)" | 26 bool "netcat server options (-let)" |
31 default y | 27 default y |
32 depends on NETCAT | 28 depends on NETCAT |
33 help | 29 help |
34 -t allocate tty (must come before -l or -L) | 30 -t allocate tty (must come before -l or -L) |
35 -l listen for one incoming connection. | 31 -l listen for one incoming connection. |
36 -L listen for multiple incoming connections (server mode). | 32 -L listen for multiple incoming connections (server mode). |
37 | 33 |
38 Any additional command line arguments after -l or -L are executed | 34 Any additional command line arguments after -l or -L are executed |
39 to handle each incoming connection. If none, the connection is | 35 to handle each incoming connection. If none, the connection is |
40 forwarded to stdin/stdout. | 36 forwarded to stdin/stdout. |
41 | 37 |
42 For a quick-and-dirty server, try something like: | 38 For a quick-and-dirty server, try something like: |
43 netcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l | 39 netcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l |
44 */ | 40 */ |
45 | 41 |
46 #define FOR_netcat | 42 #define FOR_netcat |
47 #include "toys.h" | 43 #include "toys.h" |
48 #include "toynet.h" | 44 #include "toynet.h" |
49 | 45 |
50 GLOBALS( | 46 GLOBALS( |
51 char *filename; // -f read from filename instead of network | 47 char *filename; // -f read from filename instead of network |
52 long quit_delay; // -q Exit after EOF from stdin after # seconds. | 48 long quit_delay; // -q Exit after EOF from stdin after # seconds. |
53 char *source_address; // -s Bind to a specific source address. | 49 char *source_address; // -s Bind to a specific source address. |
54 long port; // -p Bind to a specific source port. | 50 long port; // -p Bind to a specific source port. |
55 long wait; // -w Wait # seconds for a connection. | 51 long wait; // -w Wait # seconds for a connection. |
56 ) | 52 ) |
57 | 53 |
58 static void timeout(int signum) | 54 static void timeout(int signum) |
59 { | 55 { |
60 if (TT.wait) error_exit("Timeout"); | 56 if (TT.wait) error_exit("Timeout"); |
61 exit(0); | 57 exit(0); |
62 } | 58 } |
63 | 59 |
64 static void set_alarm(int seconds) | 60 static void set_alarm(int seconds) |
65 { | 61 { |
66 signal(SIGALRM, seconds ? timeout : SIG_DFL); | 62 signal(SIGALRM, seconds ? timeout : SIG_DFL); |
67 alarm(seconds); | 63 alarm(seconds); |
68 } | 64 } |
69 | 65 |
70 // Translate x.x.x.x numeric IPv4 address, or else DNS lookup an IPv4 name. | 66 // Translate x.x.x.x numeric IPv4 address, or else DNS lookup an IPv4 name. |
71 static void lookup_name(char *name, uint32_t *result) | 67 static void lookup_name(char *name, uint32_t *result) |
72 { | 68 { |
73 struct hostent *hostbyname; | 69 struct hostent *hostbyname; |
74 | 70 |
75 hostbyname = gethostbyname(name); | 71 hostbyname = gethostbyname(name); |
76 if (!hostbyname) error_exit("no host '%s'", name); | 72 if (!hostbyname) error_exit("no host '%s'", name); |
77 *result = *(uint32_t *)*hostbyname->h_addr_list; | 73 *result = *(uint32_t *)*hostbyname->h_addr_list; |
78 } | 74 } |
79 | 75 |
80 // Worry about a fancy lookup later. | 76 // Worry about a fancy lookup later. |
81 static void lookup_port(char *str, uint16_t *port) | 77 static void lookup_port(char *str, uint16_t *port) |
82 { | 78 { |
83 *port = SWAP_BE16(atoi(str)); | 79 *port = SWAP_BE16(atoi(str)); |
84 } | 80 } |
85 | 81 |
86 void netcat_main(void) | 82 void netcat_main(void) |
87 { | 83 { |
88 int sockfd=-1, pollcount=2; | 84 int sockfd=-1, pollcount=2; |
89 struct pollfd pollfds[2]; | 85 struct pollfd pollfds[2]; |
90 | 86 |
91 memset(pollfds, 0, 2*sizeof(struct pollfd)); | 87 memset(pollfds, 0, 2*sizeof(struct pollfd)); |
92 pollfds[0].events = pollfds[1].events = POLLIN; | 88 pollfds[0].events = pollfds[1].events = POLLIN; |
93 set_alarm(TT.wait); | 89 set_alarm(TT.wait); |
94 | 90 |
95 // The argument parsing logic can't make "<2" conditional on other | 91 // The argument parsing logic can't make "<2" conditional on other |
96 // arguments like -f and -l, so we do it by hand here. | 92 // arguments like -f and -l, so we do it by hand here. |
97 if (toys.optflags&FLAG_f) { | 93 if (toys.optflags&FLAG_f) { |
98 if (toys.optc) toys.exithelp++; | 94 if (toys.optc) toys.exithelp++; |
99 } else if (!(toys.optflags&(FLAG_l|FLAG_L)) && toys.optc!=2) toys.exithelp++; | 95 } else if (!(toys.optflags&(FLAG_l|FLAG_L)) && toys.optc!=2) toys.exithelp++; |
100 | 96 |
101 if (toys.exithelp) error_exit("Argument count wrong"); | 97 if (toys.exithelp) error_exit("Argument count wrong"); |
102 | 98 |
103 if (TT.filename) pollfds[0].fd = xopen(TT.filename, O_RDWR); | 99 if (TT.filename) pollfds[0].fd = xopen(TT.filename, O_RDWR); |
104 else { | 100 else { |
105 int temp; | 101 int temp; |
106 struct sockaddr_in address; | 102 struct sockaddr_in address; |
107 | 103 |
108 // Setup socket | 104 // Setup socket |
109 sockfd = socket(AF_INET, SOCK_STREAM, 0); | 105 sockfd = socket(AF_INET, SOCK_STREAM, 0); |
110 if (-1 == sockfd) perror_exit("socket"); | 106 if (-1 == sockfd) perror_exit("socket"); |
111 fcntl(sockfd, F_SETFD, FD_CLOEXEC); | 107 fcntl(sockfd, F_SETFD, FD_CLOEXEC); |
112 temp = 1; | 108 temp = 1; |
113 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(temp)); | 109 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(temp)); |
114 memset(&address, 0, sizeof(address)); | 110 memset(&address, 0, sizeof(address)); |
115 address.sin_family = AF_INET; | 111 address.sin_family = AF_INET; |
116 if (TT.source_address || TT.port) { | 112 if (TT.source_address || TT.port) { |
117 address.sin_port = SWAP_BE16(TT.port); | 113 address.sin_port = SWAP_BE16(TT.port); |
118 if (TT.source_address) | 114 if (TT.source_address) |
119 lookup_name(TT.source_address, (uint32_t *)&address.sin_addr); | 115 lookup_name(TT.source_address, (uint32_t *)&address.sin_addr); |
120 if (bind(sockfd, (struct sockaddr *)&address, sizeof(address))) | 116 if (bind(sockfd, (struct sockaddr *)&address, sizeof(address))) |
121 perror_exit("bind"); | 117 perror_exit("bind"); |
122 } | 118 } |
123 | 119 |
124 // Dial out | 120 // Dial out |
125 | 121 |
126 if (!CFG_NETCAT_LISTEN || !(toys.optflags&(FLAG_L|FLAG_l))) { | 122 if (!CFG_NETCAT_LISTEN || !(toys.optflags&(FLAG_L|FLAG_l))) { |
127 // Figure out where to dial out to. | 123 // Figure out where to dial out to. |
128 lookup_name(*toys.optargs, (uint32_t *)&address.sin_addr); | 124 lookup_name(*toys.optargs, (uint32_t *)&address.sin_addr); |
129 lookup_port(toys.optargs[1], &address.sin_port); | 125 lookup_port(toys.optargs[1], &address.sin_port); |
130 temp = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); | 126 temp = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); |
131 if (temp<0) perror_exit("connect"); | 127 if (temp<0) perror_exit("connect"); |
132 pollfds[0].fd = sockfd; | 128 pollfds[0].fd = sockfd; |
133 | 129 |
134 // Listen for incoming connections | 130 // Listen for incoming connections |
135 | 131 |
136 } else { | 132 } else { |
137 socklen_t len = sizeof(address); | 133 socklen_t len = sizeof(address); |
138 | 134 |
139 if (listen(sockfd, 5)) error_exit("listen"); | 135 if (listen(sockfd, 5)) error_exit("listen"); |
140 if (!TT.port) { | 136 if (!TT.port) { |
141 getsockname(sockfd, (struct sockaddr *)&address, &len); | 137 getsockname(sockfd, (struct sockaddr *)&address, &len); |
142 printf("%d\n", SWAP_BE16(address.sin_port)); | 138 printf("%d\n", SWAP_BE16(address.sin_port)); |
143 fflush(stdout); | 139 fflush(stdout); |
144 } | 140 } |
145 // Do we need to return immediately because -l has arguments? | 141 // Do we need to return immediately because -l has arguments? |
146 | 142 |
147 if ((toys.optflags&FLAG_l) && toys.optc) { | 143 if ((toys.optflags&FLAG_l) && toys.optc) { |
148 if (fork()) goto cleanup; | 144 if (fork()) goto cleanup; |
149 close(0); | 145 close(0); |
150 close(1); | 146 close(1); |
151 close(2); | 147 close(2); |
152 } | 148 } |
153 | 149 |
154 for (;;) { | 150 for (;;) { |
155 pid_t child = 0; | 151 pid_t child = 0; |
156 | 152 |
157 // For -l, call accept from the _new_ thread. | 153 // For -l, call accept from the _new_ thread. |
158 | 154 |
159 pollfds[0].fd = accept(sockfd, (struct sockaddr *)&address, | 155 pollfds[0].fd = accept(sockfd, (struct sockaddr *)&address, &len); |
160 &len); | 156 if (pollfds[0].fd<0) perror_exit("accept"); |
161 if (pollfds[0].fd<0) perror_exit("accept"); | 157 |
162 | 158 // Do we need a tty? |
163 // Do we need a tty? | 159 |
164 | 160 if (toys.optflags&FLAG_t) |
165 if (toys.optflags&FLAG_t) | 161 child = forkpty(&(pollfds[1].fd), NULL, NULL, NULL); |
166 child = forkpty(&(pollfds[1].fd), NULL, NULL, NULL); | 162 |
167 | 163 // Do we need to fork and/or redirect for exec? |
168 // Do we need to fork and/or redirect for exec? | 164 |
169 | 165 else { |
170 else { | 166 if (toys.optflags&FLAG_L) child = fork(); |
171 if (toys.optflags&FLAG_L) child = fork(); | 167 if (!child && toys.optc) { |
172 if (!child && toys.optc) { | 168 int fd = pollfds[0].fd; |
173 int fd = pollfds[0].fd; | 169 |
174 | 170 if (!temp) close(sockfd); |
175 if (!temp) close(sockfd); | 171 dup2(fd, 0); |
176 dup2(fd, 0); | 172 dup2(fd, 1); |
177 dup2(fd, 1); | 173 dup2(fd, 2); |
178 dup2(fd, 2); | 174 if (fd>2) close(fd); |
179 if (fd>2) close(fd); | 175 } |
180 } | 176 } |
181 } | 177 |
182 | 178 if (child<0) error_msg("Fork failed\n"); |
183 if (child<0) error_msg("Fork failed\n"); | 179 if (child<1) break; |
184 if (child<1) break; | 180 close(pollfds[0].fd); |
185 close(pollfds[0].fd); | 181 } |
186 } | 182 } |
187 } | 183 } |
188 } | 184 |
189 | 185 // We have a connection. Disarm timeout. |
190 // We have a connection. Disarm timeout. | 186 // (Does not play well with -L, but what _should_ that do?) |
191 // (Does not play well with -L, but what _should_ that do?) | 187 set_alarm(0); |
192 set_alarm(0); | 188 |
193 | 189 if (CFG_NETCAT_LISTEN && (toys.optflags&(FLAG_L|FLAG_l) && toys.optc)) { |
194 if (CFG_NETCAT_LISTEN && (toys.optflags&(FLAG_L|FLAG_l) && toys.optc)) { | 190 execvp(*toys.optargs, toys.optargs); |
195 execvp(*toys.optargs, toys.optargs); | 191 error_exit("Exec failed"); |
196 error_exit("Exec failed"); | 192 } |
197 } | 193 |
198 | 194 // Poll loop copying stdin->socket and socket->stdout. |
199 // Poll loop copying stdin->socket and socket->stdout. | 195 for (;;) { |
200 for (;;) { | 196 int i; |
201 int i; | 197 |
202 | 198 if (0>poll(pollfds, pollcount, -1)) perror_exit("poll"); |
203 if (0>poll(pollfds, pollcount, -1)) perror_exit("poll"); | 199 |
204 | 200 for (i=0; i<pollcount; i++) { |
205 for (i=0; i<pollcount; i++) { | 201 if (pollfds[i].revents & POLLIN) { |
206 if (pollfds[i].revents & POLLIN) { | 202 int len = read(pollfds[i].fd, toybuf, sizeof(toybuf)); |
207 int len = read(pollfds[i].fd, toybuf, sizeof(toybuf)); | 203 if (len<1) goto dohupnow; |
208 if (len<1) goto dohupnow; | 204 xwrite(i ? pollfds[0].fd : 1, toybuf, len); |
209 xwrite(i ? pollfds[0].fd : 1, toybuf, len); | 205 } else if (pollfds[i].revents & POLLHUP) { |
210 } else if (pollfds[i].revents & POLLHUP) { | |
211 dohupnow: | 206 dohupnow: |
212 // Close half-connection. This is needed for things like | 207 // Close half-connection. This is needed for things like |
213 // "echo GET / | netcat landley.net 80" | 208 // "echo GET / | netcat landley.net 80" |
214 if (i) { | 209 if (i) { |
215 shutdown(pollfds[0].fd, SHUT_WR); | 210 shutdown(pollfds[0].fd, SHUT_WR); |
216 pollcount--; | 211 pollcount--; |
217 set_alarm(TT.quit_delay); | 212 set_alarm(TT.quit_delay); |
218 } else goto cleanup; | 213 } else goto cleanup; |
219 } | 214 } |
220 } | 215 } |
221 } | 216 } |
222 cleanup: | 217 cleanup: |
223 if (CFG_TOYBOX_FREE) { | 218 if (CFG_TOYBOX_FREE) { |
224 close(pollfds[0].fd); | 219 close(pollfds[0].fd); |
225 close(sockfd); | 220 close(sockfd); |
226 } | 221 } |
227 } | 222 } |