Got peer listing working

master
Keith Irwin 2022-09-06 20:57:41 -06:00
parent 1001f68ca6
commit 6d62db1acb
Signed by: ki9
GPG Key ID: DF773B3F4A88DA86
43 changed files with 458 additions and 243 deletions

View File

@ -1,69 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/api/dashboard/add
# DESCRIPTION: Add a new peer
# USAGE: add ip username querystring postdata
fail() {
printf "Status: 500 Internal Server Error\nContent-Type: text/plain\n\n${1}\n"
exit
}
[ "$#" == "3" ] || fail
source ../../env/vars
TOKENS_FILE='./tokens'
# Parse input
hostname="$(printf ${3}\n | jq -r '.name' | xargs | tr -dc '[a-z0-9]' | head -c10)"
[[ ${#hostname} -ge 3 ]] || fail "Hostname too short"
# Check token
saved_token=$(grep "${1}" "${TOKENS_FILE}" | cut -f2)
[ "${saved_token}" == "" ] && fail "Invalid token"
printf "${2}" | grep "t=${saved_token}" || fail "Invalid token"
# Collect existing peer data
peers="$(sudo ../../lib/wg/peer/list ${1} tsv)"
hostnames="$(printf "${peers}" | awk '{print $0}')"
ipv4s="$(printf "${peers}" | awk '{print $1}')"
ipv6s="$(printf "${peers}" | awk '{print $2}')"
usernumber="$(printf ${ipv4s} head -n1 | cut -d'.' -f3)"
hostnumber=$(
printf "$(printf "${ipv4s}" | awk -F'.' '{print $NF}')
$(printf "${ipv6s}" | awk -F':' '{print $NF}')" \
| sort | uniq | \
awk -v RS='\\s+' '{ a[$1] } END { for(i = 1; i in a; ++i); print i }'
# Check if new peer already exists
printf "${hostnames}" | grep "${hostname}" && \
fail "Hostname ${hostname} already exists!"
# Create IP Addresses
ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}"
ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}"
domain="${hostname}.${username}.${TLD}"
# Create wg config
#TODO Check for /usr/bin/wg binary
privkey="$(/usr/bin/wg genkey)"
pubkey="$(echo $privkey | /usr/bin/wg pubkey)"
address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}"
server_blocks=''
while read server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_admin server_secret; do
server_psk="$(/usr/bin/wg genpsk)"
server_blocks="${server_blocks}\n[Peer] # ${server_hostname}.${TLD}\nPublicKey=${server_pubkey}\nPresharedKey=${server_psk}\nAllowedIPs=${server_ipv4}/32,${server_ipv6}/128\nEndpoint=${server_endpoint}\n"
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]
# Add new user to local server
then ../../lib/wg/user/add "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"
# Send new user config to federated server
else ../../lib/fed/add "${server_admin}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"
fi
done <../../env/servers
wg_config="[Interface] # ${hostname}.${username}.${TLD}\nPrivateKey=${privkey}\nAddress=${address}\n${WG_DNS}\n${server_blocks}"
# Respond to user
printf "Status: 200 OK\nContent-Type: text/plain\n\n${wg_config}\n"
# Update nameserver
../../lib/ns/update/add "${domain}" "${ipv4}" "${ipv6}"
# Create SSL cert
sudo ../../lib/ssl/peer/add "${hostname}" "${username}" "IP:${ipv4},IP:${ipv6}"

View File

@ -1,21 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/api/dashboard/list
# DESCRIPTION: List a user's peers, username, token from their IP
# USAGE: list ip username
[ "$#" == "1" ] || exit
TOKENS_FILE='./tokens'
source ../env/vars
# Get or set token
token="$(grep ${1} ${TOKENS_FILE} | cut -f2)"
if [ "${token}" == "" ]; then
token="$(</dev/urandom tr -dc '[:alnum:]' | fold -w 64 | head -n 1)"
printf "${1}\t${token}\n" >>"${TOKENS_FILE}"
fi
# Get peers
peers="[$(sudo ../../lib/wg/peer/list ${1} json)]"
# Send response
printf "Content-Type: text/json\n\n{\"name\":\"${2}\",\"token\":\"${token}\",\"peers\":${peers}}\n"

View File

@ -1,34 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/api/dashboard/serve
# DESCRIPTION: Listen for user dashboard requests
# USAGE: serve port
[ "$#" == "1" ] || exit
fail() {
printf "Status: 500 Internal Server Error\nContent-Type: text/plain\n\n${1}\n"
exit
}
TOKENS_FILE='tokens'
source ../env/vars
## RUNTIME
# Get user
username="$(../../lib/ns/lookup/user ${REMOTE_ADDR})"
case "${REQUEST_METHOD}" in
# List peers
'GET') ./list "${REMOTE_ADDR}" "${username}";;
# Add peer
'POST')
[ "$CONTENT_LENGTH" -gt 0 ] && read -n $CONTENT_LENGTH POST_DATA <&0
./add "${REMOTE_ADDR}" "${username}" "${QUERY_STRING}" "${POST_DATA}"
;;
# Delete peer
'DELETE') ./delete "${REMOTE_ADDR}" "${QUERY_STRING}";;
*) exit 1;;
esac

