Lier un programme Unix à une interface réseau spécifique

40

Question: Comment lancer un programme tout en s'assurant que son accès réseau est lié via une interface réseau spécifique?

Cas: je souhaite accéder à deux machines distinctes avec la même adresse IP (192.168.1.1), mais accessible via deux interfaces réseau différentes (eth1 et eth2).

Exemple:

net-bind -D eth1 -exec {Program 192.168.1.1}
net-bind -D eth2 -exec {Program 192.168.1.1}

Ce qui précède est une approximation de ce que je voudrais, inspiré par la liaison matérielle effectuée via primusrun et optirun .

Défi: comme suggéré dans un thread associé , les interfaces utilisées ne sont pas choisies par le programme, mais par le noyau (d'où la syntaxe de pré-liaison dans l'exemple ci-dessus).

J'ai trouvé des solutions connexes, qui ne sont pas satisfaisantes. Ils reposent sur des interfaces réseau de liaison via une liste noire réseau spécifique à l'utilisateur; En d'autres termes, exécuter le processus en tant qu'utilisateur ne pouvant accéder qu'à une seule interface réseau spécifique.

Skeen
la source
Voulez-vous dire que votre machine est connectée à deux réseaux différents, l'un et l'autre 192.168.1.0? À quoi ressemble votre table de routage? Si vous souhaitez limiter les interfaces visibles à partir d'un processus, la solution la plus légère serait les groupes de contrôle, un conteneur plus lourd.
lgeorget
Oui, deux réseaux différents, tous deux sur la même plage IP. Je ne suis pas certain de ne pas restreindre les interfaces visibles, mais de décider laquelle utiliser par défaut? :)
Skeen
3
Ce que vous demandez est difficile pour une bonne raison: avoir deux réseaux interconnectés en utilisant le même domaine IP revient à avoir un ascenseur dans un bâtiment de deux étages portant le même numéro. La plage IP est ce qui identifie le domaine et non l'interface de sortie. Néanmoins, il doit exister un moyen de contourner votre conception réseau défaillante avec iptables.
lgeorget
Je connecte mon système à deux infrastructures sur place différentes. En tant que telles, ces infrastructures n'ont jamais été conçues pour interagir. La conception du réseau est donc défectueuse à cet égard.
Skeen
1
Mon argument vis-à-vis des NAT était que des espaces d'adresses entiers sont généralement cachés derrière le NAT, et lorsque je connecte deux infrastructures NAT, la collision se produit. - Je ne suis pas en position de modifier l'infrastructure. - J'ai essayé d'utiliser des espaces de noms réseau avec des paires d'interfaces réseau virtuelles (une dans l'espace de noms, une dans l'espace de noms racine) pour relier l'espace de noms racine à une interface physique et l'exécution de programmes dans l'espace de noms réseau. - Cela semble fonctionner, mais je n'ai pas accès au-delà de l'espace de noms racine (c'est-à-dire pas d'accès en dehors de la machine elle-même).
Skeen

Réponses:

35

Pour Linux, cela a déjà été résolu sur le superutilisateur - Comment utiliser différentes interfaces réseau pour différents processus? .

La réponse la plus populaire utilise une LD_PRELOADastuce pour modifier la liaison réseau d'un programme, mais les noyaux modernes prennent en charge une fonctionnalité beaucoup plus flexible appelée "espaces de noms réseau" qui est exposée via le ipprogramme. Cette réponse montre comment l'utiliser. De mes propres expériences, j'ai fait ce qui suit (en tant que root):

# Add a new namespace called test_ns
ip netns add test_ns

# Set test to use eth0, after this point eth0 is not usable by programs
# outside the namespace
ip link set eth0 netns test_ns

# Bring up eth0 inside test_ns
ip netns exec test_ns ip link set eth0 up

# Use dhcp to get an ipv4 address for eth0
ip netns exec test_ns dhclient eth0

# Ping google from inside the namespace
ip netns exec test_ns ping www.google.co.uk

