mirror of
https://github.com/sheumann/hush.git
synced 2025-03-11 03:31:40 +00:00
tcpsvd,udpsvd: make them NOMMU-capable
inetd: make udp nowait work function old new delta inetd_main 1797 2036 +239 tcpudpsvd_main 1839 1973 +134 xsetenv_plain - 39 +39 xsetenv_proto 23 40 +17 bump_nofile 169 170 +1 sig_term_handler 72 69 -3 sig_child_handler 239 233 -6 connection_status 37 31 -6 parse_one_line 1102 1092 -10 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 4/4 up/down: 430/-25) Total: 405 bytes text data bss dec hex filename 798437 661 7428 806526 c4e7e busybox_old 798734 661 7428 806823 c4fa7 busybox_unstripped
This commit is contained in:
parent
9f153f610f
commit
aefed941c2
@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Automatically generated make config: don't edit
|
# Automatically generated make config: don't edit
|
||||||
# Busybox version: 1.10.0.svn
|
# Busybox version: 1.10.0.svn
|
||||||
# Thu Mar 6 20:18:05 2008
|
# Sat Mar 8 01:11:42 2008
|
||||||
#
|
#
|
||||||
CONFIG_HAVE_DOT_CONFIG=y
|
CONFIG_HAVE_DOT_CONFIG=y
|
||||||
|
|
||||||
@ -844,5 +844,5 @@ CONFIG_LPQ=y
|
|||||||
#
|
#
|
||||||
# ipsvd utilities
|
# ipsvd utilities
|
||||||
#
|
#
|
||||||
# CONFIG_TCPSVD is not set
|
CONFIG_TCPSVD=y
|
||||||
# CONFIG_UDPSVD is not set
|
CONFIG_UDPSVD=y
|
||||||
|
231
ipsvd/tcpudp.c
231
ipsvd/tcpudp.c
@ -13,12 +13,12 @@
|
|||||||
*
|
*
|
||||||
* Code inside "#ifdef SSLSVD" is for sslsvd and is currently unused.
|
* Code inside "#ifdef SSLSVD" is for sslsvd and is currently unused.
|
||||||
*
|
*
|
||||||
* Output of verbose mode matches original (modulo bugs and
|
* Busybox version exports TCPLOCALADDR instead of
|
||||||
* unimplemented stuff). Unnatural splitting of IP and PORT
|
* TCPLOCALIP + TCPLOCALPORT pair. ADDR more closely matches reality
|
||||||
* is retained (personally I prefer one-value "IP:PORT" notation -
|
* (which is "struct sockaddr_XXX". Port is not a separate entity,
|
||||||
* it is a natural string representation of struct sockaddr_XX).
|
* it's just a part of (AF_INET[6]) sockaddr!).
|
||||||
*
|
*
|
||||||
* TCPORIGDST{IP,PORT} is busybox-specific addition
|
* TCPORIGDSTADDR is Busybox-specific addition.
|
||||||
*
|
*
|
||||||
* udp server is hacked up by reusing TCP code. It has the following
|
* udp server is hacked up by reusing TCP code. It has the following
|
||||||
* limitation inherent in Unix DGRAM sockets implementation:
|
* limitation inherent in Unix DGRAM sockets implementation:
|
||||||
@ -46,6 +46,8 @@ struct globals {
|
|||||||
unsigned cur_per_host;
|
unsigned cur_per_host;
|
||||||
unsigned cnum;
|
unsigned cnum;
|
||||||
unsigned cmax;
|
unsigned cmax;
|
||||||
|
char **env_cur;
|
||||||
|
char *env_var[1]; /* actually bigger */
|
||||||
};
|
};
|
||||||
#define G (*(struct globals*)&bb_common_bufsiz1)
|
#define G (*(struct globals*)&bb_common_bufsiz1)
|
||||||
#define verbose (G.verbose )
|
#define verbose (G.verbose )
|
||||||
@ -53,21 +55,46 @@ struct globals {
|
|||||||
#define cur_per_host (G.cur_per_host)
|
#define cur_per_host (G.cur_per_host)
|
||||||
#define cnum (G.cnum )
|
#define cnum (G.cnum )
|
||||||
#define cmax (G.cmax )
|
#define cmax (G.cmax )
|
||||||
|
#define env_cur (G.env_cur )
|
||||||
|
#define env_var (G.env_var )
|
||||||
#define INIT_G() \
|
#define INIT_G() \
|
||||||
do { \
|
do { \
|
||||||
cmax = 30; \
|
cmax = 30; \
|
||||||
|
env_cur = &env_var[0]; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/* We have to be careful about leaking memory in repeated setenv's */
|
||||||
|
static void xsetenv_plain(const char *n, const char *v)
|
||||||
|
{
|
||||||
|
char *var = xasprintf("%s=%s", n, v);
|
||||||
|
*env_cur++ = var;
|
||||||
|
putenv(var);
|
||||||
|
}
|
||||||
|
|
||||||
static void xsetenv_proto(const char *proto, const char *n, const char *v)
|
static void xsetenv_proto(const char *proto, const char *n, const char *v)
|
||||||
{
|
{
|
||||||
putenv(xasprintf("%s%s=%s", proto, n, v));
|
char *var = xasprintf("%s%s=%s", proto, n, v);
|
||||||
|
*env_cur++ = var;
|
||||||
|
putenv(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void undo_xsetenv(void)
|
||||||
|
{
|
||||||
|
char **pp = env_cur = &env_var[0];
|
||||||
|
while (*pp) {
|
||||||
|
char *var = *pp;
|
||||||
|
*strchrnul(var, '=') = '\0';
|
||||||
|
unsetenv(var);
|
||||||
|
free(var);
|
||||||
|
*pp++ = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sig_term_handler(int sig)
|
static void sig_term_handler(int sig)
|
||||||
{
|
{
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf("%s: info: sigterm received, exit\n", applet_name);
|
bb_error_msg("got signal %u, exit", sig);
|
||||||
kill_myself_with_sig(sig);
|
kill_myself_with_sig(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +112,7 @@ static void print_waitstat(unsigned pid, int wstat)
|
|||||||
cause = "signal";
|
cause = "signal";
|
||||||
e = WTERMSIG(wstat);
|
e = WTERMSIG(wstat);
|
||||||
}
|
}
|
||||||
printf("%s: info: end %d %s %d\n", applet_name, pid, cause, e);
|
bb_error_msg("end %d %s %d", pid, cause, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must match getopt32 in main! */
|
/* Must match getopt32 in main! */
|
||||||
@ -113,7 +140,7 @@ static void connection_status(void)
|
|||||||
{
|
{
|
||||||
/* "only 1 client max" desn't need this */
|
/* "only 1 client max" desn't need this */
|
||||||
if (cmax > 1)
|
if (cmax > 1)
|
||||||
printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
|
bb_error_msg("status %u/%u", cnum, cmax);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sig_child_handler(int sig)
|
static void sig_child_handler(int sig)
|
||||||
@ -145,13 +172,11 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
#ifndef SSLSVD
|
#ifndef SSLSVD
|
||||||
struct bb_uidgid_t ugid;
|
struct bb_uidgid_t ugid;
|
||||||
#endif
|
#endif
|
||||||
bool need_hostnames, need_remote_ip, tcp;
|
bool tcp;
|
||||||
uint16_t local_port;
|
uint16_t local_port;
|
||||||
char *local_hostname = NULL;
|
char *preset_local_hostname = NULL;
|
||||||
char *remote_hostname = (char*)""; /* "" used if no -h */
|
char *remote_hostname = remote_hostname; /* for compiler */
|
||||||
char *local_addr = local_addr; /* gcc */
|
char *remote_addr = remote_addr; /* for compiler */
|
||||||
char *remote_addr = remote_addr; /* gcc */
|
|
||||||
char *remote_ip = remote_addr; /* gcc */
|
|
||||||
len_and_sockaddr *lsa;
|
len_and_sockaddr *lsa;
|
||||||
len_and_sockaddr local, remote;
|
len_and_sockaddr local, remote;
|
||||||
socklen_t sa_len;
|
socklen_t sa_len;
|
||||||
@ -168,12 +193,12 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
opt_complementary = "-3:i--i:ph:vv";
|
opt_complementary = "-3:i--i:ph:vv";
|
||||||
#ifdef SSLSVD
|
#ifdef SSLSVD
|
||||||
getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
|
getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
|
||||||
&str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
|
&str_c, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
|
||||||
&str_b, &str_t, &ssluser, &root, &cert, &key, &verbose
|
&str_b, &str_t, &ssluser, &root, &cert, &key, &verbose
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v",
|
getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v",
|
||||||
&str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
|
&str_c, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
|
||||||
&str_b, &str_t, &verbose
|
&str_b, &str_t, &verbose
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
@ -210,26 +235,21 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
if (!tcp)
|
if (!tcp)
|
||||||
max_per_host = 0;
|
max_per_host = 0;
|
||||||
|
|
||||||
/* stdout is used for logging, don't buffer */
|
|
||||||
setlinebuf(stdout);
|
|
||||||
bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */
|
bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */
|
||||||
|
|
||||||
need_hostnames = verbose || !(option_mask32 & OPT_E);
|
|
||||||
need_remote_ip = max_per_host || need_hostnames;
|
|
||||||
|
|
||||||
#ifdef SSLSVD
|
#ifdef SSLSVD
|
||||||
sslser = user;
|
sslser = user;
|
||||||
client = 0;
|
client = 0;
|
||||||
if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
|
if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
|
||||||
xfunc_exitcode = 100;
|
xfunc_exitcode = 100;
|
||||||
bb_error_msg_and_die("fatal: -U ssluser must be set when running as root");
|
bb_error_msg_and_die("-U ssluser must be set when running as root");
|
||||||
}
|
}
|
||||||
if (option_mask32 & OPT_u)
|
if (option_mask32 & OPT_u)
|
||||||
if (!uidgid_get(&sslugid, ssluser, 1)) {
|
if (!uidgid_get(&sslugid, ssluser, 1)) {
|
||||||
if (errno) {
|
if (errno) {
|
||||||
bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
|
bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
|
||||||
}
|
}
|
||||||
bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser);
|
bb_error_msg_and_die("unknown user/group '%s'", ssluser);
|
||||||
}
|
}
|
||||||
if (!cert) cert = "./cert.pem";
|
if (!cert) cert = "./cert.pem";
|
||||||
if (!key) key = cert;
|
if (!key) key = cert;
|
||||||
@ -246,7 +266,7 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
|
|
||||||
sig_block(SIGCHLD);
|
sig_block(SIGCHLD);
|
||||||
signal(SIGCHLD, sig_child_handler);
|
signal(SIGCHLD, sig_child_handler);
|
||||||
signal(SIGTERM, sig_term_handler);
|
bb_signals(BB_SIGS_FATAL, sig_term_handler);
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
if (max_per_host)
|
if (max_per_host)
|
||||||
@ -254,6 +274,8 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
|
|
||||||
local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
|
local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
|
||||||
lsa = xhost2sockaddr(argv[0], local_port);
|
lsa = xhost2sockaddr(argv[0], local_port);
|
||||||
|
argv += 2;
|
||||||
|
|
||||||
sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
|
sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||||
setsockopt_reuseaddr(sock);
|
setsockopt_reuseaddr(sock);
|
||||||
sa_len = lsa->len; /* I presume sockaddr len stays the same */
|
sa_len = lsa->len; /* I presume sockaddr len stays the same */
|
||||||
@ -274,14 +296,13 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa);
|
char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa);
|
||||||
printf("%s: info: listening on %s", applet_name, addr);
|
bb_error_msg("listening on %s, starting", addr);
|
||||||
free(addr);
|
free(addr);
|
||||||
#ifndef SSLSVD
|
#ifndef SSLSVD
|
||||||
if (option_mask32 & OPT_u)
|
if (option_mask32 & OPT_u)
|
||||||
printf(", uid %u, gid %u",
|
printf(", uid %u, gid %u",
|
||||||
(unsigned)ugid.uid, (unsigned)ugid.gid);
|
(unsigned)ugid.uid, (unsigned)ugid.gid);
|
||||||
#endif
|
#endif
|
||||||
puts(", starting");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main accept() loop */
|
/* Main accept() loop */
|
||||||
@ -297,14 +318,15 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
close(0);
|
close(0);
|
||||||
again2:
|
again2:
|
||||||
sig_unblock(SIGCHLD);
|
sig_unblock(SIGCHLD);
|
||||||
|
local.len = remote.len = sa_len;
|
||||||
if (tcp) {
|
if (tcp) {
|
||||||
remote.len = sa_len;
|
|
||||||
conn = accept(sock, &remote.u.sa, &remote.len);
|
conn = accept(sock, &remote.u.sa, &remote.len);
|
||||||
} else {
|
} else {
|
||||||
/* In case recv_from_to won't be able to recover local addr.
|
/* In case recv_from_to won't be able to recover local addr.
|
||||||
* Also sets port - recv_from_to is unable to do it. */
|
* Also sets port - recv_from_to is unable to do it. */
|
||||||
local = *lsa;
|
local = *lsa;
|
||||||
conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.u.sa, &local.u.sa, sa_len);
|
conn = recv_from_to(sock, NULL, 0, MSG_DONTWAIT | MSG_PEEK,
|
||||||
|
&remote.u.sa, &local.u.sa, sa_len);
|
||||||
}
|
}
|
||||||
sig_block(SIGCHLD);
|
sig_block(SIGCHLD);
|
||||||
if (conn < 0) {
|
if (conn < 0) {
|
||||||
@ -317,19 +339,19 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
if (max_per_host) {
|
if (max_per_host) {
|
||||||
/* Drop connection immediately if cur_per_host > max_per_host
|
/* Drop connection immediately if cur_per_host > max_per_host
|
||||||
* (minimizing load under SYN flood) */
|
* (minimizing load under SYN flood) */
|
||||||
remote_ip = xmalloc_sockaddr2dotted_noport(&remote.u.sa);
|
remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa);
|
||||||
cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
|
cur_per_host = ipsvd_perhost_add(remote_addr, max_per_host, &hccp);
|
||||||
if (cur_per_host > max_per_host) {
|
if (cur_per_host > max_per_host) {
|
||||||
/* ipsvd_perhost_add detected that max is exceeded
|
/* ipsvd_perhost_add detected that max is exceeded
|
||||||
* (and did not store ip in connection table) */
|
* (and did not store ip in connection table) */
|
||||||
free(remote_ip);
|
free(remote_addr);
|
||||||
if (msg_per_host) {
|
if (msg_per_host) {
|
||||||
/* don't block or test for errors */
|
/* don't block or test for errors */
|
||||||
ndelay_on(0);
|
send(0, msg_per_host, len_per_host, MSG_DONTWAIT);
|
||||||
write(0, msg_per_host, len_per_host);
|
|
||||||
}
|
}
|
||||||
goto again1;
|
goto again1;
|
||||||
}
|
}
|
||||||
|
/* NB: remote_addr is not leaked, it is stored in conn table */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tcp) {
|
if (!tcp) {
|
||||||
@ -372,19 +394,21 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
pid = fork();
|
pid = vfork();
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
bb_perror_msg("fork");
|
bb_perror_msg("vfork");
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid != 0) {
|
if (pid != 0) {
|
||||||
/* parent */
|
/* Parent */
|
||||||
cnum++;
|
cnum++;
|
||||||
if (verbose)
|
if (verbose)
|
||||||
connection_status();
|
connection_status();
|
||||||
if (hccp)
|
if (hccp)
|
||||||
hccp->pid = pid;
|
hccp->pid = pid;
|
||||||
|
/* clean up changes done by vforked child */
|
||||||
|
undo_xsetenv();
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,78 +418,93 @@ int tcpudpsvd_main(int argc, char **argv)
|
|||||||
if (tcp)
|
if (tcp)
|
||||||
close(sock);
|
close(sock);
|
||||||
|
|
||||||
if (need_remote_ip)
|
{ /* vfork alert! every xmalloc in this block should be freed! */
|
||||||
remote_addr = xmalloc_sockaddr2dotted(&remote.u.sa);
|
char *local_hostname = local_hostname; /* for compiler */
|
||||||
|
char *local_addr = NULL;
|
||||||
|
char *free_me0 = NULL;
|
||||||
|
char *free_me1 = NULL;
|
||||||
|
char *free_me2 = NULL;
|
||||||
|
|
||||||
if (need_hostnames) {
|
if (verbose || !(option_mask32 & OPT_E)) {
|
||||||
if (option_mask32 & OPT_h) {
|
if (!max_per_host) /* remote_addr is not yet known */
|
||||||
remote_hostname = xmalloc_sockaddr2host_noport(&remote.u.sa);
|
free_me0 = remote_addr = xmalloc_sockaddr2dotted(&remote.u.sa);
|
||||||
if (!remote_hostname) {
|
if (option_mask32 & OPT_h) {
|
||||||
bb_error_msg("warning: cannot look up hostname for %s", remote_addr);
|
free_me1 = remote_hostname = xmalloc_sockaddr2host_noport(&remote.u.sa);
|
||||||
remote_hostname = (char*)"";
|
if (!remote_hostname) {
|
||||||
|
bb_error_msg("cannot look up hostname for %s", remote_addr);
|
||||||
|
remote_hostname = remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Find out local IP peer connected to.
|
||||||
|
* Errors ignored (I'm not paranoid enough to imagine kernel
|
||||||
|
* which doesn't know local IP). */
|
||||||
|
if (tcp)
|
||||||
|
getsockname(0, &local.u.sa, &local.len);
|
||||||
|
/* else: for UDP it is done earlier by parent */
|
||||||
|
local_addr = xmalloc_sockaddr2dotted(&local.u.sa);
|
||||||
|
if (option_mask32 & OPT_h) {
|
||||||
|
local_hostname = preset_local_hostname;
|
||||||
|
if (!local_hostname) {
|
||||||
|
free_me2 = local_hostname = xmalloc_sockaddr2host_noport(&local.u.sa);
|
||||||
|
if (!local_hostname)
|
||||||
|
bb_error_msg_and_die("cannot look up hostname for %s", local_addr);
|
||||||
|
}
|
||||||
|
/* else: local_hostname is not NULL, but is NOT malloced! */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Find out local IP peer connected to.
|
if (verbose) {
|
||||||
* Errors ignored (I'm not paranoid enough to imagine kernel
|
pid = getpid();
|
||||||
* which doesn't know local IP). */
|
if (max_per_host) {
|
||||||
if (tcp) {
|
bb_error_msg("concurrency %s %u/%u",
|
||||||
local.len = sa_len;
|
remote_addr,
|
||||||
getsockname(0, &local.u.sa, &local.len);
|
cur_per_host, max_per_host);
|
||||||
|
}
|
||||||
|
bb_error_msg((option_mask32 & OPT_h)
|
||||||
|
? "start %u %s-%s (%s-%s)"
|
||||||
|
: "start %u %s-%s",
|
||||||
|
pid,
|
||||||
|
local_addr, remote_addr,
|
||||||
|
local_hostname, remote_hostname);
|
||||||
}
|
}
|
||||||
local_addr = xmalloc_sockaddr2dotted(&local.u.sa);
|
|
||||||
if (!local_hostname) {
|
if (!(option_mask32 & OPT_E)) {
|
||||||
local_hostname = xmalloc_sockaddr2host_noport(&local.u.sa);
|
/* setup ucspi env */
|
||||||
if (!local_hostname)
|
const char *proto = tcp ? "TCP" : "UDP";
|
||||||
bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_addr);
|
|
||||||
|
/* Extract "original" destination addr:port
|
||||||
|
* from Linux firewall. Useful when you redirect
|
||||||
|
* an outbond connection to local handler, and it needs
|
||||||
|
* to know where it originally tried to connect */
|
||||||
|
if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &local.u.sa, &local.len) == 0) {
|
||||||
|
char *addr = xmalloc_sockaddr2dotted(&local.u.sa);
|
||||||
|
xsetenv_plain("TCPORIGDSTADDR", addr);
|
||||||
|
free(addr);
|
||||||
|
}
|
||||||
|
xsetenv_plain("PROTO", proto);
|
||||||
|
xsetenv_proto(proto, "LOCALADDR", local_addr);
|
||||||
|
xsetenv_proto(proto, "REMOTEADDR", remote_addr);
|
||||||
|
if (option_mask32 & OPT_h) {
|
||||||
|
xsetenv_proto(proto, "LOCALHOST", local_hostname);
|
||||||
|
xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
|
||||||
|
}
|
||||||
|
//compat? xsetenv_proto(proto, "REMOTEINFO", "");
|
||||||
|
/* additional */
|
||||||
|
if (cur_per_host > 0) /* can not be true for udp */
|
||||||
|
xsetenv_plain("TCPCONCURRENCY", utoa(cur_per_host));
|
||||||
}
|
}
|
||||||
|
free(local_addr);
|
||||||
|
free(free_me0);
|
||||||
|
free(free_me1);
|
||||||
|
free(free_me2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
xdup2(0, 1);
|
||||||
pid = getpid();
|
|
||||||
printf("%s: info: pid %u from %s\n", applet_name, pid, remote_addr);
|
|
||||||
if (max_per_host)
|
|
||||||
printf("%s: info: concurrency %u %s %u/%u\n",
|
|
||||||
applet_name, pid, remote_ip, cur_per_host, max_per_host);
|
|
||||||
printf("%s: info: start %u %s:%s :%s:%s\n",
|
|
||||||
applet_name, pid,
|
|
||||||
local_hostname, local_addr,
|
|
||||||
remote_hostname, remote_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(option_mask32 & OPT_E)) {
|
|
||||||
/* setup ucspi env */
|
|
||||||
const char *proto = tcp ? "TCP" : "UDP";
|
|
||||||
|
|
||||||
/* Extract "original" destination addr:port
|
|
||||||
* from Linux firewall. Useful when you redirect
|
|
||||||
* an outbond connection to local handler, and it needs
|
|
||||||
* to know where it originally tried to connect */
|
|
||||||
if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->u.sa, &lsa->len) == 0) {
|
|
||||||
char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa);
|
|
||||||
xsetenv("TCPORIGDSTADDR", addr);
|
|
||||||
free(addr);
|
|
||||||
}
|
|
||||||
xsetenv("PROTO", proto);
|
|
||||||
xsetenv_proto(proto, "LOCALADDR", local_addr);
|
|
||||||
xsetenv_proto(proto, "LOCALHOST", local_hostname);
|
|
||||||
xsetenv_proto(proto, "REMOTEADDR", remote_addr);
|
|
||||||
if (option_mask32 & OPT_h) {
|
|
||||||
xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
|
|
||||||
}
|
|
||||||
xsetenv_proto(proto, "REMOTEINFO", "");
|
|
||||||
/* additional */
|
|
||||||
if (cur_per_host > 0) /* can not be true for udp */
|
|
||||||
xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
|
|
||||||
}
|
|
||||||
|
|
||||||
dup2(0, 1);
|
|
||||||
|
|
||||||
signal(SIGTERM, SIG_DFL);
|
signal(SIGTERM, SIG_DFL);
|
||||||
signal(SIGPIPE, SIG_DFL);
|
signal(SIGPIPE, SIG_DFL);
|
||||||
signal(SIGCHLD, SIG_DFL);
|
signal(SIGCHLD, SIG_DFL);
|
||||||
sig_unblock(SIGCHLD);
|
sig_unblock(SIGCHLD);
|
||||||
|
|
||||||
argv += 2;
|
|
||||||
#ifdef SSLSVD
|
#ifdef SSLSVD
|
||||||
strcpy(id, utoa(pid));
|
strcpy(id, utoa(pid));
|
||||||
ssl_io(0, argv);
|
ssl_io(0, argv);
|
||||||
|
@ -130,8 +130,13 @@
|
|||||||
* tening service socket, and must accept at least one connection request
|
* tening service socket, and must accept at least one connection request
|
||||||
* before exiting. Such a server would normally accept and process incoming
|
* before exiting. Such a server would normally accept and process incoming
|
||||||
* connection requests until a timeout.
|
* connection requests until a timeout.
|
||||||
*
|
*/
|
||||||
* In short: "stream" can be "wait" or "nowait"; "dgram" must be "wait".
|
|
||||||
|
/* Despite of above doc saying that dgram services must use "wait",
|
||||||
|
* "udp nowait" servers are implemented in busyboxed inetd.
|
||||||
|
* IPv6 addresses are also implemented. However, they may look ugly -
|
||||||
|
* ":::service..." means "address '::' (IPv6 wildcard addr)":"service"...
|
||||||
|
* You have to put "tcp6"/"udp6" in protocol field to select IPv6.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Here's the scoop concerning the user[:group] feature:
|
/* Here's the scoop concerning the user[:group] feature:
|
||||||
@ -832,9 +837,6 @@ static NOINLINE servtab_t *parse_one_line(void)
|
|||||||
if (sep->se_socktype == SOCK_DGRAM) {
|
if (sep->se_socktype == SOCK_DGRAM) {
|
||||||
if (sep->se_proto_no == IPPROTO_TCP)
|
if (sep->se_proto_no == IPPROTO_TCP)
|
||||||
goto parse_err;
|
goto parse_err;
|
||||||
/* "udp nowait" is a small fork bomb :) */
|
|
||||||
if (!sep->se_wait)
|
|
||||||
goto parse_err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if the hostname specifier is a comma separated list
|
/* check if the hostname specifier is a comma separated list
|
||||||
@ -1195,7 +1197,7 @@ int inetd_main(int argc, char **argv)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int ready_fd_cnt;
|
int ready_fd_cnt;
|
||||||
int ctrl, accepted_fd;
|
int ctrl, accepted_fd, new_udp_fd;
|
||||||
fd_set readable;
|
fd_set readable;
|
||||||
|
|
||||||
if (maxsock < 0)
|
if (maxsock < 0)
|
||||||
@ -1220,12 +1222,43 @@ int inetd_main(int argc, char **argv)
|
|||||||
ready_fd_cnt--;
|
ready_fd_cnt--;
|
||||||
ctrl = sep->se_fd;
|
ctrl = sep->se_fd;
|
||||||
accepted_fd = -1;
|
accepted_fd = -1;
|
||||||
if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
|
new_udp_fd = -1;
|
||||||
ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
|
if (!sep->se_wait) {
|
||||||
if (ctrl < 0) {
|
if (sep->se_socktype == SOCK_STREAM) {
|
||||||
if (errno != EINTR)
|
ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
|
||||||
bb_perror_msg("accept (for %s)", sep->se_service);
|
if (ctrl < 0) {
|
||||||
continue;
|
if (errno != EINTR)
|
||||||
|
bb_perror_msg("accept (for %s)", sep->se_service);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* "nowait" udp */
|
||||||
|
if (sep->se_socktype == SOCK_DGRAM
|
||||||
|
&& sep->se_family != AF_UNIX
|
||||||
|
) {
|
||||||
|
/* How udp "nowait" works:
|
||||||
|
* child peeks at (received and buffered by kernel) UDP packet,
|
||||||
|
* performs connect() on the socket so that it is linked only
|
||||||
|
* to this peer. But this also affects parent, because descriptors
|
||||||
|
* are shared after fork() a-la dup(). When parent performs
|
||||||
|
* select(), it will see this descriptor connected to the peer (!)
|
||||||
|
* and still readable, will act on it and mess things up
|
||||||
|
* (can create many copies of same child, etc).
|
||||||
|
* Parent must create and use new socket instead. */
|
||||||
|
new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
|
||||||
|
if (new_udp_fd < 0) { /* error: eat packet, forget about it */
|
||||||
|
udp_err:
|
||||||
|
recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
setsockopt_reuseaddr(new_udp_fd);
|
||||||
|
/* TODO: better do bind after vfork in parent,
|
||||||
|
* so that we don't have two wildcard bound sockets
|
||||||
|
* even for a brief moment? */
|
||||||
|
if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
|
||||||
|
close(new_udp_fd);
|
||||||
|
goto udp_err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1283,10 +1316,15 @@ int inetd_main(int argc, char **argv)
|
|||||||
|
|
||||||
if (pid > 0) { /* parent */
|
if (pid > 0) { /* parent */
|
||||||
if (sep->se_wait) {
|
if (sep->se_wait) {
|
||||||
|
/* tcp wait: we passed listening socket to child,
|
||||||
|
* will wait for child to terminate */
|
||||||
sep->se_wait = pid;
|
sep->se_wait = pid;
|
||||||
remove_fd_from_set(sep->se_fd);
|
remove_fd_from_set(sep->se_fd);
|
||||||
/* we passed listening socket to child,
|
}
|
||||||
* will wait for child to terminate */
|
if (new_udp_fd >= 0) {
|
||||||
|
/* udp nowait: child connected the socket,
|
||||||
|
* we created and will use new, unconnected one */
|
||||||
|
xmove_fd(new_udp_fd, sep->se_fd);
|
||||||
}
|
}
|
||||||
restore_sigmask(&omask);
|
restore_sigmask(&omask);
|
||||||
maybe_close(accepted_fd);
|
maybe_close(accepted_fd);
|
||||||
@ -1313,39 +1351,20 @@ int inetd_main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
/* child */
|
/* child */
|
||||||
setsid();
|
setsid();
|
||||||
#if 0
|
/* "nowait" udp */
|
||||||
/* This does not work.
|
if (new_udp_fd >= 0) {
|
||||||
* Actually, it _almost_ works. The idea behind it is: child
|
|
||||||
* can peek at (already received and buffered by kernel) UDP packet,
|
|
||||||
* and perform connect() on the socket so that it is linked only
|
|
||||||
* to this peer. But this also affects parent, because descriptors
|
|
||||||
* are shared after fork() a-la dup(). When parent returns to
|
|
||||||
* select(), it will see this descriptor attached to the peer (!)
|
|
||||||
* and likely still readable, will act on it and mess things up
|
|
||||||
* (can create many copies of same child, etc).
|
|
||||||
* If child will create new socket instead, then bind() and
|
|
||||||
* connect() it to peer's address, descriptor aliasing problem
|
|
||||||
* is solved, but first packet cannot be "transferred" to the new
|
|
||||||
* socket. It is not a problem if child can account for this,
|
|
||||||
* but our child will exec - and exec'ed program does not know
|
|
||||||
* about this "lost packet" problem! Pity... */
|
|
||||||
/* "nowait" udp[6]. Hmmm... */
|
|
||||||
if (!sep->se_wait
|
|
||||||
&& sep->se_socktype == SOCK_DGRAM
|
|
||||||
&& sep->se_family != AF_UNIX
|
|
||||||
) {
|
|
||||||
len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
|
len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
|
||||||
/* peek at the packet and remember peer addr */
|
/* peek at the packet and remember peer addr */
|
||||||
int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
|
int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
|
||||||
&lsa->u.sa, &lsa->len);
|
&lsa->u.sa, &lsa->len);
|
||||||
if (r >= 0)
|
if (r < 0)
|
||||||
/* make this socket "connected" to peer addr:
|
goto do_exit1;
|
||||||
* only packets from this peer will be recv'ed,
|
/* make this socket "connected" to peer addr:
|
||||||
* and bare write()/send() will work on it */
|
* only packets from this peer will be recv'ed,
|
||||||
connect(ctrl, &lsa->u.sa, lsa->len);
|
* and bare write()/send() will work on it */
|
||||||
|
connect(ctrl, &lsa->u.sa, lsa->len);
|
||||||
free(lsa);
|
free(lsa);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
/* prepare env and exec program */
|
/* prepare env and exec program */
|
||||||
pwd = getpwnam(sep->se_user);
|
pwd = getpwnam(sep->se_user);
|
||||||
if (pwd == NULL) {
|
if (pwd == NULL) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user