Eu escrevi um programa para consultar a interface Linux rtnetlink(7) usando RTM_GETADDR
for family AF_INET
. Analisando a resposta, percebi que as maiores partes da resposta parecem ser IFA_UNSPEC
registros de tipo de comprimento de 88 bytes (outras partes geralmente têm menos de 8 bytes de comprimento).
Saída de exemplo de depuração (para apenas uma interface):
DB<3> r
index 1, family 2, prefixlen 8
flags permanent
host
# len 8, type 1
address 127.0.0.1
# len 8, type 2
local 127.0.0.1
# len 7, type 3
label lo
# len 8, type 8
flags permanent
# len 20, type 6
cacheinfo: prefered forever, valid forever, cstamp 2.31, tstamp 2.31
# len 88, type 0
RT_Netlink::handle_response(lib/RT_Netlink.pm:361):
"len 88, tipo 0" é um IFA_UNSPEC
pedaço na resposta.
Então, estou me perguntando: o que são esses pedaços não especificados e por que eles são enviados na resposta?
Isto é o que a página de manual diz:
Attributes
rta_type value type description
─────────────────────────────────────────────────────────────
IFA_UNSPEC - unspecified.
IFA_ADDRESS raw protocol address interface address
IFA_LOCAL raw protocol address local address
IFA_LABEL asciiz string name of the interface
IFA_BROADCAST raw protocol address broadcast address.
IFA_ANYCAST raw protocol address anycast address
IFA_CACHEINFO struct ifa_cacheinfo Address information.
Acho que encontrei o problema:
O problema está no analisador da resposta (modelado após a fonte C em https://github.com/Yourens/rtnetlinkexample/blob/master/if_show.c , pois as páginas de manual originais eram muito ruins para entender como as coisas funcionam):
As mensagens de resposta que recebi tinham estes comprimentos: 76, 88, 88, 88
A primeira mensagem processada pelo analisador tinha 324 bytes, mas o comprimento da mensagem era de apenas 52. Então, de alguma forma, o analisador analisava após o final da mensagem atual, detectando as próximas mensagens como tipo
IFA_UNSPEC
.Especificamente, a primeira mensagem analisada tinha três vezes 88 bytes
IFA_UNSPEC
, enquanto a segunda mensagem tinha duas vezes 88 bytesIFA_UNSPEC
, a terceira tinha uma vez 88 bytesIFA_UNSPEC
e a última mensagem eventualmente não tinhaIFA_UNSPEC
.Quando eu trunquei o resultado de NLMSG_DATA() para IFA_PAYLOAD() antes de chamar IFA_RTA(), esses
IFA_UNSPEC
atributos desapareceram magicamente.Concordo que tudo soa bastante abstrato, sem apresentar muito código ausente na pergunta.
O código Perl básico para analisar a resposta era (As estruturas C originais estão presentes como dados binários, descompactados por
__U_
rotinas * correspondentes. Provavelmente essa parte introduziu o erro, pois o código C de exemplo apenas avança um ponteiro enquanto em Perl eu usei substrings):A eventual correção foi substituir a linha correspondente por:
Finalmente, aqui está um resumo com algumas saídas de depuração mostrando a diferença antes e depois da correção:
Infelizmente, a correção parece ter engolido os dados do tipo 6 (cacheinfo); talvez haja mais bugs.
Atualizar:
Eu encontrei a solução (eu acho), alterando:
para
como
IFA_PAYLOAD
parece ser o comprimento deIFA_RTA
, e não deNLMSG_DATA
. Toda a estrutura do "pacote" do netlink é um mistério (mal documentado) ou talvez até "miséria".