No meu script iptables, tenho experimentado escrever regras o mais refinadas possível. Limito quais usuários têm permissão para usar quais serviços, em parte por segurança e em parte como um exercício de aprendizado.
Usando o iptables v1.4.16.2 no Debian 6.0.6 executando o kernel 3.6.2.
No entanto, encontrei um problema que ainda não entendi ...
portas de saída para todos os usuários
Isso funciona perfeitamente bem. Eu não tenho nenhuma regra genérica de rastreamento de estado.
## Porta de saída 81 $ IPTABLES -A OUTPUT -p tcp --dport 81 -m conntrack --ctstate NOVO, ESTABELECIDO -j ACEITA $ IPTABLES -A INPUT -p tcp --sport 81 -s $ MYIP -m conntrack --ctstate ESTABELECIDO -j ACEITA
portas de saída com correspondência de usuário
## porta de saída 80 para a conta do usuário $ IPTABLES -A OUTPUT --match owner --uid-owner useraccount -p tcp --dport 80 -m conntrack --ctstate NOVO, ESTABELECIDO --sport 1024: 65535 -j ACEITAR $ IPTABLES -A INPUT -p tcp --sport 80 --dport 1024: 65535 -d $ MYIP -m conntrack --ctstate ESTABELECIDO -j ACEITA
Isso permite a saída da porta 80 apenas para a conta "useraccount", mas regras como esta para o tráfego TCP têm problemas.
## Log de saída padrão + regras de bloqueio $ IPTABLES -A OUTPUT -j LOG - prefixo de log "BAD OUTGOING" --log-ip-options --log-tcp-options --log-uid $ IPTABLES -A OUTPUT -j DROP
O problema
O trabalho acima, o usuário "useraccount" pode obter arquivos perfeitamente bem. Nenhum outro usuário no sistema pode fazer conexões de saída com a porta 80.
useraccount @ host: $ wget http://cachefly.cachefly.net/10mb.test
Mas o wget acima deixa o x7 eliminado entradas no meu syslog:
18 de outubro 02:00:35 kernel xxxx: BAD OUTGOING IN = OUT = eth0 SRC = xx.xx.xx.xx DST = 205.234.175.175 LEN = 40 TOS = 0x00 PREC = 0x00 TTL = 64 ID = 12170 DF PROTO = TCP SPT = 37792 DPT = 80 SEQ = 164520678 ACK = 3997126942 JANELA = 979 RES = 0x00 ACK URGP = 0
Não recebo essas quedas por regras semelhantes com o tráfego UDP. Eu já tenho regras em vigor que limitam quais usuários podem fazer solicitações de DNS.
Os pacotes ACK de saída descartados parecem vir da conta raiz (URGP = 0) que eu não entendo. Mesmo quando troco a conta de usuário pela raiz.
Acredito que os pacotes ACK são classificados como novos porque o conntrack começa a rastrear as conexões após a terceira etapa do handshake de três vias, mas por que estão sendo descartados?
Essas gotas podem ser ignoradas com segurança?
Editar
Então, muitas vezes vejo regras como estas, que funcionam bem para mim:
$ IPTABLES -A OUTPUT -s $ MYIP -p tcp -m tcp --dport 80 -m state --state NOVO, ESTABELECIDO -j ACEITA $ IPTABLES -A INPUT -p tcp -m tcp --sport 80 -d $ MYIP -m state --state ESTABELECIDO -j ACEITA
Troquei "-m state --state" por "-m conntrack --ctstate", pois a correspondência de estado é aparentemente obsoleta.
É uma prática recomendada ter regras genéricas de rastreamento de estado? As regras acima não são consideradas corretas?
Para um controle rígido sobre as conexões de saída dos usuários, algo assim seria melhor?
$ IPTABLES -A INPUT -m conntrack --ctstate ESTABLISHED -j ACEITAR $ IPTABLES -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACEITAR $ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner useraccount -j ACEITAR $ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner otheraccount -j ACEITAR
Respostas:
Para resumir uma longa história, o ACK foi enviado quando o soquete não pertencia a ninguém. Em vez de permitir pacotes que pertencem a um soquete que pertence ao usuário
x
, permita pacotes que pertencem a uma conexão que foi iniciada por um soquete do usuáriox
.A história mais longa.
Para entender o problema, é útil entender como
wget
as solicitações HTTP funcionam em geral.No
wget
estabelece uma conexão TCPcachefly.cachefly.net
e, uma vez estabelecido, envia uma solicitação no protocolo HTTP que diz: "Por favor, envie-me o conteúdo de/10mb.test
(GET /10mb.test HTTP/1.1
) e, a propósito, você pode não fechar a conexão depois de terminar (Connection: Keep-alive
). O motivo isso ocorre porque, se o servidor responder com um redirecionamento para uma URL no mesmo endereço IP, poderá reutilizar a conexão.Agora o servidor pode responder com: "aqui estão os dados solicitados, cuidado com os 10 MB de largura (
Content-Length: 10485760
) e sim, ok, deixarei a conexão aberta". Ou, se ele não souber o tamanho dos dados, "Aqui estão os dados, desculpe, não posso deixar a conexão aberta, mas informarei quando você pode parar de baixar os dados fechando o final da conexão".No URL acima, estamos no primeiro caso.
Portanto, assim que
wget
obtiver os cabeçalhos da resposta, ele saberá que seu trabalho está concluído depois de baixar 10 MB de dados.Basicamente, o que
wget
faz é ler os dados até 10 MB serem recebidos e sair. Mas, nesse ponto, há mais a ser feito. E o servidor? Foi dito para deixar a conexão aberta.Antes de sair,
wget
fecha (close
chamada do sistema) o descritor de arquivo do soquete. Após, oclose
sistema termina de reconhecer os dados enviados pelo servidor e envia um avisoFIN
para: "Não enviarei mais dados". Nesse ponto,close
retorna ewget
sai. Não há mais soquete associado à conexão TCP (pelo menos, não pertencente a nenhum usuário). No entanto, ainda não está terminado. Ao receber issoFIN
, o servidor HTTP vê o final do arquivo ao ler a próxima solicitação do cliente. No HTTP, isso significa "não há mais solicitação, vou fechar o meu fim". Por isso, também envia sua FIN, dizendo: "Eu também não enviarei nada, essa conexão está indo embora".Ao receber esse FIN, o cliente envia um "ACK". Mas, nesse ponto,
wget
há muito se foi, de modo que o ACK não é de nenhum usuário. É por isso que está bloqueado pelo seu firewall. Como o servidor não recebe o ACK, ele envia o FIN repetidamente até que ele desista e você verá mais ACKs descartados. Isso também significa que, ao descartar esses ACKs, você estará desnecessariamente usando os recursos do servidor (que precisa manter um soquete no estado LAST-ACK) por algum tempo.O comportamento teria sido diferente se o cliente não tivesse solicitado "Keep-alive" ou o servidor não tivesse respondido com "Keep-alive".
Como já mencionado, se você estiver usando o rastreador de conexão, o que você quer fazer é deixar todos os pacotes nos estados ESTABELECIDO e RELACIONADO passar e se preocupar apenas com
NEW
pacotes.Se você permitir
NEW
pacotes do usuário,x
mas não pacotes do usuárioy
, outros pacotes para conexões estabelecidas por usuáriox
serão processados e, como não podem ser estabelecidas conexões por usuárioy
(já que estamos bloqueando osNEW
pacotes que estabeleceriam a conexão), não haverá nenhum pacote para asy
conexões do usuário .fonte
- bem, pelo menos as regras que você mostrou não implicam isso, na verdade.
Há também um espaço para aconselhamento - não faça checagens de usuários em fluxos ESTABELECIDOS, apenas faça checagens em NEW. Também não vejo sentido em verificar a porta de origem ao verificar Incoming ESTABLISHED, qual é a diferença de qual porta era, já está no estado ESTABELECIDO do PoV do conntrack. O firewall deve ser o mais simples possível, mas eficiente, para que a abordagem mais rápida da Occam seja a mais adequada.
fonte