Como eu conecto um dispositivo veth dentro de um namespace de rede 'anônimo' a um externo?

2

Eu tenho um processo que chamou unshare para criar um novo namespace de rede apenas dentro de si. Quando ele chama execve para ativar o bash, o comando ip mostra que tenho apenas um lo device. Se eu também criar um namespace de usuário e organizar meu processo como root dentro do namespace, posso usar o comando ip para ativar esse dispositivo e ele funciona.

Eu também posso usar o comando ip para criar um dispositivo veth neste namespace. Mas ele não aparece em ip netns list e o novo dispositivo veth não aparece no namespace do nível raiz (como eu esperava). Como eu conecto um dispositivo veth no namespace de nível raiz ao meu novo dispositivo veth dentro do namespace do processo? O comando ip parece exigir que o namespace tenha um nome atribuído pelo comando ip , e o meu não, porque eu não usei ip netns add para criá-lo.

Talvez eu possa fazer isso escrevendo meu próprio programa que usou o dispositivo netlink e configurou as coisas. Mas eu realmente prefiro não fazer isso. Existe uma maneira de fazer isso através da linha de comando?

Deve haver uma maneira de fazer isso, pois os contêineres do Docker também têm seu próprio namespace de rede, e esse namespace também não tem nome. No entanto, há um dispositivo veth dentro dele conectado a um dispositivo veth fora dele.

Meu objetivo é criar dinamicamente um contexto de isolamento do processo, idealmente sem precisar se tornar raiz fora do contêiner. Para isso, vou criar um namespace PID, um namespace UID, um namespace de rede, um namespace de IPC e um namespace de montagem. Eu também posso criar um namespace cgroup, mas eles são novos e eu preciso ser capaz de rodar em versões atualmente suportadas do SLES, RHEL e Ubuntu LTS.

Eu tenho trabalhado nesse namespace por vez, e atualmente tenho espaço para nome de usuário, PID e de montagem funcionando satisfatoriamente.

Eu posso montar /proc/pid/ns/net se eu precisar, mas eu preferiria fazer isso dentro do namespace do usuário, então (novamente) eu não tenho que ser root fora do namespace. Principalmente, quero que tudo desapareça assim que todos os processos no espaço de nomes forem eliminados. Ter um monte de estados para limpar o sistema de arquivos quando eu terminar seria menos que ideal. Embora criá-lo temporariamente quando o contêiner é alocado pela primeira vez e, em seguida, removê-lo imediatamente é muito melhor do que ter que limpá-lo quando o contêiner sai.

Não, eu não posso usar o docker , lxc , rkt , ou qualquer outra solução existente de tal forma que eu estaria confiando em qualquer outra coisa que não sejam utilitários de sistema padrão (como ip ), bibliotecas de sistema como glibc e chamadas de sistema Linux.

    
por Omnifarious 05.10.2017 / 02:59

2 respostas

2

ip link tem uma opção de namespace, que além disso para um nome de namespace de rede, pode usar um PID para referenciar o namespace de um processo. Se os namespaces PID forem compartilhados entre os processos, você poderá mover os dispositivos de qualquer maneira; provavelmente é mais fácil de dentro , quando você considera PID 1 sendo "fora" . Com namespaces PID separados , você precisa mover do namespace externo (PID) para o interno.

Por exemplo, de dentro de um namespace de rede, você pode criar um par de dispositivos veth para o namespace PID 1 :

ip link add veth0 type veth peer name veth0 netns 1

Como os namespaces funcionam no Linux

Todo processo tem arquivos de referência para os namespaces em /proc/<pid>/ns/ . Além disso, ip netns cria arquivos de referência persistentes em /run/netns/ . Esses arquivos são usados com a setns chamada do sistema para alterar o namespace do encadeamento em execução para um namespace apontado por tal arquivo.

Do shell, você pode entrar em outro namespace usando o nsenter programa, fornecendo arquivos de namespace (caminhos) em argumentos.

Uma boa visão geral dos namespaces do Linux é dada na série de artigos Namespaces in operation no LWN .net.

Configurando namespaces

Quando você configura vários namespaces ( mount, pid, user, etc.), configure o namespace de rede o mais cedo possível, antes de alterar mount e pid namespaces. Se você não tiver namespaces mount ou pid compartilhados, não terá como apontar o namespace de rede para fora, porque não é possível ver os arquivos referentes aos namespaces de rede fora.

Se você precisar de mais flexibilidade do que os utilitários de linha de comando fornecem, você precisa usar as chamadas do sistema para gerenciar espaços de nome diretamente do seu programa. Para documentação, veja as páginas de manual relevantes: man 2 setns , man 2 unshare e man 7 namespaces .

    
por 05.10.2017 / 09:16
1

Um veth consiste em um par de dispositivos, você coloca cada um deles no namespace da rede (ou namespace raiz) com o qual deseja se comunicar.

Aqui está um script que chamo de raiz do namespace raiz para criar um novo namespace de rede e configurar um par veth entre o namespace raiz e o namespace da rede. A última linha inicia um xterm nesse namespace. Adapte conforme necessário.

#!/bin/bash
# Setup network namespace with veth pair, start xterm in it

if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 1>&2
   exit 1
fi

NS=${1:-ns0}
DEV=${2:-veth0}
DEV_A=${DEV}a
DEV_B=${DEV}b
ADDR=${3-:10.0.0}
ADDR_A=${ADDR}.254
ADDR_B=${ADDR}.1
MASK=${5:-24}
COL=${4:-yellow}

# echo ns=$NS dev=$DEV col=$COL mask=$MASK

ip netns add $NS
ip link add $DEV_A type veth peer name $DEV_B netns $NS
ip addr add $ADDR_A/$MASK dev $DEV_A
ip link set ${DEV}a up
ip netns exec $NS ip addr add $ADDR_B/$MASK dev $DEV_B
ip netns exec $NS ip link set ${DEV}b up
ip netns exec $NS ip route add default via $ADDR_A dev $DEV_B
ip netns exec $NS su -c "xterm -bg $COL &" your_user_id

Você também pode usar

ip link set name_of_if netns name_of_ns

para mover interfaces de rede (incluindo interfaces para dispositivos físicos) entre namespaces de rede.

Editar

Acabei de testá-lo, você também pode criar um par de dentro do novo namespace e colocar um endpoint no namespace raiz. O truque é que o namespace raiz aparentemente não tem um nome, mas é acessível como id 1 :

sudo ip link add veth1b type veth peer name veth1a netns 1

Não estou familiarizado como funciona com unshare , mas suponho que você ainda possa encontrar o namespace de rede recém-criado em /proc/<pid>/ns/<type> de alguma forma. Se não tiver um nome, deve pelo menos ter um ID numérico. ip netns list também poderia ajudar. E eu acho que tudo isso também pode ser feito com chamadas do sistema em vez de usar ip ; strace ou ltrace pode ajudar a descobrir quais são.

Editar

Eu dei uma olhada rápida em man namespaces 7 ; descobrir o namespace de /proc parece estar envolvido o suficiente (você só tem um descritor de arquivo) que talvez seja melhor criar o namespace com ip netns add e depois iniciar o programa nele com ip netns exec em vez de unshare . Supondo que você somente precise de um novo namespace de rede, e não de outra coisa, também.

    
por 05.10.2017 / 08:07