aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-03 12:09:46 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-03 12:09:46 +0000
commitb933ac1e25ec160d86b27d0b6477812fdd01afa4 (patch)
tree00b49168ec81ef2999cfb8e158e269bff3f80cdb
parent992e05b6f070562d83f9238b227e1ddbf951c9af (diff)
downloadbusybox-w32-b933ac1e25ec160d86b27d0b6477812fdd01afa4.tar.gz
busybox-w32-b933ac1e25ec160d86b27d0b6477812fdd01afa4.tar.bz2
busybox-w32-b933ac1e25ec160d86b27d0b6477812fdd01afa4.zip
ipsvd: fixes and improvements after testing
-rw-r--r--ipsvd/Kbuild4
-rw-r--r--ipsvd/tcpudp.c (renamed from ipsvd/tcpsvd.c)498
-rw-r--r--ipsvd/udpsvd.c307
3 files changed, 349 insertions, 460 deletions
diff --git a/ipsvd/Kbuild b/ipsvd/Kbuild
index 9eda63d20..fc34fea49 100644
--- a/ipsvd/Kbuild
+++ b/ipsvd/Kbuild
@@ -5,5 +5,5 @@
5# Licensed under the GPL v2, see the file LICENSE in this tarball. 5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6 6
7lib-y:= 7lib-y:=
8lib-$(CONFIG_TCPSVD) += tcpsvd.o ipsvd_perhost.o 8lib-$(CONFIG_TCPSVD) += tcpudp.o ipsvd_perhost.o
9lib-$(CONFIG_UDPSVD) += udpsvd.o 9lib-$(CONFIG_UDPSVD) += tcpudp.o ipsvd_perhost.o
diff --git a/ipsvd/tcpsvd.c b/ipsvd/tcpudp.c
index 056deff33..419551d8d 100644
--- a/ipsvd/tcpsvd.c
+++ b/ipsvd/tcpudp.c
@@ -7,13 +7,295 @@
7 * Licensed under GPLv2, see file LICENSE in this tarball for details. 7 * Licensed under GPLv2, see file LICENSE in this tarball for details.
8 */ 8 */
9 9
10/* TCP and UDP server are using a lot of same string constants
11 * We reuse them by keeping both in one source file */
12
13#include "busybox.h"
14
15static unsigned verbose;
16
17static void sig_term_handler(int sig)
18{
19 if (verbose)
20 printf("%s: info: sigterm received, exit\n", applet_name);
21 exit(0);
22}
23
24/* Little bloated, but tries to give accurate info how child exited.
25 * Makes easier to spot segfaulting children etc... */
26static void print_waitstat(unsigned pid, int wstat)
27{
28 unsigned e = 0;
29 const char *cause = "?exit";
30
31 if (WIFEXITED(wstat)) {
32 cause++;
33 e = WEXITSTATUS(wstat);
34 } else if (WIFSIGNALED(wstat)) {
35 cause = "signal";
36 e = WTERMSIG(wstat);
37 }
38 printf("%s: info: end %d %s %d\n", applet_name, pid, cause, e);
39}
40
41
42#if ENABLE_UDPSVD
43/* Based on ipsvd ipsvd-0.12.1. This udpsvd accepts all options
44 * which are supported by one from ipsvd-0.12.1, but not all are
45 * functional. See help text at the end of this file for details.
46 *
47 * Output of verbose mode matches original (modulo bugs and
48 * unimplemented stuff). Unnatural splitting of IP and PORT
49 * is retained (personally I prefer one-value "IP:PORT" notation -
50 * it is a natural string representation of struct sockaddr_XX).
51 */
52
53#include "udp_io.c"
54
55int udpsvd_main(int argc, char **argv);
56int udpsvd_main(int argc, char **argv)
57{
58 const char *instructs;
59 char *str_t, *user;
60 unsigned opt;
61
62 char *remote_hostname = (char*)""; /* used if no -h */
63 char *local_hostname = NULL;
64 char *remote_ip;
65 char *local_ip;// = local_ip; /* gcc */
66 uint16_t local_port, remote_port;
67 len_and_sockaddr remote;
68 len_and_sockaddr *localp;
69 int wstat;
70 unsigned pid;
71 struct bb_uidgid_t ugid;
72
73 enum {
74 OPT_v = (1 << 0),
75 OPT_u = (1 << 1),
76 OPT_l = (1 << 2),
77 OPT_h = (1 << 3),
78 OPT_p = (1 << 4),
79 OPT_i = (1 << 5),
80 OPT_x = (1 << 6),
81 OPT_t = (1 << 7),
82 };
83
84 opt_complementary = "-3:ph:vv";
85 opt = getopt32(argc, argv, "vu:l:hpi:x:t:",
86 &user, &local_hostname, &instructs, &instructs, &str_t, &verbose);
87 if (opt & OPT_u) {
88 if (!get_uidgid(&ugid, user, 1))
89 bb_error_msg_and_die("unknown user/group: %s", user);
90 }
91 argv += optind;
92 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
93 argv[0] = (char*)"0.0.0.0";
94
95 /* stdout is used for logging, don't buffer */
96 setlinebuf(stdout);
97 bb_sanitize_stdio(); /* fd# 1,2 must be opened */
98
99 signal(SIGTERM, sig_term_handler);
100 signal(SIGPIPE, SIG_IGN);
101
102 local_port = bb_lookup_port(argv[1], "udp", 0);
103 localp = xhost2sockaddr(argv[0], local_port);
104 /* fd #0 is the open UDP socket */
105 xmove_fd(xsocket(localp->sa.sa_family, SOCK_DGRAM, 0), 0);
106 setsockopt_reuseaddr(0); /* crucial */
107 xbind(0, &localp->sa, localp->len);
108 socket_want_pktinfo(0); /* needed for recv_from_to to work */
109
110 if (opt & OPT_u) { /* drop permissions */
111 xsetgid(ugid.gid);
112 xsetuid(ugid.uid);
113 }
114
115 if (verbose) {
116 /* we do it only for ":port" cosmetics... oh well */
117 char *addr = xmalloc_sockaddr2dotted(&localp->sa, localp->len);
118
119 printf("%s: info: listening on %s", applet_name, addr);
120 free(addr);
121 if (option_mask32 & OPT_u)
122 printf(", uid %u, gid %u",
123 (unsigned)ugid.uid, (unsigned)ugid.gid);
124 puts(", starting");
125 }
126
127 again:
128 /* if (recvfrom(0, NULL, 0, MSG_PEEK, &remote.sa, &localp->len) < 0) { */
129 if (recv_from_to(0, NULL, 0, MSG_PEEK, &remote.sa, &localp->sa, localp->len) < 0) {
130 bb_perror_msg("recvfrom");
131 goto again;
132 }
133
134 while ((pid = fork()) < 0) {
135 bb_perror_msg("fork failed, sleeping");
136 sleep(5);
137 }
138 if (pid > 0) { /* parent */
139 while (wait_pid(&wstat, pid) < 0)
140 bb_perror_msg("error waiting for child");
141 if (verbose)
142 print_waitstat(pid, wstat);
143 goto again;
144 }
145
146 /* Child */
147
148 if (verbose) {
149 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, localp->len);
150 local_ip = xmalloc_sockaddr2dotted_noport(&localp->sa, localp->len);
151
152 pid = getpid();
153 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
154
155 if (!local_hostname) {
156 local_hostname = xmalloc_sockaddr2host_noport(&localp->sa, localp->len);
157 if (!local_hostname)
158 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
159 }
160 if (opt & OPT_h) {
161 remote_hostname = xmalloc_sockaddr2host(&remote.sa, localp->len);
162 if (!remote_hostname) {
163 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
164 remote_hostname = (char*)"";
165 }
166 }
167
168 remote_port = get_nport(&remote.sa);
169 remote_port = ntohs(remote_port);
170 printf("%s: info: %u %s:%s :%s:%s:%u\n",
171 applet_name, pid, local_hostname, local_ip,
172 remote_hostname, remote_ip, remote_port);
173 }
174
175 /* Doesn't work:
176 * we cannot replace fd #0 - we will lose pending packet
177 * which is already buffered for us! And we cannot use fd #1
178 * instead - it will "intercept" all following packets, but child
179 * do not expect data coming *from fd #1*! */
180#if 0
181 /* Make it so that local addr is fixed to localp->sa
182 * and we don't accidentally accept packets to other local IPs. */
183 /* NB: we possibly bind to the _very_ same_ address & port as the one
184 * already bound in parent! This seems to work in Linux.
185 * (otherwise we can move socket to fd #0 only if bind succeeds) */
186 close(0);
187 set_nport(localp, htons(local_port));
188 xmove_fd(xsocket(localp->sa.sa_family, SOCK_DGRAM, 0), 0);
189 setsockopt_reuseaddr(0); /* crucial */
190 xbind(0, &localp->sa, localp->len);
191#endif
192
193 /* Make plain write to fd #1 work for the child by supplying default
194 * destination address. This also restricts incoming packets
195 * to ones coming from this remote IP. */
196 xconnect(0, &remote.sa, localp->len);
197 dup2(0 ,1);
198
199 signal(SIGTERM, SIG_DFL);
200 signal(SIGPIPE, SIG_DFL);
201
202 argv += 2;
203 BB_EXECVP(argv[0], argv);
204 bb_perror_msg_and_die("exec '%s'", argv[0]);
205}
206
207
208/*
209udpsvd [-hpvv] [-u user] [-l name] [-i dir|-x cdb] [-t sec] host port prog
210
211udpsvd creates an UDP/IP socket, binds it to the address host:port,
212and listens on the socket for incoming datagrams.
213
214If a datagram is available on the socket, udpsvd conditionally starts
215a program, with standard input reading from the socket, and standard
216output redirected to standard error, to handle this, and possibly
217more datagrams. udpsvd does not start the program if another program
218that it has started before still is running. If the program exits,
219udpsvd again listens to the socket until a new datagram is available.
220If there are still datagrams available on the socket, the program
221is restarted immediately.
222
223udpsvd optionally checks for special intructions depending on
224the IP address or hostname of the client sending the datagram which
225not yet was handled by a running program, see ipsvd-instruct(5)
226for details.
227
228Attention:
229UDP is a connectionless protocol. Most programs that handle user datagrams,
230such as talkd(8), keep running after receiving a datagram, and process
231subsequent datagrams sent to the socket until a timeout is reached.
232udpsvd only checks special instructions for a datagram that causes a startup
233of the program; not if a program handling datagrams already is running.
234It doesn't make much sense to restrict access through special instructions
235when using such a program.
236
237On the other hand, it makes perfectly sense with programs like tftpd(8),
238that fork to establish a separate connection to the client when receiving
239the datagram. In general it's adequate to set up special instructions for
240programs that support being run by tcpwrapper.
241Options
242
243host
244 host either is a hostname, or a dotted-decimal IP address, or 0.
245 If host is 0, udpsvd accepts datagrams to any local IP address.
246port
247 udpsvd accepts datagrams to host:port. port may be a name from
248 /etc/services or a number.
249prog
250 prog consists of one or more arguments. udpsvd normally runs prog
251 to handle a datagram, and possibly more, that is sent to the socket,
252 if there is no program that was started before by udpsvd still running
253 and handling datagrams.
254-i dir
255 read instructions for handling new connections from the instructions
256 directory dir. See ipsvd-instruct(5) for details.
257-x cdb
258 read instructions for handling new connections from the constant
259 database cdb. The constant database normally is created from
260 an instructions directory by running ipsvd-cdb(8).
261-t sec
262 timeout. This option only takes effect if the -i option is given.
263 While checking the instructions directory, check the time of last
264 access of the file that matches the clients address or hostname if any,
265 discard and remove the file if it wasn't accessed within the last
266 sec seconds; udpsvd does not discard or remove a file if the user's
267 write permission is not set, for those files the timeout is disabled.
268 Default is 0, which means that the timeout is disabled.
269-l name
270 local hostname. Do not look up the local hostname in DNS, but use name
271 as hostname. By default udpsvd looks up the local hostname once at startup.
272-u user[:group]
273 drop permissions. Switch user ID to user's UID, and group ID to user's
274 primary GID after creating and binding to the socket. If user
275 is followed by a colon and a group name, the group ID is switched
276 to the GID of group instead. All supplementary groups are removed.
277-h
278 Look up the client's hostname in DNS.
279-p
280 paranoid. After looking up the client's hostname in DNS, look up
281 the IP addresses in DNS for that hostname, and forget the hostname
282 if none of the addresses match the client's IP address. You should
283 set this option if you use hostname based instructions. The -p option
284 implies the -h option.
285-v
286 verbose. Print verbose messages to standard output.
287-vv
288 more verbose. Print more verbose messages to standard output.
289*/
290#endif
291
292
293#if ENABLE_TCPSVD
10/* Based on ipsvd ipsvd-0.12.1. This tcpsvd accepts all options 294/* Based on ipsvd ipsvd-0.12.1. This tcpsvd accepts all options
11 * which are supported by one from ipsvd-0.12.1, but not all are 295 * which are supported by one from ipsvd-0.12.1, but not all are
12 * functional. See help text at the end of this file for details. 296 * functional. See help text at the end of this file for details.
13 * 297 *
14 * Code inside "#ifdef SSLSVD" is for sslsvd and is currently unused. 298 * Code inside "#ifdef SSLSVD" is for sslsvd and is currently unused.
15 * Code inside #if 0" is parts of original tcpsvd which are not implemented
16 * for busyboxed version.
17 * 299 *
18 * Output of verbose mode matches original (modulo bugs and 300 * Output of verbose mode matches original (modulo bugs and
19 * unimplemented stuff). Unnatural splitting of IP and PORT 301 * unimplemented stuff). Unnatural splitting of IP and PORT
@@ -25,7 +307,6 @@
25 307
26#include <limits.h> 308#include <limits.h>
27#include <linux/netfilter_ipv4.h> /* wants <limits.h> */ 309#include <linux/netfilter_ipv4.h> /* wants <limits.h> */
28#include "busybox.h"
29#include "ipsvd_perhost.h" 310#include "ipsvd_perhost.h"
30 311
31#ifdef SSLSVD 312#ifdef SSLSVD
@@ -33,10 +314,8 @@
33#include "ssl_io.h" 314#include "ssl_io.h"
34#endif 315#endif
35 316
36
37static unsigned max_per_host; /* originally in ipsvd_check.c */ 317static unsigned max_per_host; /* originally in ipsvd_check.c */
38static unsigned cur_per_host; 318static unsigned cur_per_host;
39static unsigned verbose;
40static unsigned cnum; 319static unsigned cnum;
41static unsigned cmax = 30; 320static unsigned cmax = 30;
42 321
@@ -66,13 +345,6 @@ static void connection_status(void)
66 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax); 345 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
67} 346}
68 347
69static void sig_term_handler(int sig)
70{
71 if (verbose)
72 printf("%s: info: sigterm received, exit\n", applet_name);
73 exit(0);
74}
75
76static void sig_child_handler(int sig) 348static void sig_child_handler(int sig)
77{ 349{
78 int wstat; 350 int wstat;
@@ -83,22 +355,8 @@ static void sig_child_handler(int sig)
83 ipsvd_perhost_remove(pid); 355 ipsvd_perhost_remove(pid);
84 if (cnum) 356 if (cnum)
85 cnum--; 357 cnum--;
86 if (verbose) { 358 if (verbose)
87 /* Little bloated, but tries to give accurate info 359 print_waitstat(pid, wstat);
88 * how child exited. Makes easier to spot segfaulting
89 * children etc... */
90 unsigned e = 0;
91 const char *cause = "?exit";
92 if (WIFEXITED(wstat)) {
93 cause++;
94 e = WEXITSTATUS(wstat);
95 } else if (WIFSIGNALED(wstat)) {
96 cause = "signal";
97 e = WTERMSIG(wstat);
98 }
99 printf("%s: info: end %d %s %d\n",
100 applet_name, pid, cause, e);
101 }
102 } 360 }
103 if (verbose) 361 if (verbose)
104 connection_status(); 362 connection_status();
@@ -118,20 +376,13 @@ int tcpsvd_main(int argc, char **argv)
118 int sock; 376 int sock;
119 int conn; 377 int conn;
120 unsigned backlog = 20; 378 unsigned backlog = 20;
121 union { 379 len_and_sockaddr *lsa;
122 struct sockaddr sa; 380 uint16_t local_port;
123 struct sockaddr_in sin; 381 uint16_t remote_port = remote_port; /* gcc */
124 USE_FEATURE_IPV6(struct sockaddr_in6 sin6;)
125 } sock_adr;
126 socklen_t sockadr_size;
127 uint16_t local_port = local_port;
128 uint16_t remote_port;
129 char *local_hostname = NULL; 382 char *local_hostname = NULL;
130 char *remote_hostname = (char*)""; /* "" used if no -h */ 383 char *remote_hostname = (char*)""; /* "" used if no -h */
131 char *local_ip = local_ip; /* gcc */ 384 char *local_ip = local_ip; /* gcc */
132 char *remote_ip = remote_ip; /* gcc */ 385 char *remote_ip = remote_ip; /* gcc */
133 //unsigned iscdb = 0; /* = option_mask32 & OPT_x (TODO) */
134 //unsigned long timeout = 0;
135#ifndef SSLSVD 386#ifndef SSLSVD
136 struct bb_uidgid_t ugid; 387 struct bb_uidgid_t ugid;
137#endif 388#endif
@@ -168,7 +419,6 @@ int tcpsvd_main(int argc, char **argv)
168 } 419 }
169 if (option_mask32 & OPT_b) 420 if (option_mask32 & OPT_b)
170 backlog = xatou(str_b); 421 backlog = xatou(str_b);
171// if (option_mask32 & OPT_t) timeout = xatou(str_t);
172#ifdef SSLSVD 422#ifdef SSLSVD
173 if (option_mask32 & OPT_U) ssluser = (char*)optarg; break; 423 if (option_mask32 & OPT_U) ssluser = (char*)optarg; break;
174 if (option_mask32 & OPT_slash) root = (char*)optarg; break; 424 if (option_mask32 & OPT_slash) root = (char*)optarg; break;
@@ -224,7 +474,10 @@ int tcpsvd_main(int argc, char **argv)
224 ipsvd_perhost_init(cmax); 474 ipsvd_perhost_init(cmax);
225 475
226 local_port = bb_lookup_port(argv[1], "tcp", 0); 476 local_port = bb_lookup_port(argv[1], "tcp", 0);
227 sock = create_and_bind_stream_or_die(argv[0], local_port); 477 lsa = xhost2sockaddr(argv[0], local_port);
478 sock = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
479 setsockopt_reuseaddr(sock); /* desirable */
480 xbind(sock, &lsa->sa, lsa->len);
228 xlisten(sock, backlog); 481 xlisten(sock, backlog);
229 /* ndelay_off(sock); - it is the default I think? */ 482 /* ndelay_off(sock); - it is the default I think? */
230 483
@@ -235,11 +488,9 @@ int tcpsvd_main(int argc, char **argv)
235 xsetuid(ugid.uid); 488 xsetuid(ugid.uid);
236 } 489 }
237#endif 490#endif
238 close(0);
239 491
240 if (verbose) { 492 if (verbose) {
241 /* we do it only for ":port" cosmetics... oh well */ 493 /* we do it only for ":port" cosmetics... oh well */
242 len_and_sockaddr *lsa = xhost2sockaddr(argv[0], local_port);
243 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len); 494 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len);
244 495
245 printf("%s: info: listening on %s", applet_name, addr); 496 printf("%s: info: listening on %s", applet_name, addr);
@@ -260,32 +511,35 @@ int tcpsvd_main(int argc, char **argv)
260 while (cnum >= cmax) 511 while (cnum >= cmax)
261 sig_pause(); /* wait for any signal (expecting SIGCHLD) */ 512 sig_pause(); /* wait for any signal (expecting SIGCHLD) */
262 513
263 sockadr_size = sizeof(sock_adr); 514 /* Accept a connection to fd #0 */
515 again1:
516 close(0);
517 again2:
264 sig_unblock(SIGCHLD); 518 sig_unblock(SIGCHLD);
265 conn = accept(sock, &sock_adr.sa, &sockadr_size); 519 conn = accept(sock, &lsa->sa, &lsa->len);
266 sig_block(SIGCHLD); 520 sig_block(SIGCHLD);
267 if (conn == -1) { 521 if (conn < 0) {
268 if (errno != EINTR) 522 if (errno != EINTR)
269 bb_perror_msg("accept"); 523 bb_perror_msg("accept");
270 goto again; 524 goto again2;
271 } 525 }
526 xmove_fd(conn, 0);
272 527
273 if (max_per_host) { 528 if (max_per_host) {
274 /* we drop connection immediately if cur_per_host > max_per_host 529 /* Drop connection immediately if cur_per_host > max_per_host
275 * (minimizing load under SYN flood) */ 530 * (minimizing load under SYN flood) */
276 remote_ip = xmalloc_sockaddr2dotted_noport(&sock_adr.sa, sockadr_size); 531 remote_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
277 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp); 532 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
278 if (cur_per_host > max_per_host) { 533 if (cur_per_host > max_per_host) {
279 free(remote_ip);
280 /* ipsvd_perhost_add detected that max is exceeded 534 /* ipsvd_perhost_add detected that max is exceeded
281 * (and did not store us in connection table) */ 535 * (and did not store ip in connection table) */
536 free(remote_ip);
282 if (msg_per_host) { 537 if (msg_per_host) {
283 ndelay_on(conn); 538 /* don't block or test for errors */
284 /* don't test for errors */ 539 ndelay_on(0);
285 write(conn, msg_per_host, len_per_host); 540 write(0, msg_per_host, len_per_host);
286 } 541 }
287 close(conn); 542 goto again1;
288 goto again;
289 } 543 }
290 } 544 }
291 545
@@ -296,12 +550,10 @@ int tcpsvd_main(int argc, char **argv)
296 pid = fork(); 550 pid = fork();
297 if (pid == -1) { 551 if (pid == -1) {
298 bb_perror_msg("fork"); 552 bb_perror_msg("fork");
299 close(conn);
300 goto again; 553 goto again;
301 } 554 }
302 if (pid != 0) { 555 if (pid != 0) {
303 /* parent */ 556 /* parent */
304 close(conn);
305 if (hccp) 557 if (hccp)
306 hccp->pid = pid; 558 hccp->pid = pid;
307 goto again; 559 goto again;
@@ -309,44 +561,50 @@ int tcpsvd_main(int argc, char **argv)
309 561
310 /* Child: prepare env, log, and exec prog */ 562 /* Child: prepare env, log, and exec prog */
311 563
312 close(sock); 564 close(sock); /* listening socket */
313 565 /* Find out local IP peer connected to.
314 if (!max_per_host && need_remote_ip) 566 * Errors ignored (I'm not paranoid enough to imagine kernel
315 remote_ip = xmalloc_sockaddr2dotted_noport(&sock_adr.sa, sizeof(sock_adr)); 567 * which doesn't know local IP). */
316 /* else it is already done */ 568 getsockname(0, &lsa->sa, &lsa->len);
317 569
318 remote_port = get_nport(&sock_adr.sa); 570 if (need_remote_ip) {
319 remote_port = ntohs(remote_port); 571 if (!max_per_host)
320 572 remote_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
321 if (verbose) { 573 /* else it is already done */
322 pid = getpid(); 574 remote_port = get_nport(&lsa->sa);
323 printf("%s: info: pid %d from %s\n", applet_name, pid, remote_ip); 575 remote_port = ntohs(remote_port);
324 }
325
326 if (need_hostnames && (option_mask32 & OPT_h)) {
327 remote_hostname = xmalloc_sockaddr2host(&sock_adr.sa, sizeof(sock_adr));
328 if (!remote_hostname) {
329 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
330 remote_hostname = (char*)"";
331 }
332 } 576 }
333 577
334 sockadr_size = sizeof(sock_adr);
335 /* Errors ignored (I'm not paranoid enough to imagine kernel
336 * which doesn't know local ip) */
337 getsockname(conn, &sock_adr.sa, &sockadr_size);
338
339 if (need_hostnames) { 578 if (need_hostnames) {
340 local_ip = xmalloc_sockaddr2dotted_noport(&sock_adr.sa, sockadr_size); 579 if (option_mask32 & OPT_h) {
341 local_port = get_nport(&sock_adr.sa); 580 remote_hostname = xmalloc_sockaddr2host(&lsa->sa, lsa->len);
581 if (!remote_hostname) {
582 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
583 remote_hostname = (char*)"";
584 }
585 }
586 local_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
587 local_port = get_nport(&lsa->sa);
342 local_port = ntohs(local_port); 588 local_port = ntohs(local_port);
343 if (!local_hostname) { 589 if (!local_hostname) {
344 local_hostname = xmalloc_sockaddr2host_noport(&sock_adr.sa, sockadr_size); 590 local_hostname = xmalloc_sockaddr2host_noport(&lsa->sa, lsa->len);
345 if (!local_hostname) 591 if (!local_hostname)
346 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip); 592 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
347 } 593 }
348 } 594 }
349 595
596 if (verbose) {
597 pid = getpid();
598 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
599 if (max_per_host)
600 printf("%s: info: concurrency %u %s %u/%u\n",
601 applet_name, pid, remote_ip, cur_per_host, max_per_host);
602 printf("%s: info: start %u %s:%s :%s:%s:%u\n",
603 applet_name, pid,
604 local_hostname, local_ip,
605 remote_hostname, remote_ip, (unsigned)remote_port);
606 }
607
350 if (!(option_mask32 & OPT_E)) { 608 if (!(option_mask32 & OPT_E)) {
351 /* setup ucspi env */ 609 /* setup ucspi env */
352 610
@@ -354,10 +612,9 @@ int tcpsvd_main(int argc, char **argv)
354 * from Linux firewall. Useful when you redirect 612 * from Linux firewall. Useful when you redirect
355 * an outbond connection to local handler, and it needs 613 * an outbond connection to local handler, and it needs
356 * to know where it originally tried to connect */ 614 * to know where it originally tried to connect */
357 sockadr_size = sizeof(sock_adr); 615 if (getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) {
358 if (getsockopt(conn, SOL_IP, SO_ORIGINAL_DST, &sock_adr.sa, &sockadr_size) == 0) { 616 char *ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
359 char *ip = xmalloc_sockaddr2dotted_noport(&sock_adr.sa, sockadr_size); 617 unsigned port = get_nport(&lsa->sa);
360 unsigned port = get_nport(&sock_adr.sa);
361 port = ntohs(port); 618 port = ntohs(port);
362 xsetenv("TCPORIGDSTIP", ip); 619 xsetenv("TCPORIGDSTIP", ip);
363 xsetenv("TCPORIGDSTPORT", utoa(port)); 620 xsetenv("TCPORIGDSTPORT", utoa(port));
@@ -378,68 +635,6 @@ int tcpsvd_main(int argc, char **argv)
378 xsetenv("TCPCONCURRENCY", utoa(cur_per_host)); 635 xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
379 } 636 }
380 637
381#if 0
382 if (instructs) {
383 ac = ipsvd_check(iscdb, &inst, &match, (char*)instructs,
384 remote_ip, remote_hostname, timeout);
385 if (ac == -1) drop2("cannot check inst", remote_ip);
386 if (ac == IPSVD_ERR) drop2("cannot read", (char*)instructs);
387 } else
388 ac = IPSVD_DEFAULT;
389#endif
390
391 if (max_per_host && verbose)
392 printf("%s: info: concurrency %u %s %u/%u\n",
393 applet_name, pid, remote_ip, cur_per_host, max_per_host);
394
395 if (verbose) {
396 printf("%s: info: start %u %s:%s :%s:%s:%u\n",
397 applet_name, pid,
398 local_hostname, local_ip,
399 remote_hostname, remote_ip, (unsigned)remote_port);
400#if 0
401 switch(ac) {
402 case IPSVD_DENY:
403 printf("deny "); break;
404 case IPSVD_DEFAULT:
405 case IPSVD_INSTRUCT:
406 printf("start "); break;
407 case IPSVD_EXEC:
408 printf("exec "); break;
409 }
410 ...
411 if (instructs) {
412 printf(" ");
413 if (iscdb) {
414 printf((char*)instructs);
415 printf("/");
416 }
417 outfix(match.s);
418 if(inst.s && inst.len && (verbose > 1)) {
419 printf(": ");
420 printf(&inst);
421 }
422 }
423 printf("\n");
424#endif
425 }
426
427#if 0
428 if (ac == IPSVD_DENY) {
429 close(conn);
430 _exit(100);
431 }
432 if (ac == IPSVD_EXEC) {
433 args[0] = "/bin/sh";
434 args[1] = "-c";
435 args[2] = inst.s;
436 args[3] = 0;
437 run = args;
438 } else
439 run = argv + 2; /* below: we use argv+2 (was using run) */
440#endif
441
442 xmove_fd(conn, 0);
443 dup2(0, 1); 638 dup2(0, 1);
444 639
445 signal(SIGTERM, SIG_DFL); 640 signal(SIGTERM, SIG_DFL);
@@ -552,3 +747,4 @@ prog
552 more verbose. Print more verbose messages to standard output. 747 more verbose. Print more verbose messages to standard output.
553 * no difference between -v and -vv in busyboxed version 748 * no difference between -v and -vv in busyboxed version
554*/ 749*/
750#endif
diff --git a/ipsvd/udpsvd.c b/ipsvd/udpsvd.c
deleted file mode 100644
index 700e1aff4..000000000
--- a/ipsvd/udpsvd.c
+++ /dev/null
@@ -1,307 +0,0 @@
1/* Based on ipsvd utilities written by Gerrit Pape <pape@smarden.org>
2 * which are released into public domain by the author.
3 * Homepage: http://smarden.sunsite.dk/ipsvd/
4 *
5 * Copyright (C) 2007 Denis Vlasenko.
6 *
7 * Licensed under GPLv2, see file LICENSE in this tarball for details.
8 */
9
10/* Based on ipsvd ipsvd-0.12.1. This tcpsvd accepts all options
11 * which are supported by one from ipsvd-0.12.1, but not all are
12 * functional. See help text at the end of this file for details.
13 *
14 * Code inside #if 0" is parts of original tcpsvd which are not implemented
15 * for busyboxed version.
16 *
17 * Output of verbose mode matches original (modulo bugs and
18 * unimplemented stuff). Unnatural splitting of IP and PORT
19 * is retained (personally I prefer one-value "IP:PORT" notation -
20 * it is a natural string representation of struct sockaddr_XX).
21 */
22
23#include "busybox.h"
24
25#include "udp_io.c"
26
27unsigned verbose;
28
29static void sig_term_handler(int sig)
30{
31 if (verbose)
32 printf("%s: info: sigterm received, exit\n", applet_name);
33 exit(0);
34}
35
36int udpsvd_main(int argc, char **argv);
37int udpsvd_main(int argc, char **argv)
38{
39 const char *instructs;
40 char *str_t, *user;
41 unsigned opt;
42
43 char *remote_hostname;
44 char *local_hostname = NULL;
45 char *remote_ip;
46 char *local_ip = local_ip; /* gcc */
47 uint16_t local_port, remote_port;
48 len_and_sockaddr remote;
49 len_and_sockaddr *localp;
50 int sock;
51 int wstat;
52 unsigned pid;
53 struct bb_uidgid_t ugid;
54
55 enum {
56 OPT_v = (1 << 0),
57 OPT_u = (1 << 1),
58 OPT_l = (1 << 2),
59 OPT_h = (1 << 3),
60 OPT_p = (1 << 4),
61 OPT_i = (1 << 5),
62 OPT_x = (1 << 6),
63 OPT_t = (1 << 7),
64 };
65
66 opt_complementary = "-3:ph:vv";
67 opt = getopt32(argc, argv, "vu:l:hpi:x:t:",
68 &user, &local_hostname, &instructs, &instructs, &str_t, &verbose);
69 //if (opt & OPT_x) iscdb =1;
70 //if (opt & OPT_t) timeout = xatou(str_t);
71 if (!(opt & OPT_h))
72 remote_hostname = (char *)"";
73 if (opt & OPT_u) {
74 if (!get_uidgid(&ugid, user, 1))
75 bb_error_msg_and_die("unknown user/group: %s", user);
76 }
77 argv += optind;
78 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
79 argv[0] = (char*)"0.0.0.0";
80
81 /* stdout is used for logging, don't buffer */
82 setlinebuf(stdout);
83 bb_sanitize_stdio(); /* fd# 1,2 must be opened */
84
85 signal(SIGTERM, sig_term_handler);
86 signal(SIGPIPE, SIG_IGN);
87
88 local_port = bb_lookup_port(argv[1], "udp", 0);
89 localp = xhost2sockaddr(argv[0], local_port);
90 sock = xsocket(localp->sa.sa_family, SOCK_DGRAM, 0);
91 xmove_fd(sock, 0); /* fd# 0 is the open UDP socket */
92 xbind(0, &localp->sa, localp->len);
93 socket_want_pktinfo(0);
94
95 if (opt & OPT_u) { /* drop permissions */
96 xsetgid(ugid.gid);
97 xsetuid(ugid.uid);
98 }
99
100 if (verbose) {
101 /* we do it only for ":port" cosmetics... oh well */
102 char *addr = xmalloc_sockaddr2dotted(&localp->sa, localp->len);
103 printf("%s: info: listening on %s", applet_name, addr);
104 free(addr);
105 if (option_mask32 & OPT_u)
106 printf(", uid %u, gid %u",
107 (unsigned)ugid.uid, (unsigned)ugid.gid);
108 puts(", starting");
109 }
110
111 again:
112 /* if (recvfrom(0, NULL, 0, MSG_PEEK, &remote.sa, &localp->len) < 0) { */
113 if (recv_from_to(0, NULL, 0, MSG_PEEK, &remote.sa, &localp->sa, localp->len) < 0) {
114 bb_perror_msg("recvfrom");
115 goto again;
116 }
117
118 while ((pid = fork()) < 0) {
119 bb_perror_msg("fork failed, sleeping");
120 sleep(5);
121 }
122 if (pid > 0) { /* parent */
123 while (wait_pid(&wstat, pid) == -1)
124 bb_perror_msg("error waiting for child");
125 if (verbose)
126 printf("%s: info: end %u\n", applet_name, pid);
127 goto again;
128 }
129
130 /* Child */
131
132#if 0
133 /* I'd like to make it so that local addr is fixed to localp->sa,
134 * but how? The below trick doesn't work... */
135 close(0);
136 set_nport(localp, htons(local_port));
137 xmove_fd(xsocket(localp->sa.sa_family, SOCK_DGRAM, 0), 0);
138 xbind(0, &localp->sa, localp->len);
139#endif
140
141 if (verbose) {
142 local_ip = xmalloc_sockaddr2dotted_noport(&localp->sa, localp->len);
143 if (!local_hostname) {
144 local_hostname = xmalloc_sockaddr2host_noport(&localp->sa, localp->len);
145 if (!local_hostname)
146 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
147 }
148 }
149
150 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, localp->len);
151 remote_port = get_nport(&remote.sa);
152 remote_port = ntohs(remote_port);
153 if (verbose)
154 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
155
156 if (opt & OPT_h) {
157 remote_hostname = xmalloc_sockaddr2host(&remote.sa, localp->len);
158 if (!remote_hostname) {
159 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
160 remote_hostname = (char*)"";
161 }
162 }
163
164#if 0
165 if (instructs) {
166 ac = ipsvd_check(iscdb, &inst, &match, (char*)instructs,
167 remote_ip, remote_hostname.s, timeout);
168 if (ac == -1) discard("unable to check inst", remote_ip);
169 if (ac == IPSVD_ERR) discard("unable to read", (char*)instructs);
170 } else
171 ac = IPSVD_DEFAULT;
172#endif
173
174 if (verbose) {
175#if 0
176 out("%s: info: ", applet_name);
177 switch(ac) {
178 case IPSVD_DENY: out("deny "); break;
179 case IPSVD_DEFAULT: case IPSVD_INSTRUCT: out("start "); break;
180 case IPSVD_EXEC: out("exec "); break;
181 }
182#endif
183 printf("%s: info: %u %s:%s :%s:%s:%u\n",
184 applet_name, pid, local_hostname, local_ip,
185 remote_hostname, remote_ip, remote_port);
186#if 0
187 if (instructs) {
188 out(" ");
189 if (iscdb) {
190 out((char*)instructs); out("/");
191 }
192 outfix(match.s);
193 if(inst.s && inst.len && (verbose > 1)) {
194 out(": "); outinst(&inst);
195 }
196 }
197#endif
198 }
199
200#if 0
201 if (ac == IPSVD_DENY) {
202 recv(0, 0, 0, 0);
203 _exit(100);
204 }
205 if (ac == IPSVD_EXEC) {
206 args[0] = "/bin/sh";
207 args[1] = "-c";
208 args[2] = inst.s;
209 args[3] = NULL;
210 run = args;
211 } else run = prog;
212#endif
213 /* Make plain write(1) work for the child by supplying default
214 * destination address */
215 xconnect(0, &remote.sa, localp->len);
216 dup2(0, 1);
217
218 signal(SIGTERM, SIG_DFL);
219 signal(SIGPIPE, SIG_DFL);
220
221 argv += 2;
222 BB_EXECVP(argv[0], argv);
223 bb_perror_msg_and_die("exec '%s'", argv[0]);
224}
225
226/*
227udpsvd [-hpvv] [-u user] [-l name] [-i dir|-x cdb] [-t sec] host port prog
228
229udpsvd creates an UDP/IP socket, binds it to the address host:port,
230and listens on the socket for incoming datagrams.
231
232If a datagram is available on the socket, udpsvd conditionally starts
233a program, with standard input reading from the socket, and standard
234output redirected to standard error, to handle this, and possibly
235more datagrams. udpsvd does not start the program if another program
236that it has started before still is running. If the program exits,
237udpsvd again listens to the socket until a new datagram is available.
238If there are still datagrams available on the socket, the program
239is restarted immediately.
240
241udpsvd optionally checks for special intructions depending on
242the IP address or hostname of the client sending the datagram which
243not yet was handled by a running program, see ipsvd-instruct(5)
244for details.
245
246Attention:
247UDP is a connectionless protocol. Most programs that handle user datagrams,
248such as talkd(8), keep running after receiving a datagram, and process
249subsequent datagrams sent to the socket until a timeout is reached.
250udpsvd only checks special instructions for a datagram that causes a startup
251of the program; not if a program handling datagrams already is running.
252It doesn't make much sense to restrict access through special instructions
253when using such a program.
254
255On the other hand, it makes perfectly sense with programs like tftpd(8),
256that fork to establish a separate connection to the client when receiving
257the datagram. In general it's adequate to set up special instructions for
258programs that support being run by tcpwrapper.
259Options
260
261host
262 host either is a hostname, or a dotted-decimal IP address, or 0.
263 If host is 0, udpsvd accepts datagrams to any local IP address.
264port
265 udpsvd accepts datagrams to host:port. port may be a name from
266 /etc/services or a number.
267prog
268 prog consists of one or more arguments. udpsvd normally runs prog
269 to handle a datagram, and possibly more, that is sent to the socket,
270 if there is no program that was started before by udpsvd still running
271 and handling datagrams.
272-i dir
273 read instructions for handling new connections from the instructions
274 directory dir. See ipsvd-instruct(5) for details.
275-x cdb
276 read instructions for handling new connections from the constant
277 database cdb. The constant database normally is created from
278 an instructions directory by running ipsvd-cdb(8).
279-t sec
280 timeout. This option only takes effect if the -i option is given.
281 While checking the instructions directory, check the time of last
282 access of the file that matches the clients address or hostname if any,
283 discard and remove the file if it wasn't accessed within the last
284 sec seconds; udpsvd does not discard or remove a file if the user's
285 write permission is not set, for those files the timeout is disabled.
286 Default is 0, which means that the timeout is disabled.
287-l name
288 local hostname. Do not look up the local hostname in DNS, but use name
289 as hostname. By default udpsvd looks up the local hostname once at startup.
290-u user[:group]
291 drop permissions. Switch user ID to user's UID, and group ID to user's
292 primary GID after creating and binding to the socket. If user
293 is followed by a colon and a group name, the group ID is switched
294 to the GID of group instead. All supplementary groups are removed.
295-h
296 Look up the client's hostname in DNS.
297-p
298 paranoid. After looking up the client's hostname in DNS, look up
299 the IP addresses in DNS for that hostname, and forget the hostname
300 if none of the addresses match the client's IP address. You should
301 set this option if you use hostname based instructions. The -p option
302 implies the -h option.
303-v
304 verbose. Print verbose messages to standard output.
305-vv
306 more verbose. Print more verbose messages to standard output.
307*/