#!/bin/sh

# Copyright (c) 2012 Igor Bogomazov <[email protected]>

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# revision 2012101100

set -e

# remove DIR_ROOT and build from scratch
DIR_REFRESH="${DIR_REFRESH:-}"

# network end-point in main netspace
IF_SKYPE_M="${IF_SKYPE_M:-skype-m}"
# IP-address in main netspace
IP_M="${IP_M:-172.31.255.254}"
# network end-point in jailed netspace
IF_SKYPE_S="${IF_SKYPE_S:-skype-s}"
# IP-address in jail
IP_S="${IP_S:-172.31.255.255}"
# network namespace
NS_SKYPE="${NS_SKYPE:-skype-ns}"
# routing network interface
IF="${IF:-eth0}"
# always pingable IP-address to test network
IP_AVAIL="${IP_AVAIL:-8.8.8.8}"
# chroot location
DIR_ROOT="${DIR_ROOT:-/opt/skype-root}"
# bind directories from main filesystem
DIR_MOUNT="${DIR_MOUNT:-/dev /sys /proc /tmp/.X11-unix}"
# address length
test -n "$MACH" || {
       uname -m | grep -q '[^0-9]64' && MACH=64 || MACH=32
}
# skype URL
URL_SKYPE="${URL_SKYPE:-http://www.skype.com/go/getskype-linux-deb-$MACH}"
# skype user UID
UID_SKYPE="${UID_SKYPE:-43981}"
# skype username
USER_SKYPE="${USER_SKYPE:-skype}"

# protect PID-space
mount_opts="$(
       cat /proc/self/mounts | \
       awk '($2 ~ "^/proc/*$") {print $1 " " $2 " -o " $4}'
)"
mount -t proc $mount_opts,remount,hidepid=2

# isolating network space
ip netns list | grep -q -x "$NS_SKYPE" || \
       ip netns add "$NS_SKYPE"
ip link show "$IF_SKYPE_M" >/dev/null 2>&1 || {
       ip link show "$IF_SKYPE_S" >/dev/null 2>&1 \
               && ip link del "$IF_SKYPE_S" \
               || true
       ip netns exec "$NS_SKYPE" ip link show "$IF_SKYPE_S" >/dev/null 2>&2 \
               && ip netns exec "$NS_SKYPE" ip link del "$IF_SKYPE_S" \
               || true
       ip link add name "$IF_SKYPE_M" type veth peer name "$IF_SKYPE_S" \
               && ip link set "$IF_SKYPE_S" netns "$NS_SKYPE"
}
# private network configuration
ip link set "$IF_SKYPE_M" up
ip route get to "$IP_S" | grep -q '^'"$IP_S"' dev '"$IF_SKYPE_M" || {
       ip addr flush dev "$IF_SKYPE_M" \
               && ip addr add "$IP_M"/31 dev "$IF_SKYPE_M"
}
ip netns exec "$NS_SKYPE" ip link set "$IF_SKYPE_S" up
ip netns exec "$NS_SKYPE" ip route get to "$IP_M" \
       | grep -Eq '^'"$IP_M"' dev '"$IF_SKYPE_S"'[[:space:]]+' || {
       ip netns exec "$NS_SKYPE" ip addr flush dev "$IF_SKYPE_S" \
               && ip netns exec "$NS_SKYPE" ip addr add "$IP_S"/31 dev "$IF_SKYPE_S" \
               && ip netns exec "$NS_SKYPE" ip route add default via "$IP_M"
}
# enabling forwarding
iptables -t filter -S FORWARD | \
       grep -q -E -- '-i[[:space:]]+'"$IF_SKYPE_M"'[[:space:]]+' || \
       iptables -A FORWARD -i "$IF_SKYPE_M" -o "$IF" \
               -m state \! --state INVALID,UNTRACKED \
               -j ACCEPT \
               -m comment --comment 'fwd Skype outgoing traffic'
iptables -t filter -S FORWARD | \
       grep -q -E -- '-o[[:space:]]+'"$IF_SKYPE_M"'[[:space:]]+' || \
       iptables -A FORWARD -o "$IF_SKYPE_M" -i "$IF" \
               -m state --state RELATED,ESTABLISHED \
               -j ACCEPT \
               -m comment --comment 'fwd Skype incoming traffic'
