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 ++; } _