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);
 }