Il est également possible de gérer les espaces de noms réseau dans une certaine mesure avec les commandes unshareet nsenter. Cela vous permet également de créer des espaces distincts pour les PID, les utilisateurs et les points de montage. Pour plus d'informations, voir:

Graeme
la source
"après ce point, eth0 ne sera plus utilisable par des programmes situés en dehors de l'espace de noms" - Je supprime donc la connexion pour tous les autres problèmes que vous rencontrez?
Skeen
1
@Skeen, oui, on peut donc supposer que vous pousseriez une interface qu'aucun autre programme n'utilise dans l'espace de noms et n'utiliseriez votre interface principale normalement.
Graeme
1
@Graerne; Les deux interfaces sont utilisées activement; Je ne peux pas me permettre d'enlever les interfaces.
Skeen
et quoi avec la passerelle par défaut? wvdialpar exemple ne semble pas le configurer du tout ... il doit donc être défini dans l'espace de noms lui
Flash Thunder
Pourriez-vous inclure des instructions sur la façon d'annuler cela? Est-ce que tu veux juste ip netns remove test_nsretourner à la normale? Ou devez-vous faire quelque chose de spécial?
Multihunter
17

J'accepte la réponse de Graeme ceci est simplement un suivi pour expliquer les changements que j'ai apportés à sa suggestion pour résoudre mon problème.

Au lieu de lier l'interface physique à l'intérieur de l'espace de noms, j'ai créé une paire d'interface réseau virtuelle, avec une extrémité dans l'espace de nom réseau et une autre à la racine. Les packages sont ensuite routés via ce réseau virtuel de l'espace de noms vers l'espace de noms racine, puis vers l'interface physique. - En tant que tel, je peux exécuter tous mes transferts de données ordinaires et, en outre, démarrer des processus qui ne peuvent accéder qu'à une interface spécifique.

# Create the eth0 network namespace
ip netns add eth0_ns

# Create the virtual network pair
ip link add v_eth0a type veth peer name v_eth0b

# Move v_eth0a to the eth0_ns namespace, the virtual pair is now split
# between two network namespaces.
ip link set v_eth0a netns eth0_ns

# Configure the ends of the virtual network pairs
ip netns exec eth0_ns ifconfig v_eth0a up {{NAMESPACE_IP}} netmask {{NAMESPACE_NETMASK}}
ifconfig v_eth0b up {{ROOT_NS_IP}} netmask {{ROOT_NS_NETMASK}}

# Setup routing from namespace to root
ip netns exec eth0_ns route add default gw {{ROOT_NS_IP}} dev v_eth0a

# Setup IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s {{ROUTE_SOURCE}}/24 -o {{NETWORK_INTERFACE}} -j SNAT --to-source {{ROUTE_TARGET}}

Une fois que les interfaces ont été configurées pour eth0 et eth1, avec leurs espaces de noms respectifs eth0_ns et eth1_ns, les programmes peuvent être exécutés sur l’interface spécifiée via;

ip netns exec eth0_ns fish
ip netns exec eth1_ns fish
Skeen
la source
4
Bien joué! Je pense que vous pouvez également créer un périphérique de pontage et relier l'espace de noms par défaut et la paire virtuelle à l'un des périphériques physiques. Cela semble équivalent cependant.
Graeme
1
J'ai essayé de relier le périphérique virtuel et physique; Je n'ai pas pu atteindre le réseau externe avec cette solution.
Skeen
2
Je l'ai fait, mais seulement à partir du nouvel espace de noms. Je pense que le problème que je rencontrais était lié au gestionnaire de réseau. Je n’ai pas compris si j’aurais mis à jour ma réponse.
Graeme
J'ai le même problème, mais je n'ai pas utilisé cette solution. Que dois-je entrer exactement dans {{ROUTE_SOURCE}} et {{ROUTE_TARGET}} à la dernière étape?
Litov
@Graeme, du moins sur Ubuntu, j'ai pu retrouver la connectivité à la fois dans l'espace de noms et dans l'espace de noms global en émettant dhclient <bridge>par ici .
Chris Hunt
4

