História das interfaces programáticas para iptables, ipchains e ipfw
Tive que mexer um pouco com as iptablesregras do Go recentemente e notei que as bibliotecas de wrapper do docker e do coreosexec() para o iptablescomando e a tela raspam a saída padrão. Isso me pareceu surpreendente.
Em Python-land, há python-iptables :
A interoperabilidade com iptables é alcançada usando as bibliotecas C iptables (libiptc, libxtables e as extensões iptables), não chamando o binário iptables e analisando sua saída.
Eu acho que uma biblioteca Python tem permissão para carregar bibliotecas C em tempo de execução, e Go não pode [editar: estou errado], mas não poderia Go vincular estaticamente a essas bibliotecas? Porque a biblioteca Go teria que obter libxtables.aetc. de algum lugar? (Estou dpkg -Lusando os -devpacotes relevantes no Debian e só vejo .sos.)
De qualquer forma, de acordo com o FAQ do Netfilter :
4.5 Existe uma API C / C ++ para adicionar / remover regras?
A resposta infelizmente é: Não.
Agora você pode pensar 'mas e quanto ao libiptc?'. Como foi apontado inúmeras vezes na (s) lista (s) de discussão, o libiptc NUNCA foi feito para ser usado como uma interface pública. Não garantimos uma interface estável e está planejado removê-la na próxima encarnação do pacote Linux
Estamos bem cientes de que existe uma falta fundamental para essa API e estamos trabalhando para melhorar essa situação. Até então, é recomendado usar system () ou abrir um pipe em stdin de iptables-restore. Este último lhe dará um desempenho muito melhor. Filtragem. libiptc é uma camada muito baixa para ser usada razoavelmente de qualquer maneira.
Ok, então talvez você não deva tratar essas bibliotecas C como estáveis. Então eu pensei "por que não falar com /procou qualquer coisa diretamente?" Acontece que a iptablesmaioria não usa /procpara falar com o kernel (apenas para ler nomes de tabelas?), E a interface principal está na verdade getsockopt()e setsockopt()em um soquete não acoplado.
Essa foi outra surpresa! (Mas talvez seja apenas porque eu não estou familiarizado com este tipo de código que parece uma forma engraçada de interagir com o kernel.)
Eu fiz um pouco de trás arqueologia de iptablesque ipchainsa ipfwe encontrou uma página homem ipfw partir de 1997 que me fez sentir um pouco melhor:
BUGS
The setsockopt(2) interface is a crock. This should be
put under /proc/sys/net/ipv4 and the world would be a bet-
ter place.
Você pode encontrar em outro lugar que "O utilitário ipfw apareceu pela primeira vez no FreeBSD 2.0" e
HISTORY
Initially this utility was written for BSDI by:
Daniel Boulet <[email protected]>
The FreeBSD version is written completely by:
Ugen J.S.Antsilevich <[email protected]>
while synopsis partially compatible with old one.
Aqui está a versão do FreeBSD 2.0 de ipfw1994 . Ele ainda usa setsockopt(), mas parece usar em kvm_read()vez de getsockopt().
Minhas perguntas
- Por favor, corrija tudo o que eu disse errado acima :)
- Por que eles escolheram
{get,set}sockopt()em primeiro lugar? É incomum ou apenas novo para mim? - Por que não foi alterado em algum momento? Como algo abaixo do
/procque a página do manual de 1997 sugere. - Por que eles nunca criaram uma interface C estável / pública para
iptables?
Minhas perguntas de acompanhamento
"Não exatamente, a interface principal é a família NETLINK_NETFILTER do netlink"
Obrigado por este ponteiro!
Estou olhando para https://git.netfilter.org/iptables/treee libipqparece estar usando apenas um soquete netlink, a menos que esteja faltando alguma coisa.
$ ick "socket\("
include/libiptc/libiptc.h
158:int iptc_get_raw_socket(void);
include/libiptc/libip6tc.h
152:int ip6tc_get_raw_socket(void);
utils/nfsynproxy.c
129: fd = socket(AF_INET, SOCK_STREAM, 0);
libiptc/libiptc.c
1312: sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
extensions/libxt_set.h
14: int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
libipq/libipq.c
223: h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_FIREWALL);
225: h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_IP6_FW);
libxtables/xtables.c
881: sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
As libipqmaterial parece "normal" para mim: fazer um socket, vinculá-lo com um sockaddr, sendto(), recvfrom(), etc.
Também xtables-monitorparece estar usando alguns mnl_socket_*wrappers que fazem coisas de netlink.
Mas eu não consigo descobrir libiptce xtables- nenhuma menção ao netlink, e eles nem ligam o socket.
https://git.netfilter.org/iptables/tree/libxtables/xtables.c#n881
https://git.netfilter.org/iptables/tree/libiptc/libiptc.c#n1312
Existem outros exemplos que não (parecem?) Usar netlink, como este código do depurador rr do mozilla: https://github.com/mozilla/rr/blob/master/src/test/netfilter.c
E o netlink é apenas Linux, do ano 2000 (2.2), enquanto esse {get,set}sockopt()material em (pelo menos) ipfwé mais antigo, e na terra do BSD.
Não tenho mais certeza de qual é a minha pergunta :) Como os soquetes não-netlink de alguma forma se comunicam com a coisa correta do lado do kernel sem mesmo bind()um sockaddr?
Respostas
Eu acho que uma biblioteca Python tem permissão para carregar bibliotecas C em tempo de execução, e Go não pode
Go pode usar bibliotecas C compartilhadas.
Acontece que a
iptablesmaioria não usa/procpara falar com o kernel (apenas para ler nomes de tabelas?), E a interface principal é na verdadegetsockopt()esetsockopt().
Por que eles escolheram
{get,set}sockopt()em primeiro lugar? É incomum ou apenas novo para mim?
(Essa resposta afirmava anteriormente, incorretamente, que a interface principal é netlinka NETLINK_NETFILTERfamília de.)
Você está correto, iptablesusa chamadas para getsockoptem sockets não ligados do tipo adequado para interagir com o kernel, o que acaba por pôr em do kernel netfilterde código . Suspeito que seja por razões históricas ...
A propósito, getsockopte setsockoptfuncionam em soquetes em uma variedade de estados, incluindo não acoplados, e precisam porque são usados para definir opções antes de conectar. A conexão netfilter-via- sockopté efetivamente um canal lateral.
Por que não foi alterado em algum momento? Como algo abaixo do
/procque a página do manual de 1997 sugere.
Provavelmente há uma série de razões, mas uma é sem dúvida a compatibilidade com versões anteriores - no Linux, as interfaces de espaço do usuário nunca devem quebrar. Assim, embora uma nova interface pudesse ser fornecida, a existente permaneceria, o que reduz o incentivo para melhorá-la ou reescrever programas que já funcionam.
Contanto que a iptablesferramenta de linha de comando pudesse ser usada sem muito esforço e fornecer uma interface melhor envolvesse muito mais esforço, a mudança seria difícil. Uma libiptcbiblioteca de estilo bem mantida também teria sido uma possibilidade, mas nunca houve muito incentivo para os iptablesdesenvolvedores fazerem isso.
Por que eles nunca criaram uma interface C estável / pública para
iptables?
Porque “eles” nunca chegaram a isso. Agora iptablesestá a ser eliminada em favor de nftables, que inclui um número de bibliotecas que fornecem acesso a diferentes níveis de abstração ( libnftables, libnftnl, libnfnetlink). Isso usa netlink, que foi projetado como uma interface baseada em sockets para transferir informações entre o kernel e o espaço do usuário, e é um ajuste natural para ferramentas como nftables(e iptables). A netlinkdocumentação lista as outras famílias disponíveis; eles cobrem muitas funcionalidades hospedadas no kernel. netlink.
Você pode encontrar https://github.com/vishvananda/netlinkútil para começar a dirigir iptablesdo Go. (É necessário muito trabalho para isso, mas é melhor do que começar do zero.)