diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-12 23:13:50 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-12 23:13:50 +0000 |
commit | 4cf1d08fc2e50f9abda999d468c5e972ff4995c2 (patch) | |
tree | 58dd8efdd7d0f0990d30d8b5f5f53cf2ee35d444 /networking | |
parent | 4e6d5117b839cef41cd3919966f95bf25d24d8d9 (diff) | |
download | busybox-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.c | 258 | ||||
-rw-r--r-- | networking/nc_bloaty.c | 7 |
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 |
236 | static void echo_stream(int, servtab_t *); | 237 | static void echo_stream(int, servtab_t *); |
237 | static void echo_dg(int, servtab_t *); | 238 | static 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 |
241 | static void discard_stream(int, servtab_t *); | 242 | static void discard_stream(int, servtab_t *); |
242 | static void discard_dg(int, servtab_t *); | 243 | static 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 |
246 | static void machtime_stream(int, servtab_t *); | 247 | static void machtime_stream(int, servtab_t *); |
247 | static void machtime_dg(int, servtab_t *); | 248 | static 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 |
251 | static void daytime_stream(int, servtab_t *); | 252 | static void daytime_stream(int, servtab_t *); |
252 | static void daytime_dg(int, servtab_t *); | 253 | static 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 |
256 | static void chargen_stream(int, servtab_t *); | 257 | static void chargen_stream(int, servtab_t *); |
257 | static void chargen_dg(int, servtab_t *); | 258 | static void chargen_dg(int, servtab_t *); |
258 | #endif | 259 | #endif |
259 | 260 | ||
260 | struct builtin { | 261 | struct 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 | ||
269 | static const struct builtin builtins[] = { | 269 | static 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 | |||
371 | static void rearm_alarm(void) | 367 | static 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 */ |
1405 | static void discard_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) | 1441 | static 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 */ |
1411 | static void discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) | 1455 | static 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 |
1421 | static void initring(void) | 1465 | static 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 | */ |
1501 | static unsigned machtime(void) | 1545 | static 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) { |