util  Check-in [75223838e1]

Overview
Comment:add vpn tool
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 75223838e1bae48168201470b2857ed20c47e2be32b5a2dd6c661568bdcc1aae
User & Date: lexi on 2019-05-03 15:21:43
Other Links: manifest | tags
Context
2019-05-04
02:38
updates check-in: 05feae3cd3 user: lexi tags: trunk
2019-05-03
15:21
add vpn tool check-in: 75223838e1 user: lexi tags: trunk
2019-05-01
01:03
refactor tenki check-in: 70991b55c3 user: lexi tags: trunk
Changes

Added vpn/conf version [d086ba0334].

            1  +# [ʞ] vpn/conf
            2  +#  ~ lexi hale <lexi@hale.su>
            3  +#  © public domain / CC0
            4  +
            5  +# this  is  the   master  configuration  file  for
            6  +# openvpn used by the  `vpn` utility. these should
            7  +# be  sane-enough defaults  for almost  all cases.
            8  +# server-specific  config  should   be  placed  in
            9  +# $server/conf in this directory
           10  +
           11  +client
           12  +pull
           13  +
           14  +group nobody
           15  +
           16  +resolv-retry infinite
           17  +nobind
           18  +
           19  +persist-key
           20  +persist-tun
           21  +
           22  +log log
           23  +mute-replay-warnings
           24  +verb 3
           25  +mute 10

