如何configuration允许UDP广播的Linuxnetworking命名空间

我试图在Linux中使用ip netns系列命令来创build一个networking命名空间,我可以运行一个使用UDP广播的程序。 我不需要访问Internet,也不需要访问根名称空间上的任何接口(但是,如果这是实现工作的必要条件,那么这是绝对可以接受的)。

这里是一个Ruby中的示例服务器和客户端(用Ruby 1.9.3进行testing,但我希望它可以在其他版本中使用):

 #! /usr/bin/env ruby require 'socket' PORT = 5000 case ARGV[0] when 'server' soc = UDPSocket.open begin soc.bind('', PORT) puts "SERVER #{Process.pid} listening on #{PORT}" msg = soc.recv(1) puts "SERVER got msg: #{msg}" ensure soc.close end when 'client' soc = UDPSocket.open begin soc.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true) puts "CLIENT sending message" soc.send('m', 0, '<broadcast>', PORT) ensure soc.close end else abort "usage: #{$0} {server | client}" end 

它创build一个服务器或客户端。 服务器侦听0.0.0.0接口( soc.bind('', ...) )。 客户端发送一个消息到广播地址( soc.send(..., ..., '<broadcast>', ...) )。

在根名称空间中运行时,它似乎正常工作:

 $ ./udp-broadcast.rb server & sleep 0.5 && sudo netstat --listen --udp -p | grep 5000 && ./udp-broadcast.rb client SERVER 22981 listening on 5000 udp 0 0 *:5000 *:* 22981/ruby CLIENT sending message SERVER got msg: m 

这是一个脚本,我尝试创build一个新的networking命名空间并运行相同的命令:

 #! set -e NS=udp-broadcast-test nsexec="ip netns exec $NS" ip netns add $NS trap "ip netns delete $NS" EXIT $nsexec ip link set lo up # Can loopback have a broadcast address? # $nsexec ip link set lo broadcast 255.255.255.255 # RTNETLINK answers: Invalid argument # $nsexec ip addr add broadcast 255.255.255.255 dev lo # RTNETLINK answers: Invalid argument $nsexec ip link add veth0 type veth peer name veth1 $nsexec ifconfig veth0 192.168.99.1/24 up $nsexec ip link $nsexec ip route $nsexec ifconfig timeout 2s $nsexec ./udp-broadcast.rb server & sleep 0.2 $nsexec netstat -n --udp --listen -p timeout 2s $nsexec ./udp-broadcast.rb client wait 

运行时,会产生以下输出:

 $ sudo ./netns.sh 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: veth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether e2:a1:c4:14:c4:5e brd ff:ff:ff:ff:ff:ff 3: veth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether a6:2f:84:9f:08:36 brd ff:ff:ff:ff:ff:ff 192.168.99.0/24 dev veth0 proto kernel scope link src 192.168.99.1 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) veth0 Link encap:Ethernet HWaddr a6:2f:84:9f:08:36 inet addr:192.168.99.1 Bcast:192.168.99.255 Mask:255.255.255.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) SERVER 23320 listening on 5000 Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name udp 0 0 0.0.0.0:5000 0.0.0.0:* 23320/ruby CLIENT sending message ./udp-broadcast.rb:23:in `send': Network is unreachable - sendto(2) (Errno::ENETUNREACH) from ./udp-broadcast.rb:23:in `<main>' 

现在,如果我更改服务器正在侦听的地址,并且客户端发送消息到192.168.99.1 ,那么消息就会通过,所以我知道我的veth0至less部分工作。

如何configuration广播消息可以通过的东西? 服务器/客户端代码是从更大的代码库中提取的,不容易改变,所以我唯一可以改变的就是我的networkingconfiguration。

那么,这是不起作用的一些原因。

  1. 你创build一个veth对,然后不能将其中的一面添加到新的networking命名空间。
  2. 其中一个veths双方是不起来的。
  3. 在你的例子中指定广播地址为255.255.255.255会导致路由表查找,并且数据包将被发送到默认路由。
  4. 因此,您不要使用SO_BINDTODEVICE来指定您实际想要发送到哪个接口。 请注意,这需要root权限,这在很多情况下并不理想。

此外,您没有设置子名称空间和父名称空间之间的任何路由关系,所以它甚至不能直接ping主机。

一般来说,除了提供基本networking服务之外,将通用广播地址用于任何事情都不是一个好的做法。 你应该使用你所瞄准的子网的广播地址。

我得到了你提到的所有工作,为networking命名空间做准备。

 # ip netns add TEST # ip link add veth0 type veth peer name veth1 # ip link set dev veth1 netns TEST # ip link set dev veth0 up # ip netns exec TEST ip link set dev veth1 up # ip netns exec TEST ip addr add 10.10.10.10/32 dev veth1 # ip route add 10.10.10.10/32 dev veth0 # ip netns exec TEST ip route add 192.168.1.3/32 dev veth1 # ping -c1 10.10.10.10 PING 10.10.10.10 (10.10.10.10) 56(84) bytes of data. 64 bytes from 10.10.10.10: icmp_seq=1 ttl=64 time=0.202 ms --- 10.10.10.10 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.202/0.202/0.202/0.000 ms 

这是使用的脚本。 注意SO_BINDTODEVICE调用..

 #!/usr/bin/python import socket as sock import sys, time, os if __name__ == "__main__": if sys.argv[1] == "server": s = sock.socket(sock.AF_INET, sock.SOCK_DGRAM) s.bind(('0.0.0.0', 50000)) data = s.recvfrom(50) print "Got {0}".format(data) elif sys.argv[1] == "client": s = sock.socket(sock.AF_INET, sock.SOCK_DGRAM) s.setsockopt(sock.SOL_SOCKET, sock.SO_BROADCAST, 1) s.setsockopt(sock.SOL_SOCKET, sock.SO_BINDTODEVICE, "veth0") s.connect(('255.255.255.255', 50000)) s.send("hello world\n") 

然后结果..

 # ip netns exec TEST python test.py server & [1] 24961 # python test.py client Got ('hello world\n', ('192.168.1.3', 41971)) 

这个特定的问题是通过添加一个默认路由veth0veth0

 $nsexec ip route add default via 192.168.99.1 dev veth0 

在使veth0向上的行之后立即添加该行,脚本成功运行。