#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/)) 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) `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`.
- 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
## 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/* && rm -rf /var/lib/apt/lists/*
# Create dirs and temp files # Create dirs and temp files
RUN mkdir /usr/lib/wgapi /var/log/wgapi /var/local/wgapi RUN mkdir /usr/lib/wagon /var/log/wagon /var/local/wagon
RUN touch /var/local/wgapi/tokens RUN touch /var/local/wagon/tokens
RUN chown -R www-data:www-data /usr/lib/wgapi /var/log/wgapi /var/local/wgapi RUN chown -R www-data:www-data /usr/lib/wagon /var/log/wagon /var/local/wagon
# Configure apache # Configure apache
RUN a2enmod cgi rewrite 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_peer.cgi /usr/lib/cgi-bin/peer
COPY admin_user.cgi /usr/lib/cgi-bin/user COPY admin_user.cgi /usr/lib/cgi-bin/user
# TODO: Copy only needed libs # TODO: Copy only needed libs
COPY lib/ /usr/lib/wgapi/ COPY lib/ /usr/lib/wagon/
# Run time! # Run time!
EXPOSE ${PORT} EXPOSE ${PORT}

View File

@ -1,24 +1,24 @@
#!/bin/bash #!/bin/bash
# FILE: wgapi:back/admin_peer.cgi # FILE: wagon:back/admin_peer.cgi
# DESCRIPTION: Recieves incoming admin requests for peer operations # DESCRIPTION: Recieves incoming admin requests for peer operations
source /etc/wgapi/config source /etc/wagon/config
case "${REQUEST_METHOD}" in case "${REQUEST_METHOD}" in
# List peers # 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 # 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 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 # Needed for CORS preflight
'OPTIONS') /usr/lib/wgapi/http_res 200;; 'OPTIONS') /usr/lib/wagon/http_res 200;;
# Bad request # Bad request
*) printf 'Invalid HTTP verb' | /usr/lib/wgapi/http_res 405;; *) printf 'Invalid HTTP verb' | /usr/lib/wagon/http_res 405;;
esac esac

View File

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

View File

@ -7,9 +7,9 @@ RUN apt-get update && apt-get install --yes \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Create dirs and temp files # Create dirs and temp files
RUN mkdir /usr/lib/wgapi /var/log/wgapi /var/local/wgapi RUN mkdir /usr/lib/wagon /var/log/wagon /var/local/wagon
RUN touch /var/local/wgapi/tokens RUN touch /var/local/wagon/tokens
RUN chown -R www-data:www-data /usr/lib/wgapi /var/log/wgapi /var/local/wgapi RUN chown -R www-data:www-data /usr/lib/wagon /var/log/wagon /var/local/wagon
# Configure apache # Configure apache
RUN a2enmod cgi rewrite 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.cgi /usr/lib/cgi-bin/index.cgi
COPY dashboard_ssl.cgi /usr/lib/cgi-bin/ssl COPY dashboard_ssl.cgi /usr/lib/cgi-bin/ssl
# TODO: Copy only needed libs # TODO: Copy only needed libs
COPY lib/ /usr/lib/wgapi/ COPY lib/ /usr/lib/wagon/
# Run time! # Run time!
EXPOSE ${PORT} EXPOSE ${PORT}

View File

@ -1,24 +1,24 @@
#!/bin/bash #!/bin/bash
# FILE: wgapi:back/dashboard.cgi # FILE: wagon:back/dashboard.cgi
# DESCRIPTION: Recieves incoming dashboard API requests # DESCRIPTION: Recieves incoming dashboard API requests
source /etc/wgapi/config source /etc/wagon/config
case "${REQUEST_METHOD}" in case "${REQUEST_METHOD}" in
# List peers # 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 # 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 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 # Needed for CORS preflight
'OPTIONS') /usr/lib/wgapi/http_res 200;; 'OPTIONS') /usr/lib/wagon/http_res 200;;
# Bad request # Bad request
*) printf 'Invalid HTTP verb' | /usr/lib/wgapi/http_res 405;; *) printf 'Invalid HTTP verb' | /usr/lib/wagon/http_res 405;;
esac esac

View File

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

View File

