
Estou usando "tcpdump" para capturar tráfego e quero filtrar por métodos HTTP. Quando tenho pacotes IPv4, estou usando: tcpdump -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'
Para filtrar pacotes HTTP GET.
Infelizmente, o tcp[]
filtro não funciona em pacotes IPv6. De acordo com os documentos
Expressões aritméticas em cabeçalhos da camada de transporte, como
tcp[0]
, não funcionam em pacotes IPv6.
Então, estou procurando outra maneira de filtrar apenas métodos HTTP para tráfego IPv6 usando tcpdump.
Tentei procurar uma solução, mas parece que ela inclui um uso de grep que não é adequado às minhas necessidades, pois quero enviar todo o tráfego filtrado diretamente para um arquivo pcap
Responder1
Limitações do tcpdump
IPv6 a partir das versões 4.99.x
Para IPv4, para obter o deslocamento da carga útil no pacote, pode-se calcular mais ou menos o deslocamento da carga útil usandoDIH do IPv4+ Deslocamento de dados do TCPpara levar em conta também as opções IPv4 e TCP. Isso é simples o suficiente para ser incluído emtcpdumpdiretamente quando gera o filtro de bytecode BPF (alguma documentação BPF disponível, por exemplolá).
Para IPv6, em vez disso, pode haver um número variável (possivelmente entre 0 e 9) de cabeçalho de extensão entre o cabeçalho fixo e o cabeçalho superior. Isso significaria incluir código para possivelmente 10 casos (0, 1, 2, ... 9 cabeçalhos de extensão) para encontrar o deslocamento da carga útil em um pacote, assumindo que não há peculiaridades adicionais para certos casos, nem mesmo tentando ter proteção contra pacotes malformados. (o que pode levar a uma correspondência de falso positivo): só posso assumir que isso não foi implementado devido à complexidade e à falta de vontade de fornecer uma implementação falha, ignorando tais cabeçalhos.
Mesmo um teste simples como ip6 and tcp dst port 80
não considera cabeçalhos de extensão como visto no código BPF gerado abaixo:
$ tcpdump --version
tcpdump version 4.99.3
libpcap version 1.10.3 (with TPACKET_V3)
OpenSSL 3.0.9 30 May 2023
$ tcpdump -y EN10MB -d ip6 and tcp dst port 80
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 7
(002) ldb [20]
(003) jeq #0x6 jt 4 jf 7
(004) ldh [56]
(005) jeq #0x50 jt 6 jf 7
(006) ret #262144
(007) ret #0
então pode perder o trânsito.
A partir do tcpdump 4.99.x, parece que o único local onde o tratamento adequado dos cabeçalhos de extensão IPv6 está em vigor está documentado no final da página de manual:
ip6 proto
deveria perseguir a cadeia de cabeçalho, mas neste momento isso não acontece.ip6 protochain
é fornecido para esse comportamento.
Na verdade, atualmente a partir do tcpdump 4.99.x ip6 and tcp
é equivalente a ip6 proto 6
(eles produzem o mesmo bytecode):
$ tcpdump -y EN10MB -d ip6 and tcp
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 8
(002) ldb [20]
(003) jeq #0x6 jt 7 jf 4
(004) jeq #0x2c jt 5 jf 8
(005) ldb [54]
(006) jeq #0x6 jt 7 jf 8
(007) ret #262144
(008) ret #0
while ip6 protochain 6
faz uma verificação muito mais completa e seria o que deveria ser esperado em qualquer teste envolvendo uma camada superior (cabeçalho de transporte final), como o TCP:
$ tcpdump -y EN10MB -d ip6 protochain 6
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 35
(002) ldb [20]
(003) ldx #0x28
(004) jeq #0x6 jt 32 jf 5
(005) jeq #0x3b jt 32 jf 6
(006) jeq #0x0 jt 10 jf 7
(007) jeq #0x3c jt 10 jf 8
(008) jeq #0x2b jt 10 jf 9
(009) jeq #0x2c jt 10 jf 19
(010) ldb [x + 14]
(011) st M[0]
(012) ldb [x + 15]
(013) add #1
(014) mul #8
(015) add x
(016) tax
(017) ld M[0]
(018) ja 4
(019) jeq #0x33 jt 20 jf 32
(020) txa
(021) ldb [x + 14]
(022) st M[0]
(023) txa
(024) add #1
(025) tax
(026) ldb [x + 14]
(027) add #2
(028) mul #4
(029) tax
(030) ld M[0]
(031) ja 4
(032) add #0
(033) jeq #0x6 jt 34 jf 35
(034) ret #262144
(035) ret #0
Acima dos 4 testes, incluindo jt 10
as linhas entre (10
) e (018) ja 4
faça um loop em 4 dos cabeçalhos de extensão IPv6 específicos para ignorá-los, enquanto (19)
lida (31)
com o IPSec AH. Eu não saberia como gerar esse código em outro lugar com otcpdumplinguagem (em vez de, digamos, diretaBPFcódigo). O uso ip6 protochain 6 and ip6 and tcp dst port 80
apenas começa do zero, ou pior, em vez de capitalizar o cabeçalho TCP recém-obtido.
O mesmo tipo de problema é descrito em vários recursos e ferramentas de rede para Linux. Exemplo:tc u32
diz:
icmp_code
VAL_MASK_8Suponha um protocolo de próximo cabeçalho icmp ou ipv6-icmp e corresponda aos valores dos campos Tipo ou Código.Isso é perigoso, pois o código assumetamanho mínimo de cabeçalho para IPv4 efalta de cabeçalhos de extensão para IPv6.
Tudo isso sem considerar que especificamente para HTTP, quando a conexão é reutilizada, a próxima consulta HTTP pode nem estar no início de um limite de pacote, ou também que tal consulta incorporada como dados em vez de consulta pode corresponder se tais dados aparecem no início do limite do pacote.
Teste para o caso do cabeçalho de extensão 0 usando tcpdump
a versão 4.99.x
Aqui está o teste com 0 cabeçalhos de extensão, ou seja, no mesmo nível do quetcpdumpatualmente faz, com verificação mínima feita:
tcpdump -n -s 0 -A 'ip6[6] == 6 and ( ip6[4:2] - ((ip6[52] & 0xf0) >> 2) >= 4 ) and ip6[40 + ((ip6[52] & 0xf0) >> 2) :4] == 0x47455420'
que pode ser documentado assim (ainda apenas para o caso do cabeçalho de extensão 0, onde o cabeçalho TCP sempre começa na posição 40):
O próximo cabeçalho é TCP
ip6[6] == 6
IPv6comprimento da carga útil:
ip6[4:2]
TCPdeslocamento de dados (tamanho fixo do IPv6 de 40 + 12 = 52) (e ajuste adequado para obter bytes)
(ip6[52] & 0xf0) >> 2
Comprimento da carga útil TCP = comprimento da carga útil IPv6 - deslocamento de dados TCP
Teste se há pelo menos 4 bytes de carga TCP para pelo menos o comprimento de "GET"
ip6[4:2] - ((ip6[52] & 0xf0) >> 2) >= 4
a string de 4 bytes "GET" codificada em ASCII/UTF-8 pode ser representada com o valor de 4 bytes 0x47455420
O deslocamento da carga útil TCP é o comprimento fixo do cabeçalho IPv6 (40) + deslocamento de dados TCP
40 + ((ip6[52] & 0xf0) >> 2)
teste se a primeira palavra de 4 bytes começando no comprimento do cabeçalho fixo IPv6 (40) + deslocamento de dados é igual ao valor da string "GET"
ip6[40 + ((ip6[52] & 0xf0) >> 2) :4] = 0x47455420
nftáveiscom kernel Linux >= 5.15.54 +tcpdump
Eu proponho um método alternativo simples somente para Linux usandonftáveise exigindo um kernel suficientemente recente (versão do kernel Linux>= 5.15.54portado de5.16) assim comonftáveis>= 1.0.1para apoiar o@ih
(cabeçalho interno/carga útil) carga útil bruta, em vez de apenas @th
(cabeçalho de transporte) porquenftáveisem si é muito limitado para realizar processamento arbitrário de @th
maneira útil.
O datagrama IPv6 já foi analisado, incluindo qualquer cabeçalho de extensão IPv6, e os ponteiros @th e @in já estão disponíveis paranftáveis: nenhum processamento adicional é necessário para obter todos os casos. eu confio emnftáveisfalhar na verificação se o pacote é muito curto sem ter que calcular o tamanho real da carga útil do TCP (ao contrário detcpdumpe BPF,nftáveisnão é possível fazer subtrações, portanto não há como verificar o tamanho corretamente).
OnftáveisO exemplo abaixo tenta imitar o exemplo preciso do OP, mas nem sempre consegue em todos os detalhes sem alguma adaptação. Sem direção nem porta, captura pacotes de entrada antes do NAT e pacotes de saída após o NAT (daí os ganchos e prioridades escolhidos). O pacote selecionado é finalmenteenviado para onfloginstalação:
Na segunda forma de invocação (senflog_groupé especificado), o kernel do Linux passará o pacote para nfnetlink_log que enviará o log através de um soquete netlink para o grupo especificado. Um processo do espaço do usuário pode se inscrever no grupo para receber os logs [...]
table ip6 special_log
delete table ip6 special_log
table ip6 special_log {
chain log_to_nflog {
log group 4242
}
chain ih_filter {
meta l4proto tcp @ih,0,32 0x47455420 counter jump log_to_nflog
}
chain c_ingress {
type filter hook prerouting priority -150; policy accept;
jump ih_filter
}
chain c_egress {
type filter hook postrouting priority 150; policy accept;
jump ih_filter
}
}
No Linux, onflogrecurso está disponível como uma pseudo-interface para (libpcape)tcpdump:
# tcpdump -D |grep nflog
12.nflog (Linux netfilter log (NFLOG) interface) [none]
Os pacotes selecionados pornftáveispode assim ser exibido com (reutilizando o mesmo grupo NFLOG: 4242):
tcpdump -n -s 0 -A -i nflog:4242
Advertência: há mais latência do que com uma captura direta.
Nota: manuseio correto pornftáveisde um caso com um cabeçalho de extensão foi realmente testado com UDP (em vez de TCP) e pacotes fragmentados (tratados peloCabeçalho do fragmento) usando socat
(em um namespace de rede separado para evitar nf_defrag_ipv6
a ativação) porque é muito mais fácil gerar um pacote fragmentado com UDP do que com TCP e não encontrei outro método para ter um cabeçalho de extensão em algum lugar.