Comando para executar um processo filho "offline" (sem rede externa) no Linux

15

Eu tenho um programa que gostaria de testar no modo offline sem desligar minha rede atual. Esse programa ainda precisaria se conectar aos soquetes locais, incluindo soquetes de domínio unix e loopback. Ele também precisa ouvir no loopback e estar visível para outros aplicativos.

Mas as tentativas de conexão com uma máquina remota devem falhar.

Eu gostaria de ter um utilitário que funcione como strace/ unshare/ sudoe simplesmente execute um comando com a Internet (e LAN) oculta e tudo o mais ainda funcionando:

$ offline my-program-to-test

Esta pergunta tem dicas para a resposta: Bloquear o acesso à rede de um processo?

Existem algumas sugestões, como executar como outro usuário e manipular o iptables ou unshare -n. Mas, em ambos os casos, não conheço o encantamento de compartilhar soquetes de domínio unix e loopback com o sistema principal - as respostas a essa pergunta me dizem apenas como cancelar o compartilhamento de toda a rede.

O programa que estou testando ainda precisa se conectar ao meu servidor X e ao dbus e até conseguir ouvir no loopback as conexões de outros aplicativos no sistema.

Idealmente, eu gostaria de evitar a criação de chroots ou usuários ou VMs ou similares, pois isso se torna tão irritante quanto desconectar o cabo de rede. ou seja, o ponto da questão é como posso fazer isso tão simples quanto um sudo.

Eu adoraria que o processo fosse executado 100% normalmente, exceto que as chamadas de rede que especificam um endereço não local falhariam. Idealmente, mantendo o mesmo uid, mesmo homedir, mesmo pwd, o mesmo tudo, exceto ... offline.

Estou usando o Fedora 18, então as respostas não portáveis ​​do Linux são boas (até mesmo esperadas).

Fico feliz em resolver isso escrevendo um programa em C, se é isso que está envolvido, então as respostas que envolvem escrever C estão bem. Só não sei quais syscalls o programa C precisaria fazer para revogar o acesso à rede externa enquanto mantinha a rede local.

Qualquer desenvolvedor que tente oferecer suporte ao "modo offline" provavelmente apreciaria este utilitário!

Havoc P
fonte

Respostas:

9

A resposta tradicional é executar o programa como outro usuário e usá-lo iptables -m owner. Dessa forma, a configuração de rede é compartilhada. No entanto, com o advento dos namespaces, existe uma maneira mais fácil.

Com espaços para nome, você compartilha a rede e cria um link de rede virtual se precisar de acesso limitado à rede.

Para compartilhar soquetes de domínio unix, tudo que você precisa é ter um kernel recente o suficiente, após este patch de 2010 , para 2.6.36 ou superior (que é o caso de todas as distribuições atuais no momento da escrita, exceto RHEL / CentOS).

Execute o programa em seu próprio espaço para nome IP. Antes de iniciar o programa, estabeleça uma interface Ethernet virtual. Parece não haver muita documentação; Encontrei o encantamento certo em alguns blogs:

No snippet abaixo, eu uso o wrapper thisns_exec is listado na página de manual para exibir o lado do host do link de rede do processo em execução no namespace restrito. Na verdade, você não precisa disso: pode configurar o lado do host do link de fora do espaço para nome restrito. Fazer isso de dentro para facilitar o controle de fluxo, caso contrário, você precisará de alguma sincronização para configurar o link depois que ele for estabelecido, mas antes de iniciar o programa.setns

unshare -n -- sh -c '
  # Create a virtual ethernet interface called "confined",
  # with the other end called "global" in the namespace of PID 1
  ip link add confined type veth peer name global netns 1

  # Bring up the confined end of the network link
  ip addr add 172.16.0.2/30 dev confined
  ip link set confined up

  # Bring up the global end of the network link
  ns_exec /proc/1/ns/net ifconfig global 172.16.0.1 netmask 255.255.255.252 up

  # Execute the test program
  exec sudo -E -u "$TARGET_USER" "$0" "$@"
' /path/to/program --argument

Você precisa fazer tudo isso como root. A introdução de espaços para nome de usuário no kernel 3.8 pode tornar isso possível sem permissões especiais, exceto a configuração do final global do link de rede.

Não sei como compartilhar localhost entre os dois namespaces. Interfaces Ethernet virtuais criam uma ponte ponto a ponto. Você pode usar iptablesregras de encaminhamento para redirecionar o tráfego de / para, lose desejar.

Gilles 'SO- parar de ser mau'
fonte
Boas informações adicionais, obrigado. Acho que o veth me fornece um link para "fora" do namespace, mas meu novo namespace ainda equivale a um nó de rede separado, em vez do mesmo nó de rede menos as interfaces não locais. As implicações são (?): Soquetes de domínio / resumo do Unix ainda falhariam e o loopback poderia ser encaminhado via iptables, mas o encaminhamento não alcança compartilhamento - ou seja, o namespace original e o restrito podem estar ouvindo o loopback e os dois conjuntos de (dinamicamente mudando ao) portas teriam de ser visível em ambos os namespaces ... começando a adivinhar o que eu quero é impossível aqui: - /
Havoc P
1

Isso também pode ser alcançado com cgroups de correspondência de regras do iptables. Eu escrevi uma ferramenta para abstrair as etapas. Embora exija permissões de root para a configuração inicial e, de outra forma, seja um binário setuid, acho que oferece uma maneira bastante direta de lidar com o problema na questão. Requer uma versão do iptables recente o suficiente e que os módulos netfilter adequados estejam disponíveis.

https://github.com/quitesimpleorg/qsni

crtxcr
fonte
0

/ !! \ Essa provavelmente não é uma resposta válida, pois isso reduzirá todo o seu tráfego, não apenas o tráfego de um único pid.

Eu não o usei, mas acho que você poderia usar o Comcast:

https://github.com/tylertreat/Comcast

definido como 100% de perda de pacotes

Novamente, eu não testei isso, mas teoricamente, modificado a partir do leia-me, você pode fazer:


Linux

No Linux, você pode usar iptablespara descartar pacotes de entrada e saída.

$ iptables -A INPUT -m statistic --mode random --probability 1 -j DROP
$ iptables -A OUTPUT -m statistic --mode random --probability 1 -j DROP

Como alternativa, você pode usar o tcque suporta algumas opções adicionais.

$ tc qdisc change dev eth0 root netem reorder 0 duplicate 0 corrupt 1

Reiniciar:

$ tc qdisc del dev eth0 root netem
ThorSummoner
fonte