15
back/docker-compose.yml Normal file
View File

@ -0,0 +1,15 @@
version: '3'
services:
dashboard:
build: srv/dashboard
container_name: wgapi_dashboard
cap_add:
- NET_ADMIN
network_mode: host
volumes:
- './etc:/etc/wgapi:ro'
- './lib:/usr/local/bin:ro'
- './srv/dashboard/tokens:/var/local/wgapi_tokens'
- './srv/dashboard:/var/www/cgi-bin:ro'
# ports:
# - '8080:80/tcp'

22
back/etc/config Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
# FILE: /etc/wgapi/config
# DESCRIPTION: Admin-editable configs
export TLD='gf4'
export LOGFILE='/var/log/apache2/error.log'
export LOCAL_SERVER='ksn'
export IPV4_NET='10.4.0.0/16'
export IPV6_NET='fd69:1337:0:420:f4:f4::/96'
export WG_DNS='DNS=10.4.0.1,10.4.0.3,fd69:1337:0:420:f4:f4:0:1,fd69:1337:0:420:f4:f4:0:3'
export LIB_DIR='/usr/local/bin'
export TOKENS_FILE='/var/local/wgapi_tokens'
export SERVERS_FILE='/etc/wgapi/servers'
export SSL_CONFIG_DIR="/etc/ssl/private/${TLD}"
export SSL_CA_CERT="${SSL_CONFIG_DIR}/_ca.crt"
export SSL_CA_KEY="${SSL_CONFIG_DIR}/_ca.key"
export SSL_ORG='My Org'
export SSL_DAYS='3650'
export SSL_CA_PASS='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
export DNS_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxw=='
export DNS_MASTER='10.4.0.1'
export DNS_TTL='86400'

3
back/etc/servers Executable file
View File

@ -0,0 +1,3 @@
# host ipv4 ipv6 pubkey wg-endpoint admin-endpoint secret
ksn 10.4.0.1 fd69:1337:0:420:f4:f4:0:1 /LrbvvmXLk2ZmU94JZua+eliqySuJ4QMHApthjvhO3s= 172.93.54.60:52348 https://wgapi-admin.ksn.gf4 Mipto0ncZ2KFglNHshfKCrYxyLtAfakfkt4q9SoHxr1lW
krow 10.4.0.3 fd69:1337:0:420:f4:f4:0:3 6VA79LOmlUaJSD1AiLEMCtnjMRZ7rwRrdbtNSCDtO2k= 85.17.214.157:56333 https://wgapi-admin.krow.gf4 x32JMJmET3ehGUJ1meGjqdkd9HBI3LhqxFMYzrVsw

26
back/lib/http_res Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash
# FILE: wgapi:back/lib/http/res
# DESCRIPTION: Formats an http response from arguments
# USAGE: [printf "message" |] res [200] [text/plain]
# Parse status
status=''
case "${1}" in
''|'0'|'200') status='Status: 200 OK\n';;
'400') status='Status: 400 Bad Request\n';;
'500') status='Status: 500 Internal Server Error\n';;
*) exit 3;;
esac
# Parse inputs
body="$(cat)"
content_type=''
if [ "${2}" == '' ] && [ "${body}" == '' ]
then content_type=''
elif [ "${2}" == '' ]
then content_type='Content-type: text/plain\n'
else content_type="Content-type: ${2}\n"
fi
# Send response
printf "${status}${content_type}\n${body}\n"

View File

@ -1,7 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/lookup/host
# DESCRIPTION: Get a hostname from an IP address
# USAGE: host ip
[ "$#" == "1" ] || exit
./send "${1}" | cut -d'=' -f2 | cut -d'.' -f1 | xargs

View File

@ -1,9 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/lookup/send
# DESCRIPTION: Send nslookup command to DNS master server
# USAGE: send cmd
[ "$#" == "1" ] || exit
source ../../../env/vars
# TODO: Check that nslookup is installed
/usr/bin/nslookup "${1}" "${DNS_MASTER}"

View File

@ -1,7 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/lookup/user
# DESCRIPTION: Get a username from an IP address
# USAGE: user ip
[ "$#" == "1" ] || exit
./send "${1}" | cut -d'=' -f2 | cut -d'.' -f1 | xargs

View File

@ -1,10 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/update/add
# DESCRIPTION: Add a new peer's domain to nameserver
# USAGE: add domain ipv4 ipv6
source ../../../../env/vars
# Keep these updates seperate because the zones are different
./send "update add ${1}. ${DNS_TTL} A ${2}\nupdate add ${1}. ${DNS_TTL} AAAA ${3}\nupdate add *.${1}. ${DNS_TTL} CNAME ${1}."
./send "update add $(./rev_ipv4 $2) ${DNS_TTL} PTR ${1}."
./send "update add $(./rev_ipv6 $3) ${DNS_TTL} PTR ${1}."

