É possível forçar a reflexão fwmark em pacotes de resposta TCP arbitrários?

0

Alguém resolveu o problema de fwmarks serem perdidos em respostas de conexão de soquete TCP?

Antecedentes:

Preciso garantir que as respostas sejam enviadas na mesma interface em que suas solicitações foram recebidas e que a interface de saída de rede não seja distinguível por nenhum outro meio, como o roteamento baseado em origem; por isso esta resposta começou-me a ver o encaminhamento baseado em políticas. No começo, parecia não funcionar para o meu caso em todos os (usei o tcpdump para observar o tráfego na interface, bem como direcionar o iptables para registrar os metadados do pacote em ambas as direções), e nesse ponto, eu vi que os pacotes recebidos estavam de fato sendo marcados de acordo com a interface de entrada, como eu desejava. Mas os pacotes de saída não retiveram a mesma marca! Reduzi meu caso de teste de uma conexão de soquete para um simples ping (ICMP echo), e quando percebi que o fwmark estava sendo perdido, fiz mais pesquisas e descobri o parâmetro sysctl" fwmark_reflect ". Isso permitiu, e resolveu o problema para o meu caso de teste simplificado, mas é claro, já que o sysctl está relacionado apenas a "pacotes IP originados no kernel que não possuem soquete de usuário associado a eles", isso não ajuda no problema original: estabelecendo conexões de socket, como ssh ...

Mais detalhes de apoio:

Regras de marcação de pacotes do iptables:

-A PREROUTING -i ens3 -j MARK --set-mark 1 -A PREROUTING -i ens4 -j MARK --set-mark 2

Regras de roteamento (algumas são duplicadas porque eu estava tentando de tudo, por desespero):     lista de regras #ip     0: de todo local de pesquisa     0: de todos os fwmark 0x1 lookup mgmt     0: de todos os fwmark 0x2 lookup cust     10: de todos os fwmark 0x1 lookup mgmt     20: de todos os fwmark 0x2 lookup cust     32766: de toda a pesquisa principal     32767: de todo o padrão de pesquisa     65536: de todos os fwmark 0x2 oif ens4 lookup cust

#ip route list table mgmt
  default via 10.100.16.1 dev ens3 
#ip route list table cust

default via 10.100.16.1 dev ens4 ip route get 221.194.47.243 mark 2 221.194.47.243 via 10.100.16.1 dev ens4 src 10.100.16.13 mark 2

Saída LOG do Iptables para echo-request-e resposta (o round-trip completo está completo; o remote reflete o recebimento bem-sucedido):

[27314.322482] pIng IN=ens4 OUT= MAC=00:00:17:01:8c:ff:00:00:17:01:cf:b5:08:00 SRC=10.100.21.143 DST=10.100.16.13 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=18269 DF PROTO=ICMP TYPE=8 CODE=0 ID=14889 SEQ=1 MARK=0x2

[27314.323446] pOng IN= OUT=ens4 SRC=10.100.16.13 DST=10.100.21.143 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=39688 PROTO=ICMP TYPE=0 CODE=0 ID=14889 SEQ=1 MARK=0x2

Metadados registrados semelhantes ao tentar uma conexão de soquete à porta 22 (falha de conexão de relatórios remotos, porque obviamente com o fwmark original perdido, a tabela de roteamento tenta enviar a interface errada):

[23305.165235] ens4-PRERT IN=ens4 OUT= MAC=00:00:17:01:8c:ff:00:00:17:23:a9:ae:08:00 SRC=156.151.8.14 DST=10.100.16.13 LEN=60 TOS=0x10 PREC=0x20 TTL=41 ID=45069 DF PROTO=TCP SPT=5874 DPT=22 WINDOW=14600 RES=0x00 SYN URGP=0 MARK=0x2

[23305.169993] output IN= OUT=ens3 SRC=10.100.16.13 DST=156.151.8.14 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=5874 WINDOW=26844 RES=0x00 ACK SYN URGP=0

Desculpas pela duração deste post. Eu tenho batido minha cabeça contra a parede deste problema por um bom tempo, e não consegui pensar em uma maneira mais concisa de comunicar todos os detalhes relevantes. Gostaria muito de receber qualquer orientação que alguém possa dar, mesmo que seja "isso não é possível". Felicidades!

    
por wajiii 12.01.2018 / 03:24

1 resposta

2

Seguindo meu comentário, aqui está uma solução que deve funcionar como você pretende. Observe que o pedido é o contrário dos exemplos no link Netfilter Connmark , mas desde as suas decisões são feitos com pacotes de entrada, não de saída, essa é a ordem certa para ir. Então, remova suas duas regras MARK anteriores (eu as coloquei de volta aqui) e substitua por:

# iptables -t mangle -A INPUT -i ens3 -j MARK --set-mark 1
# iptables -t mangle -A INPUT -i ens4 -j MARK --set-mark 2    
# iptables -t mangle -A INPUT -j CONNMARK --save-mark

# iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark

Estou usando INPUT (que é chamado depois de PREROUTING, mas apenas para fluxos locais) por uma questão de simetria e clareza: isso é para conexões locais, não para encaminhamento. Usar PREROUTING em vez de INPUT (mas manter OUTPUT) daria os mesmos resultados.

Isso usa o conntrack, que está rastreando todos os fluxos, para lembrar a marca e colocá-la de volta no pacote de saída gerado localmente, porque o conntrack sabe que é parte do mesmo fluxo.

O uso de uma regra OUTPUT na tabela mangle aciona uma verificação de reencaminhamento (veja este Linux routing e netfilter schematic ), e é isso que é necessário para rotear de acordo com a marca.

Se você estiver usando outras regras -t mangle ou se o servidor também estiver encaminhando, as regras precisarão ser alteradas. De qualquer forma, o --save-mark provavelmente deve ser o último em INPUT, e o --restore-mark será o primeiro em OUTPUT.

A marca está definida para pacotes de resposta não-usuário (como o TCP RST), então fwmark_reflect pode nem ser mais necessário ou pode interferir, você deve testar.

    
por 04.03.2018 / 21:04