Ограничение TCP-запросов на IP - PullRequest
4 голосов
/ 02 июня 2010

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

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

private static final Timer restrictTimer = new Timer();

Поэтому, когда пользователь подключается к серверу, я добавляю его IP-адрес в список с ограничениями и запускаю задачу, чтобы не ограничивать его через X секунд.

restrictedIPs.add(socket.getInetAddress());

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

},  MIN_REQUEST_INTERVAL);

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

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

Ответы [ 2 ]

2 голосов
/ 02 июня 2010

Один из вариантов - использовать 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 (не гарантируется без ошибок). Вам следует рассмотреть возможность использования семафора для подсчета, поскольку вы (вероятно) будете запускать этот код из множества потоков, конечно, в зависимости от вашей модели потоков.

1 голос
/ 02 июня 2010

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

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

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

},  MIN_REQUEST_INTERVAL);

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

...