Solution I: préchargement d'une bibliothèque spécifique

  • App-Route-Jail : utilisez ld_preload pour forcer la passerelle d'interface (bonne idée mais nécessite des fonctionnalités de racine ou de marque). L'utilisation est détaillée dans les notes ci-dessous.

  • Proxybound : utilisez ld_preload pour forcer un proxy à une application spécifique (il s'agit d'un proxy plutôt que d'une interface)

  • Force-Bind : avoir beaucoup de fonctionnalités mais les liaisons sont fausses (non fiable)

  • Bind-Interface-IP : connexions trop simples et fuites (non fiables)

  • Bind-IP : trop simple et connexions fuites (non fiables)

Solution II: espace utilisateur Linux

  • Espace utilisateur linux classique ip-netns : une excellente solution, mais nécessite une racine et une interface ne peut exister que sur un seul espace utilisateur

  • Firejail : Firejail peut forcer une application à utiliser un réseau spécifique, mais la compatibilité est limitée (par exemple, il n'est pas compatible avec les interfaces tun). FireJail ne nécessite pas de racinefirejail --dns=8.8.8.8 --noprofile --net=eth0 --ip=192.168.1.1 app-command

  • Firejail avec netns : Firejail peut forcer une application à utiliser un espace utilisateur spécifique créé séparément, ce qui nous permet de nommer des espaces sans root.firejail --dns=8.8.8.8 --noprofile --netns=nameOfyourNS app-command

  • Firejail avec masquerade et bridge : Firejail peut forcer une application à utiliser une interface spécifique avec iptables masquerade , ce qui est génial et ne nécessite pas de racine mais cela nécessite ip_forward et pourrait entraîner des problèmes de sécurité.firejail --net=br0 firefox

Solution III: Linux iptables

Iptables pourrait être utilisé à cette fin, mais cela nécessite ip_forward et pourrait avoir un impact sur la sécurité s'il n'est pas correctement configuré, exemple 1 , exemple 2 , exemple 3 , exemple 4.

Remarques sur les solutions (I, II et III):

Wireguard

Si vous utilisez un VPN (particulièrement wireguard) et que vous souhaitez appliquer cette solution à une interface wireguard ( wireguard avec espace utilisateur ), vous pouvez suivre le lien qui lui est demandé pour créer un espace utilisateur contenant une interface wg (et donc limité à une interface vpn). ) et ceci peut également être combiné firejail --netns=containerpour pouvoir utiliser l’espace utilisateur sans root.

Comment trouver la passerelle d'interface

Il existe de nombreuses solutions pour trouver la passerelle. Voici quelques commandes permettant de trouver la passerelle utilisée.

$ route
$ route -n
$ ip rule list
$ ip route show
$ netstat -rn
$ cat /etc/network/interfaces
$ cat /etc/sysconfig/network-scripts/ifcfg-eth0
$ traceroute www.google.com
$ ip route show 0.0.0.0/0 dev eth0

Comment utiliser App-Route-Jail

  • Construire App-Route-Jail
git clone https://github.com/Intika-Linux-Network/App-Route-Jail.git
cd Approute-Utils
chown 755 make.sh
./make.sh
  • Ajouter une route pour les futurs paquets marqués (pour l'application jailed) dans cet exemple 192.168.1.1est utilisé comme passerelle forcée, cette règle de route n'affectera pas les autres applications, cette manipulation ne doit être effectuée qu'une seule fois au démarrage du système si vous souhaitez utiliser cette solution quotidiennement
ip rule add fwmark 10 table 100
ip route add default via 192.168.1.1 table 100
  • Démarrer l'application que vous voulez emprisonner
MARK=10 LD_PRELOAD=./mark.so firefox
  • Test de l'adresse IP wan
MARK=10 LD_PRELOAD=./mark.so wget -qO- ifconfig.me
intika
la source