--- linux-2.4.21/net/sunrpc/svcsock.c.orig 2004-04-01 12:44:56.000000000 +0200 +++ linux-2.4.21/net/sunrpc/svcsock.c 2004-04-01 12:49:17.000000000 +0200 @@ -749,21 +749,33 @@ /* 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 to 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)*10) { + 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 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 ++; }