Added vpn/vpn version [8e3b5d4148].

            1  +#!/usr/bin/env bash
            2  +# [ʞ] vpn
            3  +#  ~ lexi hale <lexi@hale.su>
            4  +#  ® affero general public license
            5  +#  $ vpn (join | part | info | clean | key) <name>
            6  +#  : vim:ft=bash
            7  +
            8  +# vpn is a simple wrapper around openvpn to make it suitable
            9  +# for everyday  use. it  takes two  arguments: the  vpn, and
           10  +# what to do with it.
           11  +#   - vpn join <vpn>: opens a connection to vpn <name>
           12  +#   - vpn part <vpn>: closes an active connection to <name>
           13  +#   - vpn info <vpn>: reports the status of of a vpn
           14  +#   - vpn key <host>: automatically  provisions  the  client
           15  +#                     with RSA keys from  <host> and creates
           16  +#                     a  configuration file if one does  not
           17  +#                     already exist
           18  +#   - vpn part <vpn>: closes an active connection to <vpn>
           19  +#         - vpn help: display this text
           20  +#
           21  +# a number  of environment variables affect  the behavior of
           22  +# vpn. these  are listed in  the source with  their defaults
           23  +# and an  explantion of their  function. if you do  not wish
           24  +# users  to be  able  to  change the  behavior  of vpn  with
           25  +# setenv, you must  change the param invokation  to a simple
           26  +# assignment.
           27  +#
           28  +# note  that you  may want  to  add a  visudo line  allowing
           29  +# %wheel  or  perhaps  even  all users  to  execute  openvpn
           30  +# without a  password; otherwise, only sudoers  will be able
           31  +# to  use vpn  and the  root password  will be  required for
           32  +# every state change.
           33  +__=$LINENO
           34  +
           35  +param(){ eval $1=\${$1:-$2}; }
           36  +
           37  +param vpn_basedir    ~/opt/vpn
           38  +	# the directory in which vpn's logfiles are stored, 
           39  +	# and possibly the script itself
           40  +
           41  +param vpn_confdir    $vpn_basedir
           42  +	# the directory that contains the individual vpn
           43  +	# directories
           44  +
           45  +param vpn_global     $vpn_basedir/conf
           46  +	# a configuration file that is applied to all vpns
           47  +
           48  +param vpn_srv_keydir /srv/vpn/ca
           49  +	# the directory on the server where vpn client keys
           50  +	# are stored
           51  +
           52  +param vpn_cn         $(uname -n)
           53  +	# the name of the device / user / resource connecting
           54  +	# `vpn key` will use this value to determine which
           55  +	# client keys to download. i recommend a one-key-per-
           56  +	# device setup with the certificate CN used to assign
           57  +	# a name in the tunnel's DNS server, but one-key-per-
           58  +	# user or one-key-period setups are also possible.
           59  +
           60  +param TMPDIR		 /tmp
           61  +	# a directory for temporary files, preferably one that
           62  +	# does not persist across boots (e.g. a tmpfs)
           63  +
           64  +param USER			 $(whoami)
           65  +	# the user who should own all files and processes
           66  +	# created and destroyed by vpn
           67  +
           68  +param vpn_pidbox     $TMPDIR/pid.$USER
           69  +	# a directory for storing pids in. this should be chmod
           70  +	# 700 and owned by the user invoking vpn, ideally
           71  +
           72  +param vpn_script     $0
           73  +	# a path to the executable
           74  +
           75  +param vpn_scrname    $(basename $vpn_script)
           76  +	# the name of the executable
           77  +
           78  +# thus ends the admin-configurable portion of this script.
           79  +# abandon all hope, ye who enter here
           80  +
           81  +err(){ echo -e "\e[1;31merror:\e[m" $* ; exit 1; }
           82  +assert(){ msg=$1; shift; test ! $@ && err $msg; }
           83  +
           84  +test "$1" == help || assert "incorrect number of arguments" $# -eq 2
           85  +
           86  +act=$1; target=$2
           87  +vpnd=$vpn_confdir/$target
           88  +conf=$vpnd/conf
           89  +
           90  +test "$act" == key && {
           91  +	mkdir -p $vpnd
           92  +	test -e $conf || {
           93  +		echo dev tun > $conf
           94  +		echo proto udp >> $conf
           95  +		echo remote $target 1194 >> $conf
           96  +	}
           97  +}
           98  +
           99  +assert "target \e[1m$target\e[m does not exist!" -e $vpn_confdir/$target
          100  +assert "target \e[1m$target\e[m has no configuration file" -e $conf
          101  +
          102  +pidfile="$vpn_pidbox/openvpn.$target"
          103  +
          104  +stale() {
          105  +	((clean == 1)) && {
          106  +		echo " → deleting stale pidfile"
          107  +		rm -f $pidfile
          108  +	} || {
          109  +		echo -e " - run \e[1m$vpn_scrname clean\e[m to clean up"
          110  +	}
          111  +}
          112  +
          113  +goodpid(){
          114  +	test -e $pidfile || return 1
          115  +	local proc=$(ps ho fname $(cat $pidfile)) || return 2
          116  +	test "$proc" == openvpn || return 2
          117  +	return 0
          118  +}
          119  +	
          120  +
          121  +case $act in
          122  +	# automatically provision machine
          123  +	( key | setup | provision | download | dl | k ) 
          124  +		scp $target:$vpn_srv_keydir/pki/{ca.crt,{issued,private}/$vpn_cn.\*} $vpnd/ || err "could not retrieve keys for \e[1m$target\e[m; ensure ssh is properly configured and machine keys are assigned to the correct user" ;;
          125  +
          126  +	# connect to the openvpn server
          127  +	( join | up | connect | con | start | j | u )
          128  +		# don't clobber an existing connection
          129  +		goodpid && err "\e[1m$target\e[m is already up!"
          130  +
          131  +		# make sure a private pid directory exists
          132  +		test ! -e $vpn_pidbox &&
          133  +			mkdir -p $vpn_pidbox
          134  +		chmod 700 $vpn_pidbox
          135  +
          136  +		# check and see if we're using automatic
          137  +		# host certificates; tell openvpn if so
          138  +		test -e $vpnd/ca.crt && {
          139  +			hostcert=$vpnd/$vpn_cn
          140  +			cmd=(
          141  +				--askpass
          142  +				--ca   $vpnd/ca.crt
          143  +				--cert $hostcert.crt
          144  +				--key  $hostcert.key
          145  +			)
          146  +		}
          147  +
          148  +		touch $pidfile # make sure invoker owns it
          149  +		chmod 600 $pidfile # bc fuck you, that's why
          150  +		sudo openvpn --daemon --config $vpn_global \
          151  +		                      --config $conf       \
          152  +							  --user $USER         \
          153  +							  ${cmd[@]}            \
          154  +		                      --writepid $pidfile || rm $pidfile;;
          155  +
          156  +	# kill an existing connection
          157  +	( part | down | disc* | stop | p | d )
          158  +		test -e $pidfile && {
          159  +			goodpid && {
          160  +				kill $(cat $pidfile) && rm -f $pidfile
          161  +			} || {
          162  +				echo -e "\e[1;33mwarn:\e[m pidfile exists but does not name an openvpn process"
          163  +				echo " → removing pidfile for safety"
          164  +				rm -f $pidfile
          165  +			}
          166  +
          167  +		} || {
          168  +			echo -ne "\e[1mvpn $target\e[m is not up"
          169  +		} ;;
          170  +
          171  +	# clean up dirty pidfiles
          172  +	( clean | wipe | clear | fix | tidy ) clean=1 ;&
          173  +	# return profile status
          174  +	( info | stat* | detail* | i )
          175  +		echo -ne "\e[1mvpn $target:\e[m "
          176  +		test ! -e $pidfile && {
          177  +			echo -ne "\e[31mno\e[m current connection"
          178  +			pids=($(pidof openvpn))
          179  +			let pidc=${#pids}
          180  +			((pidc > 0)) && {
          181  +				echo ", but $pidc vpn instances are running"
          182  +				exit 2
          183  +			} || { echo; exit 0; }
          184  +		} || {
          185  +			echo -n "pidfile exists"
          186  +			proc=$(ps ho fname $(cat $pidfile))
          187  +			(($? != 0)) && {
          188  +				echo ", but there are no processes with that pid"
          189  +				stale; exit 1
          190  +			} || test "$proc" == "openvpn" && {
          191  +				echo -e " and openvpn is \e[32mrunning\e[m"
          192  +				exit 0
          193  +			} || {
          194  +				echo -e " but named process is \e[31mnot a vpn instance!\e[m"
          195  +				stale; exit 1
          196  +			}
          197  +		} ;;
          198  +	( help ) head -n $(expr $__ - 1) $vpn_script |
          199  +		tail -n $(expr $__ - 2); exit 255;;
          200  +
          201  +	( * ) err "action must be one of: join | part | info | clean" ;;
          202  +esac
          203  +