aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-01 01:18:20 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-01 01:18:20 +0000
commit2856dab4770e521a87c18b04ae8ebc209a9b95f9 (patch)
treed4f6495339702c0b6d79816d0bb07ba4b6679ce8
parentf443bffd3c24c4b7fcbc0472c75e747e26c24fef (diff)
downloadbusybox-w32-2856dab4770e521a87c18b04ae8ebc209a9b95f9.tar.gz
busybox-w32-2856dab4770e521a87c18b04ae8ebc209a9b95f9.tar.bz2
busybox-w32-2856dab4770e521a87c18b04ae8ebc209a9b95f9.zip
tcpsvd: new applet
It's a GPL-ed 'clone' of Dan Bernstein's tcpserver. Author: Gerrit Pape <pape@smarden.org> http://smarden.sunsite.dk/ipsvd/ size tcpsvd.o text data bss dec hex filename 2571 4 16 2591 a1f tcpsvd.o
-rw-r--r--Config.in1
-rw-r--r--Makefile1
-rw-r--r--include/applets.h1
-rw-r--r--include/libbb.h21
-rw-r--r--include/usage.h5
-rw-r--r--ipsvd/Config.in14
-rw-r--r--ipsvd/Kbuild8
-rw-r--r--ipsvd/ipsvd_perhost.c55
-rw-r--r--ipsvd/ipsvd_perhost.h10
-rw-r--r--ipsvd/tcpsvd.c514
-rw-r--r--libbb/xconnect.c12
-rw-r--r--libbb/xfuncs.c57
-rw-r--r--networking/nc.c2
-rw-r--r--networking/tftp.c2
-rw-r--r--runit/runit_lib.c70
-rw-r--r--runit/runit_lib.h23
-rw-r--r--runit/runsv.c6
-rw-r--r--runit/runsvdir.c7
-rw-r--r--runit/svlogd.c6
19 files changed, 704 insertions, 111 deletions
diff --git a/Config.in b/Config.in
index 6192833c0..fea408148 100644
--- a/Config.in
+++ b/Config.in
@@ -500,3 +500,4 @@ source shell/Config.in
500source sysklogd/Config.in 500source sysklogd/Config.in
501source runit/Config.in 501source runit/Config.in
502source selinux/Config.in 502source selinux/Config.in
503source ipsvd/Config.in
diff --git a/Makefile b/Makefile
index 4f45ae822..5b507d9f0 100644
--- a/Makefile
+++ b/Makefile
@@ -434,6 +434,7 @@ libs-y := \
434 editors/ \ 434 editors/ \
435 findutils/ \ 435 findutils/ \
436 init/ \ 436 init/ \
437 ipsvd/ \
437 libbb/ \ 438 libbb/ \
438 libpwdgrp/ \ 439 libpwdgrp/ \
439 loginutils/ \ 440 loginutils/ \
diff --git a/include/applets.h b/include/applets.h
index 77258be42..8073c15e1 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -293,6 +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_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 297USE_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
297USE_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 298USE_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
298USE_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) 299USE_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
diff --git a/include/libbb.h b/include/libbb.h
index 7f0ad2c25..794049df9 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -266,6 +266,7 @@ char *xrealloc_getcwd_or_warn(char *cwd);
266char *xmalloc_readlink_or_warn(const char *path); 266char *xmalloc_readlink_or_warn(const char *path);
267char *xmalloc_realpath(const char *path); 267char *xmalloc_realpath(const char *path);
268extern void xstat(const char *filename, struct stat *buf); 268extern void xstat(const char *filename, struct stat *buf);
269
269/* Unlike waitpid, waits ONLY for one process, 270/* Unlike waitpid, waits ONLY for one process,
270 * It's safe to pass negative 'pids' from failed [v]fork - 271 * It's safe to pass negative 'pids' from failed [v]fork -
271 * wait4pid will return -1 and ECHILD in errno. 272 * wait4pid will return -1 and ECHILD in errno.
@@ -274,6 +275,24 @@ extern void xstat(const char *filename, struct stat *buf);
274 * if (rc > 0) bb_error_msg("exit code: %d", rc); 275 * if (rc > 0) bb_error_msg("exit code: %d", rc);
275 */ 276 */
276extern int wait4pid(int pid); 277extern int wait4pid(int pid);
278extern int wait_pid(int *wstat, int pid);
279extern int wait_nohang(int *wstat);
280//TODO: signal(sid, f) is the same? then why?
281extern void sig_catch(int,void (*)(int));
282//#define sig_ignore(s) (sig_catch((s), SIG_IGN))
283//#define sig_uncatch(s) (sig_catch((s), SIG_DFL))
284extern void sig_block(int);
285extern void sig_unblock(int);
286/* UNUSED: extern void sig_blocknone(void);*/
287extern void sig_pause(void);
288
289#define wait_crashed(w) ((w) & 127)
290#define wait_exitcode(w) ((w) >> 8)
291#define wait_stopsig(w) ((w) >> 8)
292#define wait_stopped(w) (((w) & 127) == 127)
293
294
295
277extern void xsetgid(gid_t gid); 296extern void xsetgid(gid_t gid);
278extern void xsetuid(uid_t uid); 297extern void xsetuid(uid_t uid);
279extern void xchdir(const char *path); 298extern void xchdir(const char *path);
@@ -340,7 +359,7 @@ len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t
340 * NB: does NOT do htons() internally, just direct assignment. */ 359 * NB: does NOT do htons() internally, just direct assignment. */
341void set_nport(len_and_sockaddr *lsa, unsigned port); 360void set_nport(len_and_sockaddr *lsa, unsigned port);
342/* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */ 361/* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */
343int get_nport(const len_and_sockaddr *lsa); 362int get_nport(const struct sockaddr *sa);
344/* Reverse DNS. Returns NULL on failure. */ 363/* Reverse DNS. Returns NULL on failure. */
345char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen); 364char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen);
346/* This one doesn't append :PORTNUM */ 365/* This one doesn't append :PORTNUM */
diff --git a/include/usage.h b/include/usage.h
index a19bcf7c2..09b6908f9 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -3325,6 +3325,11 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when
3325 "$ echo $?\n" \ 3325 "$ echo $?\n" \
3326 "1\n" 3326 "1\n"
3327 3327
3328#define tcpsvd_trivial_usage \
3329 "TODO"
3330#define tcpsvd_full_usage \
3331 "TODO"
3332
3328#define tftp_trivial_usage \ 3333#define tftp_trivial_usage \
3329 "[OPTION]... HOST [PORT]" 3334 "[OPTION]... HOST [PORT]"
3330#define tftp_full_usage \ 3335#define tftp_full_usage \
diff --git a/ipsvd/Config.in b/ipsvd/Config.in
new file mode 100644
index 000000000..fb2931d07
--- /dev/null
+++ b/ipsvd/Config.in
@@ -0,0 +1,14 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6menu "ipsvd utilities"
7
8config TCPSVD
9 bool "tcpsvd"
10 default n
11 help
12 tcpsvd listens on a port and runs a program for each new connection
13
14endmenu
diff --git a/ipsvd/Kbuild b/ipsvd/Kbuild
new file mode 100644
index 000000000..8050921b0
--- /dev/null
+++ b/ipsvd/Kbuild
@@ -0,0 +1,8 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7lib-y:=
8lib-$(CONFIG_TCPSVD) += tcpsvd.o ipsvd_perhost.o
diff --git a/ipsvd/ipsvd_perhost.c b/ipsvd/ipsvd_perhost.c
new file mode 100644
index 000000000..c6f7de339
--- /dev/null
+++ b/ipsvd/ipsvd_perhost.c
@@ -0,0 +1,55 @@
1#include "busybox.h"
2#include "ipsvd_perhost.h"
3
4static struct hcc *cc;
5static unsigned cclen;
6
7/* to be optimized */
8
9void ipsvd_perhost_init(unsigned c)
10{
11// free(cc);
12 cc = xzalloc(c * sizeof(*cc));
13 cclen = c;
14}
15
16unsigned ipsvd_perhost_add(const char *ip, unsigned maxconn, struct hcc **hccpp)
17{
18 unsigned i;
19 unsigned conn = 1;
20 int p = -1;
21
22 for (i = 0; i < cclen; ++i) {
23 if (cc[i].ip[0] == 0) {
24 if (p == -1) p = i;
25 continue;
26 }
27 if (strncmp(cc[i].ip, ip, sizeof(cc[i].ip)) == 0) {
28 conn++;
29 continue;
30 }
31 }
32 if (p == -1) return 0;
33 if (conn <= maxconn) {
34 strcpy(cc[p].ip, ip);
35 *hccpp = &cc[p];
36 }
37 return conn;
38}
39
40void ipsvd_perhost_remove(int pid)
41{
42 unsigned i;
43 for (i = 0; i < cclen; ++i) {
44 if (cc[i].pid == pid) {
45 cc[i].ip[0] = 0;
46 cc[i].pid = 0;
47 return;
48 }
49 }
50}
51
52//void ipsvd_perhost_free(void)
53//{
54// free(cc);
55//}
diff --git a/ipsvd/ipsvd_perhost.h b/ipsvd/ipsvd_perhost.h
new file mode 100644
index 000000000..05c939d89
--- /dev/null
+++ b/ipsvd/ipsvd_perhost.h
@@ -0,0 +1,10 @@
1struct hcc {
2 char ip[32 - sizeof(int)];
3 int pid;
4};
5
6void ipsvd_perhost_init(unsigned);
7unsigned ipsvd_perhost_add(const char *ip, unsigned maxconn, struct hcc **hccpp);
8void ipsvd_perhost_remove(int pid);
9//unsigned ipsvd_perhost_setpid(int pid);
10//void ipsvd_perhost_free(void);
diff --git a/ipsvd/tcpsvd.c b/ipsvd/tcpsvd.c
new file mode 100644
index 000000000..9a0a348de
--- /dev/null
+++ b/ipsvd/tcpsvd.c
@@ -0,0 +1,514 @@
1/*
2# /usr/bin/tcpsvd -v 0 1234 true
3tcpsvd: info: pid 24916 from 127.0.0.1
4tcpsvd: info: start 24916 localhost:127.0.0.1 ::127.0.0.1:47905
5tcpsvd: info: pid 24918 from 127.0.0.1
6tcpsvd: info: start 24918 localhost:127.0.0.1 ::127.0.0.1:47906
7# ./busybox tcpsvd -v 0 1234 true
8tcpsvd: info: pid 24924 from 127.0.0.1
9tcpsvd: info: start 24924 localhost:1234:127.0.0.1:1234 ::127.0.0.1:47908
10tcpsvd: info: pid 24926 from 127.0.0.1
11tcpsvd: info: start 24926 localhost:1234:127.0.0.1:1234 ::127.0.0.1:47909
12*/
13
14#include "busybox.h"
15#include "ipsvd_perhost.h"
16
17#ifdef SSLSVD
18#include "matrixSsl.h"
19#include "ssl_io.h"
20#endif
21
22
23static unsigned max_per_host; /* originally in ipsvd_check.c */
24static unsigned cur_per_host;
25static unsigned verbose;
26static unsigned cnum;
27static unsigned cmax = 30;
28
29/* Must match getopt32 in main! */
30enum {
31 OPT_c = (1 << 0),
32 OPT_C = (1 << 1),
33 OPT_i = (1 << 2),
34 OPT_x = (1 << 3),
35 OPT_u = (1 << 4),
36 OPT_l = (1 << 5),
37 OPT_E = (1 << 6),
38 OPT_b = (1 << 7),
39 OPT_h = (1 << 8),
40 OPT_p = (1 << 9),
41 OPT_t = (1 << 10),
42 OPT_v = (1 << 11),
43 OPT_V = (1 << 12),
44 OPT_U = (1 << 13),
45 OPT_slash = (1 << 14),
46 OPT_Z = (1 << 15),
47 OPT_K = (1 << 16),
48};
49
50static void connection_status(void)
51{
52 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
53}
54
55static void sig_term_handler(int sig)
56{
57 if (verbose)
58 printf("%s: info: sigterm received, exit\n", applet_name);
59 exit(0);
60}
61
62static void sig_child_handler(int sig)
63{
64 int wstat;
65 int pid;
66
67 while ((pid = wait_nohang(&wstat)) > 0) {
68 if (max_per_host)
69 ipsvd_perhost_remove(pid);
70 if (cnum)
71 cnum--;
72 if (verbose) {
73 /* Little bloated, but tries to give accurate info
74 * how child exited. Makes easier to spot segfaulting
75 * children etc... */
76 unsigned e = 0;
77 const char *cause = "?exit";
78 if (WIFEXITED(wstat)) {
79 cause++;
80 e = WEXITSTATUS(wstat);
81 } else if (WIFSIGNALED(wstat)) {
82 cause = "signal";
83 e = WTERMSIG(wstat);
84 }
85 printf("%s: info: end %d %s %d\n",
86 applet_name, pid, cause, e);
87 }
88 }
89 if (verbose)
90 connection_status();
91}
92
93int tcpsvd_main(int argc, char **argv);
94int tcpsvd_main(int argc, char **argv)
95{
96 char *str_c, *str_C, *str_b, *str_t;
97 char *user;
98 struct hcc *hccp;
99 const char *instructs;
100 char *msg_per_host = NULL;
101 unsigned len_per_host = len_per_host; /* gcc */
102 int need_addresses;
103 int pid;
104 int sock;
105 int conn;
106 unsigned backlog = 20;
107 union {
108 struct sockaddr sa;
109 struct sockaddr_in sin;
110 USE_FEATURE_IPV6(struct sockaddr_in6 sin6;)
111 } sock_adr;
112 socklen_t sockadr_size;
113 uint16_t local_port = local_port;
114 uint16_t remote_port;
115 unsigned port;
116 char *local_hostname = NULL;
117 char *remote_hostname = (char*)""; /* "" used if no -h */
118 char *local_ip = local_ip;
119 char *remote_ip = NULL;
120 //unsigned iscdb = 0; /* = option_mask32 & OPT_x (TODO) */
121 //unsigned long timeout = 0;
122#ifndef SSLSVD
123 struct bb_uidgid_t ugid;
124#endif
125
126 /* 3+ args, -i at most once, -p implies -h, -v is counter */
127 opt_complementary = "-3:?:i--i:ph:vv";
128#ifdef SSLSVD
129 getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
130 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
131 &str_b, &str_t, &ssluser, &root, &cert, &key, &verbose
132 );
133#else
134 getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:v",
135 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
136 &str_b, &str_t, &verbose
137 );
138#endif
139 if (option_mask32 & OPT_c)
140 cmax = xatou_range(str_c, 1, INT_MAX);
141 if (option_mask32 & OPT_C) { /* -C n[:message] */
142 max_per_host = bb_strtou(str_C, &str_C, 10);
143 if (str_C[0]) {
144 if (str_C[0] != ':')
145 bb_show_usage();
146 msg_per_host = str_C + 1;
147 len_per_host = strlen(msg_per_host);
148 }
149 }
150 if (max_per_host > cmax)
151 max_per_host = cmax;
152 if (option_mask32 & OPT_u) {
153 if (!get_uidgid(&ugid, user, 1))
154 bb_error_msg_and_die("unknown user/group: %s", user);
155 }
156 if (option_mask32 & OPT_b)
157 backlog = xatou(str_b);
158// if (option_mask32 & OPT_t) timeout = xatou(str_t);
159#ifdef SSLSVD
160 if (option_mask32 & OPT_U) ssluser = (char*)optarg; break;
161 if (option_mask32 & OPT_slash) root = (char*)optarg; break;
162 if (option_mask32 & OPT_Z) cert = (char*)optarg; break;
163 if (option_mask32 & OPT_K) key = (char*)optarg; break;
164#endif
165 argv += optind;
166 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
167 argv[0] = (char*)"0.0.0.0";
168
169 need_addresses = verbose || !(option_mask32 & OPT_E);
170
171#ifdef SSLSVD
172 sslser = user;
173 client = 0;
174 if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
175 xfunc_exitcode = 100;
176 bb_error_msg_and_die("fatal: -U ssluser must be set when running as root");
177 }
178 if (option_mask32 & OPT_u)
179 if (!uidgid_get(&sslugid, ssluser, 1)) {
180 if (errno) {
181 xfunc_exitcode = 100;
182 bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
183 }
184 xfunc_exitcode = 111;
185 bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser);
186 }
187 if (!cert) cert = "./cert.pem";
188 if (!key) key = cert;
189 if (matrixSslOpen() < 0)
190 fatal("cannot initialize ssl");
191 if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
192 if (client)
193 fatal("cannot read cert, key, or ca file");
194 fatal("cannot read cert or key file");
195 }
196 if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
197 fatal("cannot create ssl session");
198#endif
199
200 sig_block(SIGCHLD);
201 signal(SIGCHLD, sig_child_handler);
202 signal(SIGTERM, sig_term_handler);
203 signal(SIGPIPE, SIG_IGN);
204
205 if (max_per_host)
206 ipsvd_perhost_init(cmax);
207
208 port = bb_lookup_port(argv[1], "tcp", 0);
209 sock = create_and_bind_stream_or_die(argv[0], port);
210 xlisten(sock, backlog);
211 /* ndelay_off(sock); - it is the default I think? */
212
213#ifndef SSLSVD
214 if (option_mask32 & OPT_u) {
215 /* drop permissions */
216 xsetgid(ugid.gid);
217 xsetuid(ugid.uid);
218 }
219#endif
220 bb_sanitize_stdio(); /* fd# 1,2 must be opened */
221 close(0);
222
223 if (verbose) {
224 /* we do it only for ":port" cosmetics... oh well */
225 len_and_sockaddr *lsa = xhost2sockaddr(argv[0], port);
226 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len);
227
228 printf("%s: info: listening on %s", applet_name, addr);
229 free(addr);
230#ifndef SSLSVD
231 if (option_mask32 & OPT_u)
232 printf(", uid %u, gid %u",
233 (unsigned)ugid.uid, (unsigned)ugid.uid);
234#endif
235 puts(", starting");
236 }
237
238 /* The rest is a main accept() loop */
239
240 again:
241 hccp = NULL;
242
243 while (cnum >= cmax)
244 sig_pause(); /* wait for any signal (expecting SIGCHLD) */
245
246 sockadr_size = sizeof(sock_adr);
247 sig_unblock(SIGCHLD);
248 conn = accept(sock, &sock_adr.sa, &sockadr_size);
249 sig_block(SIGCHLD);
250 if (conn == -1) {
251 if (errno != EINTR)
252 bb_perror_msg("accept");
253 goto again;
254 }
255
256 if (max_per_host) {
257 /* we drop connection immediately if cur_per_host > max_per_host
258 * (minimizing load under SYN flood) */
259 free(remote_ip);
260 remote_ip = xmalloc_sockaddr2dotted_noport(&sock_adr.sa, sockadr_size);
261 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
262 if (cur_per_host > max_per_host) {
263 /* ipsvd_perhost_add detected that max is exceeded
264 * (and did not store us in connection table) */
265 if (msg_per_host) {
266 ndelay_on(conn);
267 /* don't test for errors */
268 write(conn, msg_per_host, len_per_host);
269 }
270 close(conn);
271 goto again;
272 }
273 }
274
275 cnum++;
276 if (verbose)
277 connection_status();
278
279 pid = fork();
280 if (pid == -1) {
281 bb_perror_msg("fork");
282 close(conn);
283 goto again;
284 }
285 if (pid != 0) {
286 /* parent */
287 close(conn);
288 if (hccp)
289 hccp->pid = pid;
290 goto again;
291 }
292
293 /* Child: prepare env, log, and exec prog */
294
295 close(sock);
296
297 if (!max_per_host)
298 remote_ip = xmalloc_sockaddr2dotted_noport(&sock_adr.sa, sizeof(sock_adr));
299 /* else it is already done */
300
301 remote_port = get_nport(&sock_adr.sa);
302 remote_port = ntohs(remote_port);
303
304 if (verbose) {
305 pid = getpid();
306 printf("%s: info: pid %d from %s\n", applet_name, pid, remote_ip);
307 }
308
309 if (need_addresses && (option_mask32 & OPT_h)) {
310 remote_hostname = xmalloc_sockaddr2host(&sock_adr.sa, sizeof(sock_adr));
311 if (!remote_hostname) {
312 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
313 remote_hostname = (char*)"";
314 }
315 }
316
317 sockadr_size = sizeof(sock_adr);
318 /* Errors ignored (I'm not paranoid enough to imagine kernel
319 * which doesn't know local ip) */
320 getsockname(conn, &sock_adr.sa, &sockadr_size);
321
322 if (need_addresses) {
323 local_ip = xmalloc_sockaddr2dotted_noport(&sock_adr.sa, sockadr_size);
324 local_port = get_nport(&sock_adr.sa);
325 local_port = ntohs(local_port);
326 if (!local_hostname) {
327 local_hostname = xmalloc_sockaddr2host_noport(&sock_adr.sa, sockadr_size);
328 if (!local_hostname)
329 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
330 }
331 }
332
333 if (!(option_mask32 & OPT_E)) {
334 /* setup ucspi env */
335 xsetenv("PROTO", "TCP");
336 xsetenv("TCPLOCALIP", local_ip);
337 xsetenv("TCPLOCALPORT", utoa(local_port));
338 xsetenv("TCPLOCALHOST", local_hostname);
339 xsetenv("TCPREMOTEIP", remote_ip);
340 xsetenv("TCPREMOTEPORT", utoa(remote_port));
341 if (option_mask32 & OPT_h) {
342 xsetenv("TCPREMOTEHOST", remote_hostname);
343 }
344 xsetenv("TCPREMOTEINFO", "");
345 /* additional */
346 if (cur_per_host > 0)
347 xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
348 }
349
350#if 0
351 if (instructs) {
352 ac = ipsvd_check(iscdb, &inst, &match, (char*)instructs,
353 remote_ip, remote_hostname, timeout);
354 if (ac == -1) drop2("cannot check inst", remote_ip);
355 if (ac == IPSVD_ERR) drop2("cannot read", (char*)instructs);
356 } else
357 ac = IPSVD_DEFAULT;
358#endif
359
360 if (max_per_host && verbose)
361 printf("%s: info: concurrency %u %s %u/%u\n",
362 applet_name, pid, remote_ip, cur_per_host, max_per_host);
363
364 if (verbose) {
365 printf("%s: info: start %u %s:%s :%s:%s:%u\n",
366 applet_name, pid,
367 local_hostname, local_ip,
368 remote_hostname, remote_ip, (unsigned)remote_port);
369#if 0
370 switch(ac) {
371 case IPSVD_DENY:
372 printf("deny "); break;
373 case IPSVD_DEFAULT:
374 case IPSVD_INSTRUCT:
375 printf("start "); break;
376 case IPSVD_EXEC:
377 printf("exec "); break;
378 }
379 ...
380 if (instructs) {
381 printf(" ");
382 if (iscdb) {
383 printf((char*)instructs);
384 printf("/");
385 }
386 outfix(match.s);
387 if(inst.s && inst.len && (verbose > 1)) {
388 printf(": ");
389 printf(&inst);
390 }
391 }
392 printf("\n");
393#endif
394 }
395
396#if 0
397 if (ac == IPSVD_DENY) {
398 close(conn);
399 _exit(100);
400 }
401 if (ac == IPSVD_EXEC) {
402 args[0] = "/bin/sh";
403 args[1] = "-c";
404 args[2] = inst.s;
405 args[3] = 0;
406 run = args;
407 } else
408 run = argv + 2; /* below: we use argv+2 (was using run) */
409#endif
410
411 xmove_fd(conn, 0);
412 dup2(0, 1);
413 signal(SIGTERM, SIG_DFL);
414 signal(SIGPIPE, SIG_DFL);
415 signal(SIGCHLD, SIG_DFL);
416 sig_unblock(SIGCHLD);
417
418 argv += 2;
419#ifdef SSLSVD
420 strcpy(id, utoa(pid);
421 ssl_io(0, argv);
422#else
423 BB_EXECVP(argv[0], argv);
424#endif
425 bb_perror_msg_and_die("exec '%s'", argv[0]);
426}
427
428/*
429tcpsvd [-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name] [-i dir|-x cdb] [ -t sec] host port prog
430
431tcpsvd creates a TCP/IP socket, binds it to the address host:port,
432and listens on the socket for incoming connections.
433
434On each incoming connection, tcpsvd conditionally runs a program,
435with standard input reading from the socket, and standard output
436writing to the socket, to handle this connection. tcpsvd keeps
437listening on the socket for new connections, and can handle
438multiple connections simultaneously.
439
440tcpsvd optionally checks for special instructions depending
441on the IP address or hostname of the client that initiated
442the connection, see ipsvd-instruct(5).
443
444host
445 host either is a hostname, or a dotted-decimal IP address,
446 or 0. If host is 0, tcpsvd accepts connections to any local
447 IP address.
448port
449 tcpsvd accepts connections to host:port. port may be a name
450 from /etc/services or a number.
451prog
452 prog consists of one or more arguments. For each connection,
453 tcpsvd normally runs prog, with file descriptor 0 reading from
454 the network, and file descriptor 1 writing to the network.
455 By default it also sets up TCP-related environment variables,
456 see tcp-environ(5)
457-i dir
458 read instructions for handling new connections from the instructions
459 directory dir. See ipsvd-instruct(5) for details.
460-x cdb
461 read instructions for handling new connections from the constant database
462 cdb. The constant database normally is created from an instructions
463 directory by running ipsvd-cdb(8).
464-t sec
465 timeout. This option only takes effect if the -i option is given.
466 While checking the instructions directory, check the time of last access
467 of the file that matches the clients address or hostname if any, discard
468 and remove the file if it wasn't accessed within the last sec seconds;
469 tcpsvd does not discard or remove a file if the user's write permission
470 is not set, for those files the timeout is disabled. Default is 0,
471 which means that the timeout is disabled.
472-l name
473 local hostname. Do not look up the local hostname in DNS, but use name
474 as hostname. This option must be set if tcpsvd listens on port 53
475 to avoid loops.
476-u user[:group]
477 drop permissions. Switch user ID to user's UID, and group ID to user's
478 primary GID after creating and binding to the socket. If user is followed
479 by a colon and a group name, the group ID is switched to the GID of group
480 instead. All supplementary groups are removed.
481-c n
482 concurrency. Handle up to n connections simultaneously. Default is 30.
483 If there are n connections active, tcpsvd defers acceptance of a new
484 connection until an active connection is closed.
485-C n[:msg]
486 per host concurrency. Allow only up to n connections from the same IP
487 address simultaneously. If there are n active connections from one IP
488 address, new incoming connections from this IP address are closed
489 immediately. If n is followed by :msg, the message msg is written
490 to the client if possible, before closing the connection. By default
491 msg is empty. See ipsvd-instruct(5) for supported escape sequences in msg.
492
493 For each accepted connection, the current per host concurrency is
494 available through the environment variable TCPCONCURRENCY. n and msg
495 can be overwritten by ipsvd(7) instructions, see ipsvd-instruct(5).
496 By default tcpsvd doesn't keep track of connections.
497-h
498 Look up the client's hostname in DNS.
499-p
500 paranoid. After looking up the client's hostname in DNS, look up the IP
501 addresses in DNS for that hostname, and forget about the hostname
502 if none of the addresses match the client's IP address. You should
503 set this option if you use hostname based instructions. The -p option
504 implies the -h option.
505-b n
506 backlog. Allow a backlog of approximately n TCP SYNs. On some systems n
507 is silently limited. Default is 20.
508-E
509 no special environment. Do not set up TCP-related environment variables.
510-v
511 verbose. Print verbose messsages to standard output.
512-vv
513 more verbose. Print more verbose messages to standard output.
514*/
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 118fe3e75..a331e6bc4 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -82,15 +82,15 @@ int xconnect_tcp_v4(struct sockaddr_in *s_addr)
82/* "New" networking API */ 82/* "New" networking API */
83 83
84 84
85int get_nport(const len_and_sockaddr *lsa) 85int get_nport(const struct sockaddr *sa)
86{ 86{
87#if ENABLE_FEATURE_IPV6 87#if ENABLE_FEATURE_IPV6
88 if (lsa->sa.sa_family == AF_INET6) { 88 if (sa->sa_family == AF_INET6) {
89 return lsa->sin6.sin6_port; 89 return ((struct sockaddr_in6*)sa)->sin6_port;
90 } 90 }
91#endif 91#endif
92 if (lsa->sa.sa_family == AF_INET) { 92 if (sa->sa_family == AF_INET) {
93 return lsa->sin.sin_port; 93 return ((struct sockaddr_in*)sa)->sin_port;
94 } 94 }
95 /* What? UNIX socket? IPX?? :) */ 95 /* What? UNIX socket? IPX?? :) */
96 return -1; 96 return -1;
@@ -308,12 +308,10 @@ char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen)
308 return sockaddr2str(sa, salen, 0); 308 return sockaddr2str(sa, salen, 0);
309} 309}
310 310
311/* Unused
312char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa, socklen_t salen) 311char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa, socklen_t salen)
313{ 312{
314 return sockaddr2str(sa, salen, IGNORE_PORT); 313 return sockaddr2str(sa, salen, IGNORE_PORT);
315} 314}
316*/
317 315
318char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa, socklen_t salen) 316char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa, socklen_t salen)
319{ 317{
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 68ad3dec4..b08f92d81 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -205,6 +205,63 @@ int wait4pid(int pid)
205 return 0; 205 return 0;
206} 206}
207 207
208int wait_nohang(int *wstat)
209{
210 return waitpid(-1, wstat, WNOHANG);
211}
212
213int wait_pid(int *wstat, int pid)
214{
215 int r;
216
217 do
218 r = waitpid(pid, wstat, 0);
219 while ((r == -1) && (errno == EINTR));
220 return r;
221}
222
223void sig_block(int sig)
224{
225 sigset_t ss;
226 sigemptyset(&ss);
227 sigaddset(&ss, sig);
228 sigprocmask(SIG_BLOCK, &ss, NULL);
229}
230
231void sig_unblock(int sig)
232{
233 sigset_t ss;
234 sigemptyset(&ss);
235 sigaddset(&ss, sig);
236 sigprocmask(SIG_UNBLOCK, &ss, NULL);
237}
238
239#if 0
240void sig_blocknone(void)
241{
242 sigset_t ss;
243 sigemptyset(&ss);
244 sigprocmask(SIG_SETMASK, &ss, NULL);
245}
246#endif
247
248void sig_catch(int sig, void (*f)(int))
249{
250 struct sigaction sa;
251 sa.sa_handler = f;
252 sa.sa_flags = 0;
253 sigemptyset(&sa.sa_mask);
254 sigaction(sig, &sa, NULL);
255}
256
257void sig_pause(void)
258{
259 sigset_t ss;
260 sigemptyset(&ss);
261 sigsuspend(&ss);
262}
263
264
208void xsetenv(const char *key, const char *value) 265void xsetenv(const char *key, const char *value)
209{ 266{
210 if (setenv(key, value, 1)) 267 if (setenv(key, value, 1))
diff --git a/networking/nc.c b/networking/nc.c
index 1bdecaf5e..bc7c701fe 100644
--- a/networking/nc.c
+++ b/networking/nc.c
@@ -106,7 +106,7 @@ int nc_main(int argc, char **argv)
106 if (!lport) { 106 if (!lport) {
107 socklen_t addrlen = lsa->len; 107 socklen_t addrlen = lsa->len;
108 getsockname(sfd, &lsa->sa, &addrlen); 108 getsockname(sfd, &lsa->sa, &addrlen);
109 lport = get_nport(lsa); 109 lport = get_nport(&lsa->sa);
110 fdprintf(2, "%d\n", ntohs(lport)); 110 fdprintf(2, "%d\n", ntohs(lport));
111 } 111 }
112 fcntl(sfd, F_SETFD, FD_CLOEXEC); 112 fcntl(sfd, F_SETFD, FD_CLOEXEC);
diff --git a/networking/tftp.c b/networking/tftp.c
index bbed9ac78..ea415e5fe 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -287,7 +287,7 @@ static int tftp(
287 bb_perror_msg("recvfrom"); 287 bb_perror_msg("recvfrom");
288 break; 288 break;
289 } 289 }
290 from_port = get_nport(from); 290 from_port = get_nport(&from->sa);
291 if (port == org_port) { 291 if (port == org_port) {
292 /* Our first query went to port 69 292 /* Our first query went to port 69
293 * but reply will come from different one. 293 * but reply will come from different one.
diff --git a/runit/runit_lib.c b/runit/runit_lib.c
index 4762096b4..fcb66c3db 100644
--- a/runit/runit_lib.c
+++ b/runit/runit_lib.c
@@ -385,56 +385,9 @@ int seek_set(int fd,seek_pos pos)
385#endif 385#endif
386 386
387 387
388/*** sig_block.c ***/
389
390void sig_block(int sig)
391{
392 sigset_t ss;
393 sigemptyset(&ss);
394 sigaddset(&ss, sig);
395 sigprocmask(SIG_BLOCK, &ss, NULL);
396}
397
398void sig_unblock(int sig)
399{
400 sigset_t ss;
401 sigemptyset(&ss);
402 sigaddset(&ss, sig);
403 sigprocmask(SIG_UNBLOCK, &ss, NULL);
404}
405
406void sig_blocknone(void)
407{
408 sigset_t ss;
409 sigemptyset(&ss);
410 sigprocmask(SIG_SETMASK, &ss, NULL);
411}
412
413
414/*** sig_catch.c ***/
415
416void sig_catch(int sig,void (*f)(int))
417{
418 struct sigaction sa;
419 sa.sa_handler = f;
420 sa.sa_flags = 0;
421 sigemptyset(&sa.sa_mask);
422 sigaction(sig,&sa, NULL);
423}
424
425
426/*** sig_pause.c ***/
427
428void sig_pause(void)
429{
430 sigset_t ss;
431 sigemptyset(&ss);
432 sigsuspend(&ss);
433}
434
435
436/*** str_chr.c ***/ 388/*** str_chr.c ***/
437 389
390// strchrnul?
438unsigned str_chr(const char *s,int c) 391unsigned str_chr(const char *s,int c)
439{ 392{
440 char ch; 393 char ch;
@@ -449,24 +402,3 @@ unsigned str_chr(const char *s,int c)
449 } 402 }
450 return t - s; 403 return t - s;
451} 404}
452
453
454/*** wait_nohang.c ***/
455
456int wait_nohang(int *wstat)
457{
458 return waitpid(-1, wstat, WNOHANG);
459}
460
461
462/*** wait_pid.c ***/
463
464int wait_pid(int *wstat, int pid)
465{
466 int r;
467
468 do
469 r = waitpid(pid, wstat, 0);
470 while ((r == -1) && (errno == EINTR));
471 return r;
472}
diff --git a/runit/runit_lib.h b/runit/runit_lib.h
index 9fe4166bc..25aeeaf70 100644
--- a/runit/runit_lib.h
+++ b/runit/runit_lib.h
@@ -123,32 +123,9 @@ extern int open_write(const char *);
123extern unsigned pmatch(const char *, const char *, unsigned); 123extern unsigned pmatch(const char *, const char *, unsigned);
124 124
125 125
126/*** sig.h ***/
127
128extern void sig_catch(int,void (*)(int));
129#define sig_ignore(s) (sig_catch((s), SIG_IGN))
130#define sig_uncatch(s) (sig_catch((s), SIG_DFL))
131
132extern void sig_block(int);
133extern void sig_unblock(int);
134extern void sig_blocknone(void);
135extern void sig_pause(void);
136
137
138/*** str.h ***/ 126/*** str.h ***/
139 127
140extern unsigned str_chr(const char *,int); /* never returns NULL */ 128extern unsigned str_chr(const char *,int); /* never returns NULL */
141 129
142#define str_diff(s,t) strcmp((s), (t)) 130#define str_diff(s,t) strcmp((s), (t))
143#define str_equal(s,t) (!strcmp((s), (t))) 131#define str_equal(s,t) (!strcmp((s), (t)))
144
145
146/*** wait.h ***/
147
148extern int wait_pid(int *wstat, int pid);
149extern int wait_nohang(int *wstat);
150
151#define wait_crashed(w) ((w) & 127)
152#define wait_exitcode(w) ((w) >> 8)
153#define wait_stopsig(w) ((w) >> 8)
154#define wait_stopped(w) (((w) & 127) == 127)
diff --git a/runit/runsv.c b/runit/runsv.c
index 018456847..61eb02e64 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -323,11 +323,11 @@ static void startservice(struct svdir *s)
323 close(logpipe[0]); 323 close(logpipe[0]);
324 } 324 }
325 } 325 }
326 sig_uncatch(SIGCHLD); 326 signal(SIGCHLD, SIG_DFL);
327 signal(SIGTERM, SIG_DFL);
327 sig_unblock(SIGCHLD); 328 sig_unblock(SIGCHLD);
328 sig_uncatch(SIGTERM);
329 sig_unblock(SIGTERM); 329 sig_unblock(SIGTERM);
330 execve(*run, run, environ); 330 execvp(*run, run);
331 fatal2_cannot(s->islog ? "start log/" : "start ", *run); 331 fatal2_cannot(s->islog ? "start log/" : "start ", *run);
332 } 332 }
333 if (s->state != S_FINISH) { 333 if (s->state != S_FINISH) {
diff --git a/runit/runsvdir.c b/runit/runsvdir.c
index cce2c5d9c..39929fc49 100644
--- a/runit/runsvdir.c
+++ b/runit/runsvdir.c
@@ -97,9 +97,10 @@ static void runsv(int no, const char *name)
97 prog[0] = (char*)"runsv"; 97 prog[0] = (char*)"runsv";
98 prog[1] = (char*)name; 98 prog[1] = (char*)name;
99 prog[2] = NULL; 99 prog[2] = NULL;
100 sig_uncatch(SIGHUP); 100 if (pgrp)
101 sig_uncatch(SIGTERM); 101 setsid();
102 if (pgrp) setsid(); 102 signal(SIGHUP, SIG_DFL);
103 signal(SIGTERM, SIG_DFL);
103 BB_EXECVP(prog[0], prog); 104 BB_EXECVP(prog[0], prog);
104 //pathexec_run(*prog, prog, (char* const*)environ); 105 //pathexec_run(*prog, prog, (char* const*)environ);
105 fatal2_cannot("start runsv ", name); 106 fatal2_cannot("start runsv ", name);
diff --git a/runit/svlogd.c b/runit/svlogd.c
index fb834a403..1d6625561 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -143,9 +143,9 @@ static unsigned processorstart(struct logdir *ld)
143 int fd; 143 int fd;
144 144
145 /* child */ 145 /* child */
146 sig_uncatch(SIGTERM); 146 signal(SIGTERM, SIG_DFL);
147 sig_uncatch(SIGALRM); 147 signal(SIGALRM, SIG_DFL);
148 sig_uncatch(SIGHUP); 148 signal(SIGHUP, SIG_DFL);
149 sig_unblock(SIGTERM); 149 sig_unblock(SIGTERM);
150 sig_unblock(SIGALRM); 150 sig_unblock(SIGALRM);
151 sig_unblock(SIGHUP); 151 sig_unblock(SIGHUP);