aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
Diffstat (limited to 'networking')
-rw-r--r--networking/inetd.c101
1 files changed, 60 insertions, 41 deletions
diff --git a/networking/inetd.c b/networking/inetd.c
index 0620188d6..41824dbc8 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -130,8 +130,13 @@
130 * tening service socket, and must accept at least one connection request 130 * tening service socket, and must accept at least one connection request
131 * before exiting. Such a server would normally accept and process incoming 131 * before exiting. Such a server would normally accept and process incoming
132 * connection requests until a timeout. 132 * connection requests until a timeout.
133 * 133 */
134 * In short: "stream" can be "wait" or "nowait"; "dgram" must be "wait". 134
135/* Despite of above doc saying that dgram services must use "wait",
136 * "udp nowait" servers are implemented in busyboxed inetd.
137 * IPv6 addresses are also implemented. However, they may look ugly -
138 * ":::service..." means "address '::' (IPv6 wildcard addr)":"service"...
139 * You have to put "tcp6"/"udp6" in protocol field to select IPv6.
135 */ 140 */
136 141
137/* Here's the scoop concerning the user[:group] feature: 142/* Here's the scoop concerning the user[:group] feature:
@@ -832,9 +837,6 @@ static NOINLINE servtab_t *parse_one_line(void)
832 if (sep->se_socktype == SOCK_DGRAM) { 837 if (sep->se_socktype == SOCK_DGRAM) {
833 if (sep->se_proto_no == IPPROTO_TCP) 838 if (sep->se_proto_no == IPPROTO_TCP)
834 goto parse_err; 839 goto parse_err;
835 /* "udp nowait" is a small fork bomb :) */
836 if (!sep->se_wait)
837 goto parse_err;
838 } 840 }
839 841
840 /* check if the hostname specifier is a comma separated list 842 /* check if the hostname specifier is a comma separated list
@@ -1195,7 +1197,7 @@ int inetd_main(int argc, char **argv)
1195 1197
1196 for (;;) { 1198 for (;;) {
1197 int ready_fd_cnt; 1199 int ready_fd_cnt;
1198 int ctrl, accepted_fd; 1200 int ctrl, accepted_fd, new_udp_fd;
1199 fd_set readable; 1201 fd_set readable;
1200 1202
1201 if (maxsock < 0) 1203 if (maxsock < 0)
@@ -1220,12 +1222,43 @@ int inetd_main(int argc, char **argv)
1220 ready_fd_cnt--; 1222 ready_fd_cnt--;
1221 ctrl = sep->se_fd; 1223 ctrl = sep->se_fd;
1222 accepted_fd = -1; 1224 accepted_fd = -1;
1223 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { 1225 new_udp_fd = -1;
1224 ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); 1226 if (!sep->se_wait) {
1225 if (ctrl < 0) { 1227 if (sep->se_socktype == SOCK_STREAM) {
1226 if (errno != EINTR) 1228 ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
1227 bb_perror_msg("accept (for %s)", sep->se_service); 1229 if (ctrl < 0) {
1228 continue; 1230 if (errno != EINTR)
1231 bb_perror_msg("accept (for %s)", sep->se_service);
1232 continue;
1233 }
1234 }
1235 /* "nowait" udp */
1236 if (sep->se_socktype == SOCK_DGRAM
1237 && sep->se_family != AF_UNIX
1238 ) {
1239/* How udp "nowait" works:
1240 * child peeks at (received and buffered by kernel) UDP packet,
1241 * performs connect() on the socket so that it is linked only
1242 * to this peer. But this also affects parent, because descriptors
1243 * are shared after fork() a-la dup(). When parent performs
1244 * select(), it will see this descriptor connected to the peer (!)
1245 * and still readable, will act on it and mess things up
1246 * (can create many copies of same child, etc).
1247 * Parent must create and use new socket instead. */
1248 new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
1249 if (new_udp_fd < 0) { /* error: eat packet, forget about it */
1250 udp_err:
1251 recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
1252 continue;
1253 }
1254 setsockopt_reuseaddr(new_udp_fd);
1255 /* TODO: better do bind after vfork in parent,
1256 * so that we don't have two wildcard bound sockets
1257 * even for a brief moment? */
1258 if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
1259 close(new_udp_fd);
1260 goto udp_err;
1261 }
1229 } 1262 }
1230 } 1263 }
1231 1264
@@ -1283,10 +1316,15 @@ int inetd_main(int argc, char **argv)
1283 1316
1284 if (pid > 0) { /* parent */ 1317 if (pid > 0) { /* parent */
1285 if (sep->se_wait) { 1318 if (sep->se_wait) {
1319 /* tcp wait: we passed listening socket to child,
1320 * will wait for child to terminate */
1286 sep->se_wait = pid; 1321 sep->se_wait = pid;
1287 remove_fd_from_set(sep->se_fd); 1322 remove_fd_from_set(sep->se_fd);
1288 /* we passed listening socket to child, 1323 }
1289 * will wait for child to terminate */ 1324 if (new_udp_fd >= 0) {
1325 /* udp nowait: child connected the socket,
1326 * we created and will use new, unconnected one */
1327 xmove_fd(new_udp_fd, sep->se_fd);
1290 } 1328 }
1291 restore_sigmask(&omask); 1329 restore_sigmask(&omask);
1292 maybe_close(accepted_fd); 1330 maybe_close(accepted_fd);
@@ -1313,39 +1351,20 @@ int inetd_main(int argc, char **argv)
1313#endif 1351#endif
1314 /* child */ 1352 /* child */
1315 setsid(); 1353 setsid();
1316#if 0 1354 /* "nowait" udp */
1317/* This does not work. 1355 if (new_udp_fd >= 0) {
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); 1356 len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
1338 /* peek at the packet and remember peer addr */ 1357 /* peek at the packet and remember peer addr */
1339 int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, 1358 int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
1340 &lsa->u.sa, &lsa->len); 1359 &lsa->u.sa, &lsa->len);
1341 if (r >= 0) 1360 if (r < 0)
1342 /* make this socket "connected" to peer addr: 1361 goto do_exit1;
1343 * only packets from this peer will be recv'ed, 1362 /* make this socket "connected" to peer addr:
1344 * and bare write()/send() will work on it */ 1363 * only packets from this peer will be recv'ed,
1345 connect(ctrl, &lsa->u.sa, lsa->len); 1364 * and bare write()/send() will work on it */
1365 connect(ctrl, &lsa->u.sa, lsa->len);
1346 free(lsa); 1366 free(lsa);
1347 } 1367 }
1348#endif
1349 /* prepare env and exec program */ 1368 /* prepare env and exec program */
1350 pwd = getpwnam(sep->se_user); 1369 pwd = getpwnam(sep->se_user);
1351 if (pwd == NULL) { 1370 if (pwd == NULL) {