我有两个应用程序使用相同的端口进行网络通信 (34964)。我可以控制(源代码)第一个应用程序,它使用 192.168.0.4:34964。尽管另一个应用程序尝试使用/“声明”所有 IP 地址 (0.0.0.0:34964),但我无法控制这个地址。每个应用程序都单独运行,但是当我尝试使它们同时运行时,我收到错误:无法绑定地址。
问题
有什么办法可以防止第二个应用程序使用/声明所有 IP 地址 (0.0.0.0) 并改为使用 192.168.0.5。要么在启动之前,要么将其封装在网络命名空间中?
我什么也没尝试,我已经没有想法了......
更详细的版本: 两个应用程序在两个独立的 Profinet 网络上进行通信。第一个应用程序充当 Profinet 设备并与西门子 Profinet 控制器通信,我可以访问该应用程序的源代码。第二个应用程序应充当与 Profinet 西门子设备通信的 Profinet 控制器,我目前正在使用 Codesys 来实现此目的,并且无权更改源代码。
答案1
你有几个选择。
LD_预加载
您可以使用LD_PRELOAD
库来拦截bind()
系统调用以强制绑定到特定地址。其中一个例子是这,你可以这样编译:
gcc -nostartfiles -fpic -shared bind.c -o bind.so -ldl -D_GNU_SOURCE
并像这样使用:
BIND_ADDR=127.0.0.1 LD_PRELOAD=./bind.so /path/to/myprogram
使用 Docker 的网络命名空间
您还可以选择在其自己的网络命名空间内运行您的程序。这最简单的实现此目的的方法是为您的应用程序构建 Docker 映像,然后在 Docker 下运行它,并使用 Docker 的端口映射功能在您选择的主机 IP 上公开服务。
这里有龙
我强烈推荐上述解决方案之一。我只包含以下内容,因为您询问了网络名称空间。
带 macvlan 的网络命名空间
如果您想在不使用 Docker 的情况下完成此操作,也是可以的,但需要做更多的工作。首先,创建一个新的网络命名空间:
# ip netns add myns
然后创建一个macvlan
与主机接口之一关联的接口并将其放入命名空间中:
# ip link add myiface link eth0 type macvlan mode bridge
# ip link set myiface netns myns
并为其分配本地网络上的地址:
# ip netns exec myns \
ip addr add 192.168.0.4/24 dev myiface
# ip netns exec myns \
ip link set myiface up
并在命名空间内创建适当的路由规则(用您的实际网关地址替换192.168.0.1
):
# ip netns exec myns \
ip route add default via 192.168.0.1
现在,在网络命名空间内运行您的程序:
# ip netns exec myns \
/path/to/myprogram
现在您的程序正在运行并且将仅绑定到192.168.0.4
,因为这是命名空间内唯一可见的地址。但!请注意接口的限制mavclan
:虽然网络上的其他主机能够连接到该服务,但您将无法从运行该服务的主机连接到该地址(除非您macvlan
在该主机上创建另一个接口)并通过该接口路由连接192.168.0.4
)。
带 veth 接口的网络命名空间
macvlan
您可以创建一对接口,而不是使用接口veth
,该对的一端位于网络命名空间内,另一端位于您的主机上。您将使用 ip 伪装将数据包从命名空间传递到本地网络。
创建网络命名空间:
# ip netns add myns
创建接口对:
# ip link add myiface-in type veth peer name myiface-out
将这一对的一端分配给您的网络命名空间:
# ip link setns myiface-in myns
在该对的每一端配置一个地址并打开链接:
# ip addr add 192.168.99.1/24 dev myiface-out
# ip link set myiface-out up
# ip netns exec myns ip addr add 192.168.99.2/24 dev myiface-in
# ip netns exec myns ip link set myiface-in up
在您的主机上配置 ip 伪装。这会将传入的数据包重定向192.168.0.4
到您的命名空间:
# iptables -t nat -A PREROUTING -d 192.168.0.4 -p tcp --dport 34964 -j DNAT --to-destination 192.168.99.2
# iptables -t nat -A OUTPUT -d 192.168.0.4 -p tcp --dport 34964 -j DNAT --to-destination 192.168.99.2
这将伪装出站数据包:
# iptables -t nat -A POSTROUTING -s 192.168.99.2 -j MASQUERADE
您需要确保您的主机上启用了 ip 转发 ( sysctl -w net.ipv4.ip_forward=1
) 并且您的 iptablesFORWARD
链允许转发连接 ( iptables -A FORWARD -d 192.168.99.2 -j ACCEPT
,请记住,规则是按顺序处理的,因此拒绝规则前这一项将优先)。