#!/bin/sh #------------------------------------------------------------------------------ # __FLI4LVER__ # /srv/www/admin/status_wireguard.cgi # Creation: 10.01.2020 Christoph Fritsch # Last Update: 12.09.2020 Christoph Fritsch #------------------------------------------------------------------------------ . /srv/www/include/cgi-helper . /etc/boot.d/netalias.inc PEER_FILE='/etc/wireguard/wireguard.peers' SERVER_FILE='/etc/wireguard/wireguard.names' QR_PATH='img/wireguard' ######################################################################### # download WireGuard Peer config file download_peer_config () { local interface=$1 local peerNo=$2 local peerName=$(get_peer_name $interface $peerNo) local configFileName=${peerName}".conf" local configFile="/srv/www/admin/img/wireguard/"${interface}/${configFileName} if [ -f ${configFile} ] then echo "Content-Type: text/plain" echo "Content-Disposition: attachment; filename="${configFileName} echo cat ${configFile} else show_html_header "WireGuard" show_error "${_WG_invalidFileErrorTitle}" "${_WG_invalidFileErrorMessage}" show_html_footer fi } # download WireGuard server config (e.g. to get server private key if autogenerated) download_server_config () { local interface=$1 local serverName=`grep "^$interface" $SERVER_FILE | cut -d":" -f3` local serverPort=`grep "^$interface" $SERVER_FILE | cut -d":" -f6` local serverPrivateKey=`grep "^$interface" $SERVER_FILE | cut -d":" -f4` local config_idx=`grep "^$interface" $SERVER_FILE | cut -d":" -f2` eval local wg_srv_ip4_var='WIREGUARD_'$config_idx'_LOCAL_IP4' eval local wg_srv_ip6_var='WIREGUARD_'$config_idx'_LOCAL_IP6' local wg_client_ip4=$(grep $wg_srv_ip4_var /etc/rc.cfg | cut -d"=" -f2 | cut -d"'" -f2) if [ x$wg_client_ip4 != "x" ]; then ipv4_config_string='LOCAL_IP4='${wg_client_ip4} else ipv4_config_string='# LOCAL_IP4=' fi local wg_client_ip6=$(grep $wg_srv_ip6_var /etc/rc.cfg | cut -d"=" -f2 | cut -d"'" -f2) if [ x$wg_client_ip6 != "x" ]; then ipv6_config_string='LOCAL_IP6='${wg_client_ip6} else ipv6_config_string='# LOCAL_IP6=' fi if [ x$serverName != "x" ] then echo "Content-Type: text/plain" echo "Content-Disposition: attachment; filename=vpn.txt" echo cat <" echo ""${peerTransferRXpercentage}"%" echo ""${peerTransferTXpercentage}"%" echo "" else echo "
"${_WG_DataTransferNoDataText}"
" fi } # print connection status indicator # as it is UDP there is no actual connection - we thus assume that if # last handshake was > 3min (180sec) ago, the connection is still active printConnectionStatusBar () { local timestampNow=$1 local lastHandshake=$2 local secSinceHandshake=$((timestampNow-lastHandshake)) local connectionStatus="offline" # assuming that handshake is renewed every 3min latest if [ 180 -gt ${secSinceHandshake} ]; then echo "
online
" else echo "
offline
" fi } # prepare overview table across all WireGuard configurations show_overview() { for interface in `wg show interfaces`; do local switch="odd" local numPeers=`wg show ${interface} peers | wc -l` local serverName=`grep "^$interface" $SERVER_FILE | cut -d":" -f3` local serverPort=`grep "^$interface" $SERVER_FILE | cut -d":" -f6` local timestampNow=`date +%s` local linkToInterfaceDetails=${myname}"?section="${interface} local server_cfg_link=${myname}"?action=srvcfg§ion="${interface} local ipString=$(get_interface_ipString $interface) echo "

"${serverName}"@"${interface}" ("${ipString}") on UDP port "${serverPort}" with "${numPeers}" peers configured | config download

