Was Sie verlangen, tut es nicht existieren. Aus diesem Grund sind Sie mit den Antworten unzufrieden, die Sie gefunden haben (einige davon stammen möglicherweise von mir):Alle haben Workarounds vorgeschlagen , keine echte Lösung, weder einfach noch komplex.
Lassen Sie mich erklären. Das Routing in allen Betriebssystemen wird durch die Zieladresse bestimmt:Sie können durchaus mehrere Routen haben, aber die Wahl zwischen ihnen basiert nicht auf der Anwendung, die die Verbindung aufruft, sondern einfach auf der Zieladresse. Punkt.
Lassen Sie mich Ihnen ein nicht triviales Beispiel geben. Wenn ein VPN-Client eine Verbindung zu seinem Server hergestellt hat, ist es immer noch möglich, eine Verbindung zu einer bestimmten Site, z. B. example.org, außerhalb des VPN zu leiten. Aber alle Anwendungen, die versuchen, diese spezielle Adresse zu erreichen, werden außerhalb des VPN geleitet:Einige Anwendungen können nicht durch das VPN zu example.org geleitet werden, während andere Anwendungen das VPN verlassen.
Die Situation wird noch reicher mit dem Linux-Kernel, der Quell-Routing ermöglicht:Das bedeutet, dass Sie zwei oder mehr Routing-Tabellen haben können, und die Wahl zwischen ihnen basiert auf der Quelladresse, nicht auf der Zieladresse.
Ein nicht triviales Beispiel:Mein PC hat zwei Amtsleitungen mit zwei unterschiedlichen öffentlichen IPs. Es kann über beide Schnittstellen kontaktiert werden, und es ist wichtig, dass meine Antworten auf eine bestimmte Verbindung durch dieselbe Schnittstelle gehen, über die die Verbindung eingegangen ist:Andernfalls werden sie als irrelevant verworfen, wenn sie die Person erreichen, die die Verbindung initiiert hat. Das ist Source-Routing.
Fair genug, was ist mit Verbindungen, die wir starten? Bei einigen Apps können Sie die Bindungsadresse angeben, z. B. beim openssh-Client:
-b Bindungsadresse
Verwenden Sie bind_address auf dem lokalen Computer als Quelladresse der Verbindung. Nur sinnvoll auf Systemen mit mehr als einer Adresse.
Für sie ist es kein Problem, wenn eine Instanz durch das VPN geht (z. B. Routing-Tabelle 1), während eine andere Instanz das VPN verlässt (z. B. Routing-Tabelle 2). Aber andere Apps, wie Firefox, sind nicht nur notorisch schwer an eine bestimmte Quell-IP-Adresse zu binden (aber siehe hier für eine sehr clevere Problemumgehung), sondern sind auch gemein und böse, da sie es nicht tun Sie können zwei Kopien von sich selbst gleichzeitig ausführen lassen, die jeweils an eine andere Quelladresse gebunden sind. Mit anderen Worten, während Sie dank des oben genannten Tricks eine Instanz dazu zwingen können, sich an eine Quelladresse Ihrer Wahl zu binden, können Sie keine andere Version davon an die andere Quelladresse binden.
Dies erklärt, warum wir Workarounds verwenden:Sie basieren alle auf der gleichen Idee, dass sie mit einem anderen Netzwerk-Stack arbeiten als der Rest des PCs. Sie können also in abnehmender ungefährer Reihenfolge der Komplexität VMs, Docker, Container und Namespaces haben. In jedem von ihnen haben Sie eine oder mehrere Routing-Tabellen, aber Sie können mehrere Instanzen von jedem haben (VM/Docker/Container/Namespaces) und Sie können sie auch frei mischen, wobei jede von ihnen ihre eigene App wie Firefox glücklich getrennt ausführt von den anderen.
Vielleicht interessiert Sie noch einer der Workarounds?
BEARBEITEN:
Die einfachste Problemumgehung ist ein Netzwerk-Namespace. Das folgende Skript behandelt alle notwendigen Aspekte eines NNS:Legen Sie es in eine Datei (Sie wählen Ihren Namen, ich verwende im Allgemeinen newns
, aber Sie tun, was Sie bevorzugen) in /usr/local/bin
, dann chmod 755 FILE_NAME
, und Sie können es wie folgt verwenden:
newns NAMESPACE_NAME start
newns NAMESPACE_NAME stop
Es öffnet sich ein xterm
für Sie (das liegt daran, dass ich es mag, dass xterm funktioniert, aber Sie können es ändern, wenn Sie etwas anderes verwenden möchten), das zum neuen Namensraum gehört. Innerhalb von xterm können Sie, wenn Sie möchten, Ihr VPN starten und dann Ihr Spiel starten. Mit dem folgenden Befehl können Sie leicht überprüfen, ob Sie das VPN verwenden:
wget 216.146.38.70:80 -O - -o /dev/null | cut -d" " -f6 | sed 's/<\/body><\/html>//'
die Ihnen Ihre öffentliche IP zurückgibt. Nachdem Sie das VPN in xterm eingerichtet haben, können Sie überprüfen, ob Ihre öffentliche IP in Ihren anderen Fenstern anders ist. Sie können bis zu 254 xterms mit 254 verschiedenen NNSes und verschiedenen Verbindungen öffnen.
#!/bin/bash
#
# This script will setup an internal network 10.173.N.0/24; if this causes
# any conflict, change the statement below.
export IP_BASE=10.173
# It will open an xterm window in the new network namespace; if anything
# else is required, change the statement below.
export XTERM=/usr/bin/xterm
# The script will temporarily activate ip forwarding for you. If you
# do not wish to retain this feature, you will have to issue, at the
# end of this session, the command
# echo 0 > /proc/sys/net/ipv4/ip_forward
# yourself.
###############################################################################
WHEREIS=/usr/bin/whereis
# First of all, check that the script is run by root:
[ "root" != "$USER" ] && exec sudo $0 "[email protected]"
if [ $# != 2 ]; then
echo "Usage $0 name action"
echo "where name is the network namespace name,"
echo " and action is one of start| stop| reload."
exit 1
fi
# Do we have all it takes?
IERROR1=0
IERROR2=0
IERROR3=0
export IP=$($WHEREIS -b ip | /usr/bin/awk '{print $2}')
if [ $? != 0 ]; then
echo "please install the iproute2 package"
IERROR1=1
fi
export IPTABLES=$($WHEREIS -b iptables | /usr/bin/awk '{print $2}')
if [ $? != 0 ]; then
echo "please install the iptables package"
IERROR2=1
fi
XTERM1=$($WHEREIS -b $XTERM | /usr/bin/awk '{print $2}')
if [ $? != 0 ]; then
echo "please install the $XTERM package"
IERROR3=1
fi
if [ IERROR1 == 1 -o IERROR2 == 1 -o IERROR3 == 1 ]; then
exit 1
fi
prelim() {
# Perform some preliminary setup. First, clear the proposed
# namespace name of blank characters; then create a directory
# for logging info, and a pid file in it; then determine
# how many running namespaces already exist, for the purpose
# of creating a unique network between the bridge interface (to
# be built later) and the new namespace interface. Lastly,
# enable IPv4 forwarding.
VAR=$1
export NNSNAME=${VAR//[[:space:]]}
export OUTDIR=/var/log/newns/$NNSNAME
if [ ! -d $OUTDIR ]; then
/bin/mkdir -p $OUTDIR
fi
export PID=$OUTDIR/pid$NNSNAME
# Find a free subnet
ICOUNTER=0
while true; do
let ICOUNTER=ICOUNTER+1
ip addr show | grep IP_BASE.$ICOUNTER.1 2>&1 1> /dev/null
if [ ! $? == 0 -a $ICOUNTER -lt 255 ]; then
export Nns=$ICOUNTER
break
elif [ ! $? == 0 -a $ICOUNTER -gt 254 ]; then
echo "Too many open network namespaces"
exit 1
fi
done
if [ $Nns == 1 ]; then
echo 1 > /proc/sys/net/ipv4/ip_forward
fi
}
start_nns() {
# Check whether a namespace with the same name already exists.
$IP netns list | /bin/grep $1 2> /dev/null
if [ $? == 0 ]; then
echo "Network namespace $1 already exists,"
echo "please choose another name"
exit 1
fi
# Here we take care of DNS
/bin/mkdir -p /etc/netns/$1
echo "nameserver 8.8.8.8" > /etc/netns/$1/resolv.conf
echo "nameserver 8.8.4.4" >> /etc/netns/$1/resolv.conf
# The following creates the new namespace, the veth interfaces, and
# the bridge between veth1 and a new virtual interface, tap0.
# It also assigns an IP address to the bridge, and brings everything up
$IP netns add $1
$IP link add veth-a$1 type veth peer name veth-b$1
$IP link set veth-a$1 up
$IP tuntap add tap$1 mode tap user root
$IP link set tap$1 up
$IP link add br$1 type bridge
$IP link set tap$1 master br$1
$IP link set veth-a$1 master br$1
$IP addr add $IP_BASE.$Nns.1/24 dev br$1
$IP link set br$1 up
# We need to enable NAT on the default namespace
$IPTABLES -t nat -A POSTROUTING -j MASQUERADE
# This assigns the other end of the tunnel, veth2, to the new
# namespace, gives it an IP address in the same net as the bridge above,
# brings up this and the (essential) lo interface, sets up the
# routing table by assigning the bridge interface in the default namespace
# as the default gateway, creates a new terminal in the new namespace and
# stores its pid for the purpose of tearing it cleanly, later.
$IP link set veth-b$1 netns $1
$IP netns exec $1 $IP addr add $IP_BASE.$Nns.2/24 dev veth-b$1
$IP netns exec $1 $IP link set veth-b$1 up
$IP netns exec $1 $IP link set dev lo up
$IP netns exec $1 $IP route add default via $IP_BASE.$Nns.1
$IP netns exec $1 su -c $XTERM $SUDO_USER &
$IP netns exec $1 echo "$!" > $PID
}
stop_nns() {
# Check that the namespace to be torn down really exists
$IP netns list | /bin/grep $1 2>&1 1> /dev/null
if [ ! $? == 0 ]; then
echo "Network namespace $1 does not exist,"
echo "please choose another name"
exit 1
fi
# This kills the terminal in the separate namespace,
# removes the file and the directory where it is stored, and tears down
# all virtual interfaces (veth1, tap0, the bridge, veth2 is automatically
# torn down when veth1 is), and the NAT rule of iptables.
/bin/kill -TERM $(cat $PID) 2> /dev/null 1> /dev/null
/bin/rm $PID
/bin/rmdir $OUTDIR
$IP link set br$1 down
$IP link del br$1
$IP netns del $1
$IP link set veth-a$1 down
$IP link del veth-a$1
$IP link set tap$1 down
$IP link del tap$1
$IPTABLES -t nat -D POSTROUTING -j MASQUERADE
/bin/rm /etc/netns/$1/resolv.conf
/bin/rmdir /etc/netns/$1
}
case $2 in
start)
prelim "$1"
start_nns $NNSNAME
;;
stop)
prelim "$1"
stop_nns $NNSNAME
;;
reload)
prelim "$1"
stop_nns $NNSNAME
prelim "$1"
start_nns $NNSNAME
;;
*)
# This removes the absolute path from the command name
NAME1=$0
NAMESHORT=${NAME1##*/}
echo "Usage:" $NAMESHORT "name action,"
echo "where name is the name of the network namespace,"
echo "and action is one of start|stop|reload"
;;
esac
Wenn Sie möchten, können Sie mit
sogar einen ganzen Desktop innerhalb des neuen Netzwerk-Namensraums starten sudo startx -- :2
dann können Sie mit Alt danach suchen +Strg +Fn , wobei Fn eines von F1,F2,....-
istIch muss eine Einschränkung hinzufügen:Die DNS-Behandlung innerhalb von Namespaces ist ein bisschen fehlerhaft, seien Sie geduldig.