aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojciech Kosior <kwojtus@protonmail.com>2020-06-05 13:13:25 +0200
committerWojciech Kosior <kwojtus@protonmail.com>2020-06-05 13:13:25 +0200
commit4fc3015b2dd76c0a9112794bc95e1f926c1c9f0f (patch)
treec2064fc1edea14f50e3467fd9d16c788d2febb89
parent7614d6aade16998b6d76fcc8986b603dfc01218c (diff)
download0tdns-4fc3015b2dd76c0a9112794bc95e1f926c1c9f0f.tar.gz
0tdns-4fc3015b2dd76c0a9112794bc95e1f926c1c9f0f.zip
enable come connections to bypass vpn
-rwxr-xr-xsrc/netns-script39
-rwxr-xr-xsrc/vpn_wrapper.sh30
2 files changed, 61 insertions, 8 deletions
diff --git a/src/netns-script b/src/netns-script
index 7c29811..f4380eb 100755
--- a/src/netns-script
+++ b/src/netns-script
@@ -3,9 +3,14 @@
# adapted from
# https://unix.stackexchange.com/questions/149293/feed-all-traffic-through-openvpn-for-a-specific-network-namespace-only
-# vpn_wrapper.sh creates another script of name helper_script<timestamp>.sh,
-# which gets called by openvpn process, exports NAMESPACE_NAME and WRAPPER_PID
-# variables and then runs this script
+# vpn_wrapper.sh passes the following variables through openvpn's
+# --setenv option:
+# NAMESPACE_NAME
+# WRAPPER_PID
+# VETH_HOST0
+# VETH_HOST1
+# ROUTE_THROUGH_VETH
+# PHYSICAL_IP
case $script_type in
up)
@@ -19,19 +24,45 @@ case $script_type in
ip netns exec $NAMESPACE_NAME ip addr add dev "$1" \
"$ifconfig_ipv6_local"/112
fi
+
+ # the following is done to enable some connections to bypass vpn
+ VETH0=v0tdns${WRAPPER_PID}_0
+ VETH1=v0tdns${WRAPPER_PID}_1
+ ip link add $VETH0 type veth peer name $VETH1
+ ip link set $VETH1 netns $NAMESPACE_NAME
+ ip addr add $VETH_HOST0/30 dev $VETH0
+ ip netns exec $NAMESPACE_NAME ip addr add $VETH_HOST1/30 dev $VETH1
+ ip link set $VETH0 up
+ ip netns exec $NAMESPACE_NAME ip link set $VETH1 up
;;
route-up)
- ip netns exec $NAMESPACE_NAME ip route add default via "$ifconfig_remote"
+ # TODO change to only forward from necessary interfaces
+ echo 1 > /proc/sys/net/ipv4/conf/all/forwarding
+ ip netns exec $NAMESPACE_NAME ip route add default via "$ifconfig_remote"
+
if [ -n "$ifconfig_ipv6_remote" ]; then
ip netns exec $NAMESPACE_NAME ip route add default via \
"$ifconfig_ipv6_remote"
fi
+ # here go routes for bypassing vpn
+ for ADDRESS in $ROUTE_THROUGH_VETH; do
+ ip netns exec $NAMESPACE_NAME ip route add $ADDRESS via $VETH_HOST0
+ iptables -t nat -A POSTROUTING -s $VETH_HOST1/32 \
+ -j SNAT --to-source $PHYSICAL_IP
+ done
+
+
# notify our sh process, that openvpn finished initializing
kill -usr1 $WRAPPER_PID
;;
down)
+ for ADDRESS in $ROUTE_THROUGH_VETH; do
+ iptables -t nat -D POSTROUTING -s $VETH_HOST1/32 \
+ -j SNAT --to-source $PHYSICAL_IP
+ done
+
ip netns delete $NAMESPACE_NAME
;;
esac
diff --git a/src/vpn_wrapper.sh b/src/vpn_wrapper.sh
index 848f16e..c3dfaa8 100755
--- a/src/vpn_wrapper.sh
+++ b/src/vpn_wrapper.sh
@@ -1,14 +1,31 @@
#!/bin/sh
OPENVPN_CONFIG="$1"
+PHYSICAL_IP="$2"
# rest of args is the command to run in network namespace
shift
+shift
+
+# for routing some traffic from within the namespace to physical
+# network (e.g. database connection) we need to create a veth pair;
+# as we want multiple instances of vpn_wrapper.sh to be able to
+# run simultaneously, we need unique ip addresses for them;
+# the solution is to derive an ip address from current shell's
+# PID (which is unique within a system)
+NUMBER=$((($$ - 1) * 4))
+WORD0HOST0=$(($NUMBER % 256 + 1))
+WORD0HOST1=$(($NUMBER % 256 + 2))
+NUMBER=$(($NUMBER / 256))
+WORD1=$(($NUMBER % 256))
+NUMBER=$(($NUMBER / 256))
+WORD2=$(($NUMBER % 256))
+VETH_HOST0=10.$WORD2.$WORD1.$WORD0HOST0
+VETH_HOST1=10.$WORD2.$WORD1.$WORD0HOST1
# to enable multiple instances of this script to run simultaneously,
# we tag namespace name with this shell's PID
-
-NETNS_SCRIPT=/var/lib/0tdns/netns-script
NAMESPACE_NAME=0tdns$$
+NETNS_SCRIPT=/var/lib/0tdns/netns-script
# in case we want some process in the namespace to be able
# to resolve domain names via libc we put some random public
@@ -17,8 +34,9 @@ NAMESPACE_NAME=0tdns$$
# dns addresses provided by us, it is still possible to pass
# a domain name as forwarder address to unbound, in which case
# it will try to resolve it first using libc
+DEFAULT_DNS=23.253.163.53
mkdir -p /etc/netns/$NAMESPACE_NAME/
-echo nameserver 23.253.163.53 > /etc/netns/$NAMESPACE_NAME/resolv.conf
+echo nameserver $DEFAULT_DNS > /etc/netns/$NAMESPACE_NAME/resolv.conf
# starts openvpn with our just-created helper script, which calls
# the netns-script, which creates tun inside network namespace
@@ -28,7 +46,11 @@ openvpn --ifconfig-noexec --route-noexec --up $NETNS_SCRIPT \
--route-up $NETNS_SCRIPT --down $NETNS_SCRIPT \
--config "$OPENVPN_CONFIG" --script-security 2 \
--setenv NAMESPACE_NAME $NAMESPACE_NAME \
- --setenv WRAPPER_PID $$ &
+ --setenv WRAPPER_PID $$ \
+ --setenv VETH_HOST0 $VETH_HOST0 \
+ --setenv VETH_HOST1 $VETH_HOST1 \
+ --setenv ROUTE_THROUGH_VETH $DEFAULT_DNS/32 \
+ --setenv PHYSICAL_IP $PHYSICAL_IP &
OPENVPN_PID=$!