IPTABLES - Taxa limite de um IP recebido específico

103

Não desejo limitar a taxa de um serviço específico. Meu objetivo é limitar a taxa com base apenas no endereço IP de entrada. Por exemplo, usando uma pseudo-regra:

john.domain.local (192.168.1.100) can only download from our httpd/ftp servers at "10KB/s" (instead of 1MB/s)

Como posso classificar o limite usando IPTables com base nos endereços IP recebidos?

James
fonte

Respostas:

165

O IPTables não é feito para esse tipo de trabalho, onde muitos e muitos pacotes precisam ser analisados ​​para tomar essas decisões. IPTables é parcialmente a resposta!

A resposta real para isso são os recursos impressionantes e subutilizados de controle de tráfego no Linux. Observe que mexer com isso sem saber o que está acontecendo pode fazer com que você perca a conectividade de rede com a máquina! Você foi avisado!

Supondo que eth0 seja o dispositivo de saída, você precisará criar uma fila de controle de tráfego baseada em classe que, por padrão, produzirá a maior parte do tráfego através da fila 'rápida' e colocará uma lista específica de pessoas na fila 'lenta'.

A vantagem disso é que você pode criar uma situação na qual permite muito tráfego de saída para o usuário lento, a menos que uma classe substituidora deseje a largura de banda, mas este exemplo não faz isso (sempre fornecerá 10kbps para os usuários lentos). O sistema de filas será mais ou menos assim:

                         Inbound traffic
                              +
                              |
                              |
                              v
                     +------------------+
                     |   Class 1:1      |
                     |------------------|
                     |  Root (all flows)|
                     |       100mbit    |
                     +-----+-----+------+
                           |     |
                           |     |
                           |     |
                           |     |
                           |     |
          +----------+     |     |     +----------+
          |    1:11  +-----+     +-----+    1:12  |
          |----------|                 |----------|
          | Default  |                 | Slow     |
          |100mb-80kb|                 |   80kb   |
          +----------+                 +----------+

Para fazer isso, primeiro você precisará configurar a disciplina de fila no kernel. O seguinte fará isso por você. Você deve executá-lo como um script inteiro

#!/bin/bash
tc qdisc add dev eth0 parent root handle 1: hfsc default 11
tc class add dev eth0 parent 1: classid 1:1 hfsc sc rate 100mbit ul rate 100mbit
tc class add dev eth0 parent 1:1 classid 1:11 hfsc sc rate 99920kbit ul rate 100000kbit
tc class add dev eth0 parent 1:1 classid 1:12 hfsc sc rate 80kbit ul rate 80kbit

tc qdisc add dev eth0 parent 1:11 handle 11:1 pfifo
tc qdisc add dev eth0 parent 1:12 handle 12:1 pfifo

O "padrão 11" é importante, pois indica ao kernel o que fazer com o tráfego não classificado.

Feito isso, você pode configurar uma regra do iptables para classificar pacotes que correspondem a um determinado critério. Se você planeja colocar muitas e muitas pessoas nessa regra lenta, uma regra de ipset é mais apropriada (que deveria estar disponível no rhel6, acredito).

Portanto, crie um banco de dados ipset para fazer a correspondência com ...

ipset create slowips hash:ip,port

Em seguida, crie a regra iptables para fazer a correspondência.

iptables -t mangle -I OUTPUT -m set --match-set slowips dst,src -j CLASSIFY --set-class 1:12

Isso instrui o kernel que, se você combinar o IP de destino com a porta de origem do conjunto, classifique-o na fila lenta que você configurar com o controle de tráfego.

Agora, finalmente, sempre que você quiser diminuir a velocidade de um IP, use o comando ipset para adicionar o ip ao conjunto, como este:

ipset add slowips 192.168.1.1,80
ipset add slowips 192.168.1.1,21
...

Você pode testar se funciona usando o comando "tc -s class show dev eth0" e você verá estatísticas indicando pacotes sendo redirecionados para a fila lenta.

Observe que a única desvantagem real disso é sobreviver às reinicializações. Eu não acho que exista algum script init disponível para criar os ipsets dos dumps na reinicialização (e eles também devem ser criados antes das regras do iptables) e tenho certeza de que não há scripts init para redefinir as regras de controle de tráfego na reinicialização. Se você não está incomodado, você pode recriar tudo, invocando um script no rc.local.

Matthew Ife
fonte
3
Bem, não posso agradecer o suficiente. Isso é muito descritivo e muito informativo. Mais tarde, percebi que o conhecimento da CT seria necessário e, desde então, comecei a investigar isso. Obrigado novamente!
James
Ah, e quanto a perder a conexão. Estou certificando-me de que tenho a configuração desativada antes de passar do meu VPS para a máquina host. Além disso, tenho acesso VPN à rede privada no ETH0. Eu só vou trabalhar no ETH1, então, em teoria, não terei o problema. Mas aviso ouvido!
James
2
Eu não posso te dizer quantas vezes eu li tutoriais semelhantes, este é o primeiro que fazia sentido
RC1140
5
Como nota de rodapé, normalmente é mais apropriado fazer limitação de recursos como esta em grupos de controle (novamente, também é possível e também subutilizado e impressionante), pois você pode definir limites por aplicativo em CPU, memória, IO e rede em um repositório de políticas centralizado ' Mas ainda temos que ver essa pergunta sendo colocada para oferecer uma resposta.
Matthew Ife
2
Se você não gosta da tcsintaxe, pode tentar o tcng, que adiciona uma linguagem um pouco mais amigável que gera tccomandos. Eu costumava como este em scripts shell: echo '... multi line tcng configuration ...' | tcng | sh.
Mattias Wadman
5

É tão simples quanto adotar uma regra de limitação de taxa e adicionar a -sopção. O -sswitch corresponde aos IPs recebidos. Por exemplo, iptables -A INPUT -s 1.1.1.1e depois finalizando com seu método preferido de limitação de taxa para essa regra.

Wesley
fonte
Obrigado pela sua pronta resposta. Infelizmente, meu principal problema é a segunda metade. Eu olhei para --limit e não vi nada que me permita limitar com base em KB / s - qualquer direção que você possa me indicar?
James
1
@ James, eu teria voltado para você, mas tive que sair para a casa de um amigo. Acabei de voltar e vejo que o MIfe fez um bom trabalho. =)
Wesley