aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-04-03 23:23:10 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-04-03 23:23:10 +0000
commit561b2db47066af562d596a45b36e555fbf2955bb (patch)
tree3c14327a15979a5c4ccb98fc7b007a42bc685951
parent3b913ba9d19dc6a03166f38aa9981ac9ddd1e77e (diff)
downloadbusybox-w32-561b2db47066af562d596a45b36e555fbf2955bb.tar.gz
busybox-w32-561b2db47066af562d596a45b36e555fbf2955bb.tar.bz2
busybox-w32-561b2db47066af562d596a45b36e555fbf2955bb.zip
ipsvd: make udpsvd work similar to tcpsvd (multiple parallel
children for several streams of udp packets tested to work) code size: -509 bytes git-svn-id: svn://busybox.net/trunk/busybox@18316 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--include/applets.h8
-rw-r--r--include/usage.h12
-rw-r--r--ipsvd/tcpudp.c446
3 files changed, 131 insertions, 335 deletions
diff --git a/include/applets.h b/include/applets.h
index 386f4b110..00d3aee1e 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -132,8 +132,8 @@ USE_FSCK(APPLET(fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
132//USE_E2FSCK(APPLET_NOUSAGE(fsck.ext2, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER)) 132//USE_E2FSCK(APPLET_NOUSAGE(fsck.ext2, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
133//USE_E2FSCK(APPLET_NOUSAGE(fsck.ext3, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER)) 133//USE_E2FSCK(APPLET_NOUSAGE(fsck.ext3, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
134USE_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_minix)) 134USE_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_minix))
135USE_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER,ftpget)) 135USE_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpget))
136USE_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER,ftpput)) 136USE_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpput))
137USE_FUSER(APPLET(fuser, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 137USE_FUSER(APPLET(fuser, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
138USE_GETENFORCE(APPLET(getenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) 138USE_GETENFORCE(APPLET(getenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
139USE_GETOPT(APPLET(getopt, _BB_DIR_BIN, _BB_SUID_NEVER)) 139USE_GETOPT(APPLET(getopt, _BB_DIR_BIN, _BB_SUID_NEVER))
@@ -293,7 +293,7 @@ USE_SYSLOGD(APPLET(syslogd, _BB_DIR_SBIN, _BB_SUID_NEVER))
293USE_TAIL(APPLET(tail, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 293USE_TAIL(APPLET(tail, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
294USE_TAR(APPLET(tar, _BB_DIR_BIN, _BB_SUID_NEVER)) 294USE_TAR(APPLET(tar, _BB_DIR_BIN, _BB_SUID_NEVER))
295USE_TASKSET(APPLET(taskset, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 295USE_TASKSET(APPLET(taskset, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
296USE_TCPSVD(APPLET(tcpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 296USE_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER, tcpsvd))
297USE_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 297USE_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
298USE_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 298USE_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
299USE_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) 299USE_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
@@ -311,7 +311,7 @@ USE_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
311//USE_TUNE2FS(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER)) 311//USE_TUNE2FS(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER))
312USE_APP_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_NEVER)) 312USE_APP_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_NEVER))
313USE_APP_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) 313USE_APP_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
314USE_UDPSVD(APPLET(udpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 314USE_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER, udpsvd))
315USE_UMOUNT(APPLET(umount, _BB_DIR_BIN, _BB_SUID_NEVER)) 315USE_UMOUNT(APPLET(umount, _BB_DIR_BIN, _BB_SUID_NEVER))
316USE_UNAME(APPLET(uname, _BB_DIR_BIN, _BB_SUID_NEVER)) 316USE_UNAME(APPLET(uname, _BB_DIR_BIN, _BB_SUID_NEVER))
317USE_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_NEVER)) 317USE_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_NEVER))
diff --git a/include/usage.h b/include/usage.h
index bab14f5c3..5f1bf24cb 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -3331,7 +3331,7 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when
3331/* "[-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name] [-i dir|-x cdb] [ -t sec] ip port prog..." */ 3331/* "[-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name] [-i dir|-x cdb] [ -t sec] ip port prog..." */
3332#define tcpsvd_full_usage \ 3332#define tcpsvd_full_usage \
3333 "Creates TCP socket, binds it to host:port and listens on in\n" \ 3333 "Creates TCP socket, binds it to host:port and listens on in\n" \
3334 "for incoming connections. For each connection it runs prog" \ 3334 "for incoming connections. For each connection it runs prog." \
3335 "\n" \ 3335 "\n" \
3336 "\nip IP to listen on. '0' = all" \ 3336 "\nip IP to listen on. '0' = all" \
3337 "\nport Port to listen on" \ 3337 "\nport Port to listen on" \
@@ -3339,27 +3339,29 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when
3339 "\n-l name Local hostname (else looks up local hostname in DNS)" \ 3339 "\n-l name Local hostname (else looks up local hostname in DNS)" \
3340 "\n-u user[:group] Change to user/group after bind" \ 3340 "\n-u user[:group] Change to user/group after bind" \
3341 "\n-c n Handle up to n connections simultaneously" \ 3341 "\n-c n Handle up to n connections simultaneously" \
3342 "\n-b n Allow a backlog of approximately n TCP SYNs" \
3342 "\n-C n[:msg] Allow only up to n connections from the same IP" \ 3343 "\n-C n[:msg] Allow only up to n connections from the same IP" \
3343 "\n New connections from this IP address are closed" \ 3344 "\n New connections from this IP address are closed" \
3344 "\n immediately. 'msg' is written to the peer before close" \ 3345 "\n immediately. 'msg' is written to the peer before close" \
3345 "\n-h Look up peer's hostname" \ 3346 "\n-h Look up peer's hostname" \
3346 "\n-b n Allow a backlog of approximately n TCP SYNs" \
3347 "\n-E Do not set up TCP-related environment variables" \ 3347 "\n-E Do not set up TCP-related environment variables" \
3348 "\n-v Verbose" 3348 "\n-v Verbose"
3349 3349
3350#define udpsvd_trivial_usage \ 3350#define udpsvd_trivial_usage \
3351 "[-hv] [-u user] [-l name] host port prog" 3351 "[-hEv] [-u user] [-l name] host port prog"
3352#define udpsvd_full_usage \ 3352#define udpsvd_full_usage \
3353 "Creates UDP socket, binds it to host:port and listens on in\n" \ 3353 "Creates UDP socket, binds it to host:port and listens on in\n" \
3354 "for incoming packets. When packet arrives it runs prog.\n" \ 3354 "for incoming packets. For each packet it runs prog\n" \
3355 "When prog exits, it start to listen on the socket again" \ 3355 "(redirecting all further packets with same peer ip:port to it)." \
3356 "\n" \ 3356 "\n" \
3357 "\nip IP to listen on. '0' = all" \ 3357 "\nip IP to listen on. '0' = all" \
3358 "\nport Port to listen on" \ 3358 "\nport Port to listen on" \
3359 "\nprog [arg] Program to run" \ 3359 "\nprog [arg] Program to run" \
3360 "\n-l name Local hostname (else looks up local hostname in DNS)" \ 3360 "\n-l name Local hostname (else looks up local hostname in DNS)" \
3361 "\n-u user[:group] Change to user/group after bind" \ 3361 "\n-u user[:group] Change to user/group after bind" \
3362 "\n-c n Handle up to n connections simultaneously" \
3362 "\n-h Look up peer's hostname" \ 3363 "\n-h Look up peer's hostname" \
3364 "\n-E Do not set up TCP-related environment variables" \
3363 "\n-v Verbose" 3365 "\n-v Verbose"
3364 3366
3365#define tftp_trivial_usage \ 3367#define tftp_trivial_usage \
diff --git a/ipsvd/tcpudp.c b/ipsvd/tcpudp.c
index 419551d8d..6e8ec323c 100644
--- a/ipsvd/tcpudp.c
+++ b/ipsvd/tcpudp.c
@@ -7,12 +7,51 @@
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 10/* Based on ipsvd ipsvd-0.12.1. This tcpsvd accepts all options
11 * We reuse them by keeping both in one source file */ 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 "#ifdef SSLSVD" is for sslsvd and is currently unused.
15 *
16 * Output of verbose mode matches original (modulo bugs and
17 * unimplemented stuff). Unnatural splitting of IP and PORT
18 * is retained (personally I prefer one-value "IP:PORT" notation -
19 * it is a natural string representation of struct sockaddr_XX).
20 *
21 * TCPORIGDST{IP,PORT} is busybox-specific addition
22 *
23 * udp server is hacked up by reusing TCP code. It has the following
24 * limitation inherent in Unix DGRAM sockets implementation:
25 * - local IP address is reptrieved (using recvmsg voodoo) but
26 * child's socket is not bound to it (bind cannot be called on
27 * already bound socket). Thus you still can get outgoing packets
28 * with wrong sorce IP...
29 * - don't know how to retrieve ORIGDST for udp.
30 */
31
32#include <limits.h>
33#include <linux/netfilter_ipv4.h> /* wants <limits.h> */
12 34
13#include "busybox.h" 35#include "busybox.h"
14 36
37#include "udp_io.c"
38#include "ipsvd_perhost.h"
39
40#ifdef SSLSVD
41#include "matrixSsl.h"
42#include "ssl_io.h"
43#endif
44
15static unsigned verbose; 45static unsigned verbose;
46static unsigned max_per_host;
47static unsigned cur_per_host;
48static unsigned cnum;
49static unsigned cmax = 30;
50
51static void xsetenv_proto(const char *proto, const char *n, const char *v)
52{
53 putenv(xasprintf("%s%s=%s", proto, n, v));
54}
16 55
17static void sig_term_handler(int sig) 56static void sig_term_handler(int sig)
18{ 57{
@@ -38,287 +77,6 @@ static void print_waitstat(unsigned pid, int wstat)
38 printf("%s: info: end %d %s %d\n", applet_name, pid, cause, e); 77 printf("%s: info: end %d %s %d\n", applet_name, pid, cause, e);
39} 78}
40 79
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
294/* Based on ipsvd ipsvd-0.12.1. This tcpsvd accepts all options
295 * which are supported by one from ipsvd-0.12.1, but not all are
296 * functional. See help text at the end of this file for details.
297 *
298 * Code inside "#ifdef SSLSVD" is for sslsvd and is currently unused.
299 *
300 * Output of verbose mode matches original (modulo bugs and
301 * unimplemented stuff). Unnatural splitting of IP and PORT
302 * is retained (personally I prefer one-value "IP:PORT" notation -
303 * it is a natural string representation of struct sockaddr_XX).
304 *
305 * TCPORIGDST{IP,PORT} is busybox-specific addition
306 */
307
308#include <limits.h>
309#include <linux/netfilter_ipv4.h> /* wants <limits.h> */
310#include "ipsvd_perhost.h"
311
312#ifdef SSLSVD
313#include "matrixSsl.h"
314#include "ssl_io.h"
315#endif
316
317static unsigned max_per_host; /* originally in ipsvd_check.c */
318static unsigned cur_per_host;
319static unsigned cnum;
320static unsigned cmax = 30;
321
322/* Must match getopt32 in main! */ 80/* Must match getopt32 in main! */
323enum { 81enum {
324 OPT_c = (1 << 0), 82 OPT_c = (1 << 0),
@@ -342,7 +100,9 @@ enum {
342 100
343static void connection_status(void) 101static void connection_status(void)
344{ 102{
345 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax); 103 /* UDP and "only 1 client max" TCP don't need this */
104 if (cmax > 1)
105 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
346} 106}
347 107
348static void sig_child_handler(int sig) 108static void sig_child_handler(int sig)
@@ -362,8 +122,8 @@ static void sig_child_handler(int sig)
362 connection_status(); 122 connection_status();
363} 123}
364 124
365int tcpsvd_main(int argc, char **argv); 125int tcpudpsvd_main(int argc, char **argv);
366int tcpsvd_main(int argc, char **argv) 126int tcpudpsvd_main(int argc, char **argv)
367{ 127{
368 char *str_c, *str_C, *str_b, *str_t; 128 char *str_c, *str_C, *str_b, *str_t;
369 char *user; 129 char *user;
@@ -372,11 +132,13 @@ int tcpsvd_main(int argc, char **argv)
372 char *msg_per_host = NULL; 132 char *msg_per_host = NULL;
373 unsigned len_per_host = len_per_host; /* gcc */ 133 unsigned len_per_host = len_per_host; /* gcc */
374 int need_hostnames, need_remote_ip; 134 int need_hostnames, need_remote_ip;
135 int tcp;
375 int pid; 136 int pid;
376 int sock; 137 int sock;
377 int conn; 138 int conn;
378 unsigned backlog = 20; 139 unsigned backlog = 20;
379 len_and_sockaddr *lsa; 140 len_and_sockaddr *lsa;
141 len_and_sockaddr local, remote;
380 uint16_t local_port; 142 uint16_t local_port;
381 uint16_t remote_port = remote_port; /* gcc */ 143 uint16_t remote_port = remote_port; /* gcc */
382 char *local_hostname = NULL; 144 char *local_hostname = NULL;
@@ -386,6 +148,7 @@ int tcpsvd_main(int argc, char **argv)
386#ifndef SSLSVD 148#ifndef SSLSVD
387 struct bb_uidgid_t ugid; 149 struct bb_uidgid_t ugid;
388#endif 150#endif
151 tcp = (applet_name[0] == 't');
389 152
390 /* 3+ args, -i at most once, -p implies -h, -v is counter */ 153 /* 3+ args, -i at most once, -p implies -h, -v is counter */
391 opt_complementary = "-3:?:i--i:ph:vv"; 154 opt_complementary = "-3:?:i--i:ph:vv";
@@ -420,18 +183,22 @@ int tcpsvd_main(int argc, char **argv)
420 if (option_mask32 & OPT_b) 183 if (option_mask32 & OPT_b)
421 backlog = xatou(str_b); 184 backlog = xatou(str_b);
422#ifdef SSLSVD 185#ifdef SSLSVD
423 if (option_mask32 & OPT_U) ssluser = (char*)optarg; break; 186 if (option_mask32 & OPT_U) ssluser = optarg;
424 if (option_mask32 & OPT_slash) root = (char*)optarg; break; 187 if (option_mask32 & OPT_slash) root = optarg;
425 if (option_mask32 & OPT_Z) cert = (char*)optarg; break; 188 if (option_mask32 & OPT_Z) cert = optarg;
426 if (option_mask32 & OPT_K) key = (char*)optarg; break; 189 if (option_mask32 & OPT_K) key = optarg;
427#endif 190#endif
428 argv += optind; 191 argv += optind;
429 if (!argv[0][0] || LONE_CHAR(argv[0], '0')) 192 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
430 argv[0] = (char*)"0.0.0.0"; 193 argv[0] = (char*)"0.0.0.0";
431 194
195 /* Per-IP flood protection is not thought-out for UDP */
196 if (!tcp)
197 max_per_host = 0;
198
432 /* stdout is used for logging, don't buffer */ 199 /* stdout is used for logging, don't buffer */
433 setlinebuf(stdout); 200 setlinebuf(stdout);
434 bb_sanitize_stdio(); /* fd# 1,2 must be opened */ 201 bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */
435 202
436 need_hostnames = verbose || !(option_mask32 & OPT_E); 203 need_hostnames = verbose || !(option_mask32 & OPT_E);
437 need_remote_ip = max_per_host || need_hostnames; 204 need_remote_ip = max_per_host || need_hostnames;
@@ -473,12 +240,15 @@ int tcpsvd_main(int argc, char **argv)
473 if (max_per_host) 240 if (max_per_host)
474 ipsvd_perhost_init(cmax); 241 ipsvd_perhost_init(cmax);
475 242
476 local_port = bb_lookup_port(argv[1], "tcp", 0); 243 local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
477 lsa = xhost2sockaddr(argv[0], local_port); 244 lsa = xhost2sockaddr(argv[0], local_port);
478 sock = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0); 245 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
479 setsockopt_reuseaddr(sock); /* desirable */ 246 setsockopt_reuseaddr(sock);
480 xbind(sock, &lsa->sa, lsa->len); 247 xbind(sock, &lsa->sa, lsa->len);
481 xlisten(sock, backlog); 248 if (tcp)
249 xlisten(sock, backlog);
250 else /* udp: needed for recv_from_to to work: */
251 socket_want_pktinfo(sock);
482 /* ndelay_off(sock); - it is the default I think? */ 252 /* ndelay_off(sock); - it is the default I think? */
483 253
484#ifndef SSLSVD 254#ifndef SSLSVD
@@ -503,7 +273,7 @@ int tcpsvd_main(int argc, char **argv)
503 puts(", starting"); 273 puts(", starting");
504 } 274 }
505 275
506 /* The rest is a main accept() loop */ 276 /* Main accept() loop */
507 277
508 again: 278 again:
509 hccp = NULL; 279 hccp = NULL;
@@ -516,19 +286,23 @@ int tcpsvd_main(int argc, char **argv)
516 close(0); 286 close(0);
517 again2: 287 again2:
518 sig_unblock(SIGCHLD); 288 sig_unblock(SIGCHLD);
519 conn = accept(sock, &lsa->sa, &lsa->len); 289 if (tcp) {
290 remote.len = lsa->len;
291 conn = accept(sock, &remote.sa, &remote.len);
292 } else
293 conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.sa, &local.sa, lsa->len);
520 sig_block(SIGCHLD); 294 sig_block(SIGCHLD);
521 if (conn < 0) { 295 if (conn < 0) {
522 if (errno != EINTR) 296 if (errno != EINTR)
523 bb_perror_msg("accept"); 297 bb_perror_msg(tcp ? "accept" : "recv");
524 goto again2; 298 goto again2;
525 } 299 }
526 xmove_fd(conn, 0); 300 xmove_fd(tcp ? conn : sock, 0);
527 301
528 if (max_per_host) { 302 if (max_per_host) {
529 /* Drop connection immediately if cur_per_host > max_per_host 303 /* Drop connection immediately if cur_per_host > max_per_host
530 * (minimizing load under SYN flood) */ 304 * (minimizing load under SYN flood) */
531 remote_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len); 305 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, lsa->len);
532 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp); 306 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
533 if (cur_per_host > max_per_host) { 307 if (cur_per_host > max_per_host) {
534 /* ipsvd_perhost_add detected that max is exceeded 308 /* ipsvd_perhost_add detected that max is exceeded
@@ -543,17 +317,33 @@ int tcpsvd_main(int argc, char **argv)
543 } 317 }
544 } 318 }
545 319
546 cnum++; 320 if (!tcp) {
547 if (verbose) 321 /* Voodoo magic: making udp sockets each receive its own
548 connection_status(); 322 * packets is not trivial */
323
324 /* Make plain write work for this socket by supplying default
325 * destination address. This also restricts incoming packets
326 * to ones coming from this remote IP. */
327 xconnect(0, &remote.sa, lsa->len);
328 /* Open new non-connected UDP socket for further clients */
329 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
330 setsockopt_reuseaddr(sock);
331 xbind(sock, &lsa->sa, lsa->len);
332 socket_want_pktinfo(sock);
333 }
549 334
550 pid = fork(); 335 pid = fork();
551 if (pid == -1) { 336 if (pid == -1) {
552 bb_perror_msg("fork"); 337 bb_perror_msg("fork");
553 goto again; 338 goto again;
554 } 339 }
340
341
555 if (pid != 0) { 342 if (pid != 0) {
556 /* parent */ 343 /* parent */
344 cnum++;
345 if (verbose)
346 connection_status();
557 if (hccp) 347 if (hccp)
558 hccp->pid = pid; 348 hccp->pid = pid;
559 goto again; 349 goto again;
@@ -561,35 +351,38 @@ int tcpsvd_main(int argc, char **argv)
561 351
562 /* Child: prepare env, log, and exec prog */ 352 /* Child: prepare env, log, and exec prog */
563 353
564 close(sock); /* listening socket */ 354 /* Closing tcp listening socket */
565 /* Find out local IP peer connected to. 355 if (tcp)
566 * Errors ignored (I'm not paranoid enough to imagine kernel 356 close(sock);
567 * which doesn't know local IP). */
568 getsockname(0, &lsa->sa, &lsa->len);
569 357
570 if (need_remote_ip) { 358 if (need_remote_ip) {
571 if (!max_per_host) 359 if (!max_per_host)
572 remote_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len); 360 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, lsa->len);
573 /* else it is already done */ 361 /* else it is already done */
574 remote_port = get_nport(&lsa->sa); 362 remote_port = get_nport(&remote.sa);
575 remote_port = ntohs(remote_port); 363 remote_port = ntohs(remote_port);
576 } 364 }
577 365
578 if (need_hostnames) { 366 if (need_hostnames) {
579 if (option_mask32 & OPT_h) { 367 if (option_mask32 & OPT_h) {
580 remote_hostname = xmalloc_sockaddr2host(&lsa->sa, lsa->len); 368 remote_hostname = xmalloc_sockaddr2host(&remote.sa, lsa->len);
581 if (!remote_hostname) { 369 if (!remote_hostname) {
582 bb_error_msg("warning: cannot look up hostname for %s", remote_ip); 370 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
583 remote_hostname = (char*)""; 371 remote_hostname = (char*)"";
584 } 372 }
585 } 373 }
586 local_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len); 374 /* Find out local IP peer connected to.
587 local_port = get_nport(&lsa->sa); 375 * Errors ignored (I'm not paranoid enough to imagine kernel
376 * which doesn't know local IP). */
377 if (tcp)
378 getsockname(0, &local.sa, &local.len);
379 local_ip = xmalloc_sockaddr2dotted_noport(&local.sa, lsa->len);
380 local_port = get_nport(&local.sa);
588 local_port = ntohs(local_port); 381 local_port = ntohs(local_port);
589 if (!local_hostname) { 382 if (!local_hostname) {
590 local_hostname = xmalloc_sockaddr2host_noport(&lsa->sa, lsa->len); 383 local_hostname = xmalloc_sockaddr2host_noport(&local.sa, lsa->len);
591 if (!local_hostname) 384 if (!local_hostname)
592 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip); 385 bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_ip);
593 } 386 }
594 } 387 }
595 388
@@ -605,14 +398,16 @@ int tcpsvd_main(int argc, char **argv)
605 remote_hostname, remote_ip, (unsigned)remote_port); 398 remote_hostname, remote_ip, (unsigned)remote_port);
606 } 399 }
607 400
401// TODO: stop splitiing port# from IP?
608 if (!(option_mask32 & OPT_E)) { 402 if (!(option_mask32 & OPT_E)) {
609 /* setup ucspi env */ 403 /* setup ucspi env */
404 const char *proto = tcp ? "TCP" : "UDP";
610 405
611 /* Extract "original" destination addr:port 406 /* Extract "original" destination addr:port
612 * from Linux firewall. Useful when you redirect 407 * from Linux firewall. Useful when you redirect
613 * an outbond connection to local handler, and it needs 408 * an outbond connection to local handler, and it needs
614 * to know where it originally tried to connect */ 409 * to know where it originally tried to connect */
615 if (getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) { 410 if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) {
616 char *ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len); 411 char *ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
617 unsigned port = get_nport(&lsa->sa); 412 unsigned port = get_nport(&lsa->sa);
618 port = ntohs(port); 413 port = ntohs(port);
@@ -620,18 +415,18 @@ int tcpsvd_main(int argc, char **argv)
620 xsetenv("TCPORIGDSTPORT", utoa(port)); 415 xsetenv("TCPORIGDSTPORT", utoa(port));
621 free(ip); 416 free(ip);
622 } 417 }
623 xsetenv("PROTO", "TCP"); 418 xsetenv("PROTO", proto);
624 xsetenv("TCPLOCALIP", local_ip); 419 xsetenv_proto(proto, "LOCALIP", local_ip);
625 xsetenv("TCPLOCALPORT", utoa(local_port)); 420 xsetenv_proto(proto, "LOCALPORT", utoa(local_port));
626 xsetenv("TCPLOCALHOST", local_hostname); 421 xsetenv_proto(proto, "LOCALHOST", local_hostname);
627 xsetenv("TCPREMOTEIP", remote_ip); 422 xsetenv_proto(proto, "REMOTEIP", remote_ip);
628 xsetenv("TCPREMOTEPORT", utoa(remote_port)); 423 xsetenv_proto(proto, "REMOTEPORT", utoa(remote_port));
629 if (option_mask32 & OPT_h) { 424 if (option_mask32 & OPT_h) {
630 xsetenv("TCPREMOTEHOST", remote_hostname); 425 xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
631 } 426 }
632 xsetenv("TCPREMOTEINFO", ""); 427 xsetenv_proto(proto, "REMOTEINFO", "");
633 /* additional */ 428 /* additional */
634 if (cur_per_host > 0) 429 if (cur_per_host > 0) /* can not be true for udp */
635 xsetenv("TCPCONCURRENCY", utoa(cur_per_host)); 430 xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
636 } 431 }
637 432
@@ -747,4 +542,3 @@ prog
747 more verbose. Print more verbose messages to standard output. 542 more verbose. Print more verbose messages to standard output.
748 * no difference between -v and -vv in busyboxed version 543 * no difference between -v and -vv in busyboxed version
749*/ 544*/
750#endif