Initial migration
This commit is contained in:
parent
1f823e556e
commit
163ccbd03f
17 changed files with 1369 additions and 0 deletions
35
README.md
Normal file
35
README.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
\ \ /_) ___| |
|
||||
\ \ \ / | __| _ \ | _` | __| _ \
|
||||
\ \ \ / | | __/ | | ( | | __/
|
||||
\_/\_/ _|_| \___|\____|\__,_|\__|\___|
|
||||
|
||||
|
||||
Wireguard based VPN server endpoint with LDAP support
|
||||
|
||||
Tested on Debian 12 bookworm
|
||||
|
||||
# Server Commands
|
||||
|
||||
./init.sh - setup system services (wireguard, unbound, iptables, sysctl)
|
||||
|
||||
./peer_add.sh - define new peer for a new remote device. generates config and QR code inside /etc/wireguard/clients
|
||||
|
||||
./peer_del.sh - delete a peer and salvage its ip address back to the ip pool
|
||||
|
||||
./peer_addall.sh - recreates wireguard state using existing clients in /etc/wireguard/clients dir
|
||||
|
||||
./peer_mail.sh - send the generated profile to the client and remove the sensitive data from server
|
||||
|
||||
# Server Tools
|
||||
|
||||
./gen-ip-database.sh - generate an ip pool for wireguard peers
|
||||
|
||||
./wgstats.sh - show peer stats similar based on wg show all dump
|
||||
|
||||
./wgldap.sh - tail the log of the wgldapsync service
|
||||
|
||||
# Client Side Tools
|
||||
|
||||
./client-tools/wg-rapid - modified wireguard client based on wg-quick that works with systemd-resolv
|
||||
|
||||
./client-tools/startvpn.desktop - shortcut for wg-rapid. update the parameter with peer filename
|
8
client-tools/startvpn.desktop
Executable file
8
client-tools/startvpn.desktop
Executable file
|
@ -0,0 +1,8 @@
|
|||
[Desktop Entry]
|
||||
Name=startvpn
|
||||
Exec=/usr/local/bin/wg-rapid profile
|
||||
Comment=
|
||||
Terminal=true
|
||||
Icon=network-vpn
|
||||
Type=Application
|
||||
Name[en_US]=startvpn
|
400
client-tools/wg-rapid
Executable file
400
client-tools/wg-rapid
Executable file
|
@ -0,0 +1,400 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
# Copyright (C) 2021-2022 Daniel afx <daniel@deflax.net>
|
||||
#
|
||||
|
||||
#set -e -o pipefail
|
||||
shopt -s extglob
|
||||
export LC_ALL=C
|
||||
|
||||
SELF="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
export PATH="${SELF%/*}:$PATH"
|
||||
|
||||
WG_CONFIG=""
|
||||
|
||||
CONFIG_FILE=""
|
||||
PROGRAM="${0##*/}"
|
||||
ARGS=( "$@" )
|
||||
|
||||
EXTERNAL_NETWORK_TEST_IP="1.1.1.1"
|
||||
|
||||
cmd_usage() {
|
||||
cat >&2 <<-_EOF
|
||||
Usage: $PROGRAM [ CONFIG_NAME ]
|
||||
|
||||
CONFIG_NAME is the name of a configuration file, which is also the interface
|
||||
name followed by \`.conf'. It should be a configuration found at
|
||||
/etc/wireguard/INTERFACE.conf. It is to be readable by wg(8)'s \`setconf'
|
||||
sub-command, with the exception of the following additions
|
||||
to the [Interface] section, which are handled by $PROGRAM:
|
||||
|
||||
- Address: may be specified one or more times and contains one or more
|
||||
IP addresses (with an optional CIDR mask) to be set for the interface.
|
||||
- DNS: an optional DNS server to use while the device is up.
|
||||
- MTU: an optional MTU for the interface; if unspecified, auto-calculated.
|
||||
- Table: an optional routing table to which routes will be added; if
|
||||
unspecified or \`auto', the default table is used. If \`off', no routes
|
||||
are added.
|
||||
- PreUp, PostUp, PreDown, PostDown: script snippets which will be executed
|
||||
by bash(1) at the corresponding phases of the link, most commonly used
|
||||
to configure DNS. The string \`%i' is expanded to INTERFACE.
|
||||
|
||||
If for some reason the interface is already up, you could use:
|
||||
$PROGRAM [ CONFIG_NAME ] down
|
||||
_EOF
|
||||
}
|
||||
|
||||
# Helper Functions
|
||||
auto_su() {
|
||||
[[ $UID == 0 ]] || exec sudo -p "$PROGRAM must be run as root. Please enter the password for %u to continue: " -- "$BASH" -- "$SELF" "${ARGS[@]}"
|
||||
}
|
||||
|
||||
say() {
|
||||
echo " ] $*"
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "!] $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cmd() {
|
||||
echo "#] $*" >&2
|
||||
"$@"
|
||||
}
|
||||
|
||||
execute_hooks() {
|
||||
local hook
|
||||
for hook in "$@"; do
|
||||
hook="${hook//%i/$INTERFACE}"
|
||||
echo "#] $hook" >&2
|
||||
(eval "$hook")
|
||||
done
|
||||
}
|
||||
|
||||
parse_options() {
|
||||
INTERFACE=""
|
||||
ADDRESSES=( )
|
||||
MTU=""
|
||||
DNS=( )
|
||||
DNS_SEARCH=( )
|
||||
TABLE=""
|
||||
PRE_UP=( )
|
||||
POST_UP=( )
|
||||
PRE_DOWN=( )
|
||||
POST_DOWN=( )
|
||||
local interface_section=0 line key value stripped v
|
||||
CONFIG_FILE="$1"
|
||||
[[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]] && CONFIG_FILE="/etc/wireguard/$CONFIG_FILE.conf"
|
||||
[[ -e $CONFIG_FILE ]] || die "\`$CONFIG_FILE' does not exist"
|
||||
[[ $CONFIG_FILE =~ (^|/)([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]] || die "The config file must be a valid interface name, followed by .conf"
|
||||
CONFIG_FILE="$(readlink -f "$CONFIG_FILE")"
|
||||
((($(stat -c '0%#a' "$CONFIG_FILE") & $(stat -c '0%#a' "${CONFIG_FILE%/*}") & 0007) == 0)) || echo "Warning: \`$CONFIG_FILE' is world accessible" >&2
|
||||
INTERFACE="${BASH_REMATCH[2]}"
|
||||
shopt -s nocasematch
|
||||
while read -r line || [[ -n $line ]]; do
|
||||
stripped="${line%%\#*}"
|
||||
key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}"
|
||||
value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}"
|
||||
[[ $key == "["* ]] && interface_section=0
|
||||
[[ $key == "[Interface]" ]] && interface_section=1
|
||||
if [[ $interface_section -eq 1 ]]; then
|
||||
case "$key" in
|
||||
Address) ADDRESSES+=( ${value//,/ } ); continue ;;
|
||||
MTU) MTU="$value"; continue ;;
|
||||
DNS) for v in ${value//,/ }; do
|
||||
[[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v )
|
||||
done; continue ;;
|
||||
Table) TABLE="$value"; continue ;;
|
||||
PreUp) PRE_UP+=( "$value" ); continue ;;
|
||||
PreDown) PRE_DOWN+=( "$value" ); continue ;;
|
||||
PostUp) POST_UP+=( "$value" ); continue ;;
|
||||
PostDown) POST_DOWN+=( "$value" ); continue ;;
|
||||
esac
|
||||
fi
|
||||
WG_CONFIG+="$line"$'\n'
|
||||
done < "$CONFIG_FILE"
|
||||
shopt -u nocasematch
|
||||
}
|
||||
|
||||
set_config() {
|
||||
cmd wg setconf "$INTERFACE" <(echo "$WG_CONFIG")
|
||||
}
|
||||
|
||||
# Setup Interface and Address
|
||||
add_if() {
|
||||
local ret
|
||||
if ! cmd ip link add "$INTERFACE" type wireguard; then
|
||||
ret=$?
|
||||
[[ -e /sys/module/wireguard ]] || ! command -v "${WG_QUICK_USERSPACE_IMPLEMENTATION:-wireguard-go}" >/dev/null && exit $ret
|
||||
echo "!] Missing WireGuard kernel module. Falling back to slow userspace implementation." >&2
|
||||
cmd "${WG_QUICK_USERSPACE_IMPLEMENTATION:-wireguard-go}" "$INTERFACE"
|
||||
fi
|
||||
}
|
||||
|
||||
del_if() {
|
||||
local table
|
||||
#[[ $HAVE_SET_DNS -eq 0 ]] || unset_dns
|
||||
#[[ $HAVE_SET_FIREWALL -eq 0 ]] || remove_firewall
|
||||
if [[ -z $TABLE || $TABLE == auto ]] && get_fwmark table && [[ $(wg show "$INTERFACE" allowed-ips) =~ /0(\ |$'\n'|$) ]]; then
|
||||
while [[ $(ip -4 rule show 2>/dev/null) == *"lookup $table"* ]]; do
|
||||
cmd ip -4 rule delete table $table
|
||||
done
|
||||
while [[ $(ip -4 rule show 2>/dev/null) == *"from all lookup main suppress_prefixlength 0"* ]]; do
|
||||
cmd ip -4 rule delete table main suppress_prefixlength 0
|
||||
done
|
||||
while [[ $(ip -6 rule show 2>/dev/null) == *"lookup $table"* ]]; do
|
||||
cmd ip -6 rule delete table $table
|
||||
done
|
||||
while [[ $(ip -6 rule show 2>/dev/null) == *"from all lookup main suppress_prefixlength 0"* ]]; do
|
||||
cmd ip -6 rule delete table main suppress_prefixlength 0
|
||||
done
|
||||
fi
|
||||
cmd ip link delete dev "$INTERFACE"
|
||||
}
|
||||
|
||||
add_addr() {
|
||||
local proto=-4
|
||||
[[ $1 == *:* ]] && proto=-6
|
||||
cmd ip $proto address add "$1" dev "$INTERFACE"
|
||||
}
|
||||
|
||||
set_mtu_up() {
|
||||
local mtu=0 endpoint output
|
||||
if [[ -n $MTU ]]; then
|
||||
cmd ip link set mtu "$MTU" up dev "$INTERFACE"
|
||||
return
|
||||
fi
|
||||
while read -r _ endpoint; do
|
||||
[[ $endpoint =~ ^\[?([a-z0-9:.]+)\]?:[0-9]+$ ]] || continue
|
||||
output="$(ip route get "${BASH_REMATCH[1]}" || true)"
|
||||
[[ ( $output =~ mtu\ ([0-9]+) || ( $output =~ dev\ ([^ ]+) && $(ip link show dev "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) ) ) && ${BASH_REMATCH[1]} -gt $mtu ]] && mtu="${BASH_REMATCH[1]}"
|
||||
done < <(wg show "$INTERFACE" endpoints)
|
||||
if [[ $mtu -eq 0 ]]; then
|
||||
read -r output < <(ip route show default || true) || true
|
||||
[[ ( $output =~ mtu\ ([0-9]+) || ( $output =~ dev\ ([^ ]+) && $(ip link show dev "${BASH_REMATCH[1]}") =~ mtu\ ([0-9]+) ) ) && ${BASH_REMATCH[1]} -gt $mtu ]] && mtu="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
[[ $mtu -gt 0 ]] || mtu=1500
|
||||
cmd ip link set mtu $(( mtu - 80 )) up dev "$INTERFACE"
|
||||
}
|
||||
|
||||
# Checks the active internet connection interface
|
||||
transport_interface() {
|
||||
local netiface
|
||||
netiface=$(ip route get ${EXTERNAL_NETWORK_TEST_IP} | grep -Po '(?<=dev\s)\w+' | cut -f1 -d ' ')
|
||||
if [ -z ${netiface} ]; then
|
||||
die "Unable to reach ${EXTERNAL_NETWORK_TEST_IP}. Check the Internet connection"
|
||||
exit 1
|
||||
else
|
||||
echo "${netiface}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Setup DNS
|
||||
HAVE_SET_DNS=0
|
||||
set_dns() {
|
||||
[[ ${#DNS[@]} -gt 0 ]] || return 0
|
||||
#{ printf 'nameserver %s\n' "${DNS[@]}"
|
||||
# [[ ${#DNS_SEARCH[@]} -eq 0 ]] || printf 'search %s\n' "${DNS_SEARCH[*]}"
|
||||
#} | cmd resolvconf -a "$(resolvconf_iface_prefix)$INTERFACE" -m 0 -x
|
||||
cmd resolvectl dns ${INTERFACE} "${DNS[@]}"
|
||||
cmd resolvectl domain ${INTERFACE} "~."
|
||||
cmd resolvectl domain $(transport_interface) "lan"
|
||||
HAVE_SET_DNS=1
|
||||
}
|
||||
|
||||
unset_dns() {
|
||||
[[ ${#DNS[@]} -gt 0 ]] || return 0
|
||||
cmd resolvectl domain $(transport_interface) "lan"
|
||||
cmd resolvectl domain $(transport_interface) "~."
|
||||
|
||||
}
|
||||
|
||||
# Setup Routes and Firewall
|
||||
add_route() {
|
||||
local proto=-4
|
||||
[[ $1 == *:* ]] && proto=-6
|
||||
[[ $TABLE != off ]] || return 0
|
||||
|
||||
if [[ -n $TABLE && $TABLE != auto ]]; then
|
||||
cmd ip $proto route add "$1" dev "$INTERFACE" table "$TABLE"
|
||||
elif [[ $1 == */0 ]]; then
|
||||
add_default "$1"
|
||||
else
|
||||
[[ -n $(ip $proto route show dev "$INTERFACE" match "$1" 2>/dev/null) ]] || cmd ip $proto route add "$1" dev "$INTERFACE"
|
||||
fi
|
||||
}
|
||||
|
||||
get_fwmark() {
|
||||
local fwmark
|
||||
fwmark="$(wg show "$INTERFACE" fwmark)" || return 1
|
||||
[[ -n $fwmark && $fwmark != off ]] || return 1
|
||||
printf -v "$1" "%d" "$fwmark"
|
||||
return 0
|
||||
}
|
||||
|
||||
HAVE_SET_FIREWALL=0
|
||||
add_default() {
|
||||
local table line
|
||||
if ! get_fwmark table; then
|
||||
table=51820
|
||||
while [[ -n $(ip -4 route show table $table 2>/dev/null) || -n $(ip -6 route show table $table 2>/dev/null) ]]; do
|
||||
((table++))
|
||||
done
|
||||
cmd wg set "$INTERFACE" fwmark $table
|
||||
fi
|
||||
local proto=-4 iptables=iptables pf=ip
|
||||
[[ $1 == *:* ]] && proto=-6 iptables=ip6tables pf=ip6
|
||||
cmd ip $proto route add "$1" dev "$INTERFACE" table $table
|
||||
cmd ip $proto rule add not fwmark $table table $table
|
||||
cmd ip $proto rule add table main suppress_prefixlength 0
|
||||
|
||||
local marker="-m comment --comment \"wg-quick(8) rule for $INTERFACE\"" restore=$'*raw\n' nftable="wg-quick-$INTERFACE" nftcmd
|
||||
printf -v nftcmd '%sadd table %s %s\n' "$nftcmd" "$pf" "$nftable"
|
||||
printf -v nftcmd '%sadd chain %s %s preraw { type filter hook prerouting priority -300; }\n' "$nftcmd" "$pf" "$nftable"
|
||||
printf -v nftcmd '%sadd chain %s %s premangle { type filter hook prerouting priority -150; }\n' "$nftcmd" "$pf" "$nftable"
|
||||
printf -v nftcmd '%sadd chain %s %s postmangle { type filter hook postrouting priority -150; }\n' "$nftcmd" "$pf" "$nftable"
|
||||
while read -r line; do
|
||||
[[ $line =~ .*inet6?\ ([0-9a-f:.]+)/[0-9]+.* ]] || continue
|
||||
printf -v restore '%s-I PREROUTING ! -i %s -d %s -m addrtype ! --src-type LOCAL -j DROP %s\n' "$restore" "$INTERFACE" "${BASH_REMATCH[1]}" "$marker"
|
||||
printf -v nftcmd '%sadd rule %s %s preraw iifname != "%s" %s daddr %s fib saddr type != local drop\n' "$nftcmd" "$pf" "$nftable" "$INTERFACE" "$pf" "${BASH_REMATCH[1]}"
|
||||
done < <(ip -o $proto addr show dev "$INTERFACE" 2>/dev/null)
|
||||
printf -v restore '%sCOMMIT\n*mangle\n-I POSTROUTING -m mark --mark %d -p udp -j CONNMARK --save-mark %s\n-I PREROUTING -p udp -j CONNMARK --restore-mark %s\nCOMMIT\n' "$restore" $table "$marker" "$marker"
|
||||
printf -v nftcmd '%sadd rule %s %s postmangle meta l4proto udp mark %d ct mark set mark \n' "$nftcmd" "$pf" "$nftable" $table
|
||||
printf -v nftcmd '%sadd rule %s %s premangle meta l4proto udp meta mark set ct mark \n' "$nftcmd" "$pf" "$nftable"
|
||||
[[ $proto == -4 ]] && cmd sysctl -q net.ipv4.conf.all.src_valid_mark=1
|
||||
if type -p nft >/dev/null; then
|
||||
cmd nft -f <(echo -n "$nftcmd")
|
||||
else
|
||||
echo -n "$restore" | cmd $iptables-restore -n
|
||||
fi
|
||||
HAVE_SET_FIREWALL=1
|
||||
return 0
|
||||
}
|
||||
|
||||
remove_firewall() {
|
||||
if type -p nft >/dev/null; then
|
||||
local table nftcmd
|
||||
while read -r table; do
|
||||
[[ $table == *" wg-quick-$INTERFACE" ]] && printf -v nftcmd '%sdelete %s\n' "$nftcmd" "$table"
|
||||
done < <(nft list tables 2>/dev/null)
|
||||
[[ -z $nftcmd ]] || cmd nft -f <(echo -n "$nftcmd")
|
||||
fi
|
||||
if type -p iptables >/dev/null; then
|
||||
local line iptables found restore
|
||||
for iptables in iptables ip6tables; do
|
||||
restore="" found=0
|
||||
while read -r line; do
|
||||
[[ $line == "*"* || $line == COMMIT || $line == "-A "*"-m comment --comment \"wg-quick(8) rule for $INTERFACE\""* ]] || continue
|
||||
[[ $line == "-A"* ]] && found=1
|
||||
printf -v restore '%s%s\n' "$restore" "${line/#-A/-D}"
|
||||
done < <($iptables-save 2>/dev/null)
|
||||
[[ $found -ne 1 ]] || echo -n "$restore" | cmd $iptables-restore -n
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Up/Down Functions
|
||||
cmd_up() {
|
||||
local i
|
||||
#[[ -z $(ip link show dev "$INTERFACE" 2>/dev/null) ]] || die "\`$INTERFACE' already exists"
|
||||
[[ -z $(ip link show dev "$INTERFACE" 2>/dev/null) ]] || cmd_down
|
||||
trap 'del_if; exit' INT TERM EXIT
|
||||
say "Starting UP the ${INTERFACE} interface ..."
|
||||
execute_hooks "${PRE_UP[@]}"
|
||||
add_if
|
||||
set_config
|
||||
for i in "${ADDRESSES[@]}"; do
|
||||
add_addr "$i"
|
||||
done
|
||||
set_mtu_up
|
||||
set_dns
|
||||
for i in $(while read -r _ i; do for i in $i; do [[ $i =~ ^[0-9a-z:.]+/[0-9]+$ ]] && echo "$i"; done; done < <(wg show "$INTERFACE" allowed-ips) | sort -nr -k 2 -t /); do
|
||||
add_route "$i"
|
||||
done
|
||||
execute_hooks "${POST_UP[@]}"
|
||||
trap - INT TERM EXIT
|
||||
sleep 3
|
||||
}
|
||||
|
||||
cmd_down() {
|
||||
say "Bringing DOWN the ${INTERFACE} interface ..."
|
||||
[[ " $(wg show interfaces) " == *" $INTERFACE "* ]] || die "$INTERFACE is not a WireGuard interface"
|
||||
execute_hooks "${PRE_DOWN[@]}"
|
||||
del_if
|
||||
[[ $HAVE_SET_DNS -eq 0 ]] || unset_dns
|
||||
[[ $HAVE_SET_FIREWALL -eq 0 ]] || remove_firewall
|
||||
#unset_dns || true
|
||||
#remove_firewall || true
|
||||
execute_hooks "${POST_DOWN[@]}"
|
||||
sleep 1
|
||||
}
|
||||
|
||||
# Main
|
||||
if [[ $# -eq 0 ]]; then
|
||||
cmd_usage
|
||||
exit 1
|
||||
elif [[ $# -eq 1 ]]; then
|
||||
auto_su
|
||||
parse_options "$1"
|
||||
cmd_up
|
||||
while true; do
|
||||
clear
|
||||
say "wg-rapid by afx. ver.2204"
|
||||
echo " "
|
||||
say "[q] to stop the VPN connection."
|
||||
say "[d] or close the terminal window to keep the VPN connection setup configured"
|
||||
say "[o] forward all networking through the VPN tunnel"
|
||||
say "[p] forward the predefined routes only through the VPN tunnel"
|
||||
echo " "
|
||||
wg show
|
||||
echo " "
|
||||
read -t 1 -N 1 input
|
||||
if [[ $input = "q" ]] || [[ $input = "Q" ]]; then
|
||||
echo
|
||||
break
|
||||
fi
|
||||
if [[ $input = "d" ]] || [[ $input = "D" ]]; then
|
||||
echo
|
||||
say "$PROGRAM detached."
|
||||
exit 0
|
||||
fi
|
||||
if [[ $input = "p" ]] || [[ $input = "P" ]]; then
|
||||
cmd_down
|
||||
LINE_ROUTE_LOCAL=`grep -n 'Route only vpn trafic through vpn' /etc/wireguard/$1.conf | cut -d ':' -f 1`
|
||||
((LINE_ROUTE_LOCAL=LINE_ROUTE_LOCAL+1))
|
||||
LINE_ROUTE_ALL=`grep -n 'Route ALL traffic through vpn' /etc/wireguard/$1.conf | cut -d ':' -f 1`
|
||||
((LINE_ROUTE_ALL=LINE_ROUTE_ALL+1))
|
||||
sed -i "${LINE_ROUTE_LOCAL} s/^##*//" /etc/wireguard/$1.conf
|
||||
sed -i "${LINE_ROUTE_ALL} s/^/#/" /etc/wireguard/$1.conf
|
||||
parse_options "$1"
|
||||
cmd_up
|
||||
fi
|
||||
if [[ $input = "o" ]] || [[ $input = "O" ]]; then
|
||||
cmd_down
|
||||
sleep 1
|
||||
LINE_ROUTE_LOCAL=`grep -n 'Route only vpn trafic through vpn' /etc/wireguard/$1.conf | cut -d ':' -f 1`
|
||||
((LINE_ROUTE_LOCAL=LINE_ROUTE_LOCAL+1))
|
||||
LINE_ROUTE_ALL=`grep -n 'Route ALL traffic through vpn' /etc/wireguard/$1.conf | cut -d ':' -f 1`
|
||||
((LINE_ROUTE_ALL=LINE_ROUTE_ALL+1))
|
||||
sed -i "${LINE_ROUTE_LOCAL} s/^/#/" /etc/wireguard/$1.conf
|
||||
sed -i "${LINE_ROUTE_ALL} s/^##*//" /etc/wireguard/$1.conf
|
||||
parse_options "$1"
|
||||
cmd_up
|
||||
fi
|
||||
done
|
||||
cmd_down
|
||||
elif [[ $# -eq 2 ]]; then
|
||||
auto_su
|
||||
parse_options "$1"
|
||||
if [ "$2" == "down" ]; then
|
||||
cmd_down
|
||||
exit 0
|
||||
else
|
||||
say "$PROGRAM [ CONFIG_NAME ] [ down ]"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
15
config.dist
Normal file
15
config.dist
Normal file
|
@ -0,0 +1,15 @@
|
|||
public_ifname=ens3
|
||||
ip_db=/etc/wireguard/ipdb.pool
|
||||
server_endpoint_address=wire.example.com
|
||||
net_prefix=69
|
||||
allowed_routes="10.15.0.0/16, 192.168.0.0/24"
|
||||
monitor_host=10.15.0.15
|
||||
email_origin=wire.example.com
|
||||
email_host=email-smtp.eu-west-1.amazonaws.com
|
||||
email_user=AUSER
|
||||
email_pass=APASS
|
||||
email_destination=admin@domain
|
||||
ldap_server=ldap://idm.example.com
|
||||
ldap_login=cn=admin
|
||||
ldap_password=PASS
|
||||
ldap_basedn=dc=admin,dc=com
|
44
gen-ip-database.sh
Executable file
44
gen-ip-database.sh
Executable file
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source config
|
||||
|
||||
check_root() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
printf %b\\n "] Please run the script as root."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
gen_cidr() {
|
||||
base=${1%/*}
|
||||
masksize=${1#*/}
|
||||
|
||||
[ $masksize -lt 8 ] && { echo "] Max range is /8."; exit 1;}
|
||||
|
||||
mask=$(( 0xFFFFFFFF << (32 - $masksize) ))
|
||||
|
||||
IFS=. read a b c d <<< $base
|
||||
|
||||
ip=$(( ($b << 16) + ($c << 8) + $d ))
|
||||
|
||||
ipstart=$(( $ip & $mask ))
|
||||
ipend=$(( ($ipstart | ~$mask ) & 0x7FFFFFFF ))
|
||||
|
||||
seq $ipstart $ipend | while read i; do
|
||||
echo $a.$(( ($i & 0xFF0000) >> 16 )).$(( ($i & 0xFF00) >> 8 )).$(( $i & 0x00FF ))
|
||||
done
|
||||
}
|
||||
|
||||
check_root
|
||||
|
||||
# This generates all host address for our vpn subnet but skips the following:
|
||||
# - vpn server address, which ends with .0.1
|
||||
# - the network address and the broadcast address
|
||||
# - all host addresses in between that looks like /24 net and mask, they should work but they are
|
||||
# misleading in that regard, and we do have enough addresses already
|
||||
if [ -f $ip_db ]; then
|
||||
echo "] IP pool exists at $ip_db. Remove it first."
|
||||
exit 1
|
||||
else
|
||||
gen_cidr 10.${net_prefix}.0.0/20 | grep -v \\.0$ | grep -v .255$ | grep -v \\.0\\.1$ > $ip_db
|
||||
fi
|
257
init.sh
Executable file
257
init.sh
Executable file
|
@ -0,0 +1,257 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source config
|
||||
|
||||
check_root() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
printf %b\\n "] Please run the script as root."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Welcome
|
||||
echo ""
|
||||
cat README.md
|
||||
echo ""
|
||||
|
||||
check_root
|
||||
|
||||
# enable IPv4 forwarding
|
||||
sed -i 's/\#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
|
||||
|
||||
# negate the need to reboot after the above change
|
||||
sysctl -p
|
||||
|
||||
# update/upgrade server and refresh repo
|
||||
apt update -y && apt upgrade -y && apt autoremove -y
|
||||
|
||||
# remove the default firewall
|
||||
ufw disable
|
||||
apt remove --purge ufw -y
|
||||
apt install iptables netfilter-persistent -y
|
||||
|
||||
# install fail2ban
|
||||
apt install fail2ban -y
|
||||
|
||||
# install python-ldap
|
||||
apt install python3-dev python3-pip python3-ldap -y
|
||||
|
||||
# install wireguard
|
||||
systemctl stop wg-quick@wg0.service
|
||||
systemctl disable wg-quick@wg0.service
|
||||
apt install wireguard -y
|
||||
apt install qrencode -y
|
||||
|
||||
# install jq
|
||||
apt install jq -y
|
||||
|
||||
# install curl
|
||||
apt install curl -y
|
||||
|
||||
# create Wireguard interface config
|
||||
bash -c "cat > /etc/wireguard/wg0.conf" << ENDOFFILE
|
||||
[Interface]
|
||||
PrivateKey = server_private_key
|
||||
Address = 10.net_prefix.0.1/20
|
||||
ListenPort = 550net_prefix
|
||||
|
||||
PostUp = iptables -A FORWARD -i ${public_ifname} -o wg0 -j ACCEPT; iptables -A FORWARD -i wg0 -o ${public_ifname} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -o ${public_ifname} -j MASQUERADE
|
||||
PostDown = iptables -D FORWARD -i ${public_ifname} -o wg0 -j ACCEPT; iptables -D FORWARD -i wg0 -o ${public_ifname} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -o ${public_ifname} -j MASQUERADE
|
||||
SaveConfig = true
|
||||
ENDOFFILE
|
||||
|
||||
cat << EOF | bash
|
||||
cd /etc/wireguard/
|
||||
umask 077
|
||||
[ ! -f server_private.key ] && wg genkey | tee server_private.key | wg pubkey > server_public.key
|
||||
EOF
|
||||
sed -i "s/net_prefix/${net_prefix}/g" /etc/wireguard/wg0.conf
|
||||
sed -i "s/server_private_key/$(sed 's:/:\\/:g' /etc/wireguard/server_private.key)/" /etc/wireguard/wg0.conf
|
||||
|
||||
# make root owner of the Wireguard config file
|
||||
chown -v root:root /etc/wireguard/wg0.conf
|
||||
chmod -v 600 /etc/wireguard/wg0.conf
|
||||
|
||||
# make Wireguard interface start at boot
|
||||
systemctl enable wg-quick@wg0.service
|
||||
|
||||
|
||||
# flush all chains
|
||||
iptables -P INPUT ACCEPT
|
||||
iptables -P FORWARD ACCEPT
|
||||
iptables -P OUTPUT ACCEPT
|
||||
iptables -t nat -F
|
||||
iptables -t mangle -F
|
||||
iptables -F
|
||||
# delete all chains
|
||||
iptables -X
|
||||
|
||||
# configure the firewall and make it persistent
|
||||
DEBIAN_FRONTEND=noninteractive apt install iptables-persistent -y
|
||||
systemctl enable netfilter-persistent
|
||||
iptables -P INPUT DROP
|
||||
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
iptables -A INPUT -p all -s localhost -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 655 -j ACCEPT
|
||||
iptables -A INPUT -p udp --dport 655 -j ACCEPT
|
||||
iptables -A INPUT -p tcp -s ${monitor_host} --dport 10050 -j ACCEPT
|
||||
iptables -A INPUT -p udp --dport 550${net_prefix} -j ACCEPT
|
||||
iptables -A INPUT -p all -i wg0 -j ACCEPT
|
||||
iptables -P FORWARD ACCEPT
|
||||
iptables -A FORWARD -i wg0 -o wg0 -j REJECT
|
||||
iptables -P OUTPUT ACCEPT
|
||||
netfilter-persistent save
|
||||
|
||||
# install Unbound DNS
|
||||
systemctl stop unbound.service
|
||||
systemctl disable unbound.service
|
||||
apt install unbound unbound-host -y
|
||||
|
||||
# download list of DNS root servers
|
||||
curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache
|
||||
|
||||
# create unbound log file
|
||||
mkdir -p /var/log/unbound
|
||||
chown unbound:unbound /var/log/unbound/
|
||||
touch /var/log/unbound/unbound.log
|
||||
chown unbound:unbound /var/log/unbound/unbound.log
|
||||
|
||||
echo "/var/log/unbound/unbound.log rw," > /etc/apparmor.d/local/usr.sbin.unbound
|
||||
apparmor_parser -r /etc/apparmor.d/usr.sbin.unbound
|
||||
|
||||
# create custom conf
|
||||
touch /etc/unbound/custom.conf
|
||||
chown unbound:unbound /etc/unbound/custom.conf
|
||||
|
||||
# create Unbound config file
|
||||
bash -c "cat > /etc/unbound/unbound.conf" << ENDOFFILE
|
||||
server:
|
||||
num-threads: 4
|
||||
|
||||
# enable logs
|
||||
verbosity: 1
|
||||
logfile: /var/log/unbound/unbound.log
|
||||
chroot: ""
|
||||
log-queries: yes
|
||||
|
||||
# list of root DNS servers
|
||||
root-hints: "/var/lib/unbound/root.hints"
|
||||
|
||||
# use the root server's key for DNSSEC
|
||||
auto-trust-anchor-file: "/var/lib/unbound/root.key"
|
||||
|
||||
# respond to DNS requests on all interfaces
|
||||
interface: 0.0.0.0
|
||||
max-udp-size: 3072
|
||||
|
||||
# IPs authorised to access the DNS Server
|
||||
access-control: 0.0.0.0/0 refuse
|
||||
access-control: 127.0.0.1 allow
|
||||
access-control: 10.net_prefix.0.0/20 allow
|
||||
|
||||
# not allowed to be returned for public Internet names
|
||||
private-address: 10.net_prefix.0.0/20
|
||||
|
||||
#hide DNS Server info
|
||||
hide-identity: yes
|
||||
hide-version: yes
|
||||
|
||||
# limit DNS fraud and use DNSSEC
|
||||
harden-glue: yes
|
||||
harden-dnssec-stripped: yes
|
||||
harden-referral-path: yes
|
||||
|
||||
# add an unwanted reply threshold to clean the cache and avoid, when possible, DNS poisoning
|
||||
unwanted-reply-threshold: 10000000
|
||||
|
||||
# have the validator print validation failures to the log
|
||||
val-log-level: 1
|
||||
|
||||
# minimum lifetime of cache entries in seconds
|
||||
cache-min-ttl: 1800
|
||||
|
||||
# maximum lifetime of cached entries in seconds
|
||||
cache-max-ttl: 14400
|
||||
prefetch: yes
|
||||
prefetch-key: yes
|
||||
|
||||
# additional entries
|
||||
include: /etc/unbound/custom.conf
|
||||
ENDOFFILE
|
||||
|
||||
sed -i "s/net_prefix/${net_prefix}/g" /etc/unbound/unbound.conf
|
||||
|
||||
# give root ownership of the Unbound config
|
||||
chown -R unbound:unbound /var/lib/unbound
|
||||
|
||||
# enable Unbound in place of systemd-resovled
|
||||
systemctl enable unbound-resolvconf
|
||||
systemctl enable unbound
|
||||
systemctl start unbound
|
||||
|
||||
# disable systemd-resolved
|
||||
systemctl stop systemd-resolved
|
||||
systemctl disable systemd-resolved
|
||||
unlink /etc/resolv.conf
|
||||
bash -c "cat > /etc/resolv.conf" << ENDOFFILE
|
||||
nameserver 127.0.0.1
|
||||
ENDOFFILE
|
||||
|
||||
# Initial database generation
|
||||
bash -c "./gen-ip-database.sh"
|
||||
|
||||
#provide scripts in /usr/local/bin
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cp -v ${__dir}/wgstats.sh /usr/local/bin/
|
||||
cp -v ${__dir}/wgldap.sh /usr/local/bin/
|
||||
|
||||
#install Postfix mailserver
|
||||
if [ $email_origin == "wire.example.com" ]; then
|
||||
echo "] WARN: Mailing is disabled!"
|
||||
else
|
||||
echo "] Setting up mail server $email_origin ..."
|
||||
if [ ! -f /etc/postfix/main.cf ]; then
|
||||
echo "] Mail server config does not exist. Installing..."
|
||||
|
||||
# install postfix
|
||||
echo "postfix postfix/mailname string ${email_origin}" | debconf-set-selections
|
||||
echo "postfix postfix/main_mailer_type string 'Internet Site'" | debconf-set-selections
|
||||
apt install -y postfix mailutils libsasl2-2 ca-certificates libsasl2-modules mutt zip
|
||||
|
||||
# setup mail server for email reports
|
||||
/usr/sbin/postconf -e "relayhost = [${email_host}]:587" \
|
||||
"smtp_sasl_auth_enable = yes" \
|
||||
"smtp_sasl_security_options = noanonymous" \
|
||||
"smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd" \
|
||||
"smtp_use_tls = yes" \
|
||||
"smtp_tls_security_level = encrypt" \
|
||||
"smtp_tls_note_starttls_offer = yes"
|
||||
echo "[${email_host}]:587 ${email_user}:${email_pass}" > /etc/postfix/sasl_passwd
|
||||
/usr/sbin/postmap hash:/etc/postfix/sasl_passwd
|
||||
chown root:root /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
|
||||
chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
|
||||
/usr/sbin/postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"
|
||||
/usr/sbin/postconf -e "myorigin = ${email_origin}"
|
||||
sleep 2
|
||||
service postfix restart
|
||||
fi
|
||||
fi
|
||||
|
||||
# Setup LDAP sync service
|
||||
if [ $ldap_server == "ldap://idm.example.com" ]; then
|
||||
echo "] WARN: LDAP disabled!"
|
||||
else
|
||||
echo "] Setting up LDAP server $ldap_server"
|
||||
cp -v ${__dir}/wgldapsync.service /etc/systemd/system/wgldapsync.service
|
||||
cp -v ${__dir}/wgldapsync.timer /etc/systemd/system/wgldapsync.timer
|
||||
systemctl daemon-reload
|
||||
systemctl enable wgldapsync.timer
|
||||
systemctl status wgldapsync.service
|
||||
systemctl status wgldapsync.timer
|
||||
fi
|
||||
|
||||
# reboot to make changes effective
|
||||
echo "] System reboot after 30 seconds..."
|
||||
sleep 30
|
||||
reboot
|
171
ldapsync.py
Executable file
171
ldapsync.py
Executable file
|
@ -0,0 +1,171 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import configparser
|
||||
import pprint
|
||||
import socket
|
||||
import ldap
|
||||
import subprocess
|
||||
|
||||
DEBUG = False
|
||||
DEBUG_LDAP = False
|
||||
CONFIG_PATH = "/root/wiregate/"
|
||||
LOCAL_DB_PATH = '/etc/wireguard/clients/'
|
||||
|
||||
# parse config
|
||||
cds = 'wiregate' #ConfigParser dummy section
|
||||
with open(CONFIG_PATH + '/config', 'r') as f:
|
||||
config_string = '[' + cds + ']\n' + f.read()
|
||||
config = configparser.ConfigParser()
|
||||
config.read_string(config_string)
|
||||
|
||||
baseDN = config.get(cds, 'ldap_basedn')
|
||||
LDAP_SERVER = config.get(cds, 'ldap_server')
|
||||
LDAP_LOGIN = config.get(cds, 'ldap_login') + ',' + baseDN
|
||||
LDAP_PASSWORD = config.get(cds, 'ldap_password')
|
||||
|
||||
serverhost = socket.gethostname()
|
||||
searchScope = ldap.SCOPE_SUBTREE
|
||||
|
||||
def LdapQuery(searchFilter, searchAttrs):
|
||||
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
||||
|
||||
if DEBUG_LDAP:
|
||||
print("Connecting to " + LDAP_SERVER)
|
||||
l = ldap.initialize(LDAP_SERVER)
|
||||
try:
|
||||
#l.set_option(ldap.OPT_REFERRALS, 0)
|
||||
#l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
|
||||
#l.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND)
|
||||
#l.set_option(ldap.OPT_X_TLS_DEMAND, True)
|
||||
#l.set_option(ldap.OPT_DEBUG_LEVEL, 255)
|
||||
l.set_option(ldap.OPT_NETWORK_TIMEOUT, 10.0)
|
||||
l.simple_bind_s(LDAP_LOGIN, LDAP_PASSWORD)
|
||||
|
||||
query = {}
|
||||
ldap_result_id = l.search(baseDN, searchScope, searchFilter, searchAttrs)
|
||||
while 1:
|
||||
rType, rData = l.result(ldap_result_id, 0)
|
||||
if (rData == []):
|
||||
break
|
||||
else:
|
||||
if rType == ldap.RES_SEARCH_ENTRY:
|
||||
cn = rData[0][0]
|
||||
data = rData[0][1]
|
||||
|
||||
#Flatten, just for more easy access
|
||||
for (k, v) in data.items():
|
||||
if len(v) == 1:
|
||||
data[k] = v[0]
|
||||
|
||||
#uid = data["uid"]
|
||||
query[cn] = data
|
||||
return query
|
||||
|
||||
except ldap.LDAPError as e:
|
||||
print(e)
|
||||
sys.exit(2)
|
||||
|
||||
finally:
|
||||
if DEBUG_LDAP:
|
||||
print('Server unbind.')
|
||||
l.unbind_s()
|
||||
return 0
|
||||
|
||||
def main():
|
||||
print("] WireGate LDAP sync")
|
||||
|
||||
# query ldap server and gather list of REMOTE peers which belong to cn=<HOSTNAME>,ou=Groups,baseDN
|
||||
ldapGroups = LdapQuery('(|(&(objectClass=groupOfUniqueNames)(cn=' + serverhost + ')))', ['uniqueMember'])
|
||||
|
||||
if ldapGroups == {}:
|
||||
print('] Group ' + serverhost + ' not found')
|
||||
sys.exit(1)
|
||||
|
||||
if ldapGroups != 0:
|
||||
members = ldapGroups['cn=' + serverhost + ',ou=Groups,' + baseDN]['uniqueMember']
|
||||
if not isinstance(members, list):
|
||||
members = [members]
|
||||
print('] Group: ' + serverhost)
|
||||
print('] Remote members: ' + str(len(members)))
|
||||
|
||||
remote_peers = []
|
||||
for member in members:
|
||||
d_member = member.decode('ascii')
|
||||
if DEBUG:
|
||||
print('] Processing ' + str(d_member))
|
||||
|
||||
searchFilterUser='(' + d_member.split(',')[0] + ')'
|
||||
ldapUser = LdapQuery(searchFilterUser, ['mail', 'l'])
|
||||
user = ldapUser[d_member]
|
||||
#get attributes
|
||||
#mail
|
||||
m_mail = str(user['mail'].decode('ascii'))
|
||||
m_domain = m_mail.split('@')[1]
|
||||
m_user = m_mail.split('@')[0]
|
||||
|
||||
m_peername = m_domain + '-' + m_user
|
||||
|
||||
#get additional peers provided with the l attribute
|
||||
if 'l' in user:
|
||||
labels = user['l']
|
||||
if not isinstance(labels, list):
|
||||
labels = [labels]
|
||||
for label in labels:
|
||||
peer = m_peername + '-' + str(label.decode('ascii'))
|
||||
remote_peers.append({ 'mail': m_mail, 'peer': peer })
|
||||
|
||||
#get the parent peer
|
||||
peer = m_peername
|
||||
remote_peers.append({ 'mail': m_mail, 'peer': peer })
|
||||
|
||||
#searchFilterUserSubs='(|(&(objectClass=*)(member=uid=%s,cn=users,ou=Groups,' + baseDN + ')))'
|
||||
user_subscriptions= LdapQuery('(|(&(objectClass=groupOfUniqueNames)(uniqueMember=' + str(d_member) + ')))', ['cn'])
|
||||
if DEBUG:
|
||||
pp = pprint.PrettyPrinter(depth=3)
|
||||
pp.pprint(user_subscriptions)
|
||||
|
||||
print("] Remote peers: " + str(len(remote_peers)))
|
||||
if DEBUG:
|
||||
pp = pprint.PrettyPrinter(depth=3)
|
||||
pp.pprint(remote_peers)
|
||||
|
||||
# query LOCAL peers database
|
||||
local_peers = []
|
||||
for file in os.listdir(LOCAL_DB_PATH):
|
||||
if file.endswith(".info"):
|
||||
try:
|
||||
cds = 'localdata' #ConfigParser dummy section
|
||||
with open(LOCAL_DB_PATH + '/' + file, 'r') as f:
|
||||
data_string = '[' + cds + ']\n' + f.read()
|
||||
local_peer_data = configparser.ConfigParser()
|
||||
local_peer_data.read_string(data_string)
|
||||
local_mail = local_peer_data.get(cds, 'email')
|
||||
local_peer = local_peer_data.get(cds, 'peer')
|
||||
local_peers.append({ 'mail': local_mail, 'peer': local_peer })
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sys.exit(2)
|
||||
|
||||
print("] Local peers: " + str(len(local_peers)))
|
||||
if DEBUG:
|
||||
pp = pprint.PrettyPrinter(depth=3)
|
||||
pp.pprint(local_peers)
|
||||
|
||||
# add / enable REMOTE peers if they DO NOT exist in the local database
|
||||
for r_peer in remote_peers:
|
||||
#print('add peer ' + r_peer['peer'] + ' - ' + r_peer['mail'])
|
||||
process = subprocess.Popen([CONFIG_PATH + "peer_add.sh", "-p", r_peer['peer'], "-e", r_peer['mail']])
|
||||
process.wait()
|
||||
|
||||
# disable (do not remove) LOCAL peers which DO NOT exist in the remote database
|
||||
for l_peer in local_peers:
|
||||
if l_peer not in remote_peers:
|
||||
#print('rem peer ' + l_peer['peer'] + ' - ' + l_peer['mail'])
|
||||
process = subprocess.Popen([CONFIG_PATH + "peer_disable.sh", "-p", l_peer['peer']])
|
||||
process.wait()
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
20
mail.md
Normal file
20
mail.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
Hello,
|
||||
|
||||
To be able to access the resources on our development infrastructure, you will need to set up a VPN profile.
|
||||
|
||||
To install the necessary client application, please visit the following page to obtain packages for the operating system your device is currently using:
|
||||
|
||||
https://www.wireguard.com/install/
|
||||
|
||||
Please take care of the configuration files and QR images as equivalent to a secure password.
|
||||
|
||||
For Windows, MacOS, Android and iOS simply import profile.conf or profile_alltraffic.conf file using the import tunnel function of the Wireguard software.
|
||||
|
||||
You may choose to import both versions and switch between them, where the `alltraffic` version pushes all network routes through the endpoint, which is useful for example if a third party system requires a whitelisted company address or to switch geographic policy. The tradeoff is the limited bandwidth and delay of the endpoint for every network request, which could affect some resource intensive applications.
|
||||
|
||||
The connected device follows the remote network policy for the routed traffic and DNS requests.
|
||||
|
||||
For Linux you may use the wg-rapid script `sudo cp linux/wg-rapid /usr/local/bin`. Then copy either profile.conf file or the profile_alltraffic.conf version of it as /etc/wireguard/office.conf and start with `wg-rapid office` Please not that the linux script has built-in capability to switch between preselected routes, so it doesn't matter which one of them you choose to copy in this case.
|
||||
|
||||
Using a VPN client is somewhat platform and infrastructure specific, you may always contact #team-sysops for further assistance.
|
||||
|
167
peer_add.sh
Executable file
167
peer_add.sh
Executable file
|
@ -0,0 +1,167 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source config
|
||||
|
||||
check_root() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
printf %b\\n "] Please run the script as root."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "Usage: peer_add.sh -p <peer name> -e <email address>"
|
||||
}
|
||||
|
||||
random_ip_pickup() {
|
||||
# Randomly select an IP and remove it from the pool
|
||||
local ipsleft=`cat ${ip_db} | wc -l`
|
||||
if [[ "${ipsleft}" -eq 0 ]]; then
|
||||
echo "empty"
|
||||
else
|
||||
local random_ip=$(shuf -n 1 ${ip_db})
|
||||
grep -v "${random_ip}$" ${ip_db} > ${ip_db}.tmp
|
||||
mv ${ip_db}.tmp ${ip_db}
|
||||
echo "${random_ip}"
|
||||
fi
|
||||
}
|
||||
|
||||
check_root
|
||||
|
||||
no_args="true"
|
||||
while getopts p:e: option
|
||||
do
|
||||
case $option in
|
||||
(p)
|
||||
name=${OPTARG};;
|
||||
(e)
|
||||
email=${OPTARG};;
|
||||
(*)
|
||||
usage
|
||||
exit;;
|
||||
esac
|
||||
no_args="false"
|
||||
done
|
||||
|
||||
[[ "$no_args" == "true" ]] && { usage; exit 1; }
|
||||
|
||||
# Check if IP pool exist
|
||||
if [ ! -f ${ip_db} ]; then
|
||||
echo "] IP pool does not exists at ${ip_db}. Generate it first."
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# Check if both arguments exist
|
||||
if [ -z ${name} ] || [ -z ${email} ]; then
|
||||
echo "] Not enough arguments"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if peer config exist
|
||||
if [ -f /etc/wireguard/clients/${name}_public.key ]; then
|
||||
peer_exists_in_wg=$(wg show wg0 dump | grep $(cat /etc/wireguard/clients/${name}_public.key) | wc -l)
|
||||
if [ ! ${peer_exists_in_wg} -eq 0 ]; then
|
||||
#echo "] ${name} already activated"
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate wireguard peer keys and config
|
||||
if [ -z ${server_endpoint_address} ]; then
|
||||
server_endpoint_address=$(ip addr show ${public_ifname} | grep -o "inet [0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" | grep -o "[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*")
|
||||
fi
|
||||
|
||||
# Creating clients subdir
|
||||
mkdir -p /etc/wireguard/clients
|
||||
|
||||
if [ ! -f /etc/wireguard/clients/${name}.info ]; then
|
||||
echo "] ${name} config will be generated."
|
||||
peer_address_from_pool=$(random_ip_pickup)
|
||||
if [ ${peer_address_from_pool} = "empty" ]; then
|
||||
echo "] IP Pool is empty"
|
||||
exit 5
|
||||
fi
|
||||
|
||||
bash -c "cat > /etc/wireguard/clients/${name}_wg0.conf" << ENDOFFILE
|
||||
[Interface]
|
||||
PrivateKey = client_private_key
|
||||
Address = selected_peer_address/32
|
||||
DNS = 10.net_prefix.0.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = server_public_key
|
||||
Endpoint = server_endpoint:550net_prefix
|
||||
# Route only vpn trafic through vpn
|
||||
AllowedIPs = 10.net_prefix.0.0/20, allowed_routes
|
||||
# Route ALL traffic through vpn
|
||||
#AllowedIPs = 0.0.0.0/0
|
||||
PersistentKeepalive = 21
|
||||
ENDOFFILE
|
||||
|
||||
bash -c "cat > /etc/wireguard/clients/${name}_alltraffic_wg0.conf" << ENDOFFILE
|
||||
[Interface]
|
||||
PrivateKey = client_private_key
|
||||
Address = selected_peer_address/32
|
||||
DNS = 10.net_prefix.0.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = server_public_key
|
||||
Endpoint = server_endpoint:550net_prefix
|
||||
# Route only vpn trafic through vpn
|
||||
#AllowedIPs = 10.net_prefix.0.0/20, allowed_routes
|
||||
# Route ALL traffic through vpn
|
||||
AllowedIPs = 0.0.0.0/0
|
||||
PersistentKeepalive = 21
|
||||
ENDOFFILE
|
||||
|
||||
cat << EOF | bash
|
||||
cd /etc/wireguard/clients
|
||||
umask 077
|
||||
[ ! -f ${name}_private.key ] && wg genkey | tee ${name}_private.key | wg pubkey > ${name}_public.key
|
||||
EOF
|
||||
|
||||
sed -i "s/net_prefix/${net_prefix}/g" /etc/wireguard/clients/${name}_wg0.conf
|
||||
sed -i "s#allowed_routes#${allowed_routes}#g" /etc/wireguard/clients/${name}_wg0.conf
|
||||
sed -i "s/selected_peer_address/${peer_address_from_pool}/g" /etc/wireguard/clients/${name}_wg0.conf
|
||||
sed -i "s/server_endpoint/${server_endpoint_address}/g" /etc/wireguard/clients/${name}_wg0.conf
|
||||
sed -i "s/server_public_key/$(sed 's:/:\\/:g' /etc/wireguard/server_public.key)/" /etc/wireguard/clients/${name}_wg0.conf
|
||||
sed -i "s/client_private_key/$(sed 's:/:\\/:g' /etc/wireguard/clients/${name}_private.key)/" /etc/wireguard/clients/${name}_wg0.conf
|
||||
|
||||
sed -i "s/net_prefix/${net_prefix}/g" /etc/wireguard/clients/${name}_alltraffic_wg0.conf
|
||||
sed -i "s#allowed_routes#${allowed_routes}#g" /etc/wireguard/clients/${name}_alltraffic_wg0.conf
|
||||
sed -i "s/selected_peer_address/${peer_address_from_pool}/g" /etc/wireguard/clients/${name}_alltraffic_wg0.conf
|
||||
sed -i "s/server_endpoint/${server_endpoint_address}/g" /etc/wireguard/clients/${name}_alltraffic_wg0.conf
|
||||
sed -i "s/server_public_key/$(sed 's:/:\\/:g' /etc/wireguard/server_public.key)/" /etc/wireguard/clients/${name}_alltraffic_wg0.conf
|
||||
sed -i "s/client_private_key/$(sed 's:/:\\/:g' /etc/wireguard/clients/${name}_private.key)/" /etc/wireguard/clients/${name}_alltraffic_wg0.conf
|
||||
qrencode -t PNG -o /etc/wireguard/clients/${name}_alltraffic_qr.png < /etc/wireguard/clients/${name}_alltraffic_wg0.conf
|
||||
|
||||
echo "peer=${name}" > /etc/wireguard/clients/${name}.info
|
||||
echo "email=${email}" >> /etc/wireguard/clients/${name}.info
|
||||
echo "ip=${peer_address_from_pool}" >> /etc/wireguard/clients/${name}.info
|
||||
peer_ip=$(cat /etc/wireguard/clients/${name}.info | grep "^ip=" | cut -d '=' -f 2)
|
||||
|
||||
#send mail with the generated config
|
||||
bash -c "./peer_mail.sh -p ${name}"
|
||||
else
|
||||
echo "] ${name} config already exists."
|
||||
peer_ip=$(cat /etc/wireguard/clients/${name}.info | grep "^ip=" | cut -d '=' -f 2)
|
||||
|
||||
#check if private key was previously disabled
|
||||
if [ -f /etc/wireguard/clients/${name}_public.disabled ]; then
|
||||
echo "] ${name} was previously disabled."
|
||||
mv /etc/wireguard/clients/${name}_public.disabled /etc/wireguard/clients/${name}_public.key
|
||||
fi
|
||||
|
||||
#check if peer ip already exist in the database
|
||||
ip_exists_in_pool=$(grep "${peer_ip}$" ${ip_db} | wc -l)
|
||||
if [ ${ip_exists_in_pool} -eq 1 ]; then
|
||||
echo "] ${peer_ip} exists in pool. Removing to avoid duplicates."
|
||||
grep -v "${peer_ip}$" ${ip_db} > ${ip_db}.tmp
|
||||
mv ${ip_db}.tmp ${ip_db}
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "] ${name} (${email}) config set. Endpoint address is ${server_endpoint_address}. Selected user VPN IP is ${peer_ip}"
|
||||
wg set wg0 peer $(cat /etc/wireguard/clients/${name}_public.key) allowed-ips ${peer_ip}/32 persistent-keepalive 21
|
||||
|
12
peer_addall.sh
Executable file
12
peer_addall.sh
Executable file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
ALLCLIENTS=/etc/wireguard/clients/*.info
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
for client in $ALLCLIENTS; do
|
||||
peer=$(cat ${client} | grep '^peer=' | cut -d '=' -f 2)
|
||||
email=$(cat ${client} | grep '^email=' | cut -d '=' -f 2)
|
||||
echo "] peer_add.sh - peer: $peer - email: $email"
|
||||
bash ${__dir}/peer_add.sh -p ${peer} -e ${email}
|
||||
done
|
62
peer_del.sh
Executable file
62
peer_del.sh
Executable file
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source config
|
||||
|
||||
check_root() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
printf %b\\n "] Please run the script as root."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "Usage: peer_del.sh -p <peer name>"
|
||||
}
|
||||
|
||||
check_root
|
||||
|
||||
no_args="true"
|
||||
while getopts p: option
|
||||
do
|
||||
case $option in
|
||||
(p)
|
||||
name=${OPTARG};;
|
||||
(*)
|
||||
usage
|
||||
exit;;
|
||||
esac
|
||||
no_args="false"
|
||||
done
|
||||
|
||||
[[ "$no_args" == "true" ]] && { usage; exit 1; }
|
||||
|
||||
# Check if peer config exist
|
||||
if [ ! -f /etc/wireguard/clients/${name}.info ]; then
|
||||
echo "] Peer ${name} does not exists"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "] Removing wireguard config for ${name}"
|
||||
salvaged_ip=$(cat /etc/wireguard/clients/${name}.info | grep "^ip=" | cut -d '=' -f 2)
|
||||
echo "] Salvaged IP is ${salvaged_ip} and will be returned back to ${ip_db}"
|
||||
echo ${salvaged_ip} >> ${ip_db}
|
||||
|
||||
#check if config is previously disabled
|
||||
if [ -f /etc/wireguard/clients/${name}_public.disabled ]; then
|
||||
echo "] ${name} was previously disabled."
|
||||
mv /etc/wireguard/clients/${name}_public.disabled /etc/wireguard/clients/${name}_public.key
|
||||
fi
|
||||
|
||||
wg set wg0 peer $(cat /etc/wireguard/clients/${name}_public.key) remove
|
||||
rm /etc/wireguard/clients/${name}_public.key
|
||||
rm /etc/wireguard/clients/${name}.info
|
||||
|
||||
# remove additional sensitive info
|
||||
rm -f /etc/wireguard/clients/${name}_wg0.conf
|
||||
rm -f /etc/wireguard/clients/${name}_qr.png
|
||||
rm -f /etc/wireguard/clients/${name}_alltraffic_wg0.conf
|
||||
rm -f /etc/wireguard/clients/${name}_alltraffic_qr.png
|
||||
rm -f /etc/wireguard/clients/${name}_private.key
|
||||
|
||||
exit 0
|
50
peer_disable.sh
Executable file
50
peer_disable.sh
Executable file
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source config
|
||||
|
||||
check_root() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
printf %b\\n "] Please run the script as root."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "Usage: peer_disable.sh -p <peer name>"
|
||||
}
|
||||
|
||||
check_root
|
||||
|
||||
no_args="true"
|
||||
while getopts p: option
|
||||
do
|
||||
case $option in
|
||||
(p)
|
||||
name=${OPTARG};;
|
||||
(*)
|
||||
usage
|
||||
exit;;
|
||||
esac
|
||||
no_args="false"
|
||||
done
|
||||
|
||||
[[ "$no_args" == "true" ]] && { usage; exit 1; }
|
||||
|
||||
# Check if peer config exist
|
||||
if [ ! -f /etc/wireguard/clients/${name}.info ]; then
|
||||
echo "] Peer ${name} does not exists"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
#check if config is previously disabled
|
||||
if [ -f /etc/wireguard/clients/${name}_public.disabled ]; then
|
||||
#echo "] ${name} is already disabled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "] Disable wireguard config for ${name}"
|
||||
wg set wg0 peer $(cat /etc/wireguard/clients/${name}_public.key) remove
|
||||
mv /etc/wireguard/clients/${name}_public.key /etc/wireguard/clients/${name}_public.disabled
|
||||
|
||||
exit 0
|
69
peer_mail.sh
Executable file
69
peer_mail.sh
Executable file
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source config
|
||||
|
||||
check_root() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
printf %b\\n "] Please run the script as root."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "Usage: peer_mail.sh -p <peer name>"
|
||||
}
|
||||
|
||||
check_root
|
||||
|
||||
no_args="true"
|
||||
while getopts p: option
|
||||
do
|
||||
case $option in
|
||||
(p)
|
||||
name=${OPTARG};;
|
||||
(*)
|
||||
usage
|
||||
exit;;
|
||||
esac
|
||||
no_args="false"
|
||||
done
|
||||
|
||||
[[ "$no_args" == "true" ]] && { usage; exit 1; }
|
||||
|
||||
email_client=$(cat /etc/wireguard/clients/${name}.info | grep "^email=" | cut -d '=' -f 2)
|
||||
|
||||
if [ -z ${email_client} ]; then
|
||||
echo "] Peer not found."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "] Sending the profile data to $email_destination"
|
||||
# strip non alphanumeric characters from peer name
|
||||
stname=$(echo ${name} | sed "s/[^[:alnum:]-]//g")
|
||||
|
||||
# fill profile tmp dir with data
|
||||
mkdir payload
|
||||
mkdir payload/mobile
|
||||
cp -v /etc/wireguard/clients/${name}_wg0.conf payload/profile.conf
|
||||
cp -v /etc/wireguard/clients/${name}_alltraffic_wg0.conf payload/profile_alltraffic.conf
|
||||
cp -v /etc/wireguard/clients/${name}_alltraffic_qr.png payload/mobile/profile_alltraffic_QR.png
|
||||
|
||||
mkdir payload/linux
|
||||
cp -v client-tools/wg-rapid payload/linux/wg-rapid
|
||||
cp -v client-tools/startvpn.desktop payload/linux/startvpn.desktop
|
||||
chmod +x payload/linux/startvpn.desktop
|
||||
|
||||
# pack the attachment
|
||||
cd payload
|
||||
zip -r ../payload.zip .
|
||||
cd ..
|
||||
mv payload.zip ${stname}_profile.zip
|
||||
|
||||
# sent the message
|
||||
mutt -s "WireGate VPN for ${email_client}" ${email_destination} -a ${stname}_profile.zip < mail.md
|
||||
#mutt -s "WireGate VPN for ${email_client}" ${email_client} -a ${stname}_profile.zip < mail.md
|
||||
|
||||
rm -f -r -v payload
|
||||
|
||||
exit 0
|
5
wgldap.sh
Executable file
5
wgldap.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
journalctl -u wgldapsync -f
|
7
wgldapsync.service
Normal file
7
wgldapsync.service
Normal file
|
@ -0,0 +1,7 @@
|
|||
[Unit]
|
||||
Description=WireGate LDAP auto-sync service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/root/wiregate
|
||||
ExecStart=/usr/bin/python3 /root/wiregate/ldapsync.py
|
9
wgldapsync.timer
Normal file
9
wgldapsync.timer
Normal file
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=WireGate LDAP auto-sync timer
|
||||
|
||||
[Timer]
|
||||
OnUnitActiveSec=30min
|
||||
OnBootSec=30min
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
38
wgstats.sh
Executable file
38
wgstats.sh
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/bin/bash
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
echo "] WireGate plugins:"
|
||||
systemctl list-timers --all | grep 'ACTIVATES\|wgldapsync'
|
||||
echo ""
|
||||
|
||||
echo "] WireGate peers:"
|
||||
tmpfile1=$(mktemp /tmp/wgstats.1.XXXXXX)
|
||||
tmpfile2=$(mktemp /tmp/wgstats.2.XXXXXX)
|
||||
|
||||
ALLPEERS=$(wg show all dump | grep -v off)
|
||||
|
||||
echo "$ALLPEERS" | while IFS= read -r peer ; do
|
||||
peerkey=$(echo "$peer" | cut -d $'\t' -f 2)
|
||||
peerfile=$(basename $(grep -l "${peerkey}" /etc/wireguard/clients/*_public.key))
|
||||
peername=$(echo ${peerfile} | cut -d '_' -f 1)
|
||||
clientip=$(echo "$peer" | cut -d $'\t' -f 4)
|
||||
peerip=$(echo "$peer" | cut -d $'\t' -f 5)
|
||||
peerlatesths=$(echo "$peer" | cut -d $'\t' -f 6)
|
||||
if [ ${peerlatesths} -eq 0 ]; then
|
||||
peerlatesthsfmt="Never"
|
||||
else
|
||||
peerlatesthsfmt=$(date -d@${peerlatesths})
|
||||
fi
|
||||
peerrx=$(echo "$peer" | cut -d $'\t' -f 7 | numfmt --to=iec-i --suffix=B)
|
||||
peertx=$(echo "$peer" | cut -d $'\t' -f 8 | numfmt --to=iec-i --suffix=B)
|
||||
echo "${peerlatesths},$peername,$clientip,$peerip,${peerlatesthsfmt},$peerrx,$peertx" >> $tmpfile1
|
||||
done
|
||||
|
||||
sort -k1 -n -t "," $tmpfile1 | cut -d "," -f 2- > $tmpfile2
|
||||
sed -i '1s/^/Peer,Client Address,Peer Address,Latest Handshake,Data Recieved,Data Sent\n/' $tmpfile2
|
||||
column -e -t -s "," $tmpfile2
|
||||
|
||||
rm $tmpfile1
|
||||
rm $tmpfile2
|
||||
exit 0
|
Loading…
Reference in a new issue