26
back/lib/ns_lookup_rdns Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/lookup/rdns
# DESCRIPTION: Get a domain from an IP address
# USAGE: rdns ip
# OUTPUT: The domain for that IP
# ERRORS:
# 3: bad usage
# 4: not found
# 5: server down
# 6: nslookup not found
# 7: config not found
# Accept exactly one argument
[ ${#} -eq 1 ] || exit 3
CONFIG_FILE='/etc/wgapi/config'
[ -f "${CONFIG_FILE}" ] || exit 7
source "${CONFIG_FILE}"
domain="$(${LIB_DIR}/ns_lookup_send ${1})"
case $? in
0) printf "${domain%.}" | cut -d'=' -f2 | xargs -0; exit 0;;
4) printf "Address not found: ${1}\n" >>"${LOGFILE}"; exit 4;;
5) printf "Nameserver not available: ${DNS_MASTER}\n" >>"${LOGFILE}"; exit 5;;
6) printf 'nslookup not installed!\n' >>"${LOGFILE}"; exit 6;;
*) printf "Bad usage: ${0} ${@}\n" >>"${LOGFILE}"; exit 3;;
esac

25
back/lib/ns_lookup_send Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/lookup/send
# DESCRIPTION: Send nslookup command to DNS master server
# USAGE: send cmd
# ERRORS:
# 3: bad usage
# 4: not found
# 5: server down
# 6: nslookup not found
# 7: config file not found
CONFIG_FILE='/etc/wgapi/config'
[ -f "${CONFIG_FILE}" ] || exit 7
[ "$#" == "1" ] || exit 3
[ -x /usr/bin/nslookup ] || exit 6
source "${CONFIG_FILE}"
res="$(/usr/bin/nslookup ${1} ${DNS_MASTER})"
#printf "${1} ${res}" >>"${LOGFILE}"
if printf "${res}" | grep ';; connection timed out'
then exit 5
elif printf "${res}" | grep "** server can't find "
then exit 4
else
printf "${res}"
fi

17
back/lib/ns_update_add Executable file
View File

