...
 
Commits (6)
#!/bin/bash
#!/usr/bin/env bash
# Copyright 2015 Florian Vessaz
#
# Licensed under the Apache License, Version 2.0 (the "License");
......@@ -34,9 +34,9 @@ VPNSERVER="vpn.epfl.ch"
# Target Network namespace name
NETNS_NAME="EpflVPN"
# local interface name
NETNS_LI="Bifrost"
NETNS_LI="ToEPFL"
# Remote interface name
NETNS_RI="RainbowBridge"
NETNS_RI="FromEPFL"
# Local Interface ip addr for jailed mode
NETNS_LIP=169.254.97.1/24
# Remote Interface ip addr for jailed mode
......@@ -44,8 +44,7 @@ NETNS_RIP=169.254.97.172/24
# --------------------------------------
# Exit codes
E_SUCCESS=0
# Error codes
E_USER=1
E_NOCMD=127
......@@ -55,6 +54,7 @@ die()
if [ $# -eq 0 ]; then
cat <&0 >&2
else
# shellcheck disable=SC2059
printf "$@" >&2; echo >&2
fi
if [ "$retval" = $E_USER ]; then
......@@ -100,25 +100,6 @@ usage()
EOF
}
# Reliable which:
which()
(
# Absolute/relative paths:
case "$1" in
(/*) printf '%s' "$1"; return $E_SUCCESS ;;
(*/*) printf '%s/%s' "$(pwd)" "$1"; return $E_SUCCESS ;;
esac
IFS=":"
for p in $2; do
if [ -e "$p/$1" ]; then
printf '%s/%s' "$p" "$1"
return $E_SUCCESS
fi
done
return $E_NOCMD
)
check_user()
{
if [ "$(id -u)" != '0' ]; then
......@@ -131,7 +112,7 @@ check_user()
check_openconnect()
{
if ! OPENCONNECT="$(which "$OPENCONNECT_NAME" "$PATH")"; then
if ! OPENCONNECT="$(command -v "$OPENCONNECT_NAME")"; then
die $E_NOCMD <<- EOF
ERROR: The \`$OPENCONNECT_NAME' command does not appear to exist on this system.
Please make sure that OpenConnect is installed.
......@@ -142,7 +123,7 @@ check_openconnect()
check_vpnc_script()
{
if ! VPNC_SCRIPT="$(which "$VPNC_SCRIPT_NAME" "$VPNC_SCRIPT_PATH")"; then
if ! VPNC_SCRIPT="$(PATH="$VPNC_SCRIPT_PATH" command -v "$VPNC_SCRIPT_NAME")"; then
die $E_NOCMD <<- EOF
ERROR: $VPNC_SCRIPT_NAME was not found in the following colon-delimited paths:
$VPNC_SCRIPT_PATH
......@@ -154,7 +135,7 @@ check_vpnc_script()
check_path_bins()
{
if ! which "$1" &> /dev/null; then
if ! command -v "$1" &> /dev/null; then
die $E_NOCMD <<- EOF
ERROR: "$1" was not found in \$PATH:
Please make sure that the distribution package providing "$1" is installed.
......@@ -165,14 +146,14 @@ check_path_bins()
setup_network_jail(){
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s ${NETNS_RIP} -o ${OUTGOING_INTERFACE} -j MASQUERADE
iptables -t nat -A POSTROUTING -s ${NETNS_RIP} -o "$OUTGOING_INTERFACE" -j MASQUERADE
iptables -t filter -A FORWARD -i ${NETNS_LI} -j ACCEPT
iptables -t filter -A FORWARD -o ${NETNS_LI} -j ACCEPT
# Don't try to create the NNS if it exists.
if ! ip netns list | grep "${NETNS_NAME}"; then
# Setup NS, create and configure interfaces
ip netns add ${NETNS_NAME}
else
else
echo "Detected previous namespace, recycling..."
fi
......@@ -199,7 +180,7 @@ destroy_network_jail(){
echo "Asking remaining processes to exit"
# Be nice and send SIGINT to the processes inside the jail
for pid in $(ip netns pids $NETNS_NAME); do
kill -INT $pid
kill -INT "$pid"
done
# They got 2 seconds to clear out!
[ -z "$(ip netns pids $NETNS_NAME)" ] || sleep 2
......@@ -209,14 +190,14 @@ destroy_network_jail(){
ip netns exec ${NETNS_NAME} ip link set ${NETNS_RI} down
# Kill the remaining processes in the netns
for pid in $(ip netns pids $NETNS_NAME); do
kill -KILL $pid
kill -KILL "$pid"
done
[ -z "$(ip netns pids $NETNS_NAME)" ] || sleep 1
# Cleanup local
echo "Cleaning Network Jail"
ip link del ${NETNS_LI}
ip netns del ${NETNS_NAME}
iptables -t nat -D POSTROUTING -s ${NETNS_RIP} -o ${OUTGOING_INTERFACE} -j MASQUERADE
iptables -t nat -D POSTROUTING -s ${NETNS_RIP} -o "$OUTGOING_INTERFACE" -j MASQUERADE
iptables -t filter -D FORWARD -i ${NETNS_LI} -j ACCEPT
iptables -t filter -D FORWARD -o ${NETNS_LI} -j ACCEPT
}
......@@ -229,8 +210,14 @@ connect_jailed(){
check_path_bins iptables
check_path_bins ip
EPFL_IP_ADDR="$(getent hosts epfl.ch | head -n 1 | awk '{print $1}')"
OUTGOING_INTERFACE="$(ip route get ${EPFL_IP_ADDR} | grep -oP 'dev \K[^ ]+')"
EPFL_IP_ADDR="$(getent ahostsv6 epfl.ch | head -n 1 | awk '{print $1}')"
if ! ip route get "$EPFL_IP_ADDR" &> /dev/null; then
# Fallbackk to IPv4 if we cannot route using IPv6
EPFL_IP_ADDR="$(getent ahostsv4 epfl.ch | head -n 1 | awk '{print $1}')"
fi
OUTGOING_INTERFACE="$(ip route get "$EPFL_IP_ADDR" | grep -oP 'dev \K[^ ]+')"
EPFL_SCRIPT="$0"
setup_network_jail
......@@ -265,11 +252,19 @@ if [ -n "$VPNGATEWAY" ]; then
"$VPNC_SCRIPT" "$@"
# Deserialize command
OLDIFS="$IFS"
IFS="\x1E"
# shellcheck disable=SC2206 # splitting with custom IFS
CMD=($COMMAND)
IFS="$OLDIFS"
# shellcheck disable=SC2154 # $reason is set by openconnect
if [ -n "$NETNS_NAME" ] && [ -n "$RUNAS_USER" ] && [ "$reason" = "connect" ] ; then
echo "Running requested command"
cat <<- EOF | sudo -u $RUNAS_USER bash -s &
#!/bin/bash
$COMMAND
cat <<- EOF | sudo -u "$RUNAS_USER" bash -s &
#!/usr/bin/env bash
${CMD[@]}
echo
echo "Command finished, press Ctrl-C to exit the network jail"
EOF
......@@ -280,13 +275,24 @@ if [ -n "$VPNGATEWAY" ]; then
fi
# Read command line arguments:
mode=split
mode="split"
while [ $# -gt 0 ]; do
opt="$1"; shift
case "$opt" in
(-h|--help) usage; exit ;;
(-f|--full) mode=full ;;
(-j|--jail) mode=jail ; RUNAS_USER="$1"; shift; COMMAND="$@"; break ;;
(-j|--jail) mode=jail;
RUNAS_USER="$1"
if [ -z "$RUNAS_USER" ]; then
die $E_USER "A user must be specified in jailed mode."
fi
shift
if [ $# -lt 1 ]; then
die $E_USER "A command to execute inside the jail must be specified."
fi
# Serialize the rest of the arguments, to be executed in bash inside the jail
OLDIFS="$IFS"; IFS="\x1E"; COMMAND="$*"; IFS="$OLDIFS"
break ;;
(-*) die $E_USER 'Unknown option: %s' "$opt" ;;
(*) die $E_USER 'Trailing argument: %s' "$opt" ;;
esac
......