Vanilla Development Maling List Archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
CVS update: Vanilla/newstartd
Date: Friday March 12, 1999 @ 18:34
Author: cameron
Update of /home/netrek/cvsroot/Vanilla/newstartd
In directory cvs.castle.real-time.com:/var/tmp/cvs-serv8347
Modified Files:
newstartd.c
Log Message:
clean up and add maxprocess limit to avoid denial of service attack
****************************************
Index: Vanilla/newstartd/newstartd.c
diff -u Vanilla/newstartd/newstartd.c:1.7 Vanilla/newstartd/newstartd.c:1.8
--- Vanilla/newstartd/newstartd.c:1.7 Mon Feb 15 04:24:08 1999
+++ Vanilla/newstartd/newstartd.c Fri Mar 12 18:34:08 1999
@@ -1,7 +1,7 @@
-/* $Id: newstartd.c,v 1.7 1999/02/15 10:24:08 cameron Exp $ */
+/* $Id: newstartd.c,v 1.8 1999/03/13 00:34:08 cameron Exp $ */
#ifndef lint
-static char vcid[] = "$Id: newstartd.c,v 1.7 1999/02/15 10:24:08 cameron Exp $";
+static char vcid[] = "$Id: newstartd.c,v 1.8 1999/03/13 00:34:08 cameron Exp $";
#endif /* lint */
/*
@@ -74,7 +74,11 @@
#define PORTFILE LIBDIR"/.ports" /* default .ports file path */
#define MAXPROG 16 /* maximum ports to listen to */
+#define MAXPROCESSES 8+MAXPLAYER+TESTERS+MAXWAITING
+ /* maximum processes to create */
+static int active; /* number of processes running */
+
static
struct progrecord { /* array of data read from file */
unsigned short port; /* port number to listen on */
@@ -98,27 +102,29 @@
int port_idx = -1;
int num_progs = 0;
int i;
-
+
+ active = 0;
getpath ();
/* if someone tries to ask for help, give 'em it */
if (argc == 2 && argv[1][0] == '-') {
- fprintf (stderr, "Usage: %s [portfile]\n", argv[0] );
+ fprintf (stderr, "Usage: %s [portfile] [debug]\n", argv[0] );
exit (1);
}
/* allow user to specify a port file to use */
if (argc == 2) portfile = argv[1];
+ /* allow user to ask for verbose output */
+ if (argc == 3 && !strcmp(argv[2], "debug")) debug++;
+
/* set up handlers for signals */
SIGNAL (SIGCHLD, reaper);
SIGNAL (SIGHUP, hangup);
SIGNAL (SIGUSR1, SIG_IGN);
/* detach from terminal */
- if (!debug) {
- DETACH
- }
+ DETACH
/* open the connection log file */
if ((fd = open (LogFile, O_CREAT | O_WRONLY | O_APPEND, 0600)) < 0) {
@@ -139,6 +145,7 @@
/* run until restart requested */
while (!restart) {
+ pid_t pid;
/* wait for one connection */
port_idx = get_connection (num_progs);
@@ -153,19 +160,39 @@
continue;
}
+ /* check for limit */
+ if (active > MAXPROCESSES) {
+ fprintf(stderr,
+ "newstartd: hit maximum processes, connection closed\n");
+ close (0);
+ continue;
+ }
+
/* check for internals */
if (prog[port_idx].internal) {
statistics (port_idx, num_progs);
continue;
}
- prog[port_idx].forks++;
/* fork to execute the program specified by .ports file */
- if (fork () == 0) {
+ pid = fork ();
+ if (pid == -1) {
+ perror("fork");
+ close (0);
+ continue;
+ }
+
+ if (pid == 0) {
process (port_idx); /* returns only on error */
exit (0);
}
+ prog[port_idx].forks++;
+ active++;
+
+ if (debug) fprintf (stderr, "active++: %d: pid %d port %d\n", active,
+ pid, prog[port_idx].port);
+
/* main program continues after fork, close socket to client */
close (0);
@@ -201,61 +228,70 @@
for (i = 0; i < num_progs; i++) {
sock = prog[i].sock;
if (sock < 0) {
+
+ fprintf (stderr, "port %d, %s, ", prog[i].port, prog[i].prog);
if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
perror ("socket");
sleep (1);
return -1;
}
+
+ /* we can't cope with having socket zero for a listening socket */
+ if (sock == 0) {
+ if (debug) fprintf (stderr, "gack: don't want socket zero\n");
+ if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror ("socket");
+ sleep (1);
+ close (0);
+ return -1;
+ }
+ close (0);
+ }
/* set the listening socket to close on exec so that children
don't hold open the file descriptor, thus preventing us from
restarting newstartd. */
if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
- perror ("fcntl F_SETFD FD_CLOEXEC failure");
+ perror ("fcntl F_SETFD FD_CLOEXEC");
+ close (sock);
+ sleep (1);
+ return -1;
}
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
- addr.sin_port = htons (prog[i].port);
-
+ /* set the listening socket to allow re-use of the address (port)
+ so that we don't have to pay the CLOSE_WAIT penalty if we need
+ to close and re-open the socket on restart. */
+
if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
(char *) &foo, sizeof (int)) < 0) {
- perror ("setsockopt REUSEADDR");
+ perror ("setsockopt SOL_SOCKET SO_REUSEADDR");
+ close (sock);
+ sleep (1);
return -1;
}
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = htons (prog[i].port);
+
if (bind (sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
- if (errno == ENOTSOCK) {
- perror ("bind");
- close (sock);
- prog[i].sock = -1;
- continue;
- }
- if (debug)
- fprintf (stderr, "Taking 10...\n");
- sleep (10);
- if (bind (sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
- perror ("bind");
- if (debug)
- fprintf (stderr, "Taking 10...\n");
- sleep (10);
- if (bind (sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
- perror ("bind");
- close (sock);
- prog[i].sock = -1;
- continue;
- }
- }
+ perror ("bind");
+ close (sock);
+ sleep (1);
+ continue;
}
+
if (listen (sock, 1) < 0) {
perror ("listen");
- sock = -1;
+ close (sock);
+ sleep (1);
+ continue;
}
+
prog[i].sock = sock;
- fprintf (stderr,
- "listening on %d, connection to start %s \"%s\" %s %s %s %s\n",
- prog[i].port, prog[i].prog, prog[i].progname, prog[i].arg[0],
+ fprintf (stderr, "listening fd %d, to do \"%s\" %s %s %s %s\n",
+ prog[i].sock, prog[i].progname, prog[i].arg[0],
prog[i].arg[1], prog[i].arg[2], prog[i].arg[3]);
fflush (stderr);
}
@@ -264,20 +300,33 @@
/* stage two; wait for a connection on the listening sockets */
while (1) { /* wait for a connection */
+ st = 0;
+
FD_ZERO (&accept_fds); /* clear the file descriptor mask */
for (i = 0; i < num_progs; i++) { /* set bits in mask for each sock */
sock = prog[i].sock;
if (sock < 0) continue;
FD_SET (sock, &accept_fds);
+ st++;
+ }
+
+ /* paranoia, it could be possible that we have no sockets ready */
+ if (st == 0) {
+ fprintf(stderr, "paranoia: no sockets to listen for\n");
+ sleep(1);
+ return -1;
}
/* block until select() indicates accept() will complete */
st = select (32, &accept_fds, 0, 0, 0);
if (st > 0) break;
if (restart) return -1;
+ if (errno == EINTR) continue;
+ perror("select");
+ sleep(1);
}
- /* find socket in mask that shows activity */
+ /* find one socket in mask that shows activity */
for (i = 0; i < num_progs; i++) {
sock = prog[i].sock;
if (sock < 0) continue;
@@ -289,38 +338,24 @@
len = sizeof(naddr);
- /* hack: to support reaper(), must ignore EINTR errors (TC) */
-
-nointr:
- newsock = accept (sock, (struct sockaddr*)&naddr, &len);
- if ((newsock < 0) && (errno == ECONNRESET)) {
- fprintf (stderr,"Connection reset! Socket %d (%d)\n", sock, newsock);
- sleep (1);
- goto nointr;
- }
- if ((newsock < 0) && (errno == ETIMEDOUT)) {
- fprintf (stderr,"Connection timeout! Socket is %d (%d)\n", sock, newsock);
+ while(1) {
+ newsock = accept (sock, (struct sockaddr*)&naddr, &len);
+ if (newsock >= 0) break;
+ if (errno == EINTR) continue;
+ fprintf (stderr, "port %d, %s, ", prog[i].port, prog[i].prog);
+ perror ("accept");
sleep (1);
- goto nointr;
+ return -1;
}
- if ((newsock < 0) && (errno == EINTR))
- goto nointr;
- if (newsock < 0) {
- perror ("accept");
- shutdown (sock, 2);
- close (sock);
- prog[i].sock = -1;
- return -1;
- } else {
- if (newsock != 0) {
- if (dup2 (newsock, 0) == -1) {
- perror ("dup2");
- }
- close (newsock);
+ if (newsock != 0) {
+ if (dup2 (newsock, 0) == -1) {
+/* on solaris it has been seen that fd 0 is one of our listening sockets! */
+ perror ("dup2");
}
- return i;
+ close (newsock);
}
+ return i;
}
void deny ()
@@ -439,9 +474,18 @@
void reaper (int sig)
{
int stat;
- if (debug) fprintf (stderr, "Reaping...\n");
- while (WAIT3 (&stat, WNOHANG, 0) > 0)
- ;
+ pid_t pid;
+
+ while (1) {
+ pid = WAIT3 (&stat, WNOHANG, 0);
+ if (pid > 0) {
+ active--;
+ if (debug) fprintf (stderr, "active--: %d: pid %d terminated\n",
+ active, pid);
+ }
+ break;
+ }
+
HANDLE_SIG (SIGCHLD, reaper);
}