#!/bin/bash # FILE: peer_add # DESCRIPTION: Add a new peer # USAGE: add remote_ip querystring # ERRORS: # 3: bad args/usage # 4: vars file not found # 5: Wireguard not installed # 6: Hostname in use # 7: Hostname too short # 8: Invalid token # 9: Token file not found # 10: Failed to get peer data from wg # 11: Failed to generate new IPs # 12: Servers file doesn't exist # 15: Failed to add user to local wireguard # 16: Failed to add user to federated server # 17: User not found CONFIG_FILE='/etc/wgapi/config' SERVERS_FILE='/etc/wgapi/servers' if ! [ ${#} -eq 2 ]; then printf 'ERROR! Bad input: %s %s\n' "${0}" "${*}" >>"${LOGFILE}" exit 3 fi & if ! [ -x '/usr/bin/wg' ]; then printf 'ERROR! %s could not find /usr/bin/wg\n' "${0}" >>"${LOGFILE}" exit 5 fi & if ! [ -f "${CONFIG_FILE}" ]; then printf 'ERROR! %s could not find %s!\n' "${0}" "${CONFIG_FILE}" >>"${LOGFILE}" exit 4 fi source "${CONFIG_FILE}" if ! [ -f "${SERVERS_FILE}" ]; then printf 'ERROR! %s could not find %s!\n' "${0}" "${SERVERS_FILE}" >>"${LOGFILE}" exit 12 fi & if ! [ -f "${TOKENS_FILE}" ]; then printf 'ERROR! %s could not find %s!\n' "${0}" "${TOKENS_FILE}" >>"${LOGFILE}" exit 9 fi ip="${1}" qs="$(<<<"${2}" tr '&' '\n' | sed 's/?//')" # Check hostname hostname="$(<<<"${qs}" grep -oP 'name=(.*)' | sed 's/^name//' | xargs | tr -dc 'a-z0-9' | head -c10)" printf '%s requested new peer with hostname %s\n' "${ip}" "${hostname}" >>"${LOGFILE}" if ! [[ ${#hostname} -ge 3 ]]; then printf 'Rejecting hostname %s because it is too short.\n' "${hostname}" >>"${LOGFILE}" printf 'Hostname too short\n' | "${LIB_DIR}/http_res" 400 exit 7 fi # Check token token_fail(){ printf 'Rejecting %s request for new peer due to %s token\n' "${ip}" "${1}" >>"${LOGFILE}" printf 'Invalid token\n' | "${LIB_DIR}/http_res" 403 exit 8 } saved_token="$(grep "${ip}" "${TOKENS_FILE}" | cut -f2)" [ "${saved_token}" == "" ] && token_fail 'missing' & <<<"${qs}" grep -qx "t=${saved_token}" || token_fail 'mismatched' printf '%s token was valid\n' "${ip}" >>"${LOGFILE}" # Check user username="$("${LIB_DIR}/ns_lookup_rdns" "${ip}" | cut -d'.' -f2)" || ( printf 'User not found for %s\n' "${ip}" >>"${LOGFILE}" printf 'User not found' | "${LIB_DIR}/http_res" 403 exit 17 ) printf '%s identified as %s\n' "${ip}" "${username}" >>"${LOGFILE}" domain="${hostname}.${username}.${TLD}" # Check if new peer already exists if "${LIB_DIR}/ns_lookup_send" "${domain}" >/dev/null; then printf '%s.%s.%s already exists!\n' "${hostname}" "${username}" "${TLD}" >>"${LOGFILE}" printf 'Hostname %s already exists!\n' "${hostname}" | "${LIB_DIR}/http_res" 409 exit 6 fi # Create new domain domain="${hostname:?}.${username:?}.${TLD:?}" printf 'New domain will be %s\n' "${domain}" >>"${LOGFILE}" # Create new IPs if ! peers="$("${LIB_DIR}/wg_peer_list" "${ip}" tsv)"; then printf 'ERROR! Failed to retrieve peers for %s!\n' "${ip}" >>"${LOGFILE}" exit 10 fi hostnames="$(<<<"${peers}" awk '{print $1}' | cut -d'.' -f1)" ipv4s="$(<<<"${peers}" awk '{print $2}')" ipv6s="$(<<<"${peers}" awk '{print $3}')" usernumber="$(<<<"${ipv4s}" head -n1 | cut -d'.' -f3)" # Increment hostnumber from 1 until an unused one is found used_hostnumbers="$(<<<"${ipv4s}" cut -d'.' -f4 | sort | uniq)" hostnumber=1; while <<<"${used_hostnumbers}" grep -q "${hostnumber}" do ((hostnumber++)) done ipv4="${IPV4_NET%.*.*}.${usernumber}.${hostnumber}" ipv6="${IPV6_NET%:*:*}:${usernumber}:${hostnumber}" if ! printf 'IP addresses for %s created: %s %s\n' "${domain:?}" "${ipv4:?}" "${ipv6:?}" \ >>"${LOGFILE}"; then printf 'ERROR! Failed to create IP addresses for %s!' "${domain}" >>"${LOGFILE}" exit 11 fi # Create wg config privkey="$(/usr/bin/wg genkey)" pubkey="$(echo "${privkey}" | /usr/bin/wg pubkey)" address="${ipv4}/${IPV4_NET##*/},${ipv6}/${IPV6_NET##*/}" # Update nameserver if "${LIB_DIR}/ns_update_add" "${domain:?}" "${ipv4:?}" "${ipv6:?}" then printf 'Successfully added %s to DNS server.\n' "${domain}" >>"${LOGFILE}" else printf 'ERROR! Failed to add %s %s %s to DNS server!\n' "${domain}" "${ipv4}" "${ipv6}" >>"${LOGFILE}" fi & # Create SSL cert if "${LIB_DIR}/ssl_peer_add" "${hostname:?}" "${username:?}" "IP:${ipv4},IP:${ipv6}" then printf 'Successfully signed SSL certs for %s\n' "${domain}" >>"${LOGFILE}" else printf 'ERROR! Failed to create certs for %s with IPS: %s %s!\n' "${domain}" "${ipv4}" "${ipv6}" >>"${LOGFILE}" fi # Do the wireguard and tell the user server_blocks='' while IFS=$'\t' read -r server_hostname server_ipv4 server_ipv6 server_pubkey server_endpoint server_admin server_secret; do [[ ${server_hostname:0:1} = \# ]] && continue server_psk="$(/usr/bin/wg genpsk)" server_blocks="${server_blocks}\n[Peer] # ${server_hostname}.${TLD}\nPublicKey=${server_pubkey}\nPresharedKey=${server_psk}\nAllowedIPs=${server_ipv4}/32,${server_ipv6}/128\nEndpoint=${server_endpoint}\n" if [ "${server_hostname}" == "${LOCAL_SERVER}" ]; then # Add new user to local server if "${LIB_DIR}/wg_peer_add" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128"; then printf 'Added %s to local wireguard server.\n' "${domain}" >>"${LOGFILE}" else printf 'ERROR! Failed to add %s to local wireguard server!\n' "${domain}" >>"${LOGFILE}" # TODO: clear existing progress exit 15 fi # TODO: Send new user config to federated server #else # if "${LIB_DIR}/fed_peer_add" "${server_admin}" "${pubkey}" "${server_psk}" "${ipv4}/32,${ipv6}/128" "${server_secret}"; then # printf 'Sent %s to remote wireguard server %s.\n' "${domain}" "${server_hostname}" >>"${LOGFILE}" #else # printf 'ERROR! Failed to send %s to remote wireguard server %s!\n' "${domain}" "${server_hostname}" >>"${LOGFILE}" # # TODO: clear existing progress # exit 16 #fi fi done <"${SERVERS_FILE}" wg_config="[Interface] # ${hostname}.${username}.${TLD}\nPrivateKey=${privkey:?}\nAddress=${address:?}\n${WG_DNS}\n${server_blocks:?}" <<<"${wg_config}" "${LIB_DIR}/http_res" 202