@ -0,0 +1,17 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/update/add
# DESCRIPTION: Add a new peer's domain to nameserver
# USAGE: add domain ipv4 ipv6
# ERRORS:
# 3: Bad usage
# 4: config file not found
# 5: nsupdate failed
[ ${#} -eq 3 ] || exit 3
CONFIG_FILE='/etc/wgapi/config'
[ -f "${CONFIG_FILE}" ] || exit 4
source "${CONFIG_FILE}"
# Keep these updates seperate because the zones are different
( ./send "update add ${1}. ${DNS_TTL} A ${2}\nupdate add ${1}. ${DNS_TTL} AAAA ${3}\nupdate add *.${1}. ${DNS_TTL} CNAME ${1}." \
&& ./send "update add $(./rev_ipv4 $2) ${DNS_TTL} PTR ${1}." \
&& ./send "update add $(./rev_ipv6 $3) ${DNS_TTL} PTR ${1}." ) || exit 5

View File

@ -2,8 +2,14 @@
# FILE: wgapi:back/lib/ns/update/del
# DESCRIPTION: Use nsupdate to delete host RRs
# USAGE: del domain ipv4 ipv6
# ERRORS:
# 3: Bad usage
# 4: Config not found
source ../../../../env/vars
CONFIG_FILE='/etc/wgapi/config'
[ ${#} -eq 3 ] || exit 3
[ -f "${CONFIG_FILE}" ] || exit 5
source "${CONFIG_FILE}"
# Keep these updates seperate because the zones are different
./send "update delete ${1}. A\nupdate delete ${1}. AAAA\n update delete *.${1}. CNAME"
./send "update delete $(./rev_ipv4 $2) PTR"

View File

@ -2,7 +2,12 @@
# FILE: wgapi:back/lib/ns/update/send
# DESCRIPTION: Send stuff to the nsupdate server
# USAGE: send cmd
# ERRORS:
# 3: Bad usage
# 4: Missing config file
source ../../../env/vars
CONFIG_FILE='/etc/wgapi/config'
[ -f "${CONFIG_FILE}" ] || exit 4
source "${CONFIG_FILE}"
printf "server ${DNS_MASTER}\n${1}\nsend\n" \
| nsupdate -y "${DNS_KEY}"

View File

@ -2,37 +2,48 @@
# FILE: wgapi:back/lib/ssl/peer/add
# DESCRIPTION: Create SSL certs for a new host
# USAGE: add hostname username ipstring
# ERRORS:
# 3: Bad usage
# 4: config file not found
# 5: openssl or config not found
# 6: not root
# 7: openssl failed
[ "$#" == "" ] || exit
source ../../../env/vars
#TODO Check for root
CONFIG_FILE='/etc/wgapi/config'
[ ${#} -eq 0 ] || exit 3
(( ${EUID} == 0 )) || exit 6
[ -f "${CONFIG_FILE}" ] || exit 4
[ -x '/usr/bin/openssl' ] || exit 5
[ -f '/etc/ssl/openssl.cnf' ] || exit 5
source "${CONFIG_FILE}"
# Generate key
openssl genrsa -out "${SSL_CONFIG_DIR}/${username}/${hostname}/server.key" >/dev/null 2>&1
/usr/bin/openssl genrsa -out "${SSL_CONFIG_DIR}/${username}/${hostname}/server.key" >/dev/null 2>&1 || exit 7
chmod 400 "${SSL_CONFIG_DIR}/${username}/${hostname}/server.key"
# Generate config
#TODO Make sure /etc/ssl/openssl.cnf exists
cat '/etc/ssl/openssl.cnf' \
<(printf "\n[SAN]\nsubjectAltNames=DNS:${hostname}.${username}.${TLD},DNS:*.${hostname}.${username}.${TLD},${3}") \
> "${SSL_CONFIG_DIR}/${username}/${hostname}.cnf"
# Generate CSR
openssl req -new -sha256 -reqexts SAN \
/usr/bin/openssl req -new -sha256 -reqexts SAN \
-key "${SSL_CONFIG_DIR}/${username}/${hostname}/server.key" \
-out "${SSL_CONFIG_DIR}/${username}/${hostname}.csr"
-config "${SSL_CONFIG_DIR}/${username}/${hostname}.cnf" \
-subj "/O=${SSL_ORG}/OU=${username}/CN=${hostname}.${username}.${TLD}" \
>/dev/null 2>&1
>/dev/null 2>&1 || exit 7
# Generate cert
openssl x509 -req -sha256 -extensions SAN -CAcreateserial \
/usr/bin/openssl x509 -req -sha256 -extensions SAN -CAcreateserial \
-extfile "${SSL_CONFIG_DIR}/${username}/${hostname}.cnf" \
-in "${SSL_CONFIG_DIR}/${username}/${hostname}.csr" \
-CA "${SSL_CA_CERT}" -CAkey "${SSL_CA_KEY}" \
-passin "pass:${SSL_CA_PASS}" \
-out "${SSL_CONFIG_DIR}/${username}/${hostname}/server.crt"
-days "${SSL_DAYS}" >/dev/null 2>&1
-days "${SSL_DAYS}" >/dev/null 2>&1 || exit 7
chmod 644 "${SSL_CONFIG_DIR}/${username}/${hostname}/server.crt"
# Remove old files

View File

@ -2,8 +2,11 @@
# FILE: wgapi:back/lib/ssl/peer/del
# DESCRIPTION: Delete SSL cert for a removed device
# USAGE: del hostname username
# ERRORS:
# 3: Bad usage
# 4: Not root
[ "$#" == "2" ] || exit
#TODO Check for root
[ "$#" == "2" ] || exit 3
(( ${EUID} == 0 )) || exit 4
rm -rf "${SSL_CONFIG_DIR}/${username}/${hostname}/" 2>/dev/null
rm -rf "${SSL_CONFIG_DIR}/${username}/${hostname}.*" 2>/dev/null

View File

@ -1,8 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/lib/wg/peer/add
# DESCRIPTION: Add a new peer to a wireguard interface
# USAGE: add pubkey psk allowedips
[ "$#" == "3" ] || exit
source ../../../env/vars
/usr/bin/wg set "${TLD}" peer "${1}" preshared-key <(printf "${2}") allowed-ips "${3}"

View File

@ -1,8 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/lib/wg/peer/del
# DESCRIPTION: Delete a peer from a wireguard interface
# USAGE: del pubkey
[ "$#" == "3" ] || exit
source ../../../env/vars
/usr/bin/wg set "${TLD}" peer "${1}" remove

View File

@ -1,19 +0,0 @@
#!/bin/bash
# FILE: wgapi:back/lib/wg/peer/list
# DESCRIPTION: Get peers in the same subnet as an ip
# USAGE: list ip json|tsv
[ "$#" == "2" ] || exit
source ../../../env/vars
/usr/bin/wg show "${TLD}" allowed-ips | grep "${1[.:]*}" \
| while read pubkey ipv4 ipv6; do
ipv4="${ipv4%%/*}"
ipv6="${ipv6%%/*}"
hostname="$(../../ns/lookup/host ${ipv4})"
if [ "${2}" == 'json' ]; then
#TODO Remove keys with empty ("") values
printf "{\"hostname\":\"${hostname}\",\"ipv4\":\"${ipv4}\",\"ipv6\":\"${ipv6}\",\"pubkey\":\"${pubkey}\"},"
elif [ "${2}" == 'tsv' ]; then
printf "${hostname}\t${ipv4}\t${ipv6}\t${pubkey}\n"
fi
done | sed 's/,$//' # Remove trailing comma from json

19
back/lib/wg_peer_add Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash
# FILE: wgapi:back/lib/wg/peer/add
# DESCRIPTION: Add a new peer to a wireguard interface
# USAGE: add pubkey psk allowedips
# ERRORS:
# 3: Bad usage
# 4: wg binary not found
# 5: vars not found
# 6: wg command failed
# 7: Not root
CONFIG_FILE='/etc/wgapi/config'
[ "$#" == "3" ] || exit 3
[ -x /usr/bin/wg ] || exit 4
(( ${EUID} == 0 )) || exit 7
[ -f "${CONFIG_FILE}" ] || exit 5
source "${CONFIG_FILE}"
/usr/bin/wg set "${TLD}" peer "${1}" preshared-key <(printf "${2}") allowed-ips "${3}" || exit 6

19
back/lib/wg_peer_del Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash
# FILE: wgapi:back/lib/wg/peer/del
# DESCRIPTION: Delete a peer from a wireguard interface
# USAGE: del pubkey
# ERRORS:
# 3: Bad usage
# 4: wg binary not found
# 5: config not found
# 6: wg command failed
# 7: Not root
CONFIG_FILE='/etc/wgapi/config'
[ "$#" == "3" ] || exit 3
[ -x /usr/bin/wg ] || exit 4
(( ${EUID} == 0 )) || exit 7
[ -f "${CONFIG_FILE}" ] || exit 5
source "${CONFIG_FILE}"
/usr/bin/wg set "${TLD}" peer "${1}" remove || exit 6

42
back/lib/wg_peer_list Executable file
View File

@ -0,0 +1,42 @@
#!/bin/bash
# FILE: wg_peer_list
# DESCRIPTION: Get peers in the same subnet as an ip
# USAGE: list ip json|tsv
# ERRORS:
# 3: bad usage
# 4: nslookup failed
# 5: wg failed
# 6: Config file not found
# 7: wg not found
# 8: wg found no peers
CONFIG_FILE='/etc/wgapi/config'
[ -f "${CONFIG_FILE}" ] || ( printf "ERROR! ${0} Config file not found" >&2; exit 6 )
[ ${#} -eq 2 ] || ( printf "ERROR! Bad usage: $0 $@" >&2; exit 3 )
[ -x /usr/bin/wg ] || ( printf "ERROR! ${0} /usr/bin/wg not found" >&2; exit 5 )
source "${CONFIG_FILE}"
wg_output="$(/usr/bin/wg show ${TLD} allowed-ips)"
[ ${?} -ne 0 ] && (
printf "ERROR! Wireguard failed!\n" >>${LOGFILE}
exit 5
)
user_peers="$(grep ${1%[.:]*} <<<${wg_output} 2>/dev/null)"
[ "${user_peers}" == "" ] && (
printf "ERROR! ${1} accessed the dashboard but isn't on the network!\n" >>${LOGFILE}
exit 8
)
while IFS= read -r line; do # TODO: Do these dns lookups in parallel
pubkey="$(<<<${line} cut -d ' ' -f1)"
ips="$(<<<${line} cut -d ' ' -f2)"
ipv4="$(<<<${ips} cut -d ' ' -f1)"
ipv6="$(<<<${ips} cut -d ' ' -f2)"
ipv4="${ipv4%%/*}"
ipv6="${ipv6%%/*}"
domain="$(${LIB_DIR}/ns_lookup_rdns ${ipv4} | xargs)"
[ ${?} -ne 0 ] && exit 4 # Check if nslookup failed
case "${2}" in
'json') printf "{\"domain\":\"${domain}\",\"ipv4\":\"${ipv4}\",\"ipv6\":\"${ipv6}\",\"pubkey\":\"${pubkey}\"},";;
'tsv') printf "${domain}\t${ipv4}\t${ipv6}\t${pubkey}\n";;
esac
done <<<"${user_peers}" | sed 's/\n//g' | sed 's/,$//' # Remove trailing comma and newline

View File

@ -2,18 +2,28 @@
# FILE: wgapi:back/lib/wg/user/list
# DESCRIPTION: List all devices from all users
# USAGE: list json|tsv
# ERRORS:
# 3: bad usage
# 4: nslookup failed
# 5: Config not found
# 6: wg failed
[ "$#" == "1" ] || exit
source ../../../env/vars
CONFIG_FILE='/etc/wgapi/config'
[ ${#} -eq 1 ] || exit 3
[ -f "${CONFIG_FILE}" ] || exit 5
source "${CONFIG_FILE}"
#/usr/bin/wg show ${TLD} allowed-ips
/usr/bin/wg show "${TLD}" allowed-ips \
| while read pubkey ipv4 ipv6; do
ipv4="${ipv4%%/*}"
ipv6="${ipv6%%/*}"
#TODO Combine these next two into one nslookup
username="$(../../ns/lookup/user ${ipv4})"
hostname="$(../../ns/lookup/host ${ipv4})"
domain="$(../../ns/lookup/rdns ${ipv4})"
if [ ${?} -ne 0 ]
then exit 4
fi
username="$(printf ${domain} | cut -d'.' -f2)"
hostname="$(printf ${domain} | cut -d'.' -f1)"
if [ "${2}" == 'json' ]; then
#TODO Remove keys with empty ("") values
printf "{\"hostname\":\"${hostname}.${username}.${TLD}\",\"ipv4\":\"${ipv4}\",\"ipv6\":\"${ipv6}\",\"pubkey\":\"${pubkey}\"},"

View File

@ -1,26 +0,0 @@
server {
server_name localhost;
listen 8080;
gzip off;
autoindex on;
location / {
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include /etc/nginx/fastcgi_params;
include /etc/nginx/fastcgi.conf;
root /home/ki9/src/wgapi/srv;
fastcgi_index client;
}
}
server {
server_name localhost;
listen 8081;
gzip off;
autoindex on;
location / {
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include /etc/nginx/fastcgi_params;
include /etc/nginx/fastcgi.conf;
root /home/ki9/src/wgapi/srv;
fastcgi_index fed;
}
}

0
back/api/fed/add → back/srv/admin/nginx.conf Executable file → Normal file
View File

View File

@ -0,0 +1,8 @@
FROM debian:latest
RUN apt-get update && apt-get upgrade --yes
RUN apt-get install --yes sudo apache2 openssl wireguard-tools dnsutils
COPY apache2.conf /etc/apache2/sites-available/000-default.conf
RUN a2enmod cgi rewrite
RUN echo "www-data ALL=(ALL:ALL) NOPASSWD: ALL" | sudo EDITOR='tee -a' visudo
EXPOSE 80
CMD ["apachectl", "-D", "FOREGROUND"]

100
back/srv/dashboard/add Executable file
View File

@ -0,0 +1,100 @@
#!/bin/bash
# FILE: wgapi:back/api/dashboard/add
# DESCRIPTION: Add a new peer
# USAGE: add ip querystring
# ERRORS:
# 3: bad args/usage
# 4: vars file not found
# 5: Wireguard not installed
# 6: Hostname in use
# 7: Hostname too short
# 8: Invalid token
# 9: Token file not found
# 10: Failed to get peer data from wg
# 11: Failed to create new IPs
# 12: Servers file doesn't exist
# 15: Failed to add user to local wireguard
# 16: Failed to add user to federated server
CONFIG_FILE='/etc/wgapi/config'
SERVERS_FILE='/etc/wgapi/servers'
[ ${#} -eq 2 ] || exit 3
[ -f "${CONFIG_FILE}" ] || exit 4
[ -f "${TOKENS_FILE}" ] || exit 9
[ -f "${SERVERS_FILE}" ] || exit 12
source "${CONFIG_FILE}"
# Check hostname
hostname="$(printf ${2}\n | jq -r '.name' | xargs | tr -dc '[a-z0-9]' | head -c10)"
[[ ${#hostname} -ge 3 ]] || (
printf 'Hostname too short\n' | res 400
exit 7
)
username="$(${LIB_DIR}/ns_lookup_rdns ${REMOTE_ADDR} | cut -d'.' -f2)"
[ $? -ne 0 ] && (
printf 'User not found' | "${LIB)DIR}/http_res" 403
exit 403
) ||
# Check token
token_fail(){ printf 'Invalid token\n' | res 403; exit 8; }
saved_token=$(grep "${1}" "${TOKENS_FILE}" | cut -f2)
[ "${saved_token}" == "" ] && token_fail
printf "${username}" | grep "t=${saved_token}" || token_fail
# Check if new peer already exists
printf "${hostnames}" | grep "${hostname}" && (
printf "Hostname ${hostname} already exists!\n" | res 40
exit 6
)
# Collect/parse existing peer data
# Create new IPs and domain
peers="$(sudo ${LIB_DIR}/wg_peer_list ${1} tsv)"
[ ${?} -ne 0 ] && exit 10
hostnames="$(printf "${peers}" | awk '{print $0}' | cut -d'.' -f1)"
ipv4s="$(printf "${peers}" | awk '{print $1}')"
ipv6s="$(printf "${peers}" | awk '{print $2}')"
usernumber="$(printf ${ipv4s} head -n1 | cut -d'.' -f3)"
used_ips="$(printf ${ipv4s} | cut -d'.' -f3)\n$(printf ${ipv6s} | cut -d'.' -f3)"
used_hostnumbers="$(printf ${used_ipvs} | sort | uniq)"
hostnumber=1
while printf "${used_hostnumbers}" | grep "${hostnumber}"
do hostnumber++
done
ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}"
ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}"
domain="${hostname}.${username}.${TLD}"
# TODO: Check it or exit 11
# Create wg config
#TODO Check for /usr/bin/wg binary
privkey="$(/usr/bin/wg genkey)"
pubkey="$(echo $privkey | /usr/bin/wg pubkey)"
address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}"
server_blocks=''
while read server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_admin server_secret; do
server_psk="$(/usr/bin/wg genpsk)"
server_blocks="${server_blocks}\n[Peer] # ${server_hostname}.${TLD}\nPublicKey=${server_pubkey}\nPresharedKey=${server_psk}\nAllowedIPs=${server_ipv4}/32,${server_ipv6}/128\nEndpoint=${server_endpoint}\n"
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]
# Add new user to local server
then "${LIB_DIR}/wg_peer_add" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"
[ ${?} -ne 0 ] && printf 'Failed to add new peer ${ipv4} to local server!' >&2 # TODO: clear existing progress and exit 15
# Send new user config to federated server
else "${LIB_DIR}/fed_add" "${server_admin}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"
[ ${?} -ne 0 ] && printf 'Failed to add new peer ${ipv4} to federated server ${server_hostname}!' >&2 # TODO: clear existing progress and exit 16
fi
done <${SERVERS_FILE}
wg_config="[Interface] # ${hostname}.${username}.${TLD}\nPrivateKey=${privkey}\nAddress=${address}\n${WG_DNS}\n${server_blocks}"
# Respond to user
printf "${wg_config}" | "${LIB_DIR}/http_res"
# Update nameserver
"${LIB_DIR}/ns_update_add" "${domain}" "${ipv4}" "${ipv6}"
[ ${?} -ne 0 ] && printf "Failed to add ${domain} ${ipv4} ${ipv6} to DNS server!" >&2
# Create SSL cert
sudo "${LIB_DIR}/ssl_peer_add" "${hostname}" "${username}" "IP:${ipv4},IP:${ipv6}"
[ ${?} -ne 0 ] && printf "Failed to add ${domain} ${ipv4} ${ipv6} to DNS server!" >&2

View File

@ -0,0 +1,15 @@
<VirtualHost *:80>
ServerName localhost
#ServerAdmin webmaster@localhost
DocumentRoot /var/www/cgi-bin
LogLevel info
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
ScriptAlias "/" "/var/www/cgi-bin/"
<Directory /var/www/cgi-bin/>
AllowOverride None
#Options +ExecCGI
#SetHandler cgi-script
Require all granted
</Directory>
</VirtualHost>

View File

@ -8,8 +8,8 @@ fail() {
exit
}
[ "$#" == "2" ] || fail
source ../../env/vars
TOKENS_FILE='./tokens'
CONFIG_FILE='/etc/wgapi/config'
source "${CONFIG_FILE}"
# Check token
saved_token=$(grep "${1}" "${TOKENS_FILE}" | cut -f2)
@ -24,13 +24,13 @@ printf "Status: 202 Accepted\nContent-Type: text/plain\n\nDeleted\n"
while read server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_admin server_secret; do
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]
then ../../lib/wg/user/del "${pubkey}"
else ../../lib/fed/del "${server_admin}" "${pubkey}" "${server_secret}"
then "${LIB_DIR}/wg_user_del" "${pubkey}"
else "${LIB_DIR}/fed_del" "${server_admin}" "${pubkey}" "${server_secret}"
fi
done <../../env/servers
done <${SERVERS_FILE}
# Update nameserver
../../lib/ns/update/del "${domain}" "${ipv4}" "${ipv6}"
"${LIB_DIR}/ns_update_del" "${domain}" "${ipv4}" "${ipv6}"
# Delete SSL certs
sudo ../../lib/ssl/peer/del "${hostname}" "${username}"
sudo "${LIB_DIR}/ssl_peer_del" "${hostname}" "${username}"

38
back/srv/dashboard/index.cgi Executable file
View File

@ -0,0 +1,38 @@
#!/bin/bash
# FILE: wgapi:back/api/dashboard/index.cgi
# DESCRIPTION: Recieves incoming dashboard API requests
# USAGE: serve
# ERRORS:
# 3: Bad usage
# 4: Missing vars vile
CONFIG_FILE='/etc/wgapi/config'
[ -f "${CONFIG_FILE}" ] || exit 4
source "${CONFIG_FILE}"
case "${REQUEST_METHOD}" in
# List peers
'GET')
token="$(grep ${REMOTE_ADDR} ${TOKENS_FILE} | cut -f2)"
if [ "${token}" == "" ]; then
token="$(</dev/urandom tr -dc '[:alnum:]' | fold -w 64 | head -n 1)"
printf "${REMOTE_ADDR}\t${token}\n" >>"${TOKENS_FILE}"
fi
peers="[$(sudo ${LIB_DIR}/wg_peer_list ${REMOTE_ADDR} json)]"
case ${?} in
0) printf "${peers}" | "${LIB_DIR}/http_res" 200 'application/json';;
*) printf 'Failed to lookup user' | "${LIB_DIR}/http_res" 500;;
esac
;;
# Add peer
'POST') ./add "${REMOTE_ADDR}" "${username}" "${QUERY_STRING}" "${POST_DATA}";;
# Delete peer
'DELETE') ./delete "${REMOTE_ADDR}" "${QUERY_STRING}";;
# Bad request
*) printf 'Invalid HTTP verb' | "${LIB_DIR}/http_res" 400;;
esac && exit 0

23
back/srv/dashboard/tokens Normal file
View File

@ -0,0 +1,23 @@
172.27.0.1 xxaErrLvw1iSKmI2bIvAUbZwg9qEzWgz1gUsySon59KHCkhQ3CYjPY0jm4CjNVWC
172.28.0.1 oIAPZJzFzYV9SVXJnxrE0orLfu1PH388OOXT1tSN8AqGUQKZIDBT2bNy3gPzgfwl
172.29.0.1 t5jLNjw4KF1iYQGZfTOgydhWIM6rXWrSqqFvF5hRTOhQ0X7EWeQO2a9hzpHGP5yq
172.31.0.1 ZvVtj9YuoB8lNYByZZcjwZMBNkhTKqZw5A7udSgS445fyR0T0L1SDDNQM3fMKFCE
192.168.16.1 JjZBNHWQ0WR93yX997rPBCZrofxPffbZvxnNYp0ckwX1m3okiaf3PHVNhHnCBTNu
192.168.32.1 ukFhLudFQ0afzbycnJRumyegl9wJzoVFZGkO7gy5imsgPUA3nJQ49CHD2fHcFDCP
192.168.48.1 ZFeZLxVxZA51FtS28hk7ZGfSEA860EjYWz1ekyHXjMPeTrZyZBfR0QspxTBWaUdQ
192.168.64.1 xcL8TzG8JfqAwcE40FbPefYvxElAvRevpLjrsMuRyqxT2dyKUNm4fdvXRHMixtF2
192.168.80.1 NK0msKu08pzQ1v6emm6XoU80oNLjCc87fGtZky483KvX7n7V68omWA2p3yd4CFXV
192.168.96.1 QEOihdwGeCyQy9xrXdXRmBhcgkEs2f7lj7L9uR4REr1ASZAQaMA0eP4I5LdwQfBR
192.168.128.1 iQhMunQyzDYcEZSg5A2Hu8fkcG0w9dzZeL5YQBwxxuuKw3ZtnNkLomXXQvTPe1r0
192.168.144.1 QupcdsyxDruhoQbTZsmQ0iUzH5WAjecqCnKZQCmZhEd7qtQm958mkPi12WYOQXXT
192.168.160.1 Jc5ScdryW9fZFIyxjO4eWm1Xyh5LnUB32mSliIbGiWqW8rhQcUJpDZjMSl94ch6A
192.168.176.1 hikGzZrtocvVFO3gbAU0vyjXnaAzOu8vvAUuZ68pWMJY8LtZLwyTnbCfVZQU4W3K
192.168.192.1 OyXJ6yq3GJiZsumY9wqq5XSfaC7F8oZ3A18PcjYr1AOzHOuxGdYwVpzAOwIXv0iB
192.168.208.1 JUaD2QPNTrLlrRANS0TeC57pf3c5KTV4hlDJHfrbEpYx2OtmII4rWYkebAIGcz2S
192.168.224.1 qRItfROyQPaZXLo6FnDN6A0cI6umDpW53se0wiqsuCtyUkhs8DncJd5Yroj8coAg
192.168.240.1 LqwVxAabepe3brXKwLvjNdNAz6yafipzEQ0p8gXdZBzXQlf4Rxjxbl9XHjY0fTev
172.19.0.1 2jMFQMMtSrAnT8pVxcYbL7jumL4kgFXFeGNDdvy7dtQwyPBi5GMlm12UjtIHKx9Y
172.20.0.1 QIIK8Sl6S8cE2H9xKpvwBkXZNfd2UKVJU0hnKAeEJXdxEkUHtKEGv7PQ1DbDqv0i
10.4.1.2 OYTgelpqTuHuhw9WVTXyddvqSHInQGa7zIA73JD10mKDW2eerSIQHmyjgHigXdCt
127.0.0.1 jr8a6xGb2e9c8uQUH8sWBnumg8yySGFDttOkDIKMyJ46PAuhZIJHZ4njly3pHj6P
10.4.1.10 sJmL4hnD8FvmaBI4szGDY6Y8VMYCZsNo0jHoXg8R2xesQle1ElU7WgqTxLQsXLvn

0
back/srv/fed/del Executable file
View File