编辑
在遵循@MariusMatutiae的到简介的链接之后,我通过编写脚本来生成路由表和规则解决了该问题policy routing
。
我试图在运行Minibian的Raspberry Pi上运行两个OpenVPN客户端,并使用bind.so将特定的应用程序(get_iplayer)绑定到其中一个VPN,如此处和此处所述。我最初按照此处的指南进行操作,按照此处的指示进行安装iproute
,下载和编译bind.so
。
我正在使用由专用Internet访问提供的配置文件的VPN。
一个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
导致没有连接,并且UK VPN的日志中也没有任何内容。
停止Switzerland 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
因此,据我打开或关闭不同VPN时的路由判断,ip地址没有任何变化,也没有发生任何奇怪的事情。
我不知道为什么bind.so
似乎没有效果。没有输出到终端以显示其是否成功,并且我不确定在哪里寻找日志(如果它正在输出任何内容)(终端中的输出用于命令,即get_iplayer)。
显然,我可以运行cron作业/脚本来打开和关闭VPN,以允许我成功/通过UK VPN运行get_iplayer,但是我宁愿保持两个VPN都打开,让我所有的流量都通过tun0
接口,并且仅tun1
用于需要时使用get_player bind.so
。
任何人都可以提供帮助吗?如果我们不能解决此问题,那么为编写特定的路由表或get_iplayer流程规则提供一些帮助将非常有用。
谢谢。
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路由?答案是:它不能真正路由,您的PC无法连接。
出路:
policy or source routing
,您可以在这里找到它的简要介绍。这很棘手,不是因为策略路由本身(很困难),而是因为您必须自己设置OpenVPN的两个实例之一的路由,以确保将路由规则添加到另一个路由中桌子。但这是可以做到的,因为OpenVPN提供了一条语句,--route-nopull
与--client或--pull一起使用时,接受服务器EXCEPT推送的用于路由的选项。
这使您可以根据需要设置路由。
编辑
由于您是通过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
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句