@ -7,8 +7,8 @@ RUN apt-get update && apt-get install --yes \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Create dirs and temp files # Create dirs and temp files
RUN mkdir /usr/lib/wgapi /var/log/wgapi RUN mkdir /usr/lib/wagon /var/log/wagon
RUN chown -R www-data:www-data /usr/lib/wgapi /var/log/wgapi RUN chown -R www-data:www-data /usr/lib/wagon /var/log/wagon
# Configure apache # Configure apache
RUN a2enmod cgi rewrite 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 over cgi and libs
COPY fed.cgi /usr/lib/cgi-bin/index.cgi COPY fed.cgi /usr/lib/cgi-bin/index.cgi
# TODO: Copy only needed libs # TODO: Copy only needed libs
COPY lib/ /usr/lib/wgapi/ COPY lib/ /usr/lib/wagon/
# Run time! # Run time!
EXPOSE ${PORT} EXPOSE ${PORT}

View File

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

View File

@ -4,15 +4,15 @@
# USAGE: add $remote_ip $querystring # USAGE: add $remote_ip $querystring
# QUERYSTRING: ?t=$token&host=$newhostname&user=$username&num=$usernumber # 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/?//')" ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Check token # Check token
token_fail(){ token_fail(){
printf 'Rejecting admin %s request for new peer due to %s token\n' "${ip}" "${1}" >&2 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' [ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched' <<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2 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=//')" usernumber="$(<<<"${qs}" grep -oP 'num=(.*)' | sed 's/^num=//')"
if ! domain="${hostname:?}.${username:?}.${TLD:?}"; then if ! domain="${hostname:?}.${username:?}.${TLD:?}"; then
printf 'ERROR! Hostname "%s" or username "%s" or tld "%s" missing!\n' "${hostname}" "${username}" "${TLD}" >&2 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 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 else
printf 'Admin %s requested new peer %s for user number %s\n' "${ip}" "${domain}" "${usernumber}" >&2 printf 'Admin %s requested new peer %s for user number %s\n' "${ip}" "${domain}" "${usernumber}" >&2
fi fi
@ -33,31 +33,31 @@ fi
# Check hostname length # Check hostname length
if ! [[ ${#hostname} -ge 3 ]]; then if ! [[ ${#hostname} -ge 3 ]]; then
printf 'Rejecting hostname %s because it is too short.\n' "${hostname}" >&2 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 fi
# Check if new peer already exists # 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 'Host %s already exists!\n' "${domain}" | tee >(cat 1>&2) | /usr/lib/wgapi/http_res 409; exit printf 'Host %s already exists!\n' "${domain}" | tee >(cat 1>&2) | /usr/lib/wagon/http_res 409; exit
fi fi
# Get all peer IPs # Get all peer IPs
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2 printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
# Filter out the user's # Filter out the user's
user_peers="$(grep "${IPV4_NET%.*.*}.${usernumber}." <<<"${wg_output}" 2>/dev/null)" user_peers="$(grep "${IPV4_NET%.*.*}.${usernumber}." <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == "" ]; then if [ "${user_peers}" == "" ]; then
printf "ERROR! Couldn't find any peers for %s!\n" "${IPV4_NET%.*.*}.${usernumber}." >&2 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 fi
# Get user peer domains # 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 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 fi
# Create new IPs # Create new IPs
@ -72,7 +72,7 @@ ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}"
ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}" ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}"
if ! printf 'IP addresses for %s created: %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then 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 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 fi
# Create wg config # Create wg config
@ -81,13 +81,13 @@ pubkey="$(echo "${privkey}" | /usr/bin/wg pubkey)"
address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}" address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}"
# Update nameserver # 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 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 else printf 'ERROR! Failed to add %s %s %s to DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi & fi &
# Create SSL cert # 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 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 else printf 'ERROR! Failed to create certs for %s with IPS: %s %s!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi 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 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" 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 # 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 printf 'Added %s to local wireguard server.\n' "${domain}" >&2
else else
printf 'ERROR! Failed to add %s to local wireguard server!\n' "${domain}" >&2 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 fi
# Remote server # Remote server
else 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" 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 # 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 printf 'Sent %s to remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else else
printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2 printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
fi fi
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="[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 # USAGE: del $remote_ip $querystring
# QUERYSTRING: ?t=$token&pubkey=$pubkey # QUERYSTRING: ?t=$token&pubkey=$pubkey
source /etc/wgapi/config source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')" ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Parse pubkey # Parse pubkey
@ -14,9 +14,9 @@ printf '%s requested to delete %s\n' "${ip}" "${pubkey}" >&2
# Check token # Check token
token_fail(){ token_fail(){
printf 'Rejecting admin %s request to delete peer due to %s token\n' "${ip}" "${1}" >&2 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' [ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched' <<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2 printf '%s token was valid\n' "${ip}" >&2
@ -24,33 +24,33 @@ printf '%s token was valid\n' "${ip}" >&2
# Get peer IP list # Get peer IP list
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2 printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
# Filter out this user's # Filter out this user's
user_peer="$(grep "${pubkey}" <<<"${wg_output}" 2>/dev/null)" user_peer="$(grep "${pubkey}" <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peer}" == "" ]; then if [ "${user_peer}" == "" ]; then
printf 'ERROR! Could not find user for pubkey %s!\n' "${pubkey}" >&2 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 fi
# Get peer domains # 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 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 fi
domain="$(<<<"${peer}" cut -f1)" domain="$(<<<"${peer}" cut -f1)"
ipv4="$(<<<"${peer}" cut -f2)" ipv4="$(<<<"${peer}" cut -f2)"
ipv6="$(<<<"${peer}" cut -f3)" ipv6="$(<<<"${peer}" cut -f3)"
if ! printf 'Delete request was for %s %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then 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 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 fi
# Make sure admin isn't deleting their own peer # Make sure admin isn't deleting their own peer
if [ "${ip}" == "${ipv4}" ] || [ "${ip}" == "${ipv6}" ]; then if [ "${ip}" == "${ipv4}" ] || [ "${ip}" == "${ipv6}" ]; then
printf 'Admin requested to delete peer from itself: %s.\n' "${ip}" >&2 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 fi
hostname="$(<<<"${domain}" cut -d'.' -f1)" hostname="$(<<<"${domain}" cut -d'.' -f1)"
@ -65,34 +65,34 @@ for_server_do() {
server_endpoint="${5}"; server_url="${6}"; server_secret="${7}" server_endpoint="${5}"; server_url="${6}"; server_secret="${7}"
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
# Local server # 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 printf 'Deleted %s from local wireguard server.\n' "${domain}" >&2
else else
printf 'ERROR! Failed to delete %s from local wireguard server!\n' "${domain}" >&2 printf 'ERROR! Failed to delete %s from local wireguard server!\n' "${domain}" >&2
# TODO: clear existing progress # TODO: clear existing progress
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
else else
# Federated server # 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 printf 'Deleted %s from remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else else
printf 'ERROR! Failed to delete %s from remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2 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
fi fi
}; while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_url server_secret }; 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}" & 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 # 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 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 else printf 'ERROR! Failed to delete %s %s %s from DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi & fi &
# Delete SSL cert # 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 then printf 'Successfully deleted SSL certs for %s\n' "${domain}" >&2
else printf 'ERROR! Failed to delete certs for %s!\n' "${domain}" >&2 else printf 'ERROR! Failed to delete certs for %s!\n' "${domain}" >&2
fi fi
@ -101,4 +101,4 @@ fi
# Do it before updating nameserver and certs because # Do it before updating nameserver and certs because
# if wireguard worked, there's no going back. The admin # if wireguard worked, there's no going back. The admin
# can clean up missing records and certs after checking the logs # 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 # USAGE: list $remote_ip $querystring
# QUERYSTRING: ?un=$username # QUERYSTRING: ?un=$username
source /etc/wgapi/config source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')" ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
un="$(<<<"${qs}" grep -oP 'un=(.*)' | sed 's/^un=//' | xargs)" un="$(<<<"${qs}" grep -oP 'un=(.*)' | sed 's/^un=//' | xargs)"
printf 'Admin %s requested peer listing...\n' "${ip}" >&2 printf 'Admin %s requested peer listing...\n' "${ip}" >&2
# Create token if needed # 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 if [ "${token}" == "" ]; then
printf 'Creating token for %s...\n' "${ip}" >&2 printf 'Creating token for %s...\n' "${ip}" >&2
token="$(</dev/urandom tr -dc '[:alnum:]' | fold -w64 | head -n1)" 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 fi
# Get peer IP list # Get peer IP list
if ! peers="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then if ! peers="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2 printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
# Filter out single user (if provided) # Filter out single user (if provided)
@ -28,15 +28,15 @@ if [ "${un}" != '' ]; then
peers="$(grep "${IPV4_NET%.*.*}\.${un}\." <<<"${peers}" 2>/dev/null)" peers="$(grep "${IPV4_NET%.*.*}\.${un}\." <<<"${peers}" 2>/dev/null)"
if [ "${peers}" == '' ]; then if [ "${peers}" == '' ]; then
printf 'User number %s not found!\n' "${un}" >&2 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
fi fi
# Get domains for each peer # Get domains for each peer
if peers="[$(/usr/lib/wgapi/ips_to_peers json <<<"${peers}")]"; then if peers="[$(/usr/lib/wagon/ips_to_peers json <<<"${peers}")]"; then
printf '{"token":"%s","peers":%s}' "${token:?}" "${peers:?}" | /usr/lib/wgapi/http_res 200 'application/json' printf '{"token":"%s","peers":%s}' "${token:?}" "${peers:?}" | /usr/lib/wagon/http_res 200 'application/json'
printf 'Sent peers to admin %s\n' "${ip}" >&2 printf 'Sent peers to admin %s\n' "${ip}" >&2
else else
printf 'ERROR: Failed to lookup user domain: %s\n' "${ip}" >&2 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 fi

View File

@ -4,15 +4,15 @@
# USAGE: add $remote_ip $querystring # USAGE: add $remote_ip $querystring
# QUERYSTRING: ?t=$token&host=$hostname&user=$username # QUERYSTRING: ?t=$token&host=$hostname&user=$username
source /etc/wgapi/config source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')" ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Check token # Check token
token_fail(){ token_fail(){
printf 'Rejecting admin %s request for new peer due to %s token\n' "${ip}" "${1}" >&2 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' [ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched' <<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2 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)" username="$(<<<"${qs}" grep -oP 'user=(.*)' | sed 's/^user=//' | xargs | tr -dc 'a-z0-9' | head -c10)"
if ! domain="${hostname:?}.${username:?}.${TLD:?}"; then if ! domain="${hostname:?}.${username:?}.${TLD:?}"; then
printf 'ERROR! Hostname "%s" or username "%s" or tld "%s" missing!\n' "${hostname}" "${username}" "${TLD}" >&2 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 else
printf 'Admin %s requested new user created with initial peer of %s\n' "${ip}" "${domain}" >&2 printf 'Admin %s requested new user created with initial peer of %s\n' "${ip}" "${domain}" >&2
fi fi
if ! [[ ${#hostname} -ge 3 ]]; then if ! [[ ${#hostname} -ge 3 ]]; then
printf 'Rejecting hostname %s because it is too short.\n' "${hostname}" >&2 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 elif ! [[ ${#username} -ge 3 ]]; then
printf 'Rejecting username %s because it is too short.\n' "${username}" >&2 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 fi
# Check if user already exists # Check if user already exists
if /usr/lib/wgapi/ns_lookup_axfr | grep ".${username}.${TLD}" >/dev/null; then 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/wgapi/http_res 409 printf 'User %s already exists!\n' "${username}" | tee >(cat 1>&2) | /usr/lib/wagon/http_res 409
exit exit
fi fi
# Get all peer IPs # Get all peer IPs
if ! peers="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then if ! peers="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2 printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
# Create new IPs # Create new IPs
@ -59,7 +59,7 @@ ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}"
ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}" ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}"
if ! printf 'IP addresses for %s created: %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then 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 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 fi
# Create wg config # Create wg config
@ -68,7 +68,7 @@ pubkey="$(echo "${privkey}" | /usr/bin/wg pubkey)"
address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}" address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}"
# Update nameserver # 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 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 else printf 'ERROR! Failed to add %s %s %s to DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi & fi &
@ -76,9 +76,9 @@ fi &
# Create SSL cert # Create SSL cert
if ! sudo mkdir "${SSL_CONFIG_DIR:?}/${username:?}/"; then if ! sudo mkdir "${SSL_CONFIG_DIR:?}/${username:?}/"; then
printf 'Failed to create directory %s/%s/:\n' "${SSL_CONFIG_DIR}" "${username}" >&2 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 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 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 else printf 'ERROR! Failed to create certs for %s with IPS: %s %s!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi 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 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" 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 # 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 printf 'Added %s to local wireguard server.\n' "${domain}" >&2
else else
printf 'ERROR! Failed to add %s to local wireguard server!\n' "${domain}" >&2 printf 'ERROR! Failed to add %s to local wireguard server!\n' "${domain}" >&2
# TODO: clear existing progress # TODO: clear existing progress
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
# Remote server # Remote server
else 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" 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 # 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 printf 'Sent %s to remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else else
printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2 printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
fi fi
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="[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 # USAGE: del $remote_ip $querystring
# QUERYSTRING: ?t=$token&user=$username&un=$usernumber # QUERYSTRING: ?t=$token&user=$username&un=$usernumber
source /etc/wgapi/config source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')" ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Check token # Check token
token_fail(){ token_fail(){
printf 'Rejecting admin %s request for new peer due to %s token\n' "${ip}" "${1}" >&2 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' [ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched' <<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2 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=//')" username="$(<<<"${qs}" grep -oP 'user=(.*)' | sed 's/^user=//')"
usernumber="$(<<<"${qs}" grep -oP 'un=(.*)' | sed 's/^un=//')" usernumber="$(<<<"${qs}" grep -oP 'un=(.*)' | sed 's/^un=//')"
if [[ "${username}" == "" ]]; then 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 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 else
printf 'Admin %s requested deletion of user "%s" with usernumber "%s"\n' "${ip}" "${username}" "${usernumber}" >&2 printf 'Admin %s requested deletion of user "%s" with usernumber "%s"\n' "${ip}" "${username}" "${usernumber}" >&2
fi fi
@ -31,20 +31,20 @@ fi
# Get all peer IPs # Get all peer IPs
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2 printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
# Filter out the user's # Filter out the user's
user_peers="$(grep "${IPV4_NET%.*.*}.${usernumber}." <<<"${wg_output}" 2>/dev/null)" user_peers="$(grep "${IPV4_NET%.*.*}.${usernumber}." <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == "" ]; then if [ "${user_peers}" == "" ]; then
printf "ERROR! Couldn't find any peers for %s!\n" "${IPV4_NET%.*.*}.${usernumber}." >&2 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 fi
# Get user peer domains # 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 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 fi
# Run this function in parallel in the while loop below # 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}" server_endpoint="${5}"; server_url="${6}"; server_secret="${7}"
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
# Local server # 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 printf 'Deleted %s from local wireguard server.\n' "${domain}" >&2
else else
printf 'ERROR! Failed to delete %s from local wireguard server!\n' "${domain}" >&2 printf 'ERROR! Failed to delete %s from local wireguard server!\n' "${domain}" >&2
# TODO: clear existing progress # TODO: clear existing progress
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
else else
# Federated server # 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 printf 'Deleted %s from remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else else
printf 'ERROR! Failed to delete %s from remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2 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
fi fi
} }
@ -82,10 +82,10 @@ delete_peer() {
# Remove peer from wireguard # Remove peer from wireguard
while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_url server_secret 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}" & 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 # 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 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 else printf 'ERROR! Failed to delete %s %s %s from DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi fi
@ -104,4 +104,4 @@ fi
# Do it before updating nameserver and certs because # Do it before updating nameserver and certs because
# if wireguard worked, there's no going back. The admin # if wireguard worked, there's no going back. The admin
# can clean up missing records and certs after checking the logs # 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 # USAGE: add $remote_ip $querystring
# QUERYSTRING: ?t=$token&name=$hostname # QUERYSTRING: ?t=$token&name=$hostname
source /etc/wgapi/config source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')" ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Check hostname # 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 printf '%s requested new peer with hostname %s\n' "${ip}" "${hostname}" >&2
if ! [[ ${#hostname} -ge 3 ]]; then if ! [[ ${#hostname} -ge 3 ]]; then
printf 'Rejecting hostname %s because it is too short.\n' "${hostname}" >&2 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 fi
# Check token # Check token
token_fail(){ token_fail(){
printf 'Rejecting %s request for new peer due to %s token\n' "${ip}" "${1}" >&2 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' [ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched' <<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2 printf '%s token was valid\n' "${ip}" >&2
# Check user # 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 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 printf '%s identified as %s\n' "${ip}" "${username}" >&2
domain="${hostname}.${username}.${TLD}" domain="${hostname}.${username}.${TLD}"
# Check if new peer already exists # 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 '%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 fi
# Create new domain # Create new domain
@ -46,27 +46,27 @@ printf 'New domain will be %s\n' "${domain}" >&2
# Get peer IP list # Get peer IP list
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2 printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
# Filter out this user's # Filter out this user's
user_peers="$(grep "${ip%[.:]*}" <<<"${wg_output}" 2>/dev/null)" user_peers="$(grep "${ip%[.:]*}" <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == "" ]; then if [ "${user_peers}" == "" ]; then
printf "ERROR! %s accessed the dashboard but isn't on the network!\n" "${ip}" >&2 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 fi
# Get domains # 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 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 fi
# Make sure hostname isn't taken # Make sure hostname isn't taken
hostnames="$(<<<"${peers}" awk '{print $1}' | cut -d'.' -f1)" hostnames="$(<<<"${peers}" awk '{print $1}' | cut -d'.' -f1)"
if <<<"${hostnames}" grep -x "${hostname}"; then if <<<"${hostnames}" grep -x "${hostname}"; then
printf 'User %s already has a host named %s!\n' "${username}" "${hostname}" >&2 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 fi
# Create new IPs # Create new IPs
@ -82,7 +82,7 @@ ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}"
ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}" ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}"
if ! printf 'IP addresses for %s created: %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then 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 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 fi
# Create wg config # Create wg config
@ -91,13 +91,13 @@ pubkey="$(echo "${privkey}" | /usr/bin/wg pubkey)"
address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}" address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}"
# Update nameserver # 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 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 else printf 'ERROR! Failed to add %s %s %s to DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi & fi &
# Create SSL cert # 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 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 else printf 'ERROR! Failed to create certs for %s with IPS: %s %s!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi 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 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" 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 # 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 printf 'Added %s to local wireguard server.\n' "${domain}" >&2
else else
printf 'ERROR! Failed to add %s to local wireguard server!\n' "${domain}" >&2 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 fi
# Remote server # Remote server
else 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" 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 # 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 printf 'Sent %s to remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else else
printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2 printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2
fi fi
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="[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 # USAGE: del $remote_ip $querystring
# QUERYSTRING: ?t=$token&pubkey=$pubkey # QUERYSTRING: ?t=$token&pubkey=$pubkey
source /etc/wgapi/config source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')" ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
# Parse pubkey # Parse pubkey
@ -14,9 +14,9 @@ printf '%s requested to delete %s\n' "${ip}" "${pubkey:?}" >&2
# Check token # Check token
token_fail(){ token_fail(){
printf 'Rejecting %s request to delete peer due to %s token\n' "${ip}" "${1}" >&2 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' [ "${saved_token}" == "" ] && token_fail 'missing'
<<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched' <<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched'
printf '%s token was valid\n' "${ip}" >&2 printf '%s token was valid\n' "${ip}" >&2
@ -24,33 +24,33 @@ printf '%s token was valid\n' "${ip}" >&2
# Get peer IP list # Get peer IP list
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2 printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
# Filter out this user's # Filter out this user's
user_peers="$(grep "${ip%[.:]*}" <<<"${wg_output}" 2>/dev/null)" user_peers="$(grep "${ip%[.:]*}" <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == "" ]; then if [ "${user_peers}" == "" ]; then
printf "ERROR! %s accessed the dashboard but isn't on the network!\n" "${ip}" >&2 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 fi
# Get peer domains # 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 '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 fi
domain="$(<<<"${peer}" cut -f1)" domain="$(<<<"${peer}" cut -f1)"
ipv4="$(<<<"${peer}" cut -f2)" ipv4="$(<<<"${peer}" cut -f2)"
ipv6="$(<<<"${peer}" cut -f3)" ipv6="$(<<<"${peer}" cut -f3)"
if ! printf 'Delete request was for %s %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" >&2; then 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 & 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 fi
# Make sure user isn't deleting their own peer # Make sure user isn't deleting their own peer
if [ "${ip}" == "${ipv4}" ] || [ "${ip}" == "${ipv6}" ]; then if [ "${ip}" == "${ipv4}" ] || [ "${ip}" == "${ipv6}" ]; then
printf 'User requested to delete peer from itself: %s.\n' "${ip}" >&2 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 fi
hostname="$(<<<"${domain}" cut -d'.' -f1)" hostname="$(<<<"${domain}" cut -d'.' -f1)"
@ -65,34 +65,34 @@ for_server_do() {
server_endpoint="${5}"; server_url="${6}"; server_secret="${7}" server_endpoint="${5}"; server_url="${6}"; server_secret="${7}"
if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then
# Local server # 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 printf 'Deleted %s from local wireguard server.\n' "${domain}" >&2
else else
printf 'ERROR! Failed to delete %s from local wireguard server!\n' "${domain}" >&2 printf 'ERROR! Failed to delete %s from local wireguard server!\n' "${domain}" >&2
# TODO: clear existing progress # TODO: clear existing progress
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
else else
# Federated server # 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 printf 'Deleted %s from remote wireguard server %s.\n' "${domain}" "${server_hostname}" >&2
else else
printf 'ERROR! Failed to delete %s from remote wireguard server %s!\n' "${domain}" "${server_hostname}" >&2 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
fi fi
}; while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_url server_secret }; 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}" & 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 # 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 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 else printf 'ERROR! Failed to delete %s %s %s from DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >&2
fi & fi &
# Create SSL cert # 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 then printf 'Successfully deleted SSL certs for %s\n' "${domain}" >&2
else printf 'ERROR! Failed to delete certs for %s!\n' "${domain}" >&2 else printf 'ERROR! Failed to delete certs for %s!\n' "${domain}" >&2
fi fi
@ -101,4 +101,4 @@ fi
# Do it before updating nameserver and certs because # Do it before updating nameserver and certs because
# if wireguard worked, there's no going back. The admin # if wireguard worked, there's no going back. The admin
# can clean up missing records and certs after checking the logs # 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 # DESCRIPTION: List a user's peers
# USAGE: list $remote_ip # USAGE: list $remote_ip
source /etc/wgapi/config source /etc/wagon/config
ip="${1}" ip="${1}"
printf '%s requested peer listing...\n' "${ip}" >&2 printf '%s requested peer listing...\n' "${ip}" >&2
# Create token if needed # 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 if [ "${token}" == "" ]; then
printf 'Creating token for %s...\n' "${ip}" >&2 printf 'Creating token for %s...\n' "${ip}" >&2
token="$(</dev/urandom tr -dc '[:alnum:]' | fold -w 64 | head -n 1)" 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 fi
# Get peer IP list # Get peer IP list
if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then if ! wg_output="$(sudo /usr/bin/wg show "${TLD}" allowed-ips)"; then
printf 'ERROR! Wireguard failed!\n' >&2 printf 'ERROR! Wireguard failed!\n' >&2
/usr/lib/wgapi/http_res 500; exit /usr/lib/wagon/http_res 500; exit
fi fi
# Filter out this user's # Filter out this user's
user_peers="$(grep "${ip%[.:]*}" <<<"${wg_output}" 2>/dev/null)" user_peers="$(grep "${ip%[.:]*}" <<<"${wg_output}" 2>/dev/null)"
if [ "${user_peers}" == '' ]; then if [ "${user_peers}" == '' ]; then
printf "ERROR! %s accessed the dashboard but isn't on the network!\n" "${ip}" >&2 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 fi
# Get domains for each one # Get domains for each one
if peers="[$(/usr/lib/wgapi/ips_to_peers json <<<"${user_peers}")]"; then if peers="[$(/usr/lib/wagon/ips_to_peers json <<<"${user_peers}")]"; then
printf '{"token":"%s","peers":%s}' "${token}" "${peers}" | /usr/lib/wgapi/http_res 200 'application/json' printf '{"token":"%s","peers":%s}' "${token}" "${peers}" | /usr/lib/wagon/http_res 200 'application/json'
printf 'Sent peers to user %s\n' "${ip}" >&2 printf 'Sent peers to user %s\n' "${ip}" >&2
else else
printf 'ERROR: Failed to lookup domains for user: %s\n' "${ip}" >&2 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 fi

View File

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

View File

@ -4,7 +4,7 @@
# USAGE: add $remote_ip $querystring # USAGE: add $remote_ip $querystring
# QUERYSTRING: ?secret=$secret&pubkey=$pubkey&psk=$psk&ips=$allowedips # 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/?//')" ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
secret="$(<<<"${qs}" grep -oP 'secret=(.*)' | sed 's/^secret=//' | xargs)" secret="$(<<<"${qs}" grep -oP 'secret=(.*)' | sed 's/^secret=//' | xargs)"
pubkey="$(<<<"${qs}" grep -oP 'pubkey=(.*)' | sed 's/^pubkey=//' | 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)" allowedips="$(<<<"${qs}" grep -oP 'ips=(.*)' | sed 's/^ips=//' | xargs)"
# Check that requesting ip is in the servers file # 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 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 fi
# Check server secret # 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 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 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 fi
# Add peer to wireguard # 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 printf 'Added %s to wireguard.\n' "${pubkey}" >&2
else else
printf 'ERROR! Failed to add %s to wireguard!\n' "${pubkey}" >&2 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 fi
/usr/lib/wgapi/http_res 200 /usr/lib/wagon/http_res 200

View File

@ -4,30 +4,30 @@
# USAGE: del $remote_ip $querystring # USAGE: del $remote_ip $querystring
# QUERYSTRING: ?secret=$secret&pubkey=$pubkey # QUERYSTRING: ?secret=$secret&pubkey=$pubkey
source /etc/wgapi/config source /etc/wagon/config
ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')" ip="${1}"; qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')"
secret="$(<<<"${qs}" grep -oP 'secret=(.*)' | sed 's/^secret=//' | xargs)" secret="$(<<<"${qs}" grep -oP 'secret=(.*)' | sed 's/^secret=//' | xargs)"
pubkey="$(<<<"${qs}" grep -oP 'pubkey=(.*)' | sed 's/^pubkey=//' | xargs)" pubkey="$(<<<"${qs}" grep -oP 'pubkey=(.*)' | sed 's/^pubkey=//' | xargs)"
# Check that requesting ip is in the servers file # 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 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 fi
# Check server secret # 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 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 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 fi
# Delete peer from wireguard # 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 printf 'Deleted %s from wireguard.\n' "${pubkey}" >&2
else else
printf 'ERROR! Failed to delete %s from wireguard!\n' "${pubkey}" >&2 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 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 # DESCRIPTION: Sends details about a new peer to a federated server
# USAGE: fed_peer_add url secret pubkey psk allowedips # 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}" 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 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 # DESCRIPTION: Sends details to a federated server about a peer to be deleted
# USAGE: fed_peer_del url secret pubkey # USAGE: fed_peer_del url secret pubkey
source /etc/wgapi/config source /etc/wagon/config
url="${1}"; secret="${2}"; pubkey="${3}" 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 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 #!/bin/bash
# FILE: wgapi:back/lib/http/res # FILE: wagon:back/lib/http/res
# DESCRIPTION: Formats an http response from arguments # DESCRIPTION: Formats an http response from arguments
# USAGE: [printf "message" |] res [200] [text/plain] # USAGE: [printf "message" |] res [200] [text/plain]

View File

@ -9,11 +9,11 @@
# 5: Invalid format # 5: Invalid format
# 6: Config file not found # 6: Config file not found
source /etc/wgapi/config source /etc/wagon/config
format="${1}" format="${1}"
# Perform AXFR lookup # 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 # This should read from stdin
# TODO: Run this loop in parallel # TODO: Run this loop in parallel

View File

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

View File

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

View File

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

View File

@ -1,14 +1,14 @@
#!/bin/bash #!/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 # DESCRIPTION: Add a new peer's domain to nameserver
# USAGE: add domain ipv4 ipv6 # 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} AAAA ${3}
update add *.${1}. ${DNS_TTL} CNAME ${1}. update add *.${1}. ${DNS_TTL} CNAME ${1}.
send 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 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 #!/bin/bash
# FILE: wgapi:back/lib/ns/update/del # FILE: wagon:back/lib/ns/update/del
# DESCRIPTION: Use nsupdate to delete host RRs # DESCRIPTION: Use nsupdate to delete host RRs
# USAGE: del domain ipv4 ipv6 # 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}. AAAA
update delete *.${1}. CNAME update delete *.${1}. CNAME
send send
update delete $(/usr/lib/wgapi/ns_update_rev_ipv4 "${2}") PTR update delete $(/usr/lib/wagon/ns_update_rev_ipv4 "${2}") PTR
send 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 #!/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 # DESCRIPTION: Returns the rDNS reversed version of an IPv4 address
# USAGE: rev_ipv4 10.2.0.1 # USAGE: rev_ipv4 10.2.0.1
# OUTPUT: 1.0.2.10.in-addr.arpa # OUTPUT: 1.0.2.10.in-addr.arpa

View File

@ -1,5 +1,5 @@
#!/bin/bash #!/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 # DESCRIPTION: Returns the rDNS reversed version of an IPv6 address
# USAGE: rev_ipv6 ... # USAGE: rev_ipv6 ...
# OUTPUT: ...ip6.arpa # OUTPUT: ...ip6.arpa

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,3 @@
# host ipv4 ipv6 pubkey wg-endpoint admin-endpoint secret # 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 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://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://wagon-admin.myhost2.tld XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX