Маршрут тільки певного трафіку через VPN


8

Я подивився на попередніх людей, які запитують подібні запитання, але ще не отримали прямої відповіді, яка буде працювати в моїй даній ситуації, так що тут йде ..

Я працюю на Linux (Fedora 22) і я користуюся послугою VPN, за яку я плачу, якби мені потрібні лише конкретні програми для використання VPN для свого інтернет-трафіку, і я можу використовувати стандартне з'єднання ISP для всього іншого (наприклад, перегляд веб-сторінок, тощо)

Ми зробимо це простим і обмежимо його найпоширенішою програмою, World of Warcraft, яка проходить через WINE.

Тепер, у мене є VPN налаштування через мережевий інтерфейс, так що весь мій трафік через enp10s0 (мої комп'ютери дивним ім'ям для eth0) можна тунелювати через сервіс VPN, однак, мені потрібні тільки конкретні програми (або порти цих програм, щоб бути специфічними), щоб пройти через VPN.

Як налаштувати тунель, і чи має він тільки маршрути порти, необхідні через VPN, при цьому зберігаючи все інше не-маршрутизовані?


Чи можете ви пояснити, як інші відповіді не стосуються цього питання? Що є унікальним у налаштуваннях?
Paul

1
Майже кожен з них має інший спосіб досягнення цього, і жоден з них не робить його зовсім простим. Деякі використовують окремий простір імен для програми, деякі використовують інтерфейс тунелю, деякі роблять це прямо через openvpn в терміналі, але жоден з них, який я знайшов, не дав мені жодного методу розшифрування будь-якого з них.
Josh Raymond

Дивіться мою редакцію
MariusMatutiae

Відповіді:


10

Що ви просите? ні існують. Ось чому ви не задоволені відповідями, які ви знайшли (деякі з них, можливо, є моїми): всі вони запропонували обхідні шляхи , не є справжнім рішенням, або простим, ні складним.

Дозволь пояснити. Маршрутизація у всіх ОС визначається адресою призначення: у вас може бути кілька маршрутів, але вибір між ними не заснований на застосуванні з'єднання, а просто на адресі призначення. Повна зупинка.

Дозвольте мені навести вам нетривіальний приклад. Коли клієнт VPN встановив підключення до свого сервера, все ж можна направити з'єднання на даний сайт, скажімо example.org, поза VPN. Але всі додатки, які намагаються досягти цієї спеціальної адреси, будуть маршрутизовані за межами VPN: ви не можете мати деякі додатки, які перейдуть в example.org через VPN, тоді як інші програми проходять поза VPN.

Ситуація стає багатшою з ядром Linux, що дозволяє маршрутизацію джерел: це означає, що ви можете мати дві або більше таблиць маршрутизації, і вибір між ними здійснюється на основі адреси джерела, а не адреси призначення.

Нетривіальний приклад: мій комп'ютер має дві зовнішні лінії, з двома окремими IP-адресами. Її можна зв'язати через будь-який інтерфейс, і важливо, щоб мої відповіді на дане підключення проходили через той самий інтерфейс, що й підключення через інше: інакше вони будуть відкинуті як нерелевантні, коли вони досягнуть особу, яка ініціювала з'єднання. Це маршрутизація джерела.

Досить справедливо, а як щодо з'єднань, які ми починаємо? Деякі програми дозволяють вказати адресу прив'язки, наприклад клієнт openssh :

-b bind_address

Використовуйте bind_address на локальному комп'ютері як вихідну адресу з'єднання. Корисно лише для систем з більш ніж однією адресою.

Для них немає жодної проблеми в тому, щоб один примірник проходив через VPN (скажімо, таблицю маршрутизації 1), а інший екземпляр пішов за межі VPN (скажімо, таблиця маршрутизації 2). Але інші програми, такі як Firefox, не тільки відомо, важко прив'язати до конкретного джерела IP-адреси (але див тут для дуже розумного обхідного шляху), але також є середні і неприємні в тому, що вони будуть ні дозволяють вам мати дві копії одночасно, кожен з яких пов'язаний з іншою адресою джерела. Іншими словами, в той час як завдяки вищезгаданому трюку ви можете зобов'язати один примірник прив'язати до вихідної адреси за вашим вибором, тоді ви не зможете прив'язати іншу версію до іншої адреси джерела.

Це пояснює, чому ми використовуємо обхідні шляхи: всі вони базуються на тій же ідеї, що вони працюють з окремим мережевим стеком, ніж решта комп'ютера. Таким чином, ви можете мати, у зменшенні приблизного порядку складності, віртуальні машини, докери, контейнери, простори імен. У кожному з них ви матимете одну або більше таблиць маршрутизації, але ви можете мати декілька екземплярів кожного (VM / dockers / containers / namespaces), і ви також можете вільно їх змішувати, кожен з яких має власну програму, подібну до Firefox від інших.

Можливо, ви все ще зацікавлені в одному з обхідних шляхів?

EDIT:

Найпростішою роботою навколо є мережа імен. Сценарій нижче обробляє всі необхідні аспекти 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, з 254 різними NNSes, і різні з'єднання.

#!/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, ....-

Мені потрібно додати одне застереження: обробка DNS всередині просторів імен трохи помилка, будьте терплячими.


І ось я, нарешті, маю дуже просте, але детальне пояснення того, чому те, що я намагаюся досягти, не є ні легким, ні звичайним! Дякую! Прочитавши це, я вважаю, що обхідний шлях буде доречним, оскільки це тільки трафік з певної програми, який я хочу перенаправити, і я завжди хочу, щоб ця програма була спрямована. Приклад: Я хочу, щоб VideoGameA маршрутизувався через VPN, але я не хочу, щоб інші програми проходили через нього. Чи є простий спосіб прив'язати конкретні порти тільки через інтерфейс VPN? Якщо так, то як я правильно налаштувати та підключитися до вказаного інтерфейсу?
Josh Raymond

@JoshRaymond Добре. Для того, щоб вибрати найпростіший спосіб обходу, ви повинні дати повідомлення вашої таблиці маршрутизації з VPN, і повинні сказати мені, що Video GameS використовує UDP-порти на всіх.
MariusMatutiae

Він використовує як TCP, так і UDP-порти 443, 3724 і 1119 Маршрут буде розміщено в наступному commend
Josh Raymond

$ route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 0.0.0.0 0.0.0.0 U 50 0 0 ppp0 0.0.0.0 192.168.1.1 0.0.0.0 UG 100 0 0 enp10s0 1.0.0.1 0.0.0.0 255.255.255.255 UH 0 0 0 ppp0 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 enp10s0 192.168.1.0 0.0.0.0 255.255.255.0 U 100 0 0 enp10s0 199.168.112.120 192.168.1.1 255.255.255.255 UGH 100 0 0 enp10s0
Josh Raymond

Мені цікаво, чому у відповіді @MariusMatutiae створюється кран і міст? Здається, добре працює тільки з використанням пристроїв veth.
Ian Kelling
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.