├── LICENSE ├── README.md ├── env.sh └── netns /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Peter Wu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 19 | OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | netns 2 | ===== 3 | netns is a utility that allows you to quickly setup a network namespace. It was 4 | written for the purpose of capturing network traffic from a single application 5 | (using tcpdump / dumpcap). 6 | 7 | When a network namespace is started, all commands used to set this up are 8 | printed. 9 | 10 | To execute commands inside this network namespace, use the `netns exec` command 11 | which will use `socat` to make the external DBus session visible inside this 12 | application (see `env.sh`). Adjust that file as needed. 13 | 14 | Example 15 | ------- 16 | 17 | Start network namespace: 18 | 19 | peter@al:~$ sudo ~/netns/netns 0 start 20 | # ip netns add netns0 21 | # ip link add veth0 type veth peer name veth1 22 | # ip link set veth1 netns netns0 23 | # ip link set veth0 up 24 | # ip addr add 10.9.0.1/24 dev veth0 25 | # ip netns exec netns0 ip link set veth1 up 26 | # ip netns exec netns0 ip addr add 10.9.0.2/24 dev veth1 27 | # ip netns exec netns0 ip route add default via 10.9.0.1 dev veth1 28 | # iptables -t nat -A POSTROUTING -o veth0 -j MASQUERADE 29 | # iptables -A FORWARD -i veth0 -j ACCEPT 30 | # iptables -A FORWARD -o veth0 -j ACCEPT 31 | # Done! 32 | 33 | peter@al:~$ ip addr show veth0 34 | 14: veth0@if13: mtu 1500 qdisc noqueue state UP group default qlen 1000 35 | link/ether 36:13:bd:c5:2f:e8 brd ff:ff:ff:ff:ff:ff link-netnsid 0 36 | inet 10.9.0.1/24 scope global veth0 37 | valid_lft forever preferred_lft forever 38 | inet6 fe80::3413:bdff:fec5:2fe8/64 scope link 39 | valid_lft forever preferred_lft forever 40 | 41 | **For access to external (LAN or internet) hosts, see below**. 42 | 43 | Enter the network namespace. It uses sudo to change the user back to the 44 | original user: 45 | 46 | peter@al:~$ sudo ~/netns/netns 0 exec 47 | 48 | (netns0)peter@al:~$ whoami 49 | peter 50 | 51 | (netns0)peter@al:~$ ip addr show veth1 52 | 13: veth1@if14: mtu 1500 qdisc noqueue state UP group default qlen 1000 53 | link/ether 26:01:ad:ba:a1:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0 54 | inet 10.9.0.2/24 scope global veth1 55 | valid_lft forever preferred_lft forever 56 | inet6 fe80::2401:adff:feba:a1ee/64 scope link 57 | valid_lft forever preferred_lft forever 58 | 59 | 60 | Run it without arguments to get usage information: 61 | 62 | peter@al:~$ ~/netns/netns 63 | Usage: netns ns-no [dry-]{start|stop} 64 | netns ns-no status 65 | netns ns-no exec [command [command args]] 66 | 67 | The namespace number must be between 0 and 255 (inclusive) 68 | For namespace number 4, the layout will be: 69 | 70 | (host) veth8 (10.9.4.1) 71 | | 72 | [ netns: ns4 ] 73 | | 74 | (namespace) veth9 (10.9.4.2) 75 | 76 | 77 | External access 78 | --------------- 79 | The default setup only facilitates communication between the network namespace 80 | and the main host where the commands are run. To enable access from the network 81 | namespace to external hosts, you must allow IP forwarding and enable NAT for 82 | outgoing packets over the default interface (e.g. eth0, ens3 or wlan0). This has 83 | to be done *only* once (changes are persisted until the next reboot): 84 | 85 | sudo sysctl net.ipv4.ip_forward=1 86 | sudo iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE 87 | 88 | On some systems, the default DNS servers point to a local resolver (`127.0.0.53` 89 | on Ubuntu 18.04). As the network namespace does not have such a local resolver, 90 | you should probably change `/etc/resolv.conf` to something like: 91 | 92 | nameserver 1.1.1.1 93 | 94 | 95 | bash prompt 96 | ----------- 97 | To help you identify whether your shell is in a namespace, you can look at the 98 | output of `ip link`. 99 | 100 | For your convenience, you can also make the prompt display the network namespace 101 | name by putting this in your `~/.bashrc`: 102 | 103 | _ns_name=$(ip netns identify 2>/dev/null) 104 | PS1=${_ns_name:+(${_ns_name})}${PS1} 105 | unset _ns_name 106 | 107 | To use the `ip netns identify` command as a regular user, the permissions of 108 | `/var/run/netns` need to be adjusted. For example: 109 | 110 | sudo setfacl -m u:$USER:rx /var/run/netns 111 | 112 | See also 113 | -------- 114 | "Namespaces in operation, part 7: Network namespaces [LWN.net]" 115 | by Jake Edge, January 22, 2014. Retrieved February 14, 2015. 116 | https://lwn.net/Articles/580893/ 117 | -------------------------------------------------------------------------------- /env.sh: -------------------------------------------------------------------------------- 1 | 2 | # Tries to find the D-Bus session bus address, listening on a Unix domain socket 3 | # as needed. 4 | dbus_addr() { 5 | local user home x_display dbus_file abstract_path 6 | user=${SUDO_USER:-$(id -u)} 7 | 8 | # Only start socat if not running as root. 9 | if [[ $user == root ]]; then 10 | return 11 | fi 12 | 13 | # Find dbus session bus path 14 | home=$(getent passwd "$user" | cut -d: -f6) 15 | x_display=${DISPLAY:-:0} 16 | x_display=${x_display#*:} 17 | x_display=${x_display%.*} 18 | dbus_file="$home/.dbus/session-bus/$(cat /etc/machine-id)-${x_display}" 19 | 20 | env_re="^DBUS_SESSION_BUS_ADDRESS=['\"]?unix:abstract=\\K/tmp/dbus-[a-zA-Z0-9]+" 21 | 22 | abstract_path= 23 | if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ] && [ -e "$dbus_file" ]; then 24 | abstract_path=$(grep -Po -m1 "$env_re" "$dbus_file") || : 25 | fi 26 | if [ -z "${abstract_path}" ]; then 27 | abstract_path=$(env | grep -Po -m1 "$env_re") || : 28 | fi 29 | 30 | # Hurrah! Found a Unix domain socket! 31 | if [ -n "${abstract_path}" ]; then 32 | # If the dbus session bus address is found, try to listen on a named 33 | # Unix domain socket (if not already). This ensures that it is visible 34 | # in the net namespace. 35 | if ! [ -e "${abstract_path}" ]; then 36 | sudo -u "$user" \ 37 | socat UNIX-LISTEN:$abstract_path,fork \ 38 | ABSTRACT-CONNECT:$abstract_path >&2 & 39 | fi 40 | export DBUS_SESSION_BUS_ADDRESS=unix:path=$abstract_path 41 | fi 42 | } 43 | 44 | # Only try to find the dbus session address when running outside the netns. 45 | # If inside the netns, the parent could be determined, and then a swap using 46 | # /proc/xxx/ns/net could be done, but that is ugly. 47 | [ -n "$(ip netns identify)" ] || dbus_addr 48 | -------------------------------------------------------------------------------- /netns: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Create a network namespace with two interfaces. 3 | # Copyright (C) 2015 Peter Wu 4 | # 5 | # Helpful article: 6 | # "Namespaces in operation, part 7: Network namespaces [LWN.net]" 7 | # by Jake Edge, January 22, 2014. Retrieved February 14, 2015. 8 | # https://lwn.net/Articles/580893/ 9 | 10 | print_usage() { 11 | cat <