Re: fork() flood in tcp/wait service again
Steve G <[email protected]> Sat, 12 Jul 2003 15:19:30 -0700 (PDT)
| Newsgroups | gmane.network.xinetd |
|---|---|
| Message-ID | <[email protected]> |
Hello, I have thought long and hard about the tcp/wait DOS. I have a patch that I would like people to try out before I commit it to cvs. Basically what it does is create a drain_tcp function. It is called from the service_postmortum and it calls accept in a non-blocking mode just one time. The pros: it will stop DOS conditions, it doesn't lose all connections in the queue if more requests are queued. The cons: It might lose 1 legitimate request for perfectly functioning tcp/wait services. (tcp/nowait services are unaffected by the patch.) Improvements: Add a service flags option that enables this call so that only admins that have a known bad program can have the tcp/wait socket drained. Everyone with well behaving tcp/wait applications won't lose the 1 connection that gets drained. So, all interested parties please give this a try and let's see if we can finalize a solution. -Steve Grubb __________________________________ Do you Yahoo!? SBC Yahoo! DSL - Now only $29.95 per month! http://sbc.yahoo.com
tcp_wait.patch
(application/octet-stream, 1.9 KB)
diff -ur xinetd/service.c xinetd.new/service.c
--- xinetd/service.c 2003-07-12 18:00:48.000000000 -0400
+++ xinetd.new/service.c 2003-07-12 17:59:17.000000000 -0400
@@ -894,6 +894,8 @@
if (cp) {
if ( SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM )
drain( cp->co_descriptor ) ;
+ else
+ drain_tcp( cp->co_descriptor );
free(cp);
cp = NULL;
}
diff -ur xinetd/util.c xinetd.new/util.c
--- xinetd/util.c 2003-07-12 18:00:49.000000000 -0400
+++ xinetd.new/util.c 2003-07-12 17:59:17.000000000 -0400
@@ -247,7 +247,39 @@
fcntl( sd, F_SETFL, old_val );
if ( debug.on )
- msg( LOG_DEBUG, "drain", "Socket should be empty" ) ;
+ msg( LOG_DEBUG, "drain", "UDP socket should be empty" ) ;
+}
+
+/*
+ * Empty the fd of 1 tcp connection at the most in order to assure
+ * that we are not looping on an unaccpeted connection.
+ */
+void drain_tcp( int sd )
+{
+ int sock ;
+ int old_val ;
+
+ /* Put in non-blocking mode so we don't hang. */
+ old_val = fcntl( sd, F_GETFL, FNDELAY );
+ fcntl( sd, F_SETFL, FNDELAY );
+
+ do {
+ sock = accept( sd, NULL, 0 ) ;
+ if (sock < 0) {
+ if (errno == EINTR)
+ continue;
+ }
+ else
+ close( sock );
+ break; /* We only loop once to get */
+ } while ( 1 );
+
+ /* Restore the value since the connection will be freed, not closed. */
+ if (old_val >= 0)
+ fcntl( sd, F_SETFL, old_val );
+
+ if ( debug.on )
+ msg( LOG_DEBUG, "drain_tcp", "TCP socket should be empty" ) ;
}
/*
diff -ur xinetd/util.h xinetd.new/util.h
--- xinetd/util.h 2003-07-12 18:00:49.000000000 -0400
+++ xinetd.new/util.h 2003-07-12 17:59:17.000000000 -0400
@@ -19,6 +19,7 @@
;
#endif
void drain(int sd);
+void drain_tcp(int sd);
int parse_int(const char *, int , int , int *);
int parse_base10(const char *, int *);