" echo "" local peerNo=1 for peer in `wg show ${interface} peers`; do wg show ${interface} dump | grep ${peer} | while read pubKey presharedKey endpoint allowedIPs lHandshake rx tx keepalive do local linkToPeerDetails=${myname}"?section="${interface}"&peer="${peerNo} echo "" done peerNo=$((peerNo+1)) # change row-color if [ ${switch} = "odd" ] then local switch="even" else local switch="odd" fi done echo '
"${_WG_PeerStatusTextTH}""${_WG_PeerNameTextTH}""${_WG_DataTransferTextTH}""${_WG_PeerEndpointTextTH}"
"$(printConnectionStatusBar ${timestampNow} ${lHandshake})""$(get_peer_name_byKey ${interface} ${peer})""$(convertBytes ${rx})"/"$(convertBytes ${tx})""$(printDataTransferBar ${rx} ${tx})""${endpoint}"
' done } # show peer info overview for individual WireGuard Server show_server_peers() { local interface=$1 local serverName=`grep "^$interface" $SERVER_FILE | cut -d":" -f3` local serverPort=`grep "^$interface" $SERVER_FILE | cut -d":" -f6` local numPeers=`wg show $interface peers | wc -l` local peers=`wg show $interface peers` local server_cfg_link=${myname}"?action=srvcfg§ion="${interface} local ipString=$(get_interface_ipString $interface) echo "

"${serverName}"@"${interface}" ("${ipString}") on UDP port "${serverPort}" with "${numPeers}" peers configured - config download

