Skip to content

Instantly share code, notes, and snippets.

@dpino dpino/ns-inet.sh
Last active Jan 23, 2020

Embed
What would you like to do?
Setup a network namespace with Internet access
#!/usr/bin/env bash
# set -x
# Returns all available interfaces, except "lo" and "veth*".
available_interfaces()
{
local ifaces=(`ip li sh | cut -d " " -f 2`)
local ret=()
for each in ${ifaces[@]}; do
each=${each::-1}
if [[ ${each} != "lo" && ${each} != veth* ]]; then
ret+=( "$each" )
fi
done
echo ${ret[@]}
}
IFACE="$1"
if [[ -z "$IFACE" ]]; then
ifaces=$(available_interfaces)
if [[ ${#ifaces[@]} -gt 0 ]]; then
IFACE=${ifaces[0]}
echo "Using interface $IFACE"
else
echo "Usage: ./ns-inet <IFACE>"
exit 1
fi
fi
NS="ns1"
VETH="veth1"
VPEER="vpeer1"
VETH_ADDR="10.200.1.1"
VPEER_ADDR="10.200.1.2"
if [[ $EUID -ne 0 ]]; then
echo "You must be root to run this script"
exit 1
fi
trap cleanup EXIT
cleanup()
{
ip li delete ${VETH} 2>/dev/null
}
# Remove namespace if it exists.
ip netns del $NS &>/dev/null
# Create namespace
ip netns add $NS
# Create veth link.
ip link add ${VETH} type veth peer name ${VPEER}
# Add peer-1 to NS.
ip link set ${VPEER} netns $NS
# Setup IP address of ${VETH}.
ip addr add ${VETH_ADDR}/24 dev ${VETH}
ip link set ${VETH} up
# Setup IP ${VPEER}.
ip netns exec $NS ip addr add ${VPEER_ADDR}/24 dev ${VPEER}
ip netns exec $NS ip link set ${VPEER} up
ip netns exec $NS ip link set lo up
ip netns exec $NS ip route add default via ${VETH_ADDR}
# Enable IP-forwarding.
echo 1 > /proc/sys/net/ipv4/ip_forward
# Flush forward rules.
iptables -P FORWARD DROP
iptables -F FORWARD
# Flush nat rules.
iptables -t nat -F
# Enable masquerading of 10.200.1.0.
iptables -t nat -A POSTROUTING -s ${VPEER_ADDR}/24 -o ${IFACE} -j MASQUERADE
iptables -A FORWARD -i ${IFACE} -o ${VETH} -j ACCEPT
iptables -A FORWARD -o ${IFACE} -i ${VETH} -j ACCEPT
# Get into namespace
ip netns exec ${NS} /bin/bash --rcfile <(echo "PS1=\"${NS}> \"")
@purpletech77

This comment has been minimized.

Copy link

purpletech77 commented Nov 9, 2016

Hi,
Iam able to ping the host IP with your script from ns1, but Iam not able to ping outside of the host - Any idea ?

Thanks .

@andrew160

This comment has been minimized.

Copy link

andrew160 commented Nov 25, 2016

@purpletech77 Make sure you got the interface name right. For me it was enp0s3, and not eth0. Now it works perfectly 😄

@markododa

This comment has been minimized.

Copy link

markododa commented Feb 3, 2017

if the system uses a local dns server (like dnsmasqd on ubuntu ), a resolv.conf needs to be setup for the namespace, for example
mkdir -p /etc/netns/ns1/
echo 'nameserver 8.8.8.8' > /etc/netns/ns1/resolv.conf

@EJohnF

This comment has been minimized.

Copy link

EJohnF commented Feb 15, 2017

It works fine for me if change row 49:
iptables -t nat -A POSTROUTING -s ${VPEER_ADDR}/24 -o eth0 -j MASQUERADE
to
iptables -t nat -A POSTROUTING -s ${VETH_ADDR}/24 -o eth0 -j MASQUERADE

And it's logically true. In this row you set up the iptable routing. And try to connect eth0 with virtual interface.
But, VPEER_ADDR - locate in the ns1 network namespace while VETH_ADDR in global(default).

Am I right that it's a mistake in that row?

@aneeshdurg

This comment has been minimized.

Copy link

aneeshdurg commented Sep 12, 2018

I don't think that row makes a difference, it's only looking at the prefix, right?

@mcgovern612

This comment has been minimized.

Copy link

mcgovern612 commented Jun 26, 2019

Any ideas why I would be able to ping from the namespace, but not wget or curl?

@dpino

This comment has been minimized.

Copy link
Owner Author

dpino commented Jun 27, 2019

Hi, sorry for not replying comments before. This is the first time I noticed there were actually comments here.

@mcgovern612 Are you pinging to an IPv4 address or to a host name? Maybe that's the issue and what's not actually working is DNS resolution (I generally ping to an IPv4 address and wget or curl an URL resource). For name host resolution check the comment by @markoda (https://gist.github.com/dpino/6c0dca1742093346461e11aa8f608a99#gistcomment-1987705) or add an external nameserver to your /etc/resolv.conf.

@dpino

This comment has been minimized.

Copy link
Owner Author

dpino commented Jun 27, 2019

@EJohnF About line 49, I actually tried both VPEER_ADDR and VETH_ADDR and it works in both cases. That said, I think it's more correct to apply source natting in the host interface since the host interface should be reachable from the network namespace.

@dpino

This comment has been minimized.

Copy link
Owner Author

dpino commented Jun 27, 2019

@andrew160 nice catch, the "eth0" string should be another variable in the script.

@mcgovern612

This comment has been minimized.

Copy link

mcgovern612 commented Jun 27, 2019

@dpino DNS is working as ping can resolve hostnames, and in wget calls I can see resolution but it just doesn't connect.

I must say though, thank you for the awesome script and blog description. It was very useful for someone who has never used network namespaces.

@Lu-Yi-Hsun

This comment has been minimized.

Copy link

Lu-Yi-Hsun commented Nov 30, 2019

@dpino

I can ping 8.8.8.8

But can not ping www.google.com

How to fix ?
Have been set nameserver

@dpino

This comment has been minimized.

Copy link
Owner Author

dpino commented Dec 1, 2019

@Lu-Yi-Hsun I have modified the script to fix the "eth0" issue pointed out by other users before, as well as introducing other improvements like select a default interface (if only one is available) and remove veth interfaces on exit.

I run this new version of the script in my laptop and this is what I got when pinging 8.8.8.8 and www.google.com:

$ sudo ./ns-inet.sh 
Using interface wlp59s0
ns1> ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=53 time=18.1 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=53 time=17.7 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=53 time=17.9 ms
^C
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 17.663/17.873/18.089/0.173 ms
ns1> ping www.google.com
PING www.google.com (216.58.206.228) 56(84) bytes of data.
64 bytes from par10s34-in-f4.1e100.net (216.58.206.228): icmp_seq=1 ttl=53 time=17.6 ms
64 bytes from par10s34-in-f4.1e100.net (216.58.206.228): icmp_seq=2 ttl=53 time=17.5 ms
64 bytes from par10s34-in-f4.1e100.net (216.58.206.228): icmp_seq=3 ttl=53 time=17.0 ms
^C
--- www.google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 17.027/17.370/17.602/0.247 ms
ns1> 

So, I don't know what could be the reason why you can ping 8.8.8.8 but not www.google.com. It seems likely is due to a configuration problem in your settings or environment. Can you resolve www.google.com out of a networking namespace?

@Lu-Yi-Hsun

This comment has been minimized.

Copy link

Lu-Yi-Hsun commented Dec 1, 2019

@dpino

thank you!
I find the problem.

ns1 sent ping www.google.com
VPEER ----DNS(packet)------>VETH
VPEER<---------ICMP(Destination Unreachable, Communication Administratively Prohibited)--------VETH
Firewall block the packet sent from VETH to wlpXXs0

so this can fix my problem

sudo systemctl stop firewalld
@tokolar

This comment has been minimized.

Copy link

tokolar commented Dec 28, 2019

@dpino

Is it supposed to work with firefox as well? Hoped so but not working

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.