explain why we put subprocess in the dict
[0tDNS.git] / src / vpn_wrapper.sh
blob23688393391e0a6192fbd8f39da7a66491283863
1 #!/bin/sh
3 # We give the full path, because PATH environment variable
4 # might be unset if run by cron
5 OVPN_COMMAND="/usr/sbin/openvpn"
7 OPENVPN_CONFIG="$1"
8 # for routing some traffic from within the namespace to physical
9 # network (e.g. database connection) we need to create a veth pair;
10 # ip datagrams routed through veth pair are going to have veth's private address
11 # as their source address - we need to change it to the address of our physical
12 # network device using iptables' SNAT. This address is provided by the caller.
13 PHYSICAL_IP="$2"
14 # as we want multiple instances of vpn_wrapper.sh to be able to
15 # run simultaneously, we need unique ip addresses for veth devices, which
16 # caller provides to us in command line arguments
17 VETH_HOST0="$3"
18 VETH_HOST1="$4"
19 # caller specifies space-delimited subnets, traffic to which should not be
20 # routed through the vpn (<database_ip>/32 is going to be here)
21 ROUTE_THROUGH_VETH="$5"
22 # we use a unique id provided in 6th argument to tag namespace name
23 ID="$6"
25 # rest of args is the command to run in network namespace
26 for _ in `seq 6`; do
27 shift
28 done
30 # to enable multiple instances of this script to run simultaneously,
31 # we tag namespace name
32 NAMESPACE_NAME=0tdns$ID
33 NETNS_SCRIPT=/var/lib/0tdns/netns-script
35 # in case we want some process in the namespace to be able
36 # to resolve domain names via libc we put some random public
37 # dns in namespace sepcific's resolv.conf;
38 # note, that while libunbound we're using will probably have
39 # dns addresses provided by us, it is still possible to pass
40 # a domain name as forwarder address to unbound, in which case
41 # it will try to resolve it first using libc
42 DEFAULT_DNS=23.253.163.53
43 mkdir -p /etc/netns/$NAMESPACE_NAME/
44 echo nameserver $DEFAULT_DNS > /etc/netns/$NAMESPACE_NAME/resolv.conf
46 # starts openvpn with our just-created helper script, which calls
47 # the netns-script, which creates tun inside network namespace
48 # of name $NAMESPACE_NAME
49 # we could consider using --daemon option instead of &
50 $OVPN_COMMAND --ifconfig-noexec --route-noexec --up $NETNS_SCRIPT \
51 --route-up $NETNS_SCRIPT --down $NETNS_SCRIPT \
52 --config "$OPENVPN_CONFIG" --script-security 2 \
53 --connect-timeout 20 --connect-retry-max 1 \
54 --setenv NAMESPACE_NAME $NAMESPACE_NAME \
55 --setenv WRAPPER_PID $$ \
56 --setenv VETH_HOST0 $VETH_HOST0 \
57 --setenv VETH_HOST1 $VETH_HOST1 \
58 --setenv ROUTE_THROUGH_VETH $ROUTE_THROUGH_VETH\ $DEFAULT_DNS/32 \
59 --setenv PHYSICAL_IP $PHYSICAL_IP &
61 OPENVPN_PID=$!
63 # waiting for signal from our netns script
64 # https://stackoverflow.com/questions/9052847/implementing-infinite-wait-in-shell-scripting
65 trap true usr1
67 # wait on openvpn process;
68 # if we get sigusr1 from netns-script - wait will
69 # terminate with 138 (128 + signal number);
70 # if openvpn process dies - wait will also terminate,
71 # but with openvpn's exit value
72 wait $OPENVPN_PID
74 if [ $? = 138 ]; then
75 # we received sigusr1 from netns-script, namespace is ready
77 # run the provided command inside newly created namespace
78 # under '0tdns' user;
79 sudo ip netns exec $NAMESPACE_NAME sudo -u 0tdns "$@"
81 if [ $? = 0 ]; then
82 RETVAL=0
83 else
84 RETVAL=2
87 # close the connection
88 kill $OPENVPN_PID
89 wait $OPENVPN_PID
90 else
91 RETVAL=1
94 # we no longer need those
95 rm -r /etc/netns/$NAMESPACE_NAME/
97 # return 0 on success, 1 on failed vpn connection,
98 # 2 on problems within the program we ran in the namespace
99 exit $RETVAL