Limit TCP requests per IP
I'm wondering how to limit the TCP requests per client (per specific IP) in Java. For example, I would like to allow a maximum of X requests per Y seconds for each client IP. I thought of using static Timer/TimerTask in combination with a HashSet of temporary restricted IPs.
private static final Set<InetAddress> restrictedIPs = Collections.synchronizedSet(new HashSet<InetAddress>());
private static final Timer restrictTimer = new Timer();
So when a user connects to the server, I add his IP to the restricted list, and start a task to unrestrict him in X seconds.
restrictedIPs.add(socket.getInetAddress());
restrictTimer.schedule(new TimerTask()
{
public void run()
{
restrictedIPs.remove(socket.getInetA开发者_开发技巧ddress());
}
}, MIN_REQUEST_INTERVAL);
My problem is that at the time the task will run, the socket object may be closed, and the remote IP address won't be accessible anymore...
Any ideas welcomed! Also, if someone knows a Java-framework-built-in way to achieve this, I'd really like to hear it.
One option is to use netfilter to accomplish this. Not 'pure' java, but probably the solution which will be most robust and error-free. This example taken from debian-administration
iptables -I INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent \
--set
iptables -I INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent \
--update --seconds 60 --hitcount 4 -j DROP
EDIT:
To just quick-fix your code, save the IP address and add a count before you block, i.e (pseudo):
IPaddress addr = socket.getAddress();
int hitcount = hitcountMap.get(addr).value();
if (hitcount <= HIT_MAX) {
//only increase if person hasn't reached roof, prevents 'overblocking'
hitcountMap.get(addr).increase();
unblockTimer.schedule(hitcountMap.get(addr).decrease(), BLOCK_TIMEOUT);
}
if (hitcount > HIT_MAX) {
connection.drop();
}
This should make the block last at a maximum BLOCK_TIMEOUT (not guaranteed bug-free). You should consider using a semaphore for the counting, since you will (probably) run this code from many threads, depending on your threading model of course.
A simple solution for this would be:
final InetAddress ip = socket.getInetAddress();
restrictedIPs.add(ip);
restrictTimer.schedule(new TimerTask()
{
public void run()
{
restrictedIPs.remove(ip);
}
}, MIN_REQUEST_INTERVAL);
The problem with this method is that it requires extra threads to remove the restricted IP addresses. Maybe it is easier to keep a Map of InetAddress to a timestamp, to keep track of the last time they accessed a page. This way, you can simply check this timestamp each time a client starts a request.
精彩评论