" echo "" local switch="odd" local peerNo=1 for peerKey in ${peers}; do local peerEndpoint=`wg show ${interface} endpoints | grep ${peerKey} | cut -d$'\t' -f2` #get_dns_name ${peerEndpoint} #local peerEndpointDNS=$res local linkToPeerDetails=${myname}"?section="${interface}"&peer="${peerNo} local peerLatestHandshakeTimestamp=`wg show ${interface} latest-handshakes | grep ${peerKey} | cut -d$'\t' -f2` local timestampNow=`date +%s` wg show ${interface} transfer | grep ${peerKey} | while read pubKey rx tx do echo "" done peerNo=$((peerNo+1)) # change row-color if [ ${switch} = "odd" ] then switch="even" else switch="odd" fi done echo '
"${_WG_PeerStatusTextTH}""${_WG_PeerNameTextTH}""${_WG_DataTransferTextTH}""${_WG_PeerEndpointTextTH}"
"$(printConnectionStatusBar ${timestampNow} ${peerLatestHandshakeTimestamp})""$(get_peer_name_byKey ${interface} ${peerKey})""$(convertBytes ${rx})"/"$(convertBytes ${tx})""$(printDataTransferBar ${rx} ${tx})""${peerEndpoint}"
' } # show all relevant peer infos, QRCode and link to config file show_peer_info() { local interface=$1 local peerNo=$2 local peerName=$(get_peer_name $interface $peerNo) local peerPrivateKey=`grep "^$interface:[0-9]*:$peerNo" $PEER_FILE | cut -d":" -f4` local peerPublicKey=`grep "^$interface:[0-9]*:$peerNo" $PEER_FILE | cut -d":" -f5` local peerInfo=`wg show $interface dump | grep $peerPublicKey` # dump output is separated by tab (-d$'\t') but gets lost in variable $peerInfo local peerPresharedKey=`echo -e $peerInfo | cut -d' ' -f2` local peerEndpoint=`echo $peerInfo | cut -d' ' -f3` local peerAllowedIPs=`echo $peerInfo | cut -d' ' -f4` local peerLatestHandshakeTimestamp=`echo $peerInfo | cut -d' ' -f5` local timestampNow=`date +%s` local peerConfigFileName=${peerName}".conf" local peerConfigFile="/srv/www/admin/img/wireguard/"${interface}/${peerConfigFileName} local peerIPString=$(grep ^Address $peerConfigFile | sed 's/Address = //g' | sed 's/, / | /g') # show "(never)" if we have not seen a handshake yet if [ $peerLatestHandshakeTimestamp -eq 0 ]; then local peerLatestHandshake="(never)" # otherwise show x sec ago + readable time of last handshake else local secSinceHandshake=$((timestampNow-peerLatestHandshakeTimestamp)) local readableHandshakeTime=`date -d @${peerLatestHandshakeTimestamp} +'%d.%m.%Y %H:%M:%S'` local peerLatestHandshake=${secSinceHandshake}" sec ago ("${readableHandshakeTime}")" fi local peerTransferRX=`echo $peerInfo | cut -d' ' -f6` local peerTransferTX=`echo $peerInfo | cut -d' ' -f7` local peerTransferTotal=$((peerTransferTX+peerTransferRX)) local peerPersistentKeepalive=`echo $peerInfo | cut -d' ' -f8` local qrCodeFile=${QR_PATH}"/"${interface}"/"${peerName}".png" local peer_link=${myname}"?action=download§ion="${interface}"&peer="${peerNo} local download=""${_WG_DownloadCfgTextTH}"" echo "" echo "" echo "" echo "" echo "" echo "" echo "" echo "" echo "" echo "" echo "" echo "" echo "" echo '
KeyValueQRCode
"${_WG_PeerNameTextTH}""${peerName}"\"QRCode\"
"${_WG_PeerEndpointTextTH}""${peerEndpoint}"
Peer IPv4 | IPv6"${peerIPString}"
"${_WG_PeerLatestHandshakeTextTH}"" # assuming that handshake is renewed every 3min latest if [ 180 -gt ${secSinceHandshake} ]; then echo "
"${peerLatestHandshake}"
" else echo "
"${peerLatestHandshake}"
" fi echo "
"${_WG_PeerPrivateKeyTextTH}""${peerPrivateKey}"
"${_WG_PeerPublicKeyTextTH}""${peerPublicKey}"
"${_WG_PeerPresharedKeyTextTH}""${peerPresharedKey}"
"${_WG_AllowedIPsTextTH}""${peerAllowedIPs}"
"${_WG_KeepAliveIntervalTextTH}""${peerPersistentKeepalive}"
"${_WG_DataTransferTextTH}""$(convertBytes ${peerTransferRX})" / "$(convertBytes ${peerTransferTX})"
"$(printDataTransferBar ${peerTransferRX} ${peerTransferTX})"
"${download}"
' } ######################################################################### # Define important variables # sanitize $FORM_action so it can be safely used FORM_action=$(echo "$FORM_action" | sed 's/[^a-zA-Z0-9_]//g') # set default section if not given otherwise if [ "$FORM_section" = "" ]; then FORM_section="overview" fi # set default peer if not given otherwise if [ "$FORM_peer" = "" ]; then FORM_peer="all" fi ######################################################################### wgInterfaces=`wg |grep interface | cut -d":" -f2 | sed 's/^[ ]*//' | sort` interface_tabs="" for availableInterface in overview $wgInterfaces; do if [ $FORM_section == $availableInterface ]; then section_link="no" else section_link="${myname}?section=$availableInterface" fi alias_name="" net_alias_lookup_name $availableInterface alias_name if [ x"$alias_name" != "x" ] then interface=`echo "${alias_name} [$availableInterface]"` else interface=$availableInterface fi interface_tabs="${interface_tabs} ${interface} ${section_link}" done # if one of the wg-interfaces is chosen get its peers peer_tabs='' if [ `echo "${wgInterfaces}" | grep "$FORM_section"` ] then peers=`grep ^$FORM_section: $PEER_FILE | cut -d":" -f3` for peer in all $peers; do if [ $FORM_peer == $peer ]; then peer_link="no" else peer_link="${myname}?section=$FORM_section&peer=$peer" fi #match interface:configNo:peerNo) peerName=$(get_peer_name $FORM_section $peer) if [ x"$peerName" != "x" ] then peer=`echo "${peerName} [peer$peer]"` elif [ $peer != all ] then peer="[peer$peer]" fi peer_tabs="${peer_tabs} ${peer} ${peer_link}" done fi # Security case $FORM_action in download) download_peer_config $FORM_section $FORM_peer exit 0;; srvcfg) download_server_config $FORM_section exit 0;; wg_status) sec_action="view" ;; wg_keys) sec_action="admin" ;; *) sec_action="view" ;; esac check_rights "wireguard" "$sec_action" show_html_header "WireGuard" # bindet automatisch Skripte ein wenn richtig benannt /srv/www/admin/OpenVPN.cgi, /srv/www/css/OpenVPN.css, /srv/www/lang/OpenVPN.de show_tab_header ${interface_tabs} show_tab_header ${peer_tabs} case $FORM_section in overview) show_overview ;; wg[0-9]*) case $FORM_peer in all) show_server_peers ${FORM_section} ;; [0-9]*) show_peer_info $FORM_section $FORM_peer ;; *) show_error "Error: invalid peer" "The given link is not valid!" ;; esac ;; *) show_error "Error: invalid section" "The given link is not valid!" ;; esac show_tab_footer show_tab_footer show_html_footer