I'm trying to use the ip netns
family of commands in Linux to create a network namespace in which I can run a program that uses UDP broadcast. I do not need access to the Internet, or any interface on the root namespace (but if that's what's necessary to get things working, it's definitely acceptable).
Here's an example server and client in Ruby (tested with Ruby 1.9.3, but I expect it will work in other versions):
#! /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
It creates either a server or client. The server listens on the 0.0.0.0
interface (soc.bind('', ...)
). The client sends a message to the broadcast address (soc.send(..., ..., '<broadcast>', ...)
).
When run within the root namespace, it seems to work correctly:
$ ./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
Here is a script where I attempt to create a new network namespace and run the same commands:
#!
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
When run, it produces the following output:
$ 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>'
Now, if I change the address that the server is listening on, and that the client sends a message to, to 192.168.99.1
, then the message gets through, so I know my veth0
at least partially works.
How can I configure things such that the broadcast message gets through? The server/client code is extracted from a larger codebase and not easily changed, so the only thing I can change is my network configuration.