Iptables: combinando tráfego de saída com conntrack e owner. Funciona com gotas estranhas

11

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
arcX
fonte
Você poderia postar todas as regras, incluindo a cadeia FORWARD e a tabela nat, se esse host também estiver roteando o tráfego da LAN.
Serge
Este host não está fazendo nenhum roteamento, o tráfego se origina da máquina com essas regras. Publiquei apenas as regras relevantes para o tráfego de saída específico.
arcX

Respostas:

16

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ário x.

A história mais longa.

Para entender o problema, é útil entender como wgetas solicitações HTTP funcionam em geral.

No

wget http://cachefly.cachefly.net/10mb.test

wgetestabelece uma conexão TCP cachefly.cachefly.nete, 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 wgetobtiver os cabeçalhos da resposta, ele saberá que seu trabalho está concluído depois de baixar 10 MB de dados.

Basicamente, o que wgetfaz é 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, wgetfecha ( closechamada do sistema) o descritor de arquivo do soquete. Após, o closesistema termina de reconhecer os dados enviados pelo servidor e envia um aviso FINpara: "Não enviarei mais dados". Nesse ponto, closeretorna e wgetsai. 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 isso FIN, 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, wgethá 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 NEWpacotes.

Se você permitir NEWpacotes do usuário, xmas não pacotes do usuário y, outros pacotes para conexões estabelecidas por usuário xserão processados ​​e, como não podem ser estabelecidas conexões por usuário y(já que estamos bloqueando os NEWpacotes que estabeleceriam a conexão), não haverá nenhum pacote para as yconexões do usuário .

Stéphane Chazelas
fonte
3

Isso permite a saída da porta 80 somente para a conta "useraccount"

- 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.

poige
fonte
1
Obrigado pelo conselho. Geralmente sou a favor da simplicidade, mas esse não é o objetivo deste exercício em particular.
arcX
1
@arcX, este exercício pode falhar por ser muito complexo e inconsistente - IOW, o comportamento que você vê não pode ser devido a internos do netfilter (bugs, peculiaridades), mas à maneira como você o usa. Tente simplificar o conjunto de regras primeiro ...
poige 20/10/12