Roteie o tráfego por uma interface específica para um processo no Linux

20

É possível rotear o tráfego usado por um processo em uma interface específica?

Por exemplo, o tráfego de rede pelo aplicativo de download deve sempre usar a interface, wlan0enquanto todos os outros aplicativos na máquina devem usar eth0.

É possível ter esse tipo de regra no Linux?

Suresh
fonte

Respostas:

22

Isso pode ser feito usando namespaces de rede Linux.

Aqui está um artigo que explica como. Basicamente, você cria um namespace de rede com uma rota padrão diferente e executa os processos que precisam dele lá. Você conecta o namespace de rede recém-criado ao adaptador físico com uma ponte (mas outras soluções são possíveis, é claro).

Atualização: do kernel 3.14 é ainda mais fácil usar grupos de controle, conforme descrito neste artigo . Voce tem que:

1) defina um grupo de controle net_cls para anotar os pacotes de um determinado processo com um classid (ou grupo de processos, observe que não deve haver nenhum relacionamento pai-filho entre eles)

2) use o módulo iptables cgroup (adicionado no Linux 3.14) para marcar os pacotes

3) use o roteamento de política (regra de regra adicione fwmark ....) para criar uma nova tabela de roteamento para os pacotes marcados

A vantagem é que não precisamos fazer a ponte e tudo é muito mais dinâmico, graças ao cgroups.

chripell
fonte
14

Eu tenho lutado muuuito com isso, então aqui está uma solução COMPLETA. Ele foi testado no Ubuntu 15 e 16. Você pode usá-lo especialmente com o OpenVPN para rotear certos aplicativos fora da interface de túnel da VPN.

A solução completa "cgroup"

Como isso funciona?

  • O kernel do Linux colocará o aplicativo em um grupo de controle . O tráfego de rede dos aplicativos neste cgroup será identificado pelo ID da classe no nível do controlador de rede.
  • O iptables marcará esse tráfego e o forçará a sair com o IP correto
  • O ip route processará o tráfego marcado em uma tabela de roteamento diferente, com uma rota padrão para o IP do gateway desejado.

Script automatizado

Eu criei um script novpn.sh para automatizar a instalação e execução de dependências. Testado no Ubuntu.

Inicie sua VPN primeiro.

wget https://gist.githubusercontent.com/kriswebdev/a8d291936fe4299fb17d3744497b1170/raw/cf8b37fbe6c3f50a0be825eb77cafa3e0134946f/novpn.sh
# If you don't use eth0, edit the script setting.
sudo chmod +x novpn.sh
./novpn.sh traceroute www.google.com
./novpn.sh --help

Manual de instruções

Primeiro, instale o suporte e as ferramentas do cgroup:

sudo apt-get install cgroup-lite cgmanager cgroup-tools

Reinicialize (pode não ser necessário).

Você precisa do iptables 1.6 .0+. Obtenha o iptables 1.6.0 release source , extraia-o e execute-o (o --disable-nftablessinalizador evitará erros) no diretório iptables source:

sudo apt-get install dh-autoreconf bison flex
./configure --prefix=/usr      \
            --sbindir=/sbin    \
            --disable-nftables \
            --enable-libipq    \
            --with-xtlibdir=/lib/xtables
make
sudo make install
iptables --version

Agora, a configuração real. Defina um grupo de controle chamado novpn. Os processos neste cgroup terão um classid de 0x00110011(11:11).

sudo su
mkdir /sys/fs/cgroup/net_cls/novpn
cd /sys/fs/cgroup/net_cls/novpn
echo 0x00110011 > net_cls.classid

Agora, vamos supor que a interface que você deseja usar para o aplicativo específico esteja eth0com um IP de gateway 10.0.0.1. Substitua- os pelo que você realmente deseja (obtenha as informações ip route). Execute ainda como root:

# Add mark 11 on packets of classid 0x00110011
iptables -t mangle -A OUTPUT -m cgroup --cgroup 0x00110011 -j MARK --set-mark 11

# Force the packets to exit through eth0 with NAT
iptables -t nat -A POSTROUTING -m cgroup --cgroup 0x00110011 -o eth0 -j MASQUERADE

# Define a new "novpn" routing table
# DO THIS JUST ONCE !
echo 11 novpn >> /etc/iproute2/rt_tables

# Packets with mark 11 will use novpn
ip rule add fwmark 11 table novpn

# Novpn has a default gateway to the interface you want to use
ip route add default via 10.0.0.1 table novpn

