aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-12 23:13:50 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-12 23:13:50 +0000
commit4cf1d08fc2e50f9abda999d468c5e972ff4995c2 (patch)
tree58dd8efdd7d0f0990d30d8b5f5f53cf2ee35d444 /networking
parent4e6d5117b839cef41cd3919966f95bf25d24d8d9 (diff)
downloadbusybox-w32-4cf1d08fc2e50f9abda999d468c5e972ff4995c2.tar.gz
busybox-w32-4cf1d08fc2e50f9abda999d468c5e972ff4995c2.tar.bz2
busybox-w32-4cf1d08fc2e50f9abda999d468c5e972ff4995c2.zip
nc: remove a bit of bloat
inetd: more NOMMU fixes rx: shrink devfsd: minor shrink vlock: shrink tcpudp: narrow down window where we have no wildcard socket parse_one_line 1015 1102 +87 init_ring - 53 +53 xzalloc_lsa - 48 +48 read_byte 51 50 -1 rearm_alarm 28 25 -3 nc_main 1028 1000 -28 initring 53 - -53 vlock_main 583 496 -87 reread_config_file 1089 991 -98 rx_main 1046 912 -134 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 1/6 up/down: 188/-404) Total: -216 bytes text data bss dec hex filename 800120 661 7428 808209 c5511 busybox_old 799796 661 7428 807885 c53cd busybox_unstripped
Diffstat (limited to 'networking')
-rw-r--r--networking/inetd.c258
-rw-r--r--networking/nc_bloaty.c7
2 files changed, 158 insertions, 107 deletions
diff --git a/networking/inetd.c b/networking/inetd.c
index 8a4c9fbf6..463c7cfcf 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -3,6 +3,7 @@
3/* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */ 3/* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */
4/* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */ 4/* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */
5/* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */ 5/* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */
6/* IPv6 support, many bug fixes by Denys Vlasenko (c) 2008 */
6/* 7/*
7 * Copyright (c) 1983,1991 The Regents of the University of California. 8 * Copyright (c) 1983,1991 The Regents of the University of California.
8 * All rights reserved. 9 * All rights reserved.
@@ -38,21 +39,17 @@
38 39
39/* Inetd - Internet super-server 40/* Inetd - Internet super-server
40 * 41 *
41 * This program invokes all internet services as needed. 42 * This program invokes configured services when a connection
42 * connection-oriented services are invoked each time a 43 * from a peer is established or a datagram arrives.
44 * Connection-oriented services are invoked each time a
43 * connection is made, by creating a process. This process 45 * connection is made, by creating a process. This process
44 * is passed the connection as file descriptor 0 and is 46 * is passed the connection as file descriptor 0 and is
45 * expected to do a getpeername to find out the source host 47 * expected to do a getpeername to find out peer's host
46 * and port. 48 * and port.
47 *
48 * Datagram oriented services are invoked when a datagram 49 * Datagram oriented services are invoked when a datagram
49 * arrives; a process is created and passed a pending message 50 * arrives; a process is created and passed a pending message
50 * on file descriptor 0. Datagram servers may either connect 51 * on file descriptor 0. peer's address can be obtained
51 * to their peer, freeing up the original socket for inetd 52 * using recvfrom.
52 * to receive further messages on, or "take over the socket",
53 * processing all arriving datagrams and, eventually, timing
54 * out. The first type of server is said to be "multi-threaded";
55 * the second type of server "single-threaded".
56 * 53 *
57 * Inetd uses a configuration file which is read at startup 54 * Inetd uses a configuration file which is read at startup
58 * and, possibly, at some later time in response to a hangup signal. 55 * and, possibly, at some later time in response to a hangup signal.
@@ -60,28 +57,28 @@
60 * order shown below. Continuation lines for an entry must begin with 57 * order shown below. Continuation lines for an entry must begin with
61 * a space or tab. All fields must be present in each entry. 58 * a space or tab. All fields must be present in each entry.
62 * 59 *
63 * service name must be in /etc/services 60 * service_name must be in /etc/services
64 * socket type stream/dgram/raw/rdm/seqpacket 61 * socket_type stream/dgram/raw/rdm/seqpacket
65 * protocol must be in /etc/protocols 62 * protocol must be in /etc/protocols
66 * (usually "tcp" or "udp") 63 * (usually "tcp" or "udp")
67 * wait/nowait[.max] single-threaded/multi-threaded, max # 64 * wait/nowait[.max] single-threaded/multi-threaded, max #
68 * user[.group] or user[:group] user/group to run daemon as 65 * user[.group] or user[:group] user/group to run daemon as
69 * server program full path name 66 * server_program full path name
70 * server program arguments maximum of MAXARGS (20) 67 * server_program_arguments maximum of MAXARGS (20)
71 * 68 *
72 * For RPC services 69 * For RPC services
73 * service name/version must be in /etc/rpc 70 * service_name/version must be in /etc/rpc
74 * socket type stream/dgram/raw/rdm/seqpacket 71 * socket_type stream/dgram/raw/rdm/seqpacket
75 * rpc/protocol "rpc/tcp" etc 72 * rpc/protocol "rpc/tcp" etc
76 * wait/nowait[.max] single-threaded/multi-threaded 73 * wait/nowait[.max] single-threaded/multi-threaded
77 * user[.group] or user[:group] user to run daemon as 74 * user[.group] or user[:group] user to run daemon as
78 * server program full path name 75 * server_program full path name
79 * server program arguments maximum of MAXARGS (20) 76 * server_program_arguments maximum of MAXARGS (20)
80 * 77 *
81 * For non-RPC services, the "service name" can be of the form 78 * For non-RPC services, the "service name" can be of the form
82 * hostaddress:servicename, in which case the hostaddress is used 79 * hostaddress:servicename, in which case the hostaddress is used
83 * as the host portion of the address to listen on. If hostaddress 80 * as the host portion of the address to listen on. If hostaddress
84 * consists of a single `*' character, INADDR_ANY is used. 81 * consists of a single '*' character, INADDR_ANY is used.
85 * 82 *
86 * A line can also consist of just 83 * A line can also consist of just
87 * hostaddress: 84 * hostaddress:
@@ -102,7 +99,7 @@
102 * one line for any given RPC service, even if the host-address 99 * one line for any given RPC service, even if the host-address
103 * specifiers are different. 100 * specifiers are different.
104 * 101 *
105 * Comment lines are indicated by a `#' in column 1. 102 * Comment lines are indicated by a '#' in column 1.
106 */ 103 */
107 104
108/* inetd rules for passing file descriptors to children 105/* inetd rules for passing file descriptors to children
@@ -133,6 +130,8 @@
133 * tening service socket, and must accept at least one connection request 130 * tening service socket, and must accept at least one connection request
134 * before exiting. Such a server would normally accept and process incoming 131 * before exiting. Such a server would normally accept and process incoming
135 * connection requests until a timeout. 132 * connection requests until a timeout.
133 *
134 * In short: "stream" can be "wait" or "nowait"; "dgram" must be "wait".
136 */ 135 */
137 136
138/* Here's the scoop concerning the user[:group] feature: 137/* Here's the scoop concerning the user[:group] feature:
@@ -152,26 +151,27 @@
152 151
153#include <syslog.h> 152#include <syslog.h>
154#include <sys/un.h> 153#include <sys/un.h>
154
155#include "libbb.h" 155#include "libbb.h"
156 156
157#if ENABLE_FEATURE_INETD_RPC
158#include <rpc/rpc.h>
159#include <rpc/pmap_clnt.h>
160#endif
161
157#if !BB_MMU 162#if !BB_MMU
158/* stream versions of these builtins are forking, 163/* stream version of chargen is forking but not execing,
159 * can't do that (easily) on NOMMU */ 164 * can't do that (easily) on NOMMU */
160#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
161#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 0
162#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 165#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
163#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0 166#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0
164#endif 167#endif
165 168
166#if ENABLE_FEATURE_INETD_RPC
167#include <rpc/rpc.h>
168#include <rpc/pmap_clnt.h>
169#endif
170
171#define _PATH_INETDPID "/var/run/inetd.pid" 169#define _PATH_INETDPID "/var/run/inetd.pid"
172 170
173#define CNT_INTERVAL 60 /* servers in CNT_INTERVAL sec. */ 171#define CNT_INTERVAL 60 /* servers in CNT_INTERVAL sec. */
174#define RETRYTIME (60*10) /* retry after bind or server fail */ 172#define RETRYTIME 60 /* retry after bind or server fail */
173
174// TODO: explain, or get rid of setrlimit games
175 175
176#ifndef RLIMIT_NOFILE 176#ifndef RLIMIT_NOFILE
177#define RLIMIT_NOFILE RLIMIT_OFILE 177#define RLIMIT_NOFILE RLIMIT_OFILE
@@ -209,20 +209,21 @@ typedef struct servtab_t {
209#else 209#else
210#define is_rpc_service(sep) 0 210#define is_rpc_service(sep) 0
211#endif 211#endif
212 pid_t se_wait; /* 0:"nowait", 1:"wait" */ 212 pid_t se_wait; /* 0:"nowait", 1:"wait", >1:"wait" */
213 /* and waiting for this pid */
213 socktype_t se_socktype; /* SOCK_STREAM/DGRAM/RDM/... */ 214 socktype_t se_socktype; /* SOCK_STREAM/DGRAM/RDM/... */
214 family_t se_family; /* AF_UNIX/INET[6] */ 215 family_t se_family; /* AF_UNIX/INET[6] */
215 smallint se_proto_no; /* almost "getprotobyname(se_proto)" */ 216 /* se_proto_no is used by RPC code only... hmm */
217 smallint se_proto_no; /* IPPROTO_TCP/UDP, n/a for AF_UNIX */
216 smallint se_checked; /* looked at during merge */ 218 smallint se_checked; /* looked at during merge */
219 unsigned se_max; /* allowed instances per minute */
220 unsigned se_count; /* number started since se_time */
221 unsigned se_time; /* whem we started counting */
217 char *se_user; /* user name to run as */ 222 char *se_user; /* user name to run as */
218 char *se_group; /* group name to run as, can be NULL */ 223 char *se_group; /* group name to run as, can be NULL */
219#ifdef INETD_BUILTINS_ENABLED 224#ifdef INETD_BUILTINS_ENABLED
220 const struct builtin *se_builtin; /* if built-in, description */ 225 const struct builtin *se_builtin; /* if built-in, description */
221#endif 226#endif
222// TODO: wrong algorithm!!!
223 unsigned se_max; /* max # of instances of this service */
224 unsigned se_count; /* number started since se_time */
225 unsigned se_time; /* start of se_count */
226 struct servtab_t *se_next; 227 struct servtab_t *se_next;
227 len_and_sockaddr *se_lsa; 228 len_and_sockaddr *se_lsa;
228 char *se_program; /* server program */ 229 char *se_program; /* server program */
@@ -231,60 +232,54 @@ typedef struct servtab_t {
231} servtab_t; 232} servtab_t;
232 233
233#ifdef INETD_BUILTINS_ENABLED 234#ifdef INETD_BUILTINS_ENABLED
234 /* Echo received data */ 235/* Echo received data */
235#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 236#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
236static void echo_stream(int, servtab_t *); 237static void echo_stream(int, servtab_t *);
237static void echo_dg(int, servtab_t *); 238static void echo_dg(int, servtab_t *);
238#endif 239#endif
239 /* Internet /dev/null */ 240/* Internet /dev/null */
240#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 241#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
241static void discard_stream(int, servtab_t *); 242static void discard_stream(int, servtab_t *);
242static void discard_dg(int, servtab_t *); 243static void discard_dg(int, servtab_t *);
243#endif 244#endif
244 /* Return 32 bit time since 1900 */ 245/* Return 32 bit time since 1900 */
245#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 246#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
246static void machtime_stream(int, servtab_t *); 247static void machtime_stream(int, servtab_t *);
247static void machtime_dg(int, servtab_t *); 248static void machtime_dg(int, servtab_t *);
248#endif 249#endif
249 /* Return human-readable time */ 250/* Return human-readable time */
250#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 251#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
251static void daytime_stream(int, servtab_t *); 252static void daytime_stream(int, servtab_t *);
252static void daytime_dg(int, servtab_t *); 253static void daytime_dg(int, servtab_t *);
253#endif 254#endif
254 /* Familiar character generator */ 255/* Familiar character generator */
255#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 256#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
256static void chargen_stream(int, servtab_t *); 257static void chargen_stream(int, servtab_t *);
257static void chargen_dg(int, servtab_t *); 258static void chargen_dg(int, servtab_t *);
258#endif 259#endif
259 260
260struct builtin { 261struct builtin {
261 const char *bi_service; /* internally provided service name */ 262 /* NB: not necessarily NUL terminated */
262 uint8_t bi_fork; /* 1 if stream fn should run in child */ 263 char bi_service7[7]; /* internally provided service name */
263 /* All builtins are "nowait" */ 264 uint8_t bi_fork; /* 1 if stream fn should run in child */
264 /* uint8_t bi_wait; */ /* 1 if should wait for child */
265 void (*bi_stream_fn)(int, servtab_t *); 265 void (*bi_stream_fn)(int, servtab_t *);
266 void (*bi_dgram_fn)(int, servtab_t *); 266 void (*bi_dgram_fn)(int, servtab_t *);
267}; 267};
268 268
269static const struct builtin builtins[] = { 269static const struct builtin builtins[] = {
270#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 270#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
271 /* Echo received data */
272 { "echo", 1, echo_stream, echo_dg }, 271 { "echo", 1, echo_stream, echo_dg },
273#endif 272#endif
274#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 273#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
275 /* Internet /dev/null */
276 { "discard", 1, discard_stream, discard_dg }, 274 { "discard", 1, discard_stream, discard_dg },
277#endif 275#endif
278#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 276#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
279 /* Familiar character generator */
280 { "chargen", 1, chargen_stream, chargen_dg }, 277 { "chargen", 1, chargen_stream, chargen_dg },
281#endif 278#endif
282#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 279#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
283 /* Return 32 bit time since 1900 */
284 { "time", 0, machtime_stream, machtime_dg }, 280 { "time", 0, machtime_stream, machtime_dg },
285#endif 281#endif
286#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 282#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
287 /* Return human-readable time */
288 { "daytime", 0, daytime_stream, daytime_dg }, 283 { "daytime", 0, daytime_stream, daytime_dg },
289#endif 284#endif
290}; 285};
@@ -305,8 +300,8 @@ struct globals {
305 FILE *fconfig; 300 FILE *fconfig;
306 char *default_local_hostname; 301 char *default_local_hostname;
307#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 302#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
308 char *endring; 303 char *end_ring;
309 char *ringpos; 304 char *ring_pos;
310 char ring[128]; 305 char ring[128];
311#endif 306#endif
312 fd_set allsock; 307 fd_set allsock;
@@ -333,8 +328,8 @@ struct BUG_G_too_big {
333#define default_local_hostname (G.default_local_hostname) 328#define default_local_hostname (G.default_local_hostname)
334#define first_ps_byte (G.first_ps_byte ) 329#define first_ps_byte (G.first_ps_byte )
335#define last_ps_byte (G.last_ps_byte ) 330#define last_ps_byte (G.last_ps_byte )
336#define endring (G.endring ) 331#define end_ring (G.end_ring )
337#define ringpos (G.ringpos ) 332#define ring_pos (G.ring_pos )
338#define ring (G.ring ) 333#define ring (G.ring )
339#define allsock (G.allsock ) 334#define allsock (G.allsock )
340#define line (G.line ) 335#define line (G.line )
@@ -357,6 +352,8 @@ static len_and_sockaddr *xzalloc_lsa(int family)
357 int sz; 352 int sz;
358 353
359 sz = sizeof(struct sockaddr_in); 354 sz = sizeof(struct sockaddr_in);
355 if (family == AF_UNIX)
356 sz = sizeof(struct sockaddr_un);
360#if ENABLE_FEATURE_IPV6 357#if ENABLE_FEATURE_IPV6
361 if (family == AF_INET6) 358 if (family == AF_INET6)
362 sz = sizeof(struct sockaddr_in6); 359 sz = sizeof(struct sockaddr_in6);
@@ -367,7 +364,6 @@ static len_and_sockaddr *xzalloc_lsa(int family)
367 return lsa; 364 return lsa;
368} 365}
369 366
370
371static void rearm_alarm(void) 367static void rearm_alarm(void)
372{ 368{
373 if (!alarm_armed) { 369 if (!alarm_armed) {
@@ -660,10 +656,8 @@ static NOINLINE servtab_t *parse_one_line(void)
660 } 656 }
661 657
662 arg = next_word(&cp); 658 arg = next_word(&cp);
663 if (arg == NULL) { 659 if (arg == NULL) /* a blank line. */
664 /* A blank line. */
665 goto more; 660 goto more;
666 }
667 661
668 /* [host:]service socktype proto wait user[:group] prog [args] */ 662 /* [host:]service socktype proto wait user[:group] prog [args] */
669 /* Check for "host:...." line */ 663 /* Check for "host:...." line */
@@ -764,9 +758,9 @@ static NOINLINE servtab_t *parse_one_line(void)
764 } 758 }
765 /* we don't really need getprotobyname()! */ 759 /* we don't really need getprotobyname()! */
766 if (strcmp(arg, "tcp") == 0) 760 if (strcmp(arg, "tcp") == 0)
767 sep->se_proto_no = 6; 761 sep->se_proto_no = IPPROTO_TCP; /* = 6 */
768 if (strcmp(arg, "udp") == 0) 762 if (strcmp(arg, "udp") == 0)
769 sep->se_proto_no = 17; 763 sep->se_proto_no = IPPROTO_UDP; /* = 17 */
770 if (six) 764 if (six)
771 *six = '6'; 765 *six = '6';
772 if (!sep->se_proto_no) /* not tcp/udp?? */ 766 if (!sep->se_proto_no) /* not tcp/udp?? */
@@ -785,7 +779,11 @@ static NOINLINE servtab_t *parse_one_line(void)
785 if (errno) 779 if (errno)
786 goto parse_err; 780 goto parse_err;
787 } 781 }
788 sep->se_wait = (strcmp(arg, "wait") == 0); 782 sep->se_wait = (arg[0] != 'n' || arg[1] != 'o');
783 if (!sep->se_wait) /* "no" seen */
784 arg += 2;
785 if (strcmp(arg, "wait") != 0)
786 goto parse_err;
789 787
790 /* user[:group] prog [args] */ 788 /* user[:group] prog [args] */
791 sep->se_user = xstrdup(next_word(&cp)); 789 sep->se_user = xstrdup(next_word(&cp));
@@ -804,48 +802,56 @@ static NOINLINE servtab_t *parse_one_line(void)
804 if (sep->se_program == NULL) 802 if (sep->se_program == NULL)
805 goto parse_err; 803 goto parse_err;
806#ifdef INETD_BUILTINS_ENABLED 804#ifdef INETD_BUILTINS_ENABLED
807 /* sep->se_builtin = NULL; - done by new_servtab() */
808 if (strcmp(sep->se_program, "internal") == 0 805 if (strcmp(sep->se_program, "internal") == 0
806 && strlen(sep->se_service) <= 7
809 && (sep->se_socktype == SOCK_STREAM 807 && (sep->se_socktype == SOCK_STREAM
810 || sep->se_socktype == SOCK_DGRAM) 808 || sep->se_socktype == SOCK_DGRAM)
811 ) { 809 ) {
812 int i; 810 int i;
813 for (i = 0; i < ARRAY_SIZE(builtins); i++) 811 for (i = 0; i < ARRAY_SIZE(builtins); i++)
814 if (strcmp(builtins[i].bi_service, sep->se_service) == 0) 812 if (strncmp(builtins[i].bi_service7, sep->se_service, 7) == 0)
815 goto found_bi; 813 goto found_bi;
816 bb_error_msg("unknown internal service %s", sep->se_service); 814 bb_error_msg("unknown internal service %s", sep->se_service);
817 goto parse_err; 815 goto parse_err;
818 found_bi: 816 found_bi:
819 sep->se_builtin = &builtins[i]; 817 sep->se_builtin = &builtins[i];
820 sep->se_wait = 0; /* = builtins[i].bi_wait; - always 0 */ 818 /* stream builtins must be "nowait", dgram must be "wait" */
819 if (sep->se_wait != (sep->se_socktype == SOCK_DGRAM))
820 goto parse_err;
821 } 821 }
822#endif 822#endif
823 argc = 0; 823 argc = 0;
824 while ((arg = next_word(&cp)) != NULL && argc < MAXARGV) { 824 while ((arg = next_word(&cp)) != NULL && argc < MAXARGV)
825 sep->se_argv[argc++] = xstrdup(arg); 825 sep->se_argv[argc++] = xstrdup(arg);
826
827 /* catch mixups. "<service> stream udp ..." == wtf */
828 if (sep->se_socktype == SOCK_STREAM) {
829 if (sep->se_proto_no == IPPROTO_UDP)
830 goto parse_err;
831 }
832 if (sep->se_socktype == SOCK_DGRAM) {
833 if (sep->se_proto_no == IPPROTO_TCP)
834 goto parse_err;
835 /* "udp nowait" is a small fork bomb :) */
836 if (!sep->se_wait)
837 goto parse_err;
826 } 838 }
827 /* while (argc <= MAXARGV) */ 839
828 /* sep->se_argv[argc++] = NULL; - done by new_servtab() */ 840 /* check if the hostname specifier is a comma separated list
829 841 * of hostnames. we'll make new entries for each address. */
830 /*
831 * Now that we've processed the entire line, check if the hostname
832 * specifier was a comma separated list of hostnames. If so
833 * we'll make new entries for each address.
834 */
835 while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) { 842 while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) {
836 nsep = dup_servtab(sep); 843 nsep = dup_servtab(sep);
837 /* 844 /* NUL terminate the hostname field of the existing entry,
838 * NUL terminate the hostname field of the existing entry, 845 * and make a dup for the new entry. */
839 * and make a dup for the new entry.
840 */
841 *hostdelim++ = '\0'; 846 *hostdelim++ = '\0';
842 nsep->se_local_hostname = xstrdup(hostdelim); 847 nsep->se_local_hostname = xstrdup(hostdelim);
843 nsep->se_next = sep->se_next; 848 nsep->se_next = sep->se_next;
844 sep->se_next = nsep; 849 sep->se_next = nsep;
845 } 850 }
846 851
847 /* Was doing it here: */ 852 /* was doing it here: */
848 /* DNS resolution, create copies for each IP address */ 853 /* DNS resolution, create copies for each IP address */
854 /* IPv6-ization destroyed it :( */
849 855
850 return sep; 856 return sep;
851} 857}
@@ -947,15 +953,9 @@ static void reread_config_file(int sig ATTRIBUTE_UNUSED)
947 switch (sep->se_family) { 953 switch (sep->se_family) {
948 struct sockaddr_un *sun; 954 struct sockaddr_un *sun;
949 case AF_UNIX: 955 case AF_UNIX:
950 /* we have poor infrastructure for AF_UNIX... */ 956 lsa = xzalloc_lsa(AF_UNIX);
951 n = strlen(sep->se_service);
952 if (n > sizeof(sun->sun_path) - 1)
953 n = sizeof(sun->sun_path) - 1;
954 lsa = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
955 lsa->len = sizeof(struct sockaddr_un);
956 sun = (struct sockaddr_un*)&lsa->u.sa; 957 sun = (struct sockaddr_un*)&lsa->u.sa;
957 sun->sun_family = AF_UNIX; 958 safe_strncpy(sun->sun_path, sep->se_service, sizeof(sun->sun_path));
958 strncpy(sun->sun_path, sep->se_service, n);
959 break; 959 break;
960 960
961 default: /* case AF_INET, case AF_INET6 */ 961 default: /* case AF_INET, case AF_INET6 */
@@ -1259,8 +1259,8 @@ int inetd_main(int argc, char **argv)
1259 sep->se_count = 0; 1259 sep->se_count = 0;
1260 } 1260 }
1261 } 1261 }
1262 /* on NOMMU, streamed echo, chargen and discard 1262 /* on NOMMU, streamed chargen
1263 * builtins wouldn't work, but they are 1263 * builtin wouldn't work, but it is
1264 * not allowed on NOMMU (ifdefed out) */ 1264 * not allowed on NOMMU (ifdefed out) */
1265#ifdef INETD_BUILTINS_ENABLED 1265#ifdef INETD_BUILTINS_ENABLED
1266 if (BB_MMU && sep->se_builtin) 1266 if (BB_MMU && sep->se_builtin)
@@ -1311,8 +1311,42 @@ int inetd_main(int argc, char **argv)
1311 continue; /* -> check next fd in fd set */ 1311 continue; /* -> check next fd in fd set */
1312 } 1312 }
1313#endif 1313#endif
1314 /* child. prepare env and exec program */ 1314 /* child */
1315 setsid(); 1315 setsid();
1316#if 0
1317/* This does not work.
1318 * Actually, it _almost_ works. The idea behind it is: child
1319 * can peek at (already received and buffered by kernel) UDP packet,
1320 * and perform connect() on the socket so that it is linked only
1321 * to this peer. But this also affects parent, because descriptors
1322 * are shared after fork() a-la dup(). When parent returns to
1323 * select(), it will see this descriptor attached to the peer (!)
1324 * and likely still readable, will act on it and mess things up
1325 * (can create many copies of same child, etc).
1326 * If child will create new socket instead, then bind() and
1327 * connect() it to peer's address, descriptor aliasing problem
1328 * is solved, but first packet cannot be "transferred" to the new
1329 * socket. It is not a problem if child can account for this,
1330 * but our child will exec - and exec'ed program does not know
1331 * about this "lost packet" problem! Pity... */
1332 /* "nowait" udp[6]. Hmmm... */
1333 if (!sep->se_wait
1334 && sep->se_socktype == SOCK_DGRAM
1335 && sep->se_family != AF_UNIX
1336 ) {
1337 len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
1338 /* peek at the packet and remember peer addr */
1339 int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
1340 &lsa->u.sa, &lsa->len);
1341 if (r >= 0)
1342 /* make this socket "connected" to peer addr:
1343 * only packets from this peer will be recv'ed,
1344 * and bare write()/send() will work on it */
1345 connect(ctrl, &lsa->u.sa, lsa->len);
1346 free(lsa);
1347 }
1348#endif
1349 /* prepare env and exec program */
1316 pwd = getpwnam(sep->se_user); 1350 pwd = getpwnam(sep->se_user);
1317 if (pwd == NULL) { 1351 if (pwd == NULL) {
1318 bb_error_msg("%s: no such user", sep->se_user); 1352 bb_error_msg("%s: no such user", sep->se_user);
@@ -1342,8 +1376,8 @@ int inetd_main(int argc, char **argv)
1342 bb_perror_msg("setrlimit"); 1376 bb_perror_msg("setrlimit");
1343 closelog(); 1377 closelog();
1344 xmove_fd(ctrl, 0); 1378 xmove_fd(ctrl, 0);
1345 dup2(0, 1); 1379 xdup2(0, 1);
1346 dup2(0, 2); 1380 xdup2(0, 2);
1347 /* NB: among others, this loop closes listening socket 1381 /* NB: among others, this loop closes listening socket
1348 * for nowait stream children */ 1382 * for nowait stream children */
1349 for (sep2 = serv_list; sep2; sep2 = sep2->se_next) 1383 for (sep2 = serv_list; sep2; sep2 = sep2->se_next)
@@ -1378,6 +1412,8 @@ static void echo_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
1378 } 1412 }
1379#else 1413#else
1380 static const char *const args[] = { "cat", NULL }; 1414 static const char *const args[] = { "cat", NULL };
1415 /* no error messages */
1416 xmove_fd(xopen("/dev/null", O_WRONLY), STDERR_FILENO);
1381 BB_EXECVP("cat", (char**)args); 1417 BB_EXECVP("cat", (char**)args);
1382 _exit(1); 1418 _exit(1);
1383#endif 1419#endif
@@ -1404,8 +1440,16 @@ static void echo_dg(int s, servtab_t *sep)
1404/* ARGSUSED */ 1440/* ARGSUSED */
1405static void discard_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1441static void discard_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
1406{ 1442{
1443#if BB_MMU
1407 while (safe_read(s, line, LINE_SIZE) > 0) 1444 while (safe_read(s, line, LINE_SIZE) > 0)
1408 continue; 1445 continue;
1446#else
1447 static const char *const args[] = { "dd", "of=/dev/null", NULL };
1448 /* no error messages */
1449 xmove_fd(xopen("/dev/null", O_WRONLY), STDERR_FILENO);
1450 BB_EXECVP("dd", (char**)args);
1451 _exit(1);
1452#endif
1409} 1453}
1410/* ARGSUSED */ 1454/* ARGSUSED */
1411static void discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1455static void discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
@@ -1418,14 +1462,14 @@ static void discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
1418 1462
1419#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1463#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
1420#define LINESIZ 72 1464#define LINESIZ 72
1421static void initring(void) 1465static void init_ring(void)
1422{ 1466{
1423 int i; 1467 int i;
1424 1468
1425 endring = ring; 1469 end_ring = ring;
1426 for (i = 0; i <= 128; ++i) 1470 for (i = 0; i <= 128; ++i)
1427 if (isprint(i)) 1471 if (isprint(i))
1428 *endring++ = i; 1472 *end_ring++ = i;
1429} 1473}
1430/* Character generator. MMU arches only. */ 1474/* Character generator. MMU arches only. */
1431/* ARGSUSED */ 1475/* ARGSUSED */
@@ -1435,8 +1479,8 @@ static void chargen_stream(int s, servtab_t *sep)
1435 int len; 1479 int len;
1436 char text[LINESIZ + 2]; 1480 char text[LINESIZ + 2];
1437 1481
1438 if (!endring) { 1482 if (!end_ring) {
1439 initring(); 1483 init_ring();
1440 rs = ring; 1484 rs = ring;
1441 } 1485 }
1442 1486
@@ -1444,14 +1488,14 @@ static void chargen_stream(int s, servtab_t *sep)
1444 text[LINESIZ + 1] = '\n'; 1488 text[LINESIZ + 1] = '\n';
1445 rs = ring; 1489 rs = ring;
1446 for (;;) { 1490 for (;;) {
1447 len = endring - rs; 1491 len = end_ring - rs;
1448 if (len >= LINESIZ) 1492 if (len >= LINESIZ)
1449 memmove(text, rs, LINESIZ); 1493 memmove(text, rs, LINESIZ);
1450 else { 1494 else {
1451 memmove(text, rs, len); 1495 memmove(text, rs, len);
1452 memmove(text + len, ring, LINESIZ - len); 1496 memmove(text + len, ring, LINESIZ - len);
1453 } 1497 }
1454 if (++rs == endring) 1498 if (++rs == end_ring)
1455 rs = ring; 1499 rs = ring;
1456 xwrite(s, text, sizeof(text)); 1500 xwrite(s, text, sizeof(text));
1457 } 1501 }
@@ -1469,20 +1513,20 @@ static void chargen_dg(int s, servtab_t *sep)
1469 if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0) 1513 if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1470 return; 1514 return;
1471 1515
1472 if (!endring) { 1516 if (!end_ring) {
1473 initring(); 1517 init_ring();
1474 ringpos = ring; 1518 ring_pos = ring;
1475 } 1519 }
1476 1520
1477 len = endring - ringpos; 1521 len = end_ring - ring_pos;
1478 if (len >= LINESIZ) 1522 if (len >= LINESIZ)
1479 memmove(text, ringpos, LINESIZ); 1523 memmove(text, ring_pos, LINESIZ);
1480 else { 1524 else {
1481 memmove(text, ringpos, len); 1525 memmove(text, ring_pos, len);
1482 memmove(text + len, ring, LINESIZ - len); 1526 memmove(text + len, ring, LINESIZ - len);
1483 } 1527 }
1484 if (++ringpos == endring) 1528 if (++ring_pos == end_ring)
1485 ringpos = ring; 1529 ring_pos = ring;
1486 text[LINESIZ] = '\r'; 1530 text[LINESIZ] = '\r';
1487 text[LINESIZ + 1] = '\n'; 1531 text[LINESIZ + 1] = '\n';
1488 sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len); 1532 sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len);
@@ -1498,7 +1542,7 @@ static void chargen_dg(int s, servtab_t *sep)
1498 * we must add 2208988800 seconds to this figure to make up for 1542 * we must add 2208988800 seconds to this figure to make up for
1499 * some seventy years Bell Labs was asleep. 1543 * some seventy years Bell Labs was asleep.
1500 */ 1544 */
1501static unsigned machtime(void) 1545static uint32_t machtime(void)
1502{ 1546{
1503 struct timeval tv; 1547 struct timeval tv;
1504 1548
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 2ee833e3f..ce4829584 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -751,6 +751,11 @@ int nc_main(int argc, char **argv)
751 if (option_mask32 & OPT_s) { /* local address */ 751 if (option_mask32 & OPT_s) { /* local address */
752 /* if o_lport is still 0, then we will use random port */ 752 /* if o_lport is still 0, then we will use random port */
753 ouraddr = xhost2sockaddr(str_s, o_lport); 753 ouraddr = xhost2sockaddr(str_s, o_lport);
754#ifdef BLOAT
755 /* prevent spurious "UDP listen needs !0 port" */
756 o_lport = get_nport(ouraddr);
757 o_lport = ntohs(o_lport);
758#endif
754 x = xsocket(ouraddr->u.sa.sa_family, x, 0); 759 x = xsocket(ouraddr->u.sa.sa_family, x, 0);
755 } else { 760 } else {
756 /* We try IPv6, then IPv4, unless addr family is 761 /* We try IPv6, then IPv4, unless addr family is
@@ -771,12 +776,14 @@ int nc_main(int argc, char **argv)
771 setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf); 776 setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf);
772#endif 777#endif
773 778
779#ifdef BLOAT
774 if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) { 780 if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) {
775 /* apparently UDP can listen ON "port 0", 781 /* apparently UDP can listen ON "port 0",
776 but that's not useful */ 782 but that's not useful */
777 if (!o_lport) 783 if (!o_lport)
778 bb_error_msg_and_die("UDP listen needs nonzero -p port"); 784 bb_error_msg_and_die("UDP listen needs nonzero -p port");
779 } 785 }
786#endif
780 787
781 FD_SET(0, &ding1); /* stdin *is* initially open */ 788 FD_SET(0, &ding1); /* stdin *is* initially open */
782 if (proggie) { 789 if (proggie) {