Estou tentando usar a família de comandos ip netns
no Linux para criar um namespace de rede no qual eu possa executar um programa que use a difusão UDP. Eu não preciso de acesso à Internet, ou qualquer interface no namespace raiz (mas se isso é necessário para fazer as coisas funcionarem, é definitivamente aceitável).
Aqui está um exemplo de servidor e cliente em Ruby (testado com o Ruby 1.9.3, mas espero que funcione em outras versões):
#! /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
Cria um servidor ou cliente. O servidor atende na interface 0.0.0.0
( soc.bind('', ...)
). O cliente envia uma mensagem para o endereço de broadcast ( soc.send(..., ..., '<broadcast>', ...)
).
Quando executado dentro do namespace raiz, parece funcionar corretamente:
$ ./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
Aqui está um script em que eu tento criar um novo namespace de rede e executar os mesmos comandos:
#!
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
Quando executado, produz a seguinte saída:
$ 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>'
Agora, se eu alterar o endereço no qual o servidor está escutando e para o qual o cliente envia uma mensagem, para 192.168.99.1
, a mensagem será transmitida, por isso sei que meu veth0
, pelo menos, funciona parcialmente. / p>
Como posso configurar coisas para que a mensagem transmitida seja transmitida? O código servidor / cliente é extraído de uma base de código maior e não é facilmente alterado, portanto, a única coisa que posso alterar é a configuração da minha rede.