

From anon@suse.de:

- Accept more connections before starting to drop them

- ratelimit the friendly warnings.


---

 25-akpm/net/sunrpc/svcsock.c |   39 ++++++++++++++++++++++++++++-----------
 1 files changed, 28 insertions(+), 11 deletions(-)

diff -puN net/sunrpc/svcsock.c~sunrpc-svcsock-drop net/sunrpc/svcsock.c
--- 25/net/sunrpc/svcsock.c~sunrpc-svcsock-drop	2004-04-04 17:48:15.569560152 -0700
+++ 25-akpm/net/sunrpc/svcsock.c	2004-04-04 18:00:37.894709576 -0700
@@ -828,21 +828,38 @@ svc_tcp_accept(struct svc_sock *svsk)
 
 	/* make sure that we don't have too many active connections.
 	 * If we have, something must be dropped.
-	 * We randomly choose between newest and oldest (in terms
-	 * of recent activity) and drop it.
+	 *
+	 * There's no point in trying to do random drop here for
+	 * DoS prevention. The NFS clients does 1 reconnect in 15
+	 * seconds. An attacker can easily beat that.
+	 *
+	 * The only somewhat efficient mechanism would be if drop
+	 * old connections from the same IP first. But right now
+	 * we don't even record the client IP in svc_sock.
 	 */
-	if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*5) {
+	if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) {
 		struct svc_sock *svsk = NULL;
 		spin_lock_bh(&serv->sv_lock);
 		if (!list_empty(&serv->sv_tempsocks)) {
-			if (net_random()&1)
-				svsk = list_entry(serv->sv_tempsocks.prev,
-						  struct svc_sock,
-						  sk_list);
-			else
-				svsk = list_entry(serv->sv_tempsocks.next,
-						  struct svc_sock,
-						  sk_list);
+			if (net_ratelimit()) {
+				/* Try to help the admin */
+				printk(KERN_NOTICE "%s: too many open TCP "
+					"sockets, consider increasing the "
+					"number of nfsd threads\n",
+						   serv->sv_name);
+				printk(KERN_NOTICE "%s: last TCP connect from "
+					"%u.%u.%u.%u:%d\n",
+					serv->sv_name,
+					NIPQUAD(sin.sin_addr.s_addr),
+					ntohs(sin.sin_port));
+			}
+			/*
+			 * Always select the oldest socket. It's not fair,
+			 * but so is life
+			 */
+			svsk = list_entry(serv->sv_tempsocks.prev,
+					  struct svc_sock,
+					  sk_list);
 			set_bit(SK_CLOSE, &svsk->sk_flags);
 			svsk->sk_inuse ++;
 		}

_