sysctl -w net.ipv4.conf."$IF_SKYPE_M".rp_filter=1
sysctl -w net.ipv4.conf."$IF_SKYPE_M".forwarding=1
sysctl -w net.ipv4.conf."$IF".forwarding=1
# also NAT
iptables -t nat -S POSTROUTING | \
       grep -q -E -- '-o[[:space:]]+'"$IF"'[[:space:]]+.*-j[[:space:]]+MASQUERADE' || \
       iptables -t nat -A POSTROUTING -o "$IF" \
               -j MASQUERADE \
               -m comment --comment 'NAT Skype traffic'

# assert internet availability at this step
test -z "$IP_AVAIL" || \
       ip netns exec "$NS_SKYPE" ping -c1 "$IP_AVAIL" >/dev/null 2>/dev/null

# if the given directory is a mountpoint?
mounted() {
       cat /proc/self/mounts | \
               cut -f2 -d' ' | \
               grep -q -x "$1"'/*' && return 0
       return 1
}

# remove target directory if requested
test -z "$DIR_REFRESH" || {
       for dir in $DIR_MOUNT ; do
               mounted "$DIR_ROOT""$dir" \
                       || continue \
                       && umount "$DIR_ROOT""$dir" || exit $?
       done
       rm --one-file-system -rf "$DIR_ROOT"
}

# filesystem isolating
chroot=
if test -z "$chroot" ; then mkdir "$DIR_ROOT" && chroot=1 || true ; fi
if test -z "$chroot" ; then
   cat "$DIR_ROOT""/etc/debian_version" || chroot=1 ;
fi
test -z "$chroot" || {
       # FIXME W: Cannot check Release signature; keyring file not available /usr/share/keyrings/debian-archive-keyring.gpg
       debootstrap --variant=minbase --include=aptitude testing "$DIR_ROOT" || exit $?
       chroot "$DIR_ROOT" aptitude --without-recommends --assume-yes --allow-untrusted install xauth fontconfig alsa-base || exit $?
       chroot "$DIR_ROOT" aptitude clean
       cat /etc/localtime >"$DIR_ROOT"'/etc/localtime'
       test -f /etc/asound.conf \
               && cat /etc/asound.conf >"$DIR_ROOT"'/etc/asound.conf'
}

# create skype user in the chroot
chroot "$DIR_ROOT" getent passwd "$USER_SKYPE" || {
       chroot "$DIR_ROOT" useradd "$USER_SKYPE" --uid "$UID_SKYPE" --comment 'skype user' --no-user-group --gid nogroup --groups audio,video --home '/home/'"$USER_SKYPE" --create-home || exit $?
       chroot "$DIR_ROOT" sh -c "echo 'XAUTHORITY=\"\${HOME}\"/.Xauthority' >> '/home/$USER_SKYPE/.profile'" || exit $?
}

chroot "$DIR_ROOT" su -l "$USER_SKYPE" -c "rm -f \"\$XAUTHORITY\" ; xauth add $(xauth list "$(hostname)"/unix:0)"

# add necessary mountpoints
# /dev may be more restricted
for dir in $DIR_MOUNT ; do
       mkdir -p "$DIR_ROOT""$dir"
       mounted "$DIR_ROOT""$dir" \
               && continue \
               || mount --bind "$dir" "$DIR_ROOT""$dir"
done

# install skype in chrooted env
test -f "$DIR_ROOT"/tmp/skype-install.deb || {
       wget -O "$DIR_ROOT"/tmp/skype-install.deb "$URL_SKYPE" || exit $?
       chroot "$DIR_ROOT" dpkg -i --force-depends /tmp/skype-install.deb || exit $?
       chroot "$DIR_ROOT" aptitude --safe-resolver --without-recommends --assume-yes --allow-untrusted install || exit $?
       chroot "$DIR_ROOT" aptitude clean
}

# run skype
# FIXME process 6425: D-Bus library appears to be incorrectly set up; failed to read machine uuid: Failed to open "/var/lib/dbus/machine-id": No such file or directory
exec ip netns exec "$NS_SKYPE" chroot "$DIR_ROOT" su -l "$USER_SKYPE" -c "exec skype"