Tim*_*mos 5 networking namespace
首先,我阅读了这篇关于网络命名空间的精彩文章,因此我或多或少知道网络命名空间的作用以及如何配置它们。
我面临的实际问题是:
(一直在尝试运行 CS 1.6、CSGO 或 TF2 服务器的人可能会在这里识别出“+ip <ip address>”问题)
通过拥有多个 IP,我无法解决问题,因为我无法告诉游戏服务器绑定到特定的 IP 地址 - 软件总是采用主 IP,因此这无法正常工作。(端口冲突,或者软件占用了27020+端口,导致服务器在局域网浏览器中不可见)
我想通过使用网络命名空间来解决它 - 每个游戏 1 个网络命名空间:
因为我将在命名空间中运行游戏软件,所以该软件只会看到 1 个 IP,并会自动获取该 IP。(嗯,这就是我的想法!)。
所以总共有 4 个网络命名空间(“default”、“csgo”、“tf2”和“cs16”)。配置如下:
- eth0 / 192.168.0.160 ("default" ns, internet access)
- veth0:0 / 192.168.0.161 ("default" ns) <======> veth0:1 / 192.168.0.171 ("csgo" NS)
- veth1:0 / 192.168.0.162 ("default" ns) <======> veth1:1 / 192.168.0.172 ("tf2" NS)
- veth2:0 / 192.168.0.163 ("default" ns) <======> veth2:1 / 192.168.0.173 ("cs16" NS)
Run Code Online (Sandbox Code Playgroud)
现在的问题是,这能而且会奏效吗?如果我在命名空间“csgo”中运行CSGO服务器软件,那么局域网服务器的公共IP是否为192.168.0.171?还是会是 192.168.0.160?或者也许是 192.168.0.161?如上所述,我真的需要为每个游戏分配一个单独的 IP 地址,以使所有 9 个服务器都出现在 LAN 浏览器中。
如果不是,这个问题真的可以通过使用网络命名空间来解决吗?
将应用程序绑定到特定的 IP 地址是一个众所周知的难题:并非所有应用程序都像ssh 一样,它允许您通过-b选项指定要绑定到的 IP 地址。例如,众所周知,Firefox 和 Chrome 不受此影响。
幸运的是,有一个解决方案:这家伙修改了bind.so系统库,允许在命令行中指定绑定地址,如下:
$ BIND_ADDR="192.0.2.100" LD_PRELOAD=/usr/lib/bind.so firefox
Run Code Online (Sandbox Code Playgroud)
通过预加载绑定共享对象,您可以绕过选择接口以不同方式绑定的系统版本。
与同时运行多个网络空间相比,这在系统资源上更容易、更轻量。
上面的网页给出了如何编译模块和两个指令此链接预编译的32位和64位版本。
(仅供参考:我知道您不感兴趣,但可以轻松修改代码以强制绑定到特定端口)。
编辑:
我完全忘记了游戏很可能会使用 UDP,而上面的技巧仅适用于 TCP 连接。我将我的答案留在原处,希望能帮助有此类 TCP 问题的人,但作为对 Timmos 的回答,这完全没用。
为了弥补我的错误,我向您传递了一个(非常简单!)我编写的脚本,该脚本设置了(可能是多个)网络命名空间之一。
#!/bin/bash
#
# This script will setup a network namespace with a macvlan
# which obtains its IP address via dhclient from the LAN on which the host is
# placed
#
set -x
# It will open an xterm window in the new network namespace; if anything
# else is required, change the statement below.
export XTERM1=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.
###############################################################################
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
IERROR3=0
export IP=$($WHEREIS -b ip | /usr/bin/awk '{print $2}')
export IPTABLES=$($WHEREIS -b iptables | /usr/bin/awk '{print $2}')
export XTERM=$($WHEREIS -b $XTERM1 | /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 [ "x$XTERM" = "x" ] ; then
echo "please install the xterm package"
IERROR3=1
fi
if [[ $IERROR1 == 0 && $IERROR2 == 0 && $IERROR3 == 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
echo 1 > /proc/sys/net/ipv4/ip_forward
}
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, and the macvlan interface
$IP netns add $1
$IP link add link eth0 mac$1 type macvlan mode bridge
# This assigns the macvlan interface, mac$1, to the new
# namespace, asks for an IP address via a call to dhclient,
# brings up this and the (essential) lo interface,
# creates a new terminal in the new namespace and
# stores its pid for the purpose of tearing it cleanly, later.
$IP link set mac$1 netns $1
$IP netns exec $1 /sbin/dhclient -v mac$1 1> /dev/null 2>&1
$IP netns exec $1 $IP link set dev lo up
$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 and
# removes the file and the directory where it is stored.
/bin/kill -TERM $(cat $PID) 2> /dev/null 1> /dev/null
/bin/rm $PID
/bin/rmdir $OUTDIR
$IP netns del $1
# This deletes the file and direcotory connected with the DNSes.
/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
Run Code Online (Sandbox Code Playgroud)
它假设您的主接口称为eth0(如果您的主接口被称为不同,请相应地更改对它的单个引用),并使用macvlan接口,这意味着您只能通过以太网连接使用该脚本。此外,它不需要使用网桥。
您可以按如下方式启动/停止单独的网络命名空间(我将脚本称为nns,但您可以随意称呼它):
nns network_namespace_1 start
nns network_namespace_2 stop
Run Code Online (Sandbox Code Playgroud)
您可以在本地 DHCP 服务器允许的范围内拥有尽可能多的不同网络命名空间,因为每个 macvlan 接口都从您的 LAN DHCP 服务器获取 IP 地址。如果已存在同名的网络命名空间,则必须选择不同的名称。
所有网络命名空间都可以相互通信,这要归功于其创建命令中的模式桥接选项。该脚本在新的网络命名空间中打开一个xterm终端(我喜欢xterm,如果您不喜欢,您可以在脚本顶部更改它),以便从 xterm 中启动您的应用程序。
我在脚本中保留了调试选项set -x,这可能会帮助您解决一些初始问题。完成后,只需删除该行。
干杯。