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 }