# Unset reverse path filtering for all interfaces, or at least for "eth0" and "all"
for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $i; done

Por fim, execute seu aplicativo na interface específica:

exit
sudo cgcreate -t $USER:$USER -a $USER:$USER -g net_cls:novpn
cgexec -g net_cls:novpn traceroute www.google.com
# Close all Firefox windows first
cgexec -g net_cls:novpn firefox

Ou se você deseja mover um processo já em execução para o cgroup, bem ... você não pode! Isso parece ser devido à função NAT (mascarada): iptables -nvL -t natnão corresponde quando o cgroup é alternado, mas iptables -nvL -t manglecorresponde.

# Get PID of the process (we'll then suppose it's 1234)
pidof firefox
# Add to cgroup - THIS DOESN'T WORK! Silently fails to produce the final result.
sudo echo 1234 > /sys/fs/cgroup/net_cls/novpn/tasks
# Remove - but this works...
sudo echo 1234 > /sys/fs/cgroup/net_cls

Créditos: nenhuma resposta estava funcionando como esperado, mas uma mistura delas funcionou: chripell answer artigo evolware Por roteamento de processo, execute 2: usando cgroups, iptables e roteamento de políticas , Como faço para que um processo específico NÃO passe por uma conexão OpenVPN? , Kill switch para OpenVPN com base em iptables

KrisWebDev
fonte
Obrigado pela ótima resposta, como faço para funcionar com o apache? Eu tentei cgexec -g net_cls:novpn apache2e me deu toda a lista de erros indefinidos variáveis!
Razzak
2
Você obterá os mesmos erros executando apache2diretamente do terminal. Isso porque apache2normalmente é lançado como um serviço, com systemctl start apache2. No entanto, isso não funcionará cgexec. O programa chamado deve ser o pai do apache2processo ( ) desejado para que o net_cls cgroup se propague. Então, você precisa encontrar o script de inicialização. Nesse caso, é sudo cgexec -g net_cls:novpn /usr/sbin/apache2ctl start. Verifique com ./novpn.sh --list.
KrisWebDev 19/07
Ele não funciona mais no ubuntu 16.04!
Razzak
2
Estou usando no Ubuntu 16.04 e está funcionando bem. Os nomes de interface foram alterados no Ubuntu 16, você pode substituir a necessidade de substituir eth0por algo como enp7s0. Obtenha as informações do ifconfigcomando
KrisWebDev
Obrigado. Mas ele não funciona no Ubuntu 18.04 porque o cpmanager foi removido devido a um conflito com o systemd
skonsoft
3

Combinando as excelentes respostas de mariusmatutiae e KrisWebDev, criei um excelente novpn.shscript do KrisWebDev, versão extensivamente modificada . Enquanto o script do KrisWebDev foi desenvolvido para coçar uma coceira mais específica (executando e movendo processos dentro / fora de uma VPN), minha versão permite executar basicamente qualquer comando em um ambiente de rede que você especificar. Você pode especificar a interface à qual se ligar, a rota padrão, especificar suas próprias regras de tabelas de ip, rotas estáticas, especificar um "teste" para confirmar que tudo está funcionando como você deseja antes de executar o comando ... etc). Ele permite que você use vários arquivos de configuração para definir qualquer número de ambientes de rede específicos nos quais você possa executar comandos / processos.

Publiquei como uma essência aqui: https://gist.github.com/level323/54a921216f0baaa163127d960bfebbf0

Pode até limpar as tabelas cgroup / iptables / routing posteriormente!

Feedback bem-vindo.

PS - Ele foi projetado para o Debian 8 (Jessie)

tudo natural
fonte
Oi @allnatural, eu gostaria de usar o script altnetworking.sh, mas o que devo colocar no arquivo de configuração?
Cris70
0

Não por aplicativo, não. Você pode fazer isso por porta ou por endereço IP, etc., ou um aplicativo pode se conectar a (e usar) uma placa de rede específica.

Você não pode configurar uma regra para fazê-lo.

Majenko
fonte
Eu tenho um aplicativo java, é possível vincular esse aplicativo a uma interface?
Suresh
Um aplicativo Java para o qual você tem o código-fonte e pode reprogramar os internos?
Majenko
Eu tenho um código-fonte de aplicativo java que usa a biblioteca http apache.
Suresh
Então eu iria para o stackoverflow.com e perguntaria aos programadores como alterar seu programa. Eu nunca programei em Java.
Majenko