Skip to content
This repository was archived by the owner on Jun 21, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .etckeeper
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,7 @@ maybe chmod 0755 'network/if-up.d/postfix'
maybe chmod 0755 'network/if-up.d/upstart'
maybe chmod 0755 'network/interfaces.d'
maybe chmod 0644 'network/interfaces.example'
maybe chmod 0755 'network/namespace.sh'
maybe chmod 0755 'newt'
maybe chmod 0644 'newt/palette.original'
maybe chmod 0644 'nova-agent.env'
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,7 @@ src/*

# Sometimes generated by ld when using firejail
ld.so.preload

# Used for server-specific network configuration
# cf network/namespace.sh
default/user_netns
25 changes: 22 additions & 3 deletions network/interfaces.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ iface eth0 inet static
netmask 255.255.255.0
gateway 192.0.2.254


# Assuming that native IPv6 is available:
iface eth0 inet6 static
address 2001:DB8:f00d:b1a::10ca1
Expand All @@ -32,6 +33,24 @@ iface he-ipv6 inet6 v4tunnel
endpoint 203.0.113.226
local 192.0.2.42
ttl 255
# Sad hack
up ip a add dev $IFACE 2001:DB8:f00:b1a::/64
down ip a del dev $IFACE 2001:DB8:f00:b1a::/64


# The bridge interface for user netns
# The network 172.19.0.0/16 is non-routable, per RFC1918
# It is used for providing IPv4 networking to users
# The network 2001:DB8:f00:b1a::/64 is reserved for documentation (RFC3849)
# and stands for the server's globally-reachable IPv6 subnet
auto br-users
iface br-users inet static
address 172.19.42.1
netmask 255.255.255.0
# disable Spanning Tree Protocol
bridge_stp off
# no delay before a port becomes available
bridge_waitport 0
# no forwarding delay
bridge_fd 0

iface br-users inet6 static
address 2001:DB8:f00:b1a::
netmask 64
112 changes: 112 additions & 0 deletions network/namespace.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/bin/sh -e
# WARNING: The environment is under the control of the user, to some extend.
# Read the pam_exec(8) manpage before editing this script.

# root has no network namespace
if [ "$PAM_USER" = root ]; then
exit 0
fi

# System users have no network namespace
# UID ranges defined by the Debian policy manual:
# https://www.debian.org/doc/debian-policy/ch-opersys.html#s9.2.2
UID=$(getent passwd "$PAM_USER" | cut -d: -f3)
if [ "$UID" -lt 1000 ]; then
exit 0
fi
if [ "$UID" -ge 60000 ] && [ "$UID" -lt 65536 ]; then
exit 0
fi

# Check the logger manpage for valid priority levels
log() {
logger --id=$$ --priority auth."$1" "$2"
}

die() {
log crit "$@"
exit 1
}

# Construct the user's IPv6, as {server_prefix}::{uid}
get_user_ipv6() {
HEX_UID=$(echo "obase=16; ${UID}" | bc)
IPV6_SUFFIX=$(echo "$HEX_UID" | rev | fold -w4 | paste -sd: | rev)
echo "${IPV6_PREFIX}::${IPV6_SUFFIX}"
}

# Execute some command in the user's netns
in_ns() {
ip netns exec "user-${PAM_USER}" "$@"
}

# SYNOPSIS: This script constructs and configures a user namespace
# for the user currently logging in.
#
# The namespace contains the following interfaces:
# - lo, the loopback interface
# - veth, a virtual Ethernet interface which is tied to a bridge.
# veth is configured with a dynamic, RFC1918 IPv4 address,
# and with a static IPv6 address.
#
# Moreover, veth's peer is userbr-${PAM_USER},
# and is attached to the br0 bridge
# (configurable as USER_BR in /etc/default/user_netns)

USER_BR="br-users"
if [ -f "/etc/default/user_netns" ]; then
. /etc/default/user_netns
fi

if [ -z "${IPV6_PREFIX}" ]; then
die "No IPv6 prefix defined in configuration"
fi

# If the user's netns exists, nothing to do
if [ -f "/var/run/netns/user-${PAM_USER}" ]; then
log info "User ${PAM_USER} already has a netns"
exit 0
fi


# Prepare the user's netns
trap 'ip netns delete "user-${PAM_USER}"' QUIT

if ! ip netns add "user-${PAM_USER}"; then
die "Failed to create netns for ${PAM_USER}"
fi

if ! in_ns ip link set dev lo up; then
die "Failed to create a loopback interface for ${PAM_USER}"
fi

# TODO: check that deleting the namespace causes the veth pair to be deleted
if ! ip link add "userbr-${PAM_USER}" type veth peer name "userbr-${PAM_USER}-peer"; then
die "Failed to create a veth pair for ${PAM_USER}"
fi

if ! ip link set "userbr-${PAM_USER}-peer" netns "user-${PAM_USER}"; then
ip link delete dev "userbr-${PAM_USER}"
die "Failed to add the veth peer to netns for ${PAM_USER}"
fi

# Renaming the interface should happen before any configuration occurs
if ! in_ns ip link set dev "userbr-${PAM_USER}-peer" name "veth"; then
die "Failed to rename interface for ${PAM_USER}"
fi

if ! ip link set "userbr-${PAM_USER}" master "$USER_BR"; then
die "Failed to add the veth for ${PAM_USER} to the bridge"
fi

if ! in_ns dhclient "veth"; then
die "Failed to configure IPv4 for ${PAM_USER}"
fi

if ! in_ns ip addr add dev "veth" "$(get_user_ip)/64"; then
die "Failed to configure IPv6 for ${PAM_USER}"
fi

# We reached the end without error: no cleanup on exit
trap - QUIT
exit 0
1 change: 1 addition & 0 deletions pam.d/common-session-noninteractive
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ session required pam_env.so
# User restrictions
session required pam_namespace.so unmnt_remnt
session required pam_limits.so
session required pam_exec.so type=session /etc/network/namespace.sh

# Passwd database handling
session sufficient pam_sss.so
Expand Down
2 changes: 1 addition & 1 deletion sysctl.conf
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
# Uncomment the next line to enable packet forwarding for IPv6
# Enabling this option disables Stateless Address Autoconfiguration
# based on Router Advertisements for this host
#net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.forwarding=1


###################################################################
Expand Down