#9 Renamed to wagon and added README info

master
Keith Irwin 2023-04-02 13:46:52 -06:00
parent aed4b3959f
commit 14c6a0a2cd
Signed by: ki9
GPG Key ID: DF773B3F4A88DA86
40 changed files with 362 additions and 257 deletions

9
LICENSE.md Normal file
View File

@ -0,0 +1,9 @@
# The MIT License (MIT)
Copyright © 2023 Keith Irwin ([ki9.gf4.pw](https://ki9.gf4.pw/))
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

116
README.md
View File

@ -1,17 +1,113 @@
# wgapi
# wagon
2022-2023 Keith Irwin ([ki9.gf4.pw](https://ki9.gf4.pw/))
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
wgapi is a web application for managing a large number of hosts on a wireguard network. Each host is assigned a domain name on a custom top-level-domain (TLD) and TLS certificates are signed by a custom certificate authority (CA) and provided to the user.
`wagon` is a an api, user dashboard, and admin ui for managing devices and services on a dns-enabled wireguard network. It was built with small web communities in mind.
## Features
## IP address allocation
- Multi-server federation (hub-and-spoke networking with one or more hubs)
- No login screen; authentication is IP-based
- Private keys are not stored in a central location
- No database; all data are stored stored in wireguard and the nameserver
`wagon` manages devices on a wireguard network, `10.X.Y.Z/16` where `X` is a number associated with the community, configured at the first setup. Servers are hosted on `10.X.0.Z/24`, where each `Z` is a different server. Finally, each user gets a number `Y` (between 1 and 254) and a `/24` subnet for each of their their devices, `Z`.
## Installation
**For example:** Your home pc could be `10.11.1.1` and your phone `10.11.1.2`. After configuring wireguard, you can use either device to ping your friend, whose pc is at `10.11.2.1`.
Installation involves multiple steps.
IPv6 is also preconfigured for a `/96` subnet, with users getting their own `/112` network for each `/128` device.
**TODO**: Write complete implementation instructions
## Nameserver
`wagon` manages a bind9 nameserver through the `nsupdate` command. Device domain names have a similar structure as IP addresses, `A.B.C`, where:
- `C` is the community's top-level-domain (TLD)
- `B` is the username
- `A` is hostname of the device
The TLD could be anything that isn't already a global TLD like `.com`. The recursive nameserver provides private wireguard IPs to on this private domain zone. It must be configured to answer `.mynet` queries only within its own network on `10.X.0.0/16`. This nameserver is then preconfigured in clients' wireguard configs' `DNS = ` setting.
**For example:** Your home pc could be `pc.myuser.mynet` and your phone `phone.myuser.mynet`. Either can ping up `phone.myfriend.mynet`. These would point to `10.11.1.1`, `10.11.1.2`, and `10.11.2.1` respectively
Servers (IPs with `Y=0`) have domains of the form `A.C`, as above. Wildcard subdomains are CNAMEd to their base address, that is, `*.phone.myuser.mynet` CNAMEs to `phone.myuser.mynet` and `*.smyerver.mynet` CNAMEs to `myserver.mynet`. Of course, this means no username can match a server hostname.
The nameserver is also preconfigured for rDNS so you can perform lookups on IP addresses:
```sh
$ nslookup 10.11.1.1
1.1.11.10.in-addr.arpa name = pc.myuser.mynet.
```
Using this setup, the community's entire wireguard network and DNS can be accessed from any device by importing a single wireguard config. One purpose of `wagon` is to easily generate these device configs.
## Certificate authority
`wagon` also automatically signs SSL certs for its own invented TLD (`.mynet`) so network-hosted services can be encrypted. The certificates are signed for the IPs and wildcard domains listed above, so, with the right web proxy configuration, a user can use the *same* certificate to self-host a service on any of these domains:
- `https://10.11.1.2/`
- `https://[fd69:1337:0:420:f4:11:1:2]/`
- `https://mypc.myuser.mynet/`
- `https://myservice.mypc.myuser.mynet/`
- `https://myotherservice.mypc.myuser.mynet/`
- `https://anyotherservice.mypc.myuser.mynet/`
The `wagon` user dashboard provides a server certificate and key that the user can download. Any wireguard-connected device with the community's ca certificate imported in their browser or OS will be able to see a green lock on their browser when visiting these private sites.
These certs can be used for other internet protocols like irc or imap.
## Self-hosting and firewalls
Since firewalls and web proxies understand CIDR notation, controlling access to services is easy:
- Allow `10.11.1.1/32` to allow access to pc.myuser.mynet only
- Allow `10.11.1.0/24` to allow access to any of myuser's devices
- Allow `10.11.2.1/32` to allow access to a friend's pc
- Allow `10.11.2.0/24` to allow access to any of a friend's devices
- Allow `10.11.0.0/16` to allow access to anyone in the community
- Allow `10.0.0.0/8` to allow access to any other community (someday, maybe)
Allowing access to virtual webservers is just as simple. For example, I can let my friend access my development server with these allow/deny lines in an nginx vhost config (only showing IPv4, but works with IPv6 too).
```nginx
server {
server_name dev.mypc.myuser.mynet;
listen 10.11.1.1:443 ssh http2;
ssl_certificate /path/to/downloaded/mypc.myuser.mynet/server.crt;
ssl_certificate_key /path/to/downloaded/mypc.myuser.mynet/server.key;
ssl_stapling off;
allow 10.11.1.0/24; # My devices
allow 10.11.2.0/24; # My friend's devices
deny all; # Everyone else
# Proxy to local dev server
location / {
proxy_pass http://localhost:8080;
}
}
```
## Dashboard
Users can access a dashboard with a list of devices and links to download `server.crt` and `server.key`. Users can add and delete these devices, and admins can add/delete devices and users from a seperate admin interface. When adding a new user or device, the dashboard displays a wireguard configuration which must be copied or saved before the page is refreshed.
In this way, there is no central server storing all the private keys, like with most wireguard dashboards. In fact, `wagon` does not have a database and does not store any data at all; everything is stored in the server's nameserver and wireguard config.
This also means there is no login to the dashboard. Users simply connect to the dashboard over wireguard from any connected device, and `wagon` will recognize your IP and serve up a list of other devices on that same `/24` subnet.
## Structure
`wagon` is written in bash and run as a cgi script. It can be run in- or outside of docker. Why bash? Because it has great "SDKs" for wireguard (`wg`), nameserver updates (`nsupdate`), and SSL certs (`openssl`). The libraries used in the scripts are themselves scripts. Each script follows the unix philosophy of handling text through standard means (arguments and stdin to stdout), so individual libraries could be replaced with faster alternatives (c, rust, go) in the future.
## Project status
The wireguard dashboard and admin are in a working alpha state. I have it implemented on my own network, [gf4](https://www.gf4.pw/), and it seems to be working there. What still needs to be done:
- The code probably contains hardcoded variables specific to gf4, that must be moved to configs/environment files
- There is almost no documentation, and extensive tutorials are needed for the initial setup of wireguard, bind9, and the CA keys.
- Future implementation of a mail relay, web proxy, and SIP server, and their respective tabs on the web dashboard
- Replacing
## Contributing
If you think you can help with any of these bulletpoints, please reach out to me:
[@ki9:gf4.pw](matrix:@ki9:gf4.pw) on matrix
[wagon@ki9.gf4.pw](mailto:wagon@ki9.gf4.pw) by email
[https://ki9.gf4.pw/contact]()

View File

@ -7,9 +7,9 @@ RUN apt-get update && apt-get install --yes \
&& rm -rf /var/lib/apt/lists/*
# Create dirs and temp files
RUN mkdir /usr/lib/wgapi /var/log/wgapi /var/local/wgapi
RUN touch /var/local/wgapi/tokens
RUN chown -R www-data:www-data /usr/lib/wgapi /var/log/wgapi /var/local/wgapi
RUN mkdir /usr/lib/wagon /var/log/wagon /var/local/wagon
RUN touch /var/local/wagon/tokens
RUN chown -R www-data:www-data /usr/lib/wagon /var/log/wagon /var/local/wagon
# Configure apache
RUN a2enmod cgi rewrite
@ -26,7 +26,7 @@ RUN echo "www-data ALL=(ALL:ALL) NOPASSWD: /usr/bin/wg, /usr/bin/openssl, /usr/b
COPY admin_peer.cgi /usr/lib/cgi-bin/peer
COPY admin_user.cgi /usr/lib/cgi-bin/user
# TODO: Copy only needed libs
COPY lib/ /usr/lib/wgapi/
COPY lib/ /usr/lib/wagon/
# Run time!
EXPOSE ${PORT}

View File

@ -1,24 +1,24 @@
#!/bin/bash
# FILE: wgapi:back/admin_peer.cgi
# FILE: wagon:back/admin_peer.cgi
# DESCRIPTION: Recieves incoming admin requests for peer operations
source /etc/wgapi/config
source /etc/wagon/config
case "${REQUEST_METHOD}" in
# List peers
'GET') /usr/lib/wgapi/admin/peer/list "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'GET') /usr/lib/wagon/admin/peer/list "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Add peer
'POST') /usr/lib/wgapi/admin/peer/add "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'POST') /usr/lib/wagon/admin/peer/add "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Delete peer
'DELETE') /usr/lib/wgapi/admin/peer/del "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'DELETE') /usr/lib/wagon/admin/peer/del "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Needed for CORS preflight
'OPTIONS') /usr/lib/wgapi/http_res 200;;
'OPTIONS') /usr/lib/wagon/http_res 200;;
# Bad request
*) printf 'Invalid HTTP verb' | /usr/lib/wgapi/http_res 405;;
*) printf 'Invalid HTTP verb' | /usr/lib/wagon/http_res 405;;
esac

View File

@ -1,20 +1,20 @@
#!/bin/bash
# FILE: wgapi:back/admin_user.cgi
# FILE: wagon:back/admin_user.cgi
# DESCRIPTION: Server for requests to /user/
source /etc/wgapi/config
source /etc/wagon/config
case "${REQUEST_METHOD}" in
# Add new user
'POST') /usr/lib/wgapi/admin/user/add "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'POST') /usr/lib/wagon/admin/user/add "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Delete user
'DELETE') /usr/lib/wgapi/admin/user/del "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'DELETE') /usr/lib/wagon/admin/user/del "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Needed for CORS preflight
'OPTIONS') /usr/lib/wgapi/http_res 200;;
'OPTIONS') /usr/lib/wagon/http_res 200;;
# Bad request
*) printf 'Invalid HTTP verb' | /usr/lib/wgapi/http_res 405;;
*) printf 'Invalid HTTP verb' | /usr/lib/wagon/http_res 405;;
esac

View File

@ -7,9 +7,9 @@ RUN apt-get update && apt-get install --yes \
&& rm -rf /var/lib/apt/lists/*
# Create dirs and temp files
RUN mkdir /usr/lib/wgapi /var/log/wgapi /var/local/wgapi
RUN touch /var/local/wgapi/tokens
RUN chown -R www-data:www-data /usr/lib/wgapi /var/log/wgapi /var/local/wgapi
RUN mkdir /usr/lib/wagon /var/log/wagon /var/local/wagon
RUN touch /var/local/wagon/tokens
RUN chown -R www-data:www-data /usr/lib/wagon /var/log/wagon /var/local/wagon
# Configure apache
RUN a2enmod cgi rewrite
@ -26,7 +26,7 @@ RUN echo "www-data ALL=(ALL:ALL) NOPASSWD: /usr/bin/wg, /usr/bin/openssl, /usr/b
COPY dashboard.cgi /usr/lib/cgi-bin/index.cgi
COPY dashboard_ssl.cgi /usr/lib/cgi-bin/ssl
# TODO: Copy only needed libs
COPY lib/ /usr/lib/wgapi/
COPY lib/ /usr/lib/wagon/
# Run time!
EXPOSE ${PORT}

View File

@ -1,24 +1,24 @@
#!/bin/bash
# FILE: wgapi:back/dashboard.cgi
# FILE: wagon:back/dashboard.cgi
# DESCRIPTION: Recieves incoming dashboard API requests
source /etc/wgapi/config
source /etc/wagon/config
case "${REQUEST_METHOD}" in
# List peers
'GET') /usr/lib/wgapi/dashboard/peer/list "${HTTP_X_REAL_IP}";;
'GET') /usr/lib/wagon/dashboard/peer/list "${HTTP_X_REAL_IP}";;
# Add peer
'POST') /usr/lib/wgapi/dashboard/peer/add "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'POST') /usr/lib/wagon/dashboard/peer/add "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Delete peer
'DELETE') /usr/lib/wgapi/dashboard/peer/del "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'DELETE') /usr/lib/wagon/dashboard/peer/del "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Needed for CORS preflight
'OPTIONS') /usr/lib/wgapi/http_res 200;;
'OPTIONS') /usr/lib/wagon/http_res 200;;
# Bad request
*) printf 'Invalid HTTP verb' | /usr/lib/wgapi/http_res 405;;
*) printf 'Invalid HTTP verb' | /usr/lib/wagon/http_res 405;;
esac

View File

@ -1,15 +1,15 @@
#!/bin/bash
# FILE: wgapi:back/dashboard_ssl.cgi
# FILE: wagon:back/dashboard_ssl.cgi
# DESCRIPTION: Sends SSL certs and keys to users
source /etc/wgapi/config
source /etc/wagon/config
case "${REQUEST_METHOD}" in
# Get cert
'GET') /usr/lib/wgapi/dashboard/ssl "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'GET') /usr/lib/wagon/dashboard/ssl "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Bad request
*) printf 'Invalid HTTP verb' | /usr/lib/wgapi/http_res 405;;
*) printf 'Invalid HTTP verb' | /usr/lib/wagon/http_res 405;;
esac

View File

@ -7,8 +7,8 @@ RUN apt-get update && apt-get install --yes \
&& rm -rf /var/lib/apt/lists/*
# Create dirs and temp files
RUN mkdir /usr/lib/wgapi /var/log/wgapi
RUN chown -R www-data:www-data /usr/lib/wgapi /var/log/wgapi
RUN mkdir /usr/lib/wagon /var/log/wagon
RUN chown -R www-data:www-data /usr/lib/wagon /var/log/wagon
# Configure apache
RUN a2enmod cgi rewrite
@ -24,7 +24,7 @@ RUN echo "www-data ALL=(ALL:ALL) NOPASSWD: /usr/bin/wg, /usr/bin/[, /usr/bin/tee
# Copy over cgi and libs
COPY fed.cgi /usr/lib/cgi-bin/index.cgi
# TODO: Copy only needed libs
COPY lib/ /usr/lib/wgapi/
COPY lib/ /usr/lib/wagon/
# Run time!
EXPOSE ${PORT}

View File

@ -1,21 +1,21 @@
#!/bin/bash
# FILE: wgapi:back/fed.cgi
# FILE: wagon:back/fed.cgi
# DESCRIPTION: Recieves incoming federated requests
source /etc/wgapi/config
source /etc/wagon/config
case "${REQUEST_METHOD}" in
# Add
'POST') /usr/lib/wgapi/fed/peer/add "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'POST') /usr/lib/wagon/fed/peer/add "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Delete
'DELETE') /usr/lib/wgapi/fed/peer/del "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
'DELETE') /usr/lib/wagon/fed/peer/del "${HTTP_X_REAL_IP}" "${QUERY_STRING}";;
# Needed for CORS preflight
'OPTIONS') /usr/lib/wgapi/http_res 200;;
'OPTIONS') /usr/lib/wagon/http_res 200;;
# Bad request
*) printf 'Invalid HTTP verb' | /usr/lib/wgapi/http_res 405;;
*) printf 'Invalid HTTP verb' | /usr/lib/wagon/http_res 405;;
esac

View File

@ -4,15 +4,15 @@
# USAGE: add $remote_ip $querystring
# QUERYSTRING: ?t=$token&host=$newhostname&user=$username&num=$usernumber
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Check token
token_fail(){
printf 'Rejecting admin %s request for new peer due to %s token\n' "${ip}" "${1}" >&2
printf 'Invalid token\n' | /usr/lib/wgapi/http_res 403; exit 1
printf 'Invalid token\n' | /usr/lib/wagon/http_res 403; exit 1
}
saved_token="$(grep "${ip}" /var/local/wgapi/tokens | cut -f2)"
saved_token="$(grep "${ip}" /var/local/wagon/tokens | cut -f2)"
[ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2
@ -23,9 +23,9 @@ username="$(<<<"${qs}" grep -oP 'user=(.*)' | sed 's/^user=//')"
usernumber="$(<<<"${qs}" grep -oP 'num=(.*)' | sed 's/^num=//')"
if ! domain="${hostname:?}.${username:?}.${TLD:?}"; then
printf 'ERROR! Hostname "%s" or username "%s" or tld "%s" missing!\n' "${hostname}" "${username}" "${TLD}" >&2
printf 'Hostname or username missing!\n' | /usr/lib/wgapi/http_res 400; exit
printf 'Hostname or username missing!\n' | /usr/lib/wagon/http_res 400; exit
elif [[ "${usernumber}" == "" ]]; then
printf 'Usernumber missing!\n' | tee >(cat 1>&2) | /usr/lib/wgapi/http_res 400; exit
printf 'Usernumber missing!\n' | tee >(cat 1>&2) | /usr/lib/wagon/http_res 400; exit
else
printf 'Admin %s requested new peer %s for user number %s\n' "${ip}" "${domain}" "${usernumber}" >&2
fi
@ -33,31 +33,31 @@ fi
# Check hostname length
if ! [[ ${#hostname} -ge 3 ]]; then
printf 'Rejecting hostname %s because it is too short.\n' "${hostname}" >&2
printf 'Hostname too short\n' | /usr/lib/wgapi/http_res 400; exit
printf 'Hostname too short\n' | /usr/lib/wagon/http_res 400; exit
fi
# Check if new peer already exists
if /usr/lib/wgapi/ns_lookup_send "${domain}" >/dev/null; then
printf 'Host %s already exists!\n' "${domain}" | tee >(cat 1>&2) | /usr/lib/wgapi/http_res 409; exit
if /usr/lib/wagon/ns_lookup_send "${domain}" >/dev/null; then
printf 'Host %s already exists!\n' "${domain}" | tee >(cat 1>&2) | /usr/lib/wagon/http_res 409; exit
fi
# Get all peer IPs
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Filter out the user's
user_peers="$(grep "${IPV4_NET%.*.*}.${usernumber}." <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == "" ]; then
printf "ERROR! Couldn't find any peers for %s!\n" "${IPV4_NET%.*.*}.${usernumber}." >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Get user peer domains
if ! peers="$(/usr/lib/wgapi/ips_to_peers tsv <<<"${user_peers}")"; then
if ! peers="$(/usr/lib/wagon/ips_to_peers tsv <<<"${user_peers}")"; then
printf 'ERROR! Failed to retrieve peers for %s!\n' "${IPV4_NET%.*.*}.${usernumber}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Create new IPs
@ -72,7 +72,7 @@ ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}"
ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}"
if ! printf 'IP addresses for %s created: %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then
printf 'ERROR! Failed to create IP addresses for %s!' "${domain}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Create wg config
@ -81,13 +81,13 @@ pubkey="$(echo "${privkey}" | /usr/bin/wg pubkey)"
address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}"
# Update nameserver
if /usr/lib/wgapi/ns_update_add "${domain:?}" "${ipv4:?}" "${ipv6:?}"
if /usr/lib/wagon/ns_update_add "${domain:?}" "${ipv4:?}" "${ipv6:?}"
then printf 'Successfully added %s to DNS server.\n' "${domain}" >&2
else printf 'ERROR! Failed to add %s %s %s to DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi &
# Create SSL cert
if /usr/lib/wgapi/ssl_peer_add "${hostname:?}" "${username:?}" "IP:${ipv4},IP:${ipv6}"
if /usr/lib/wagon/ssl_peer_add "${hostname:?}" "${username:?}" "IP:${ipv4},IP:${ipv6}"
then printf 'Successfully signed SSL certs for %s\n' "${domain}" >&2
else printf 'ERROR! Failed to create certs for %s with IPS: %s %s!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi
@ -101,22 +101,22 @@ while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey se
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
server_blocks="${server_blocks}\n[Peer] # ${server_hostname}.${TLD}\nPublicKey=${server_pubkey}\nPresharedKey=${server_psk}\nAllowedIPs=${server_ipv4}/${IPV4_NET#*/},${server_ipv6}/${IPV6_NET#*/}\nEndpoint=${server_endpoint}\n"
# Add new user to local wireguard
if /usr/lib/wgapi/wg_peer_add "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"; then
if /usr/lib/wagon/wg_peer_add "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"; then
printf 'Added %s to local wireguard server.\n' "${domain}" >&2
else
printf 'ERROR! Failed to add %s to local wireguard server!\n' "${domain}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Remote server
else
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"
# Send new user config to federated server
if /usr/lib/wgapi/fed_peer_add "${server_url}" "${server_secret}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"; then
if /usr/lib/wagon/fed_peer_add "${server_url}" "${server_secret}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"; then
printf 'Sent %s to remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else
printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
fi
fi
done </etc/wgapi/servers
done </etc/wagon/servers
wg_config="[Interface] # ${hostname}.${username}.${TLD}\nPrivateKey=${privkey:?}\nAddress=${address:?}\n${WG_DNS}\n${server_blocks:?}"
<<<"${wg_config}" /usr/lib/wgapi/http_res 202
<<<"${wg_config}" /usr/lib/wagon/http_res 202

View File

@ -4,7 +4,7 @@
# USAGE: del $remote_ip $querystring
# QUERYSTRING: ?t=$token&pubkey=$pubkey
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Parse pubkey
@ -14,9 +14,9 @@ printf '%s requested to delete %s\n' "${ip}" "${pubkey}" >&2
# Check token
token_fail(){
printf 'Rejecting admin %s request to delete peer due to %s token\n' "${ip}" "${1}" >&2
printf 'Invalid token\n' | /usr/lib/wgapi/http_res 403; exit
printf 'Invalid token\n' | /usr/lib/wagon/http_res 403; exit
}
saved_token="$(grep "${ip}" /var/local/wgapi/tokens | cut -f2)"
saved_token="$(grep "${ip}" /var/local/wagon/tokens | cut -f2)"
[ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2
@ -24,33 +24,33 @@ printf '%s token was valid\n' "${ip}" >&2
# Get peer IP list
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Filter out this user's
user_peer="$(grep "${pubkey}" <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peer}" == "" ]; then
printf 'ERROR! Could not find user for pubkey %s!\n' "${pubkey}" >&2
printf 'Peer not found' | /usr/lib/wgapi/http_res 404; exit
printf 'Peer not found' | /usr/lib/wagon/http_res 404; exit
fi
# Get peer domains
if ! peer="$(/usr/lib/wgapi/ips_to_peers tsv <<<"${user_peer}" | grep "${pubkey}")"; then
if ! peer="$(/usr/lib/wagon/ips_to_peers tsv <<<"${user_peer}" | grep "${pubkey}")"; then
printf 'ERROR! Failed to lookup domain for pubkey %s!\n' "${pubkey}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
domain="$(<<<"${peer}" cut -f1)"
ipv4="$(<<<"${peer}" cut -f2)"
ipv6="$(<<<"${peer}" cut -f3)"
if ! printf 'Delete request was for %s %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then
printf 'ERROR! Failed to collect peer data: %s %s %s\n' "${domain}" "${ipv4}" "${ipv6}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Make sure admin isn't deleting their own peer
if [ "${ip}" == "${ipv4}" ] || [ "${ip}" == "${ipv6}" ]; then
printf 'Admin requested to delete peer from itself: %s.\n' "${ip}" >&2
printf 'You cannot delete a peer from itself!' | /usr/lib/wgapi/http_res 400; exit
printf 'You cannot delete a peer from itself!' | /usr/lib/wagon/http_res 400; exit
fi
hostname="$(<<<"${domain}" cut -d'.' -f1)"
@ -65,34 +65,34 @@ for_server_do() {
server_endpoint="${5}"; server_url="${6}"; server_secret="${7}"
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
# Local server
if /usr/lib/wgapi/wg_peer_del "${pubkey}"; then
if /usr/lib/wagon/wg_peer_del "${pubkey}"; then
printf 'Deleted %s from local wireguard server.\n' "${domain}" >&2
else
printf 'ERROR! Failed to delete %s from local wireguard server!\n' "${domain}" >&2
# TODO: clear existing progress
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
else
# Federated server
if /usr/lib/wgapi/fed_peer_del "${server_url}" "${server_secret}" "${pubkey}"; then
if /usr/lib/wagon/fed_peer_del "${server_url}" "${server_secret}" "${pubkey}"; then
printf 'Deleted %s from remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else
printf 'ERROR! Failed to delete %s from remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
fi
}; while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_url server_secret
do for_server_do "${server_hostname}" "${server_ipv4}" "${server_ipv6}" "${server_pubkey}" "${server_endpoint}" "${server_url}" "${server_secret}" &
done </etc/wgapi/servers &
done </etc/wagon/servers &
# Update nameserver
if /usr/lib/wgapi/ns_update_del "${domain:?}" "${ipv4:?}" "${ipv6:?}"
if /usr/lib/wagon/ns_update_del "${domain:?}" "${ipv4:?}" "${ipv6:?}"
then printf 'Successfully deleted %s from DNS server.\n' "${domain}" >&2
else printf 'ERROR! Failed to delete %s %s %s from DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi &
# Delete SSL cert
if /usr/lib/wgapi/ssl_peer_del "${hostname:?}" "${username:?}"
if /usr/lib/wagon/ssl_peer_del "${hostname:?}" "${username:?}"
then printf 'Successfully deleted SSL certs for %s\n' "${domain}" >&2
else printf 'ERROR! Failed to delete certs for %s!\n' "${domain}" >&2
fi
@ -101,4 +101,4 @@ fi
# Do it before updating nameserver and certs because
# if wireguard worked, there's no going back. The admin
# can clean up missing records and certs after checking the logs
printf 'Deleted %s.%s.%s' "${hostname}" "${username}" "${TLD}" | /usr/lib/wgapi/http_res 202
printf 'Deleted %s.%s.%s' "${hostname}" "${username}" "${TLD}" | /usr/lib/wagon/http_res 202

View File

@ -4,23 +4,23 @@
# USAGE: list $remote_ip $querystring
# QUERYSTRING: ?un=$username
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
un="$(<<<"${qs}" grep -oP 'un=(.*)' | sed 's/^un=//' | xargs)"
printf 'Admin %s requested peer listing...\n' "${ip}" >&2
# Create token if needed
token="$(grep "${ip}" /var/local/wgapi/tokens | cut -f2)"
token="$(grep "${ip}" /var/local/wagon/tokens | cut -f2)"
if [ "${token}" == "" ]; then
printf 'Creating token for %s...\n' "${ip}" >&2
token="$(</dev/urandom tr -dc '[:alnum:]' | fold -w64 | head -n1)"
printf '%s\t%s\n' "${ip}" "${token}" >>/var/local/wgapi/tokens
printf '%s\t%s\n' "${ip}" "${token}" >>/var/local/wagon/tokens
fi
# Get peer IP list
if ! peers="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Filter out single user (if provided)
@ -28,15 +28,15 @@ if [ "${un}" != '' ]; then
peers="$(grep "${IPV4_NET%.*.*}\.${un}\." <<<"${peers}" 2>/dev/null)"
if [ "${peers}" == '' ]; then
printf 'User number %s not found!\n' "${un}" >&2
printf 'User not found!\n' | /usr/lib/wgapi/http_res 404; exit
printf 'User not found!\n' | /usr/lib/wagon/http_res 404; exit
fi
fi
# Get domains for each peer
if peers="[$(/usr/lib/wgapi/ips_to_peers json <<<"${peers}")]"; then
printf '{"token":"%s","peers":%s}' "${token:?}" "${peers:?}" | /usr/lib/wgapi/http_res 200 'application/json'
if peers="[$(/usr/lib/wagon/ips_to_peers json <<<"${peers}")]"; then
printf '{"token":"%s","peers":%s}' "${token:?}" "${peers:?}" | /usr/lib/wagon/http_res 200 'application/json'
printf 'Sent peers to admin %s\n' "${ip}" >&2
else
printf 'ERROR: Failed to lookup user domain: %s\n' "${ip}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi

View File

@ -4,15 +4,15 @@
# USAGE: add $remote_ip $querystring
# QUERYSTRING: ?t=$token&host=$hostname&user=$username
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Check token
token_fail(){
printf 'Rejecting admin %s request for new peer due to %s token\n' "${ip}" "${1}" >&2
printf 'Invalid token\n' | /usr/lib/wgapi/http_res 403; exit
printf 'Invalid token\n' | /usr/lib/wagon/http_res 403; exit
}
saved_token="$(grep "${ip}" /var/local/wgapi/tokens | cut -f2)"
saved_token="$(grep "${ip}" /var/local/wagon/tokens | cut -f2)"
[ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2
@ -22,28 +22,28 @@ hostname="$(<<<"${qs}" grep -oP 'host=(.*)' | sed 's/^host=//' | xargs | tr -dc
username="$(<<<"${qs}" grep -oP 'user=(.*)' | sed 's/^user=//' | xargs | tr -dc 'a-z0-9' | head -c10)"
if ! domain="${hostname:?}.${username:?}.${TLD:?}"; then
printf 'ERROR! Hostname "%s" or username "%s" or tld "%s" missing!\n' "${hostname}" "${username}" "${TLD}" >&2
printf 'Hostname or username missing!\n' | /usr/lib/wgapi/http_res 400; exit
printf 'Hostname or username missing!\n' | /usr/lib/wagon/http_res 400; exit
else
printf 'Admin %s requested new user created with initial peer of %s\n' "${ip}" "${domain}" >&2
fi
if ! [[ ${#hostname} -ge 3 ]]; then
printf 'Rejecting hostname %s because it is too short.\n' "${hostname}" >&2
printf 'Hostname too short\n' | /usr/lib/wgapi/http_res 400; exit
printf 'Hostname too short\n' | /usr/lib/wagon/http_res 400; exit
elif ! [[ ${#username} -ge 3 ]]; then
printf 'Rejecting username %s because it is too short.\n' "${username}" >&2
printf 'Username too short\n' | /usr/lib/wgapi/http_res 400; exit
printf 'Username too short\n' | /usr/lib/wagon/http_res 400; exit
fi
# Check if user already exists
if /usr/lib/wgapi/ns_lookup_axfr | grep ".${username}.${TLD}" >/dev/null; then
printf 'User %s already exists!\n' "${username}" | tee >(cat 1>&2) | /usr/lib/wgapi/http_res 409
if /usr/lib/wagon/ns_lookup_axfr | grep ".${username}.${TLD}" >/dev/null; then
printf 'User %s already exists!\n' "${username}" | tee >(cat 1>&2) | /usr/lib/wagon/http_res 409
exit
fi
# Get all peer IPs
if ! peers="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Create new IPs
@ -59,7 +59,7 @@ ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}"
ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}"
if ! printf 'IP addresses for %s created: %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then
printf 'ERROR! Failed to create IP addresses for %s!' "${domain}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Create wg config
@ -68,7 +68,7 @@ pubkey="$(echo "${privkey}" | /usr/bin/wg pubkey)"
address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}"
# Update nameserver
if /usr/lib/wgapi/ns_update_add "${domain:?}" "${ipv4:?}" "${ipv6:?}"
if /usr/lib/wagon/ns_update_add "${domain:?}" "${ipv4:?}" "${ipv6:?}"
then printf 'Successfully added %s to DNS server.\n' "${domain}" >&2
else printf 'ERROR! Failed to add %s %s %s to DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi &
@ -76,9 +76,9 @@ fi &
# Create SSL cert
if ! sudo mkdir "${SSL_CONFIG_DIR:?}/${username:?}/"; then
printf 'Failed to create directory %s/%s/:\n' "${SSL_CONFIG_DIR}" "${username}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
if /usr/lib/wgapi/ssl_peer_add "${hostname:?}" "${username:?}" "IP:${ipv4},IP:${ipv6}"
if /usr/lib/wagon/ssl_peer_add "${hostname:?}" "${username:?}" "IP:${ipv4},IP:${ipv6}"
then printf 'Successfully signed SSL certs for %s\n' "${domain}" >&2
else printf 'ERROR! Failed to create certs for %s with IPS: %s %s!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi
@ -92,23 +92,23 @@ while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey se
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
server_blocks="${server_blocks}\n[Peer] # ${server_hostname}.${TLD}\nPublicKey=${server_pubkey}\nPresharedKey=${server_psk}\nAllowedIPs=${server_ipv4}/${IPV4_NET#*/},${server_ipv6}/${IPV6_NET#*/}\nEndpoint=${server_endpoint}\n"
# Add new user to local wireguard
if /usr/lib/wgapi/wg_peer_add "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"; then
if /usr/lib/wagon/wg_peer_add "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"; then
printf 'Added %s to local wireguard server.\n' "${domain}" >&2
else
printf 'ERROR! Failed to add %s to local wireguard server!\n' "${domain}" >&2
# TODO: clear existing progress
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Remote server
else
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"
# Send new user config to federated server
if /usr/lib/wgapi/fed_peer_add "${server_url}" "${server_secret}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"; then
if /usr/lib/wagon/fed_peer_add "${server_url}" "${server_secret}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"; then
printf 'Sent %s to remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else
printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
fi
fi
done </etc/wgapi/servers
done </etc/wagon/servers
wg_config="[Interface] # ${hostname}.${username}.${TLD}\nPrivateKey=${privkey:?}\nAddress=${address:?}\n${WG_DNS}\n${server_blocks:?}"
<<<"${wg_config}" /usr/lib/wgapi/http_res 202
<<<"${wg_config}" /usr/lib/wagon/http_res 202

View File

@ -4,15 +4,15 @@
# USAGE: del $remote_ip $querystring
# QUERYSTRING: ?t=$token&user=$username&un=$usernumber
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Check token
token_fail(){
printf 'Rejecting admin %s request for new peer due to %s token\n' "${ip}" "${1}" >&2
printf 'Invalid token\n' | /usr/lib/wgapi/http_res 403; exit
printf 'Invalid token\n' | /usr/lib/wagon/http_res 403; exit
}
saved_token="$(grep "${ip}" /var/local/wgapi/tokens | cut -f2)"
saved_token="$(grep "${ip}" /var/local/wagon/tokens | cut -f2)"
[ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2
@ -21,9 +21,9 @@ printf '%s token was valid\n' "${ip}" >&2
username="$(<<<"${qs}" grep -oP 'user=(.*)' | sed 's/^user=//')"
usernumber="$(<<<"${qs}" grep -oP 'un=(.*)' | sed 's/^un=//')"
if [[ "${username}" == "" ]]; then
printf 'ERROR! Username missing!\n' | tee >(cat 1>&2) | /usr/lib/wgapi/http_res 400; exit
printf 'ERROR! Username missing!\n' | tee >(cat 1>&2) | /usr/lib/wagon/http_res 400; exit
elif [[ "${usernumber}" == "" ]]; then
printf 'ERROR! Usernumber missing!\n' | tee >(cat 1>&2) |/usr/lib/wgapi/http_res 400; exit
printf 'ERROR! Usernumber missing!\n' | tee >(cat 1>&2) |/usr/lib/wagon/http_res 400; exit
else
printf 'Admin %s requested deletion of user "%s" with usernumber "%s"\n' "${ip}" "${username}" "${usernumber}" >&2
fi
@ -31,20 +31,20 @@ fi
# Get all peer IPs
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Filter out the user's
user_peers="$(grep "${IPV4_NET%.*.*}.${usernumber}." <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == "" ]; then
printf "ERROR! Couldn't find any peers for %s!\n" "${IPV4_NET%.*.*}.${usernumber}." >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Get user peer domains
if ! peers="$(/usr/lib/wgapi/ips_to_peers tsv <<<"${user_peers}")"; then
if ! peers="$(/usr/lib/wagon/ips_to_peers tsv <<<"${user_peers}")"; then
printf 'ERROR! Failed to retrieve domains for peers for %s!\n' "${IPV4_NET%.*.*}.${usernumber}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Run this function in parallel in the while loop below
@ -55,20 +55,20 @@ for_server_do() {
server_endpoint="${5}"; server_url="${6}"; server_secret="${7}"
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
# Local server
if /usr/lib/wgapi/wg_peer_del "${pubkey}"; then
if /usr/lib/wagon/wg_peer_del "${pubkey}"; then
printf 'Deleted %s from local wireguard server.\n' "${domain}" >&2
else
printf 'ERROR! Failed to delete %s from local wireguard server!\n' "${domain}" >&2
# TODO: clear existing progress
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
else
# Federated server
if /usr/lib/wgapi/fed_peer_del "${server_url}" "${server_secret}" "${pubkey}"; then
if /usr/lib/wagon/fed_peer_del "${server_url}" "${server_secret}" "${pubkey}"; then
printf 'Deleted %s from remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else
printf 'ERROR! Failed to delete %s from remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
fi
}
@ -82,10 +82,10 @@ delete_peer() {
# Remove peer from wireguard
while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_url server_secret
do for_server_do "${server_hostname}" "${server_ipv4}" "${server_ipv6}" "${server_pubkey}" "${server_endpoint}" "${server_url}" "${server_secret}" &
done </etc/wgapi/servers &
done </etc/wagon/servers &
# Remove peer from nameserver
if /usr/lib/wgapi/ns_update_del "${domain:?}" "${ipv4:?}" "${ipv6:?}"
if /usr/lib/wagon/ns_update_del "${domain:?}" "${ipv4:?}" "${ipv6:?}"
then printf 'Successfully deleted %s from DNS server.\n' "${domain}" >&2
else printf 'ERROR! Failed to delete %s %s %s from DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi
@ -104,4 +104,4 @@ fi
# Do it before updating nameserver and certs because
# if wireguard worked, there's no going back. The admin
# can clean up missing records and certs after checking the logs
printf 'Deleted %s' "${username}" | /usr/lib/wgapi/http_res 202
printf 'Deleted %s' "${username}" | /usr/lib/wagon/http_res 202

View File

@ -4,7 +4,7 @@
# USAGE: add $remote_ip $querystring
# QUERYSTRING: ?t=$token&name=$hostname
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Check hostname
@ -12,31 +12,31 @@ hostname="$(<<<"${qs}" grep -oP 'name=(.*)' | sed 's/^name//' | xargs | tr -dc '
printf '%s requested new peer with hostname %s\n' "${ip}" "${hostname}" >&2
if ! [[ ${#hostname} -ge 3 ]]; then
printf 'Rejecting hostname %s because it is too short.\n' "${hostname}" >&2
printf 'Hostname too short\n' | /usr/lib/wgapi/http_res 400; exit
printf 'Hostname too short\n' | /usr/lib/wagon/http_res 400; exit
fi
# Check token
token_fail(){
printf 'Rejecting %s request for new peer due to %s token\n' "${ip}" "${1}" >&2
printf 'Invalid token\n' | /usr/lib/wgapi/http_res 403; exit
printf 'Invalid token\n' | /usr/lib/wagon/http_res 403; exit
}
saved_token="$(grep "${ip}" /var/local/wgapi/tokens | cut -f2)"
saved_token="$(grep "${ip}" /var/local/wagon/tokens | cut -f2)"
[ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2
# Check user
username="$(/usr/lib/wgapi/ns_lookup_rdns "${ip}" | cut -d'.' -f2)" || (
username="$(/usr/lib/wagon/ns_lookup_rdns "${ip}" | cut -d'.' -f2)" || (
printf 'User domains not found for %s\n' "${ip}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
)
printf '%s identified as %s\n' "${ip}" "${username}" >&2
domain="${hostname}.${username}.${TLD}"
# Check if new peer already exists
if /usr/lib/wgapi/ns_lookup_send "${domain}" >/dev/null; then
if /usr/lib/wagon/ns_lookup_send "${domain}" >/dev/null; then
printf '%s.%s.%s already exists!\n' "${hostname}" "${username}" "${TLD}" >&2
printf 'Hostname %s already exists!\n' "${hostname}" | /usr/lib/wgapi/http_res 409; exit
printf 'Hostname %s already exists!\n' "${hostname}" | /usr/lib/wagon/http_res 409; exit
fi
# Create new domain
@ -46,27 +46,27 @@ printf 'New domain will be %s\n' "${domain}" >&2
# Get peer IP list
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Filter out this user's
user_peers="$(grep "${ip%[.:]*}" <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == "" ]; then
printf "ERROR! %s accessed the dashboard but isn't on the network!\n" "${ip}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Get domains
if ! peers="$(/usr/lib/wgapi/ips_to_peers tsv <<<"${user_peers}")"; then
if ! peers="$(/usr/lib/wagon/ips_to_peers tsv <<<"${user_peers}")"; then
printf 'ERROR! Failed to parse peers for %s!\n' "${ip}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Make sure hostname isn't taken
hostnames="$(<<<"${peers}" awk '{print $1}' | cut -d'.' -f1)"
if <<<"${hostnames}" grep -x "${hostname}"; then
printf 'User %s already has a host named %s!\n' "${username}" "${hostname}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Create new IPs
@ -82,7 +82,7 @@ ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}"
ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}"
if ! printf 'IP addresses for %s created: %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then
printf 'ERROR! Failed to create IP addresses for %s!' "${domain}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Create wg config
@ -91,13 +91,13 @@ pubkey="$(echo "${privkey}" | /usr/bin/wg pubkey)"
address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}"
# Update nameserver
if /usr/lib/wgapi/ns_update_add "${domain:?}" "${ipv4:?}" "${ipv6:?}"
if /usr/lib/wagon/ns_update_add "${domain:?}" "${ipv4:?}" "${ipv6:?}"
then printf 'Successfully added %s to DNS server.\n' "${domain}" >&2
else printf 'ERROR! Failed to add %s %s %s to DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi &
# Create SSL cert
if /usr/lib/wgapi/ssl_peer_add "${hostname:?}" "${username:?}" "IP:${ipv4},IP:${ipv6}"
if /usr/lib/wagon/ssl_peer_add "${hostname:?}" "${username:?}" "IP:${ipv4},IP:${ipv6}"
then printf 'Successfully signed SSL certs for %s\n' "${domain}" >&2
else printf 'ERROR! Failed to create certs for %s with IPS: %s %s!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi
@ -111,22 +111,22 @@ while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey se
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
server_blocks="${server_blocks}\n[Peer] # ${server_hostname}.${TLD}\nPublicKey=${server_pubkey}\nPresharedKey=${server_psk}\nAllowedIPs=${server_ipv4}/${IPV4_NET#*/},${server_ipv6}/${IPV6_NET#*/}\nEndpoint=${server_endpoint}\n"
# Add new user to local wireguard
if /usr/lib/wgapi/wg_peer_add "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"; then
if /usr/lib/wagon/wg_peer_add "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"; then
printf 'Added %s to local wireguard server.\n' "${domain}" >&2
else
printf 'ERROR! Failed to add %s to local wireguard server!\n' "${domain}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Remote server
else
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"
# Send new user config to federated server
if /usr/lib/wgapi/fed_peer_add "${server_url}" "${server_secret}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"; then
if /usr/lib/wagon/fed_peer_add "${server_url}" "${server_secret}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"; then
printf 'Sent %s to remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else
printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
fi
fi
done </etc/wgapi/servers
done </etc/wagon/servers
wg_config="[Interface] # ${hostname}.${username}.${TLD}\nPrivateKey=${privkey:?}\nAddress=${address:?}\n${WG_DNS}\n${server_blocks:?}"
<<<"${wg_config}" /usr/lib/wgapi/http_res 202
<<<"${wg_config}" /usr/lib/wagon/http_res 202

View File

@ -4,7 +4,7 @@
# USAGE: del $remote_ip $querystring
# QUERYSTRING: ?t=$token&pubkey=$pubkey
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Parse pubkey
@ -14,9 +14,9 @@ printf '%s requested to delete %s\n' "${ip}" "${pubkey:?}" >&2
# Check token
token_fail(){
printf 'Rejecting %s request to delete peer due to %s token\n' "${ip}" "${1}" >&2
printf 'Invalid token\n' | /usr/lib/wgapi/http_res 403; exit
printf 'Invalid token\n' | /usr/lib/wagon/http_res 403; exit
}
saved_token="$(grep "${ip}" /var/local/wgapi/tokens | cut -f2)"
saved_token="$(grep "${ip}" /var/local/wagon/tokens | cut -f2)"
[ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2
@ -24,33 +24,33 @@ printf '%s token was valid\n' "${ip}" >&2
# Get peer IP list
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Filter out this user's
user_peers="$(grep "${ip%[.:]*}" <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == "" ]; then
printf "ERROR! %s accessed the dashboard but isn't on the network!\n" "${ip}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Get peer domains
if ! peer="$(/usr/lib/wgapi/ips_to_peers tsv <<<"${user_peers}" | grep "${pubkey}")"; then
if ! peer="$(/usr/lib/wagon/ips_to_peers tsv <<<"${user_peers}" | grep "${pubkey}")"; then
printf 'ERROR! Peer %s not found for user %s!\n' "${pubkey}" "${ip}" >&2 &
printf 'Peer not found\n' | /usr/lib/wgapi/http_res 404; exit
printf 'Peer not found\n' | /usr/lib/wagon/http_res 404; exit
fi
domain="$(<<<"${peer}" cut -f1)"
ipv4="$(<<<"${peer}" cut -f2)"
ipv6="$(<<<"${peer}" cut -f3)"
if ! printf 'Delete request was for %s %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then
printf 'ERROR! Failed to collect peer data: %s %s %s\n' "${domain}" "${ipv4}" "${ipv6}" >&2 &
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Make sure user isn't deleting their own peer
if [ "${ip}" == "${ipv4}" ] || [ "${ip}" == "${ipv6}" ]; then
printf 'User requested to delete peer from itself: %s.\n' "${ip}" >&2
printf 'You cannot delete a peer from itself!' | /usr/lib/wgapi/http_res 400; exit
printf 'You cannot delete a peer from itself!' | /usr/lib/wagon/http_res 400; exit
fi
hostname="$(<<<"${domain}" cut -d'.' -f1)"
@ -65,34 +65,34 @@ for_server_do() {
server_endpoint="${5}"; server_url="${6}"; server_secret="${7}"
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
# Local server
if /usr/lib/wgapi/wg_peer_del "${pubkey}"; then
if /usr/lib/wagon/wg_peer_del "${pubkey}"; then
printf 'Deleted %s from local wireguard server.\n' "${domain}" >&2
else
printf 'ERROR! Failed to delete %s from local wireguard server!\n' "${domain}" >&2
# TODO: clear existing progress
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
else
# Federated server
if /usr/lib/wgapi/fed_peer_del "${server_url}" "${server_secret}" "${pubkey}"; then
if /usr/lib/wagon/fed_peer_del "${server_url}" "${server_secret}" "${pubkey}"; then
printf 'Deleted %s from remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else
printf 'ERROR! Failed to delete %s from remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
fi
}; while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_url server_secret
do for_server_do "${server_hostname}" "${server_ipv4}" "${server_ipv6}" "${server_pubkey}" "${server_endpoint}" "${server_url}" "${server_secret}" &
done </etc/wgapi/servers &
done </etc/wagon/servers &
# Update nameserver
if /usr/lib/wgapi/ns_update_del "${domain:?}" "${ipv4:?}" "${ipv6:?}"
if /usr/lib/wagon/ns_update_del "${domain:?}" "${ipv4:?}" "${ipv6:?}"
then printf 'Successfully deleted %s from DNS server.\n' "${domain}" >&2
else printf 'ERROR! Failed to delete %s %s %s from DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi &
# Create SSL cert
if /usr/lib/wgapi/ssl_peer_del "${hostname:?}" "${username:?}"
if /usr/lib/wagon/ssl_peer_del "${hostname:?}" "${username:?}"
then printf 'Successfully deleted SSL certs for %s\n' "${domain}" >&2
else printf 'ERROR! Failed to delete certs for %s!\n' "${domain}" >&2
fi
@ -101,4 +101,4 @@ fi
# Do it before updating nameserver and certs because
# if wireguard worked, there's no going back. The admin
# can clean up missing records and certs after checking the logs
printf 'Deleted %s.%s.%s' "${hostname}" "${username}" "${TLD}" | /usr/lib/wgapi/http_res 202
printf 'Deleted %s.%s.%s' "${hostname}" "${username}" "${TLD}" | /usr/lib/wagon/http_res 202

View File

@ -3,36 +3,36 @@
# DESCRIPTION: List a user's peers
# USAGE: list $remote_ip
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"
printf '%s requested peer listing...\n' "${ip}" >&2
# Create token if needed
token="$(grep "${ip}" /var/local/wgapi/tokens | cut -f2)"
token="$(grep "${ip}" /var/local/wagon/tokens | cut -f2)"
if [ "${token}" == "" ]; then
printf 'Creating token for %s...\n' "${ip}" >&2
token="$(</dev/urandom tr -dc '[:alnum:]' | fold -w 64 | head -n 1)"
printf '%s\t%s\n' "${ip}" "${token}" >>/var/local/wgapi/tokens
printf '%s\t%s\n' "${ip}" "${token}" >>/var/local/wagon/tokens
fi
# Get peer IP list
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Filter out this user's
user_peers="$(grep "${ip%[.:]*}" <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == '' ]; then
printf "ERROR! %s accessed the dashboard but isn't on the network!\n" "${ip}" >&2
printf 'User not found!\n' | /usr/lib/wgapi/http_res 403; exit
printf 'User not found!\n' | /usr/lib/wagon/http_res 403; exit
fi
# Get domains for each one
if peers="[$(/usr/lib/wgapi/ips_to_peers json <<<"${user_peers}")]"; then
printf '{"token":"%s","peers":%s}' "${token}" "${peers}" | /usr/lib/wgapi/http_res 200 'application/json'
if peers="[$(/usr/lib/wagon/ips_to_peers json <<<"${user_peers}")]"; then
printf '{"token":"%s","peers":%s}' "${token}" "${peers}" | /usr/lib/wagon/http_res 200 'application/json'
printf 'Sent peers to user %s\n' "${ip}" >&2
else
printf 'ERROR: Failed to lookup domains for user: %s\n' "${ip}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi

View File

@ -4,7 +4,7 @@
# USAGE: ssl remote_ip querystring
# QUERYSTRING: ?host=$hostname&ext=crt
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Parse querystring
@ -13,42 +13,42 @@ ext="$(<<<"${qs}" grep -oP 'ext=(.*)' | sed 's/^ext=//' | xargs)"
if ! file="${hostname:?}/server.${ext:?}"; then
printf 'ERROR! Hostname "%s" or extension "%s" missing!\n' "${hostname}" "${ext}" >&2
printf 'Hostname or extension missing!\n' | /usr/lib/wgapi/http_res 400; exit
printf 'Hostname or extension missing!\n' | /usr/lib/wagon/http_res 400; exit
else
printf 'User %s requested SSL file %s\n' "${ip}" "${file}" >&2
fi
# Make sure extension is 'crt' or 'key'
if [ "${ext}" != 'crt' ] && [ "${ext}" != 'key' ]; then
printf 'Invalid extension: %s\n' "${ext}" | tee >(cat 1>&2) | /usr/lib/wgapi/http_res 400; exit
printf 'Invalid extension: %s\n' "${ext}" | tee >(cat 1>&2) | /usr/lib/wagon/http_res 400; exit
fi
# Get username
if ! domain="$(/usr/lib/wgapi/ns_lookup_rdns "${ip}")"; then
printf 'ERROR! Failed to lookup domain from user IP %s\n' "${ip}" | tee >(cat 1>&2) | /usr/lib/wgapi/http_res 500
if ! domain="$(/usr/lib/wagon/ns_lookup_rdns "${ip}")"; then
printf 'ERROR! Failed to lookup domain from user IP %s\n' "${ip}" | tee >(cat 1>&2) | /usr/lib/wagon/http_res 500
exit 7
fi; if ! username="$(<<<"${domain}" cut -d'.' -f2)"; then
printf 'ERROR! Failed to parse username from domain "%s"\n' "${domain}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
else
printf 'User %s is "%s"\n' "${ip}" "${username}" >&2
fi
if ! path="${SSL_CONFIG_DIR:?}/${username:?}/${file}"; then
printf 'ERROR! Username "%s" or SSL_CONFIG_DIR "%s" missing!\n' "${username}" "${SSL_CONFIG_DIR}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Check that the file exists
if ! [ -f "${path}" ]; then
printf 'ERROR! File missing: "%s"\n' "${path}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
# Try to return it to the user
if <"${path}" /usr/lib/wgapi/http_res 200; then
if <"${path}" /usr/lib/wagon/http_res 200; then
printf 'Sent SSL file "%s" to %s\n' "${path}" "${username}" >&2
else
printf 'ERROR! Failed to return file: "%s"\n' "${path}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi

View File

@ -4,7 +4,7 @@
# USAGE: add $remote_ip $querystring
# QUERYSTRING: ?secret=$secret&pubkey=$pubkey&psk=$psk&ips=$allowedips
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
secret="$(<<<"${qs}" grep -oP 'secret=(.*)' | sed 's/^secret=//' | xargs)"
pubkey="$(<<<"${qs}" grep -oP 'pubkey=(.*)' | sed 's/^pubkey=//' | xargs)"
@ -12,24 +12,24 @@ psk="$(<<<"${qs}" grep -oP 'psk=(.*)' | sed 's/^psk=//' | xargs)"
allowedips="$(<<<"${qs}" grep -oP 'ips=(.*)' | sed 's/^ips=//' | xargs)"
# Check that requesting ip is in the servers file
if ! sed '/^#/d' /etc/wgapi/servers | cut -f2,3 | grep -qw "${ip}"; then
if ! sed '/^#/d' /etc/wagon/servers | cut -f2,3 | grep -qw "${ip}"; then
printf "ERROR! Federated server %s requested to create new peer but isn't in servers file!/n" "${ip}" >&2
/usr/lib/wgapi/http_res 403; exit
/usr/lib/wagon/http_res 403; exit
fi
# Check server secret
local_secret="$(grep -w "^${LOCAL_SERVER}" /etc/wgapi/servers | cut -f7)"
local_secret="$(grep -w "^${LOCAL_SERVER}" /etc/wagon/servers | cut -f7)"
if ! [ "${local_secret}" == "${secret}" ]; then
printf "ERROR! Federated server %s provided a secret, %s, that doesn't match the one in our servers file, %s\n" "${ip}" "${secret}" "${local_secret}" >&2
/usr/lib/wgapi/http_res 403; exit
/usr/lib/wagon/http_res 403; exit
fi
# Add peer to wireguard
if /usr/lib/wgapi/wg_peer_add "${pubkey}" "${psk}" "${allowedips}"; then
if /usr/lib/wagon/wg_peer_add "${pubkey}" "${psk}" "${allowedips}"; then
printf 'Added %s to wireguard.\n' "${pubkey}" >&2
else
printf 'ERROR! Failed to add %s to wireguard!\n' "${pubkey}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
/usr/lib/wgapi/http_res 200
/usr/lib/wagon/http_res 200

View File

@ -4,30 +4,30 @@
# USAGE: del $remote_ip $querystring
# QUERYSTRING: ?secret=$secret&pubkey=$pubkey
source /etc/wgapi/config
source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
secret="$(<<<"${qs}" grep -oP 'secret=(.*)' | sed 's/^secret=//' | xargs)"
pubkey="$(<<<"${qs}" grep -oP 'pubkey=(.*)' | sed 's/^pubkey=//' | xargs)"
# Check that requesting ip is in the servers file
if ! sed '/^#/d' /etc/wgapi/servers | cut -f2,3 | grep -qw "${ip}"; then
if ! sed '/^#/d' /etc/wagon/servers | cut -f2,3 | grep -qw "${ip}"; then
printf "ERROR! Federated server %s requested to create new peer but isn't in servers file!/n" "${ip}" >&2
/usr/lib/wgapi/http_res 403; exit
/usr/lib/wagon/http_res 403; exit
fi
# Check server secret
local_secret="$(grep -w "^${LOCAL_SERVER}" /etc/wgapi/servers | cut -f7)"
local_secret="$(grep -w "^${LOCAL_SERVER}" /etc/wagon/servers | cut -f7)"
if ! [ "${local_secret}" == "${secret}" ]; then
printf "ERROR! Federated server %s provided a secret, %s, that doesn't match the one in our servers file, %s\n" "${ip}" "${secret}" "${local_secret}" >&2
/usr/lib/wgapi/http_res 403; exit
/usr/lib/wagon/http_res 403; exit
fi
# Delete peer from wireguard
if /usr/lib/wgapi/wg_peer_del "${pubkey}"; then
if /usr/lib/wagon/wg_peer_del "${pubkey}"; then
printf 'Deleted %s from wireguard.\n' "${pubkey}" >&2
else
printf 'ERROR! Failed to delete %s from wireguard!\n' "${pubkey}" >&2
/usr/lib/wgapi/http_res 500; exit
/usr/lib/wagon/http_res 500; exit
fi
/usr/lib/wgapi/http_res 200
/usr/lib/wagon/http_res 200

View File

@ -3,7 +3,7 @@
# DESCRIPTION: Sends details about a new peer to a federated server
# USAGE: fed_peer_add url secret pubkey psk allowedips
source /etc/wgapi/config
source /etc/wagon/config
url="${1}"; secret="${2}"; pubkey="${3}"; psk="${4}"; allowedips="${5}"
if curl --silent -o /dev/null --fail --request POST --cacert "${SSL_CA_CERT}" "${url}?secret=${secret}&pubkey=${pubkey}&psk=${psk}&ips=${allowedips}"; then

View File

@ -3,7 +3,7 @@
# DESCRIPTION: Sends details to a federated server about a peer to be deleted
# USAGE: fed_peer_del url secret pubkey
source /etc/wgapi/config
source /etc/wagon/config
url="${1}"; secret="${2}"; pubkey="${3}"
if curl --silent -o /dev/null --fail --request DELETE --cacert "${SSL_CA_CERT}" "${url}?secret=${secret}&pubkey=${pubkey}"; then

View File

@ -1,5 +1,5 @@
#!/bin/bash
# FILE: wgapi:back/lib/http/res
# FILE: wagon:back/lib/http/res
# DESCRIPTION: Formats an http response from arguments
# USAGE: [printf "message" |] res [200] [text/plain]

View File

@ -9,11 +9,11 @@
# 5: Invalid format
# 6: Config file not found
source /etc/wgapi/config
source /etc/wagon/config
format="${1}"
# Perform AXFR lookup
res="$(/usr/lib/wgapi/ns_lookup_axfr)" || exit 4
res="$(/usr/lib/wagon/ns_lookup_axfr)" || exit 4
# This should read from stdin
# TODO: Run this loop in parallel

View File

@ -1,5 +1,5 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns_lookup_rxfr
# FILE: wagon:back/lib/ns_lookup_rxfr
# DESCRIPTION: Get all records
# USAGE: ns_lookup_rxfr
# OUTPUT: The complete set of records for the TLD
@ -11,9 +11,9 @@
# 7: nslookup refused
# 8: nslookup error
source /etc/wgapi/config
source /etc/wagon/config
res="$(/usr/lib/wgapi/ns_lookup_send "-query=AXFR" "${TLD}.")"
res="$(/usr/lib/wagon/ns_lookup_send "-query=AXFR" "${TLD}.")"
case $? in
0) printf '%s' "${res}"; exit 0;;
4) printf 'Domain for %s not found!\n' "${1}" >&2; exit 4;;

View File

@ -1,5 +1,5 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns_lookup_rdns
# FILE: wagon:back/lib/ns_lookup_rdns
# DESCRIPTION: Get a domain from an IP address
# USAGE: rdns ip
# OUTPUT: The domain for that IP
@ -9,9 +9,9 @@
# 5: nslookup not found
# 6: Bad usage
source /etc/wgapi/config
source /etc/wagon/config
domain="$(/usr/lib/wgapi/ns_lookup_send "${1}")"
domain="$(/usr/lib/wagon/ns_lookup_send "${1}")"
case $? in
0) printf '%s' "${domain%.}" | cut -d'=' -f2 | xargs -0; exit 0;;
4) printf 'Domain for %s not found!\n' "${1}" >&2; exit 3;;

View File

@ -1,5 +1,5 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns_lookup_send
# FILE: wagon:back/lib/ns_lookup_send
# DESCRIPTION: Send nslookup command to DNS master server
# USAGE: send [option] cmd
# ERRORS:
@ -8,7 +8,7 @@
# 5: other nslookup error
# 6: nslookup refused
source /etc/wgapi/config
source /etc/wagon/config
# Ignore SC2068 and leave ${@} unquoted so it can expand
if ! res="$(/usr/bin/nslookup ${@} "${DNS_MASTER}")"

View File

@ -1,14 +1,14 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/update/add
# FILE: wagon:back/lib/ns/update/add
# DESCRIPTION: Add a new peer's domain to nameserver
# USAGE: add domain ipv4 ipv6
source /etc/wgapi/config
source /etc/wagon/config
/usr/lib/wgapi/ns_update_send "update add ${1}. ${DNS_TTL} A ${2}
/usr/lib/wagon/ns_update_send "update add ${1}. ${DNS_TTL} A ${2}
update add ${1}. ${DNS_TTL} AAAA ${3}
update add *.${1}. ${DNS_TTL} CNAME ${1}.
send
update add $(/usr/lib/wgapi/ns_update_rev_ipv4 "${2}") ${DNS_TTL} PTR ${1}.
update add $(/usr/lib/wagon/ns_update_rev_ipv4 "${2}") ${DNS_TTL} PTR ${1}.
send
update add $(/usr/lib/wgapi/ns_update_rev_ipv6 "${3}") ${DNS_TTL} PTR ${1}." || exit 1
update add $(/usr/lib/wagon/ns_update_rev_ipv6 "${3}") ${DNS_TTL} PTR ${1}." || exit 1

View File

@ -1,14 +1,14 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/update/del
# FILE: wagon:back/lib/ns/update/del
# DESCRIPTION: Use nsupdate to delete host RRs
# USAGE: del domain ipv4 ipv6
source /etc/wgapi/config
source /etc/wagon/config
/usr/lib/wgapi/ns_update_send "update delete ${1}. A
/usr/lib/wagon/ns_update_send "update delete ${1}. A
update delete ${1}. AAAA
update delete *.${1}. CNAME
send
update delete $(/usr/lib/wgapi/ns_update_rev_ipv4 "${2}") PTR
update delete $(/usr/lib/wagon/ns_update_rev_ipv4 "${2}") PTR
send
update delete $(/usr/lib/wgapi/ns_update_rev_ipv6 "${3}") PTR" || exit 1
update delete $(/usr/lib/wagon/ns_update_rev_ipv6 "${3}") PTR" || exit 1

View File

@ -1,5 +1,5 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/update/rev_ipv4
# FILE: wagon:back/lib/ns/update/rev_ipv4
# DESCRIPTION: Returns the rDNS reversed version of an IPv4 address
# USAGE: rev_ipv4 10.2.0.1
# OUTPUT: 1.0.2.10.in-addr.arpa

View File

@ -1,5 +1,5 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/update/rev_ipv6
# FILE: wagon:back/lib/ns/update/rev_ipv6
# DESCRIPTION: Returns the rDNS reversed version of an IPv6 address
# USAGE: rev_ipv6 ...
# OUTPUT: ...ip6.arpa

View File

@ -1,9 +1,9 @@
#!/bin/bash
# FILE: wgapi:back/lib/ns/update/send
# FILE: wagon:back/lib/ns/update/send
# DESCRIPTION: Send stuff to the nsupdate server
# USAGE: send cmd
source /etc/wgapi/config
source /etc/wagon/config
printf 'server %s\n%s\nsend\n' "${DNS_MASTER}" "${1}" \
| nsupdate -y "${DNS_KEY}" | tee >(cat 1>&2)

View File

@ -1,5 +1,5 @@
#!/bin/bash
# FILE: wgapi:back/lib/ssl/peer/add
# FILE: wagon:back/lib/ssl/peer/add
# DESCRIPTION: Create SSL certs for a new host
# USAGE: add hostname username ipstring
# ERRORS:
@ -7,7 +7,7 @@
# 7: openssl failed
# 8: failed to set permissions
source /etc/wgapi/config
source /etc/wagon/config
hostname="${1}"; username="${2}"; ipstring="${3}"
# Make a directory for the new files

View File

@ -1,9 +1,9 @@
#!/bin/bash
# FILE: wgapi:back/lib/ssl/peer/del
# FILE: wagon:back/lib/ssl/peer/del
# DESCRIPTION: Delete SSL cert for a removed device
# USAGE: del hostname username
source /etc/wgapi/config
source /etc/wagon/config
hostname="${1}"; username="${2}"
if ! sudo rm -rf "${SSL_CONFIG_DIR:?}/${username:?}/${hostname:?}/" 2>/dev/null; then

View File

@ -1,9 +1,9 @@
#!/bin/bash
# FILE: wgapi:back/lib/wg/peer/add
# FILE: wagon:back/lib/wg/peer/add
# DESCRIPTION: Add a new peer to a wireguard interface
# USAGE: add pubkey psk allowedips
source /etc/wgapi/config
source /etc/wagon/config
pubkey="${1}"; psk="${2}"; allowedips="${3}"
if ! res="$(printf '%s\n' "${psk}" | sudo /usr/bin/wg set "${TLD}" peer "${pubkey}" preshared-key /dev/stdin allowed-ips "${allowedips}")"; then

View File

@ -1,9 +1,9 @@
#!/bin/bash
# FILE: wgapi:back/lib/wg/peer/del
# FILE: wagon:back/lib/wg/peer/del
# DESCRIPTION: Delete a peer from a wireguard interface
# USAGE: del pubkey
source /etc/wgapi/config
source /etc/wagon/config
if ! res="$(sudo /usr/bin/wg set "${TLD}" peer "${1}" remove)"; then
printf 'ERROR! Wireguard failed: %s\n' "${res}" >&2

View File

@ -1,15 +1,15 @@
#!/bin/bash
# FILE: wgapi:back/lib/wg/user/list
# FILE: wagon:back/lib/wg/user/list
# DESCRIPTION: List all devices from all users
# USAGE: list json|tsv
source /etc/wgapi/config
source /etc/wagon/config
/usr/bin/wg show "${TLD}" allowed-ips | \
while IFS=$' ' read -r pubkey ipv4 ipv6; do
ipv4="${ipv4%%/*}"
ipv6="${ipv6%%/*}"
domain="$(/usr/lib/wgapi/ns_lookup_rdns "${ipv4}")" || exit 4
domain="$(/usr/lib/wagon/ns_lookup_rdns "${ipv4}")" || exit 4
username="$(<<<"${domain}" cut -d'.' -f2)"
hostname="$(<<<"${domain}" cut -d'.' -f1)"
case "${2}" in

View File

@ -1,7 +1,7 @@
version: '3'
networks:
wgapi:
name: wgapi
wagon:
name: wagon
ipam:
config:
- subnet: "172.19.0.0/16"
@ -13,22 +13,22 @@ services:
dockerfile: dashboard.Dockerfile
args:
PORT: 4442
container_name: wgapi-dashboard-backend
container_name: wagon-dashboard-backend
cap_add:
- NET_ADMIN
network_mode: host
volumes:
- '/etc/ssl/private:/etc/ssl/private'
- './etc:/etc/wgapi:ro'
- '/var/log/wgapi.log:/var/log/apache2/error.log'
- './etc:/etc/wagon:ro'
- '/var/log/wagon.log:/var/log/apache2/error.log'
dashboard-frontend:
build:
context: front
dockerfile: dashboard.Dockerfile
container_name: wgapi-dashboard-frontend
container_name: wagon-dashboard-frontend
networks:
wgapi:
wagon:
ipv4_address: 172.19.0.2
admin-backend:
@ -40,19 +40,19 @@ services:
cap_add:
- NET_ADMIN
network_mode: host
container_name: wgapi-admin-backend
container_name: wagon-admin-backend
volumes:
- '/var/log/wgapi.log:/var/log/apache2/error.log'
- '/var/log/wagon.log:/var/log/apache2/error.log'
- '/etc/ssl/private:/etc/ssl/private'
- './etc:/etc/wgapi:ro'
- './etc:/etc/wagon:ro'
admin-frontend:
build:
context: front
dockerfile: admin.Dockerfile
container_name: wgapi-admin-frontend
container_name: wagon-admin-frontend
networks:
wgapi:
wagon:
ipv4_address: 172.19.0.3
fed-backend:
@ -64,7 +64,7 @@ services:
cap_add:
- NET_ADMIN
network_mode: host
container_name: wgapi-fed-backend
container_name: wagon-fed-backend
volumes:
- '/var/log/wgapi.log:/var/log/apache2/error.log'
- './etc:/etc/wgapi:ro'
- '/var/log/wagon.log:/var/log/apache2/error.log'
- './etc:/etc/wagon:ro'

View File

@ -1,3 +1,3 @@
# host ipv4 ipv6 pubkey wg-endpoint admin-endpoint secret
myhost1 10.3.0.1 fd69:1337:0:420:f4:f3:0:1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX= 123.123.123.123:51820 https://wgapi-admin.myhost2.tld XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
myhost2 10.3.0.2 fd69:1337:0:420:f4:f3:0:2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX= 234.234.234.234:51820 https://wgapi-admin.myhost2.tld XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
myhost1 10.3.0.1 fd69:1337:0:420:f4:f3:0:1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX= 123.123.123.123:51820 https://wagon-admin.myhost2.tld XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
myhost2 10.3.0.2 fd69:1337:0:420:f4:f3:0:2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX= 234.234.234.234:51820 https://wagon-admin.myhost2.tld XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX