I've discovered a new servent, called Qtrax2, that kept hammering
and hammering, again and again.
Fed up, I've decided to code an anti-hammering engine.
It works like this:
* Each servent is allowed to make up to 10 requests / minute, within
a sliding window.
* The first time the servent crosses that threshold, a "550 Banned"
error is returned (yes, I made it up). It can be returned for both
HTTP and Gnutella connections (I realize that I don't handle 0.4
connections when I send them a 550 0.6 error, oh well!).
* At the first banning, the ban time is set to 5 minutes. It is
doubled upon each subsequent banning. During ban, we still count
requests. When the ban time expires, and if the counter is above
the threshold, we immediately reban at the next connection attempt.
* All the history is forgotten when a servent leaves its sliding window
in a non-banning state.
When banning, the error message is sent as:
HTTP/1.0 550 Banned for 2h 40m
GNUTELLA/0.6 550 Banned for 2h 40m
(that would be for a servent that keeps hammering).
I realize I'm out of specs with my 550 error, but that's precisely
why I chose that number, and why I'm communicating it to you so this
is documented and archived properly.
During banning, connections are accepted and then forgotten about.
We let them timeout on the other end and only close them when we need
new file descriptors.
Therefore, after the initial 550 error, all subsequent connections from
the same IP will be black-holed, without any feedback given.
If you wish to implement something like that in your servent, look
at the source code of gtk-gnutella, in files ban.c / ban.h, to get
the gory implementation details.
Further refinement will include the use of the "Retry-After" HTTP
header in the first 550 error, so that servents get a standard
way of knowing the banning period, without having to parse the
free-form message.
Raphael