สิ่งที่คุณจะขอไม่ได้อยู่ นี่คือเหตุผลที่คุณไม่พึงพอใจกับคำตอบที่คุณพบ (บางคำตอบอาจเป็นของฉัน): ทุกคำแนะนำมีวิธีแก้ไขไม่ใช่วิธีแก้ปัญหาของแท้ไม่ว่าจะง่ายหรือซับซ้อน
ให้ฉันอธิบาย การกำหนดเส้นทางในระบบปฏิบัติการทั้งหมดนั้นพิจารณาจากที่อยู่ปลายทาง: คุณอาจมีหลายเส้นทาง แต่ตัวเลือกระหว่างพวกเขาไม่ได้ขึ้นอยู่กับแอปพลิเคชันที่เรียกใช้การเชื่อมต่อ แต่ขึ้นอยู่กับที่อยู่ปลายทาง หยุดเต็ม
ผมขอยกตัวอย่างที่ไม่สำคัญ เมื่อไคลเอนต์ VPN ได้สร้างการเชื่อมต่อไปยังเซิร์ฟเวอร์ของตนแล้วก็ยังสามารถกำหนดเส้นทางการเชื่อมต่อไปยังเว็บไซต์ที่ระบุได้เช่น example.org นอก VPN แต่แอปพลิเคชันทั้งหมดที่พยายามเข้าถึงที่อยู่พิเศษนั้นจะถูกกำหนดเส้นทางภายนอก VPN: คุณไม่สามารถมีบางแอปพลิเคชันที่จะไปที่ example.org ผ่าน VPN ในขณะที่แอปอื่น ๆ ส่งผ่านภายนอก VPN
สถานการณ์ยิ่งสมบูรณ์ยิ่งขึ้นด้วยเคอร์เนล Linux ซึ่งอนุญาตให้เราต์ซอร์ส: หมายความว่าคุณสามารถมีตารางการเราต์ได้สองตารางขึ้นไปและตัวเลือกระหว่างมันจะขึ้นอยู่กับที่อยู่ต้นทางไม่ใช่ที่อยู่ปลายทาง
ตัวอย่างที่ไม่สำคัญ: พีซีของฉันมีสองบรรทัดภายนอกที่มีสอง IP สาธารณะที่แตกต่างกัน สามารถติดต่อผ่านทางอินเทอร์เฟซทั้งสองและเป็นสิ่งสำคัญที่การตอบกลับของฉันไปยังการเชื่อมต่อที่กำหนดให้ผ่านอินเทอร์เฟซเดียวกับที่การเชื่อมต่อมาถึง: มิฉะนั้นพวกเขาจะถูกยกเลิก นี่คือการกำหนดเส้นทางต้นทาง
เป็นธรรมพอแล้วการเชื่อมต่อที่เราเริ่มต้นล่ะ แอพบางตัวอนุญาตให้คุณระบุที่อยู่ผูกเช่นไคลเอนต์ openssh :
-b bind_address
ใช้ bind_address บนเครื่องโลคัลเป็นที่อยู่ต้นทางของการเชื่อมต่อ มีประโยชน์เฉพาะกับระบบที่มีที่อยู่มากกว่าหนึ่งแห่ง
สำหรับพวกเขาไม่มีปัญหาในการมีหนึ่งอินสแตนซ์ที่จะผ่าน VPN (เช่นตารางเส้นทาง 1) ในขณะที่อินสแตนซ์อื่นจะออกนอก VPN (พูดว่าเส้นทางตาราง 2) แต่แอปอื่น ๆ เช่น Firefox ไม่เพียง แต่จะยากที่จะผูกกับที่อยู่ IP ของแหล่งที่มา (แต่ดูที่นี่เพื่อหาวิธีแก้ปัญหาที่ชาญฉลาดมาก) แต่ยังมีค่าเฉลี่ยและน่ารังเกียจที่พวกเขาจะไม่อนุญาตให้คุณมีสำเนาสองชุด ทำงานพร้อมกันแต่ละรายการเชื่อมโยงกับที่อยู่แหล่งข้อมูลที่แตกต่างกัน กล่าวอีกนัยหนึ่งด้วยเคล็ดลับที่อ้างถึงข้างต้นคุณสามารถบังคับหนึ่งอินสแตนซ์เพื่อผูกกับที่อยู่ต้นทางที่คุณเลือกได้จากนั้นคุณจะไม่สามารถผูกรุ่นอื่นกับที่อยู่ต้นทางอื่นได้
สิ่งนี้อธิบายว่าทำไมเราจึงใช้วิธีการแก้ไขปัญหา: ทั้งหมดนั้นใช้แนวคิดเดียวกันกับที่ทำงานกับเครือข่ายสแต็กแยกต่างหากจากส่วนที่เหลือของพีซี ดังนั้นคุณสามารถลดลำดับความซับซ้อนโดยประมาณ, VMs, นักเทียบท่า, คอนเทนเนอร์, เนมสเปซ ในแต่ละตารางคุณจะมีตารางเส้นทางหนึ่งตารางขึ้นไป แต่คุณสามารถมีหลายอินสแตนซ์ของแต่ละตัว (VM / dockers / container / namespaces) และคุณยังสามารถเพิ่มพวกมันได้อย่างอิสระแต่ละตัวทำงานแอพของตัวเองเช่น Firefox จากคนอื่น ๆ
บางทีคุณยังสนใจวิธีการแก้ปัญหาข้อใดข้อหนึ่งใช่หรือไม่
แก้ไข:
การหลีกเลี่ยงปัญหาที่ง่ายที่สุดคือเนมสเปซเครือข่าย สคริปต์ด้านล่างจัดการด้านที่จำเป็นทั้งหมดของ NNS: ใส่ไว้ในไฟล์ (คุณเลือกชื่อของคุณโดยทั่วไปฉันใช้newns
แต่คุณทำสิ่งที่คุณต้องการ) ใน/usr/local/bin
แล้วchmod 755 FILE_NAME
คุณสามารถใช้มันได้ดังนี้:
newns NAMESPACE_NAME start
newns NAMESPACE_NAME stop
มันจะเปิดxterm
ให้คุณ (นั่นเป็นเพราะฉันชอบ xterm ให้ทำงาน แต่คุณสามารถเปลี่ยนได้ถ้าคุณต้องการใช้อย่างอื่น) ซึ่งเป็นของเนมสเปซใหม่ จากภายใน xterm คุณสามารถเริ่ม vpn ของคุณแล้วเริ่มเกม คุณสามารถตรวจสอบได้อย่างง่ายดายว่าคุณใช้ VPN ผ่านคำสั่งต่อไปนี้:
wget 216.146.38.70:80 -O - -o /dev/null | cut -d" " -f6 | sed 's/<\/body><\/html>//'
ซึ่งจะให้ผลตอบแทน IP สาธารณะแก่คุณ หลังจากตั้งค่า VPN ใน xterm คุณอาจตรวจสอบว่า IP สาธารณะของคุณแตกต่างในหน้าต่างอื่นของคุณหรือไม่ คุณสามารถเปิดได้ถึง 254 xterms โดยมี NNSes 254 ที่แตกต่างกันและการเชื่อมต่อที่แตกต่างกัน
#!/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 "$@"
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
หากคุณต้องการคุณสามารถเริ่มเดสก์ท็อปทั้งหมดภายในเนมสเปซเครือข่ายใหม่ได้
sudo startx -- :2
จากนั้นคุณสามารถค้นหาโดยใช้Alt+ Ctrl+ Fnโดยที่ Fn เป็นหนึ่งใน F1, F2, ....-
ฉันต้องเพิ่มหนึ่ง caveat: การจัดการ DNS ภายในเนมสเปซนั้นค่อนข้างลำบากใจเย็น ๆ