1

редактировать
Я решил проблему, написав скрипт для генерации таблиц и правил маршрутизации, после перехода по ссылке @ MariusMatutiae на введение в policy routing .


Я пытаюсь запустить два клиента OpenVPN на моем Raspberry Pi с Minibian и привязать конкретное приложение (get_iplayer) к одной из VPN с помощью bind.so, как описано здесь и здесь. Первоначально я следовал за руководство здесь, установка iproute и загрузки и компиляции bind.so , как указано там.

VPN
Я использую файлы конфигурации, предоставленные Private Internet Access.

Один VPN указывает на их сервер в Швейцарии, использует udp, и я установил опцию dev tun0 , так как я хочу, чтобы это был основной туннель, через который проходит весь трафик, за исключением того, который я объявляю явно с помощью bind.so Этот туннель работает нормально, весь трафик проходит через него.

Второй VPN указывает на сервер в Лондоне, Великобритания, использует tcp и имеет параметр dev tun1 установленный для работы в качестве второго туннеля. Этот туннель работает нормально, когда работает сам по себе. Я могу правильно запустить get_iplayer.

Проблема возникает, когда я запускаю оба экземпляра одновременно. Похоже, трафик не проходит через интерфейс tun1 , даже когда я пытаюсь использовать bind.so и подход LD_PRELOAD как объяснено в ссылках выше.

bind.so
Насколько я знаю, я правильно скомпилировал bind.so, скопировал его в /usr/lib и т.д. К сожалению, я однажды все заработал, но понятия не имею, как это произошло.

команды
Я использовал ip route чтобы найти адрес шлюза; Я уверен, что я использую правильный IP-адрес. например:

$ ip route
0.0.0.0/1 via 10.30.1.17 dev tun1 
0.0.0.0/1 via 10.198.1.5 dev tun0 
default via 192.168.1.254 dev eth0 
10.30.1.1 via 10.30.1.17 dev tun1 
10.30.1.17 dev tun1  proto kernel  scope link  src 10.30.1.18 
10.198.1.1 via 10.198.1.5 dev tun0 
10.198.1.5 dev tun0  proto kernel  scope link  src 10.198.1.6 
104.238.169.140 via 192.168.1.254 dev eth0 
128.0.0.0/1 via 10.30.1.17 dev tun1 
128.0.0.0/1 via 10.198.1.5 dev tun0 
179.43.177.66 via 192.168.1.254 dev eth0 
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.84 

Затем работает:

BIND_ADDR="10.30.1.17" LD_PRELOAD=/usr/lib/bind.so get_iplayer --type=tv

не приводит к соединению и ничего в журнале для VPN VPN.

Остановка швейцарского VPN и выполнение той же команды get_iplayer приводит к загрузке соединения и информации. ip route выдает следующее:

$ ip route
0.0.0.0/1 via 10.30.1.17 dev tun1 
default via 192.168.1.254 dev eth0 
10.30.1.1 via 10.30.1.17 dev tun1 
10.30.1.17 dev tun1  proto kernel  scope link  src 10.30.1.18
104.238.169.119 via 192.168.1.254 dev eth0 
128.0.0.0/1 via 10.30.1.17 dev tun1 
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.84

Так что нет никаких изменений в IP-адресе или что-то странное, насколько я могу судить по маршрутизации при открытии или закрытии различных VPN.

Я в растерянности относительно того, почему bind.so похоже, не имеет никакого эффекта. Нет вывода в терминал, чтобы показать, успешен он или нет, и я не уверен, где искать журнал, если он что-то выводит (вывод в терминале для команды, то есть get_iplayer).

Очевидно, что я мог запускать задания / сценарии cron, чтобы открывать и закрывать VPN, чтобы позволить мне успешно запустить get_iplayer / через британскую VPN, но я бы предпочел оставить обе VPN открытыми, весь мой трафик проходил через интерфейс tun0 и использовать только tun1 для get_player, когда мне нужно с bind.so

Кто-нибудь может помочь? Если мы не сможем решить эту проблему, была бы полезна некоторая помощь в написании конкретных таблиц маршрутизации или правил для процесса get_iplayer.

Благодарю.

1 ответ1

0

bind.so не несет ответственности за эту проблему, которая является одной из маршрутизации: в каждой таблице маршрутизации может быть только один шлюз по умолчанию, но каждый экземпляр VPN пытается установить шлюз (и маршрутизацию в целом) как лучше подходит, в результате чего таблицы с такими строками:

  0.0.0.0/1 via 10.30.1.17 dev tun1 
  0.0.0.0/1 via 10.198.1.5 dev tun0 

Какое ядро делать с этим? Должен ли он проходить через tun0 или через tun1? Ответ: на самом деле это не маршрут, ваш компьютер не может подключиться.

Пути выхода:

  1. Установите две таблицы маршрутизации с правилом, указывающим ядру, когда использовать любую из них. Это называется policy or source routing , краткое введение вы найдете здесь. Это сложно, не из-за политики маршрутизации как таковой (что является подпоркой), а потому, что вам придется самостоятельно настраивать маршрутизацию одного из двух экземпляров OpenVPN, чтобы убедиться, что правила маршрутизации добавлены к другой маршрутизации. Таблица. Но это может быть сделано, потому что OpenVPN предоставляет заявление ,

--route-nopull

При использовании с --client или --pull принимать параметры, выдвигаемые сервером, ИСКЛЮЧИТЬ для маршрутов.

что позволяет настроить маршрутизацию в соответствии с вашими потребностями.

  1. Настройте сетевое пространство имен, в котором вы запускаете один экземпляр OpenVPN, и программы, которые его используют. Вы найдете введение в пространство имен сети здесь. Это также требует некоторой работы, но это в основном рутинная работа. Если хотите, следующий скрипт (очень простой!) что я написал работает из коробки.

РЕДАКТИРОВАТЬ

Так как вы работаете с ssh-сессии, мне пришлось немного изменить мой скрипт.

Вы можете начать это с

     newnsssh NameOfNNS start

но вы все равно окажетесь в сетевом пространстве имен по умолчанию, NNS для краткости. Прежде чем получить к нему доступ, лучше всего открыть терминал:

     xterm &

Откроется графический терминал, если вы подключились к RPI с помощью

    ssh -Y me@rpi

и при условии, что переменная среды $DISPLAY установлена в:

  export DISPLAY=localhost:10.0

xterm , войдите в него и введите следующую команду:

   sudo ip netns exec NameOfNNS bash

Новая подсказка находится в новой NNS; Проверять,

    ip netns identify $$

Если ничего не возвращено, вы находитесь в NNS по умолчанию , в противном случае вам будет показано NameOfNNS. Теперь вы можете запустить OpenVPN

      openvpn --config /path/to/config/file &
      su YourName

и вы сделали. Теперь из этого xterm все программы будут маршрутизироваться этим экземпляром OpenVPN, в то время как все программы, запущенные вне этого xterm, будут запускаться за пределами OpenVPN, или через другой экземпляр OpenVPN, если вам выпал другой.

Когда вы закончите, просто закройте xterm и, в сеансе ssh,

    newnsssh NameOfNNS stop

Это все.

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


# 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. 

export 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

 export IP=$($WHEREIS -b ip | /usr/bin/awk '{print $2}')
 export IPTABLES=$($WHEREIS -b iptables | /usr/bin/awk '{print $2}')

 if [ x$IP = x ] ; then
    echo "please install the iproute2 package"
    IERROR1=1
 fi

 if [ x$IPTABLES = x ] ; then
    echo "please install the iptables package"
    IERROR2=1
 fi


 if [[ $IERROR1 == 0 && $IERROR2 == 0 ]] 
    then
    :   
 else
    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. 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


    ICOUNTER=1
    export Nns=$ICOUNTER 
    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 
ln -s /proc/1/ns/net /var/run/netns/default 2> /dev/null
#   $IP netns exec $1 bash & $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. 


rm /var/run/netns/default
$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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .