2010-06-02 3 views
4

Мне интересно, как ограничить TCP-запросы на каждого клиента (на определенный IP) в Java. Например, я хотел бы разрешить максимум X-запросов за Y секунд для каждого IP-адреса клиента. Я думал об использовании статического таймера/TimerTask в сочетании с HashSet временных ограниченных IP-адресов.Ограничить TCP-запросы на IP

private static final Set<InetAddress> restrictedIPs = Collections.synchronizedSet(new HashSet<InetAddress>()); 

private static final Timer restrictTimer = new Timer(); 

Таким образом, когда пользователь подключается к серверу, я добавляю его IP в ограниченный список, и начать задание unrestrict его через несколько секунд.

restrictedIPs.add(socket.getInetAddress()); 

restrictTimer.schedule(new TimerTask() 
{ 
    public void run() 
    { 
    restrictedIPs.remove(socket.getInetAddress()); 
    } 

}, MIN_REQUEST_INTERVAL); 

Моя проблема заключается в том, что в то время, когда задача будет выполняться, то объект сокет может быть закрыт, и удаленный IP-адрес не будет доступен больше ...

Любые идеи приветствуются! Кроме того, если кто-то знает Java-framework-встроенный способ достичь этого, я бы очень хотел его услышать.

ответ

1

Простое решение для этого было бы:

final InetAddress ip = socket.getInetAddress(); 
restrictedIPs.add(ip); 

restrictTimer.schedule(new TimerTask() 
{ 
    public void run() 
    { 
    restrictedIPs.remove(ip); 
    } 

}, MIN_REQUEST_INTERVAL); 

Проблема этого метода состоит в том, что она требует дополнительных потоков для удаления ограниченных IP-адресов. Возможно, проще сохранить карту InetAddress в метку времени, чтобы отслеживать последний раз, когда они обращались к странице. Таким образом, вы можете просто проверять эту метку времени каждый раз, когда клиент начинает запрос.

+0

Спасибо за ваш ответ! Я, вероятно, сделаю карту, как вы сказали. – asmo

+0

Как раз по проблеме с этим решением: как определить, когда удалять IP-адреса с карты? Потому что, если сервер будет работать в течение длительного времени, он будет иметь карту из тысяч IP-адресов. – asmo

+0

Пару тысяч не должно быть проблемой, но я понимаю вашу озабоченность. Вы можете запланировать очистку, которая будет выполняться каждый час или около того, чтобы удалить все старые IP-адреса (например, старше часа). – Marc

3

Один из вариантов - использовать netfilter для достижения этого. Не «чистый» java, но, вероятно, решение, которое будет наиболее надежным и безошибочным. Этот пример взят из 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:

Чтобы просто быстро исправить код, сохраните IP-адрес и добавить счетчик, прежде чем блокировать, то есть (псевдо):

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(); 
} 

Это должно сделать блок последним с максимальным BLOCK_TIMEOUT (не гарантируется отсутствие ошибок). Вы должны рассмотреть возможность использования семафора для подсчета, так как вы, вероятно, запустите этот код из многих потоков, в зависимости от вашей модели потоков.

+0

hitcount.get? Является ли hitcount int? – asmo

+0

oh, я использовал hitcount для обозначения карты И int, которую я получил от него. Смущает, изменится. –

+0

там его изменили. –

Смежные вопросы