mirror of
https://github.com/pivpn/pivpn.git
synced 2024-12-20 20:00:16 +00:00
Updates to subnet generation and client creation (#1782)
* refactor(core): allow any subnet and netmask * fix(scripts): prevent adding more clients than the subnet allows * fix(scripts): correctly remove leading zeros from ipv6 quartets * refactor(core): new probabilistic subnet generation with fallback to other RFC1918 subnets
This commit is contained in:
parent
20d3a4ccd4
commit
850e665642
6 changed files with 339 additions and 106 deletions
|
@ -1713,6 +1713,59 @@ installPiVPN() {
|
||||||
writeVPNTempVarsFile
|
writeVPNTempVarsFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decIPv4ToDot() {
|
||||||
|
local a b c d
|
||||||
|
a=$((($1 & 4278190080) >> 24))
|
||||||
|
b=$((($1 & 16711680) >> 16))
|
||||||
|
c=$((($1 & 65280) >> 8))
|
||||||
|
d=$(($1 & 255))
|
||||||
|
printf "%s.%s.%s.%s\n" $a $b $c $d
|
||||||
|
}
|
||||||
|
|
||||||
|
dotIPv4ToDec() {
|
||||||
|
local original_ifs=$IFS
|
||||||
|
IFS='.'
|
||||||
|
read -r -a array_ip <<< "$1"
|
||||||
|
IFS=$original_ifs
|
||||||
|
printf "%s\n" $((array_ip[0] * 16777216 + array_ip[1] * 65536 + array_ip[2] * 256 + array_ip[3]))
|
||||||
|
}
|
||||||
|
|
||||||
|
dotIPv4FirstDec() {
|
||||||
|
local decimal_ip decimal_mask
|
||||||
|
decimal_ip=$(dotIPv4ToDec "$1")
|
||||||
|
decimal_mask=$((2 ** 32 - 1 ^ (2 ** (32 - $2) - 1)))
|
||||||
|
printf "%s\n" "$((decimal_ip & decimal_mask))"
|
||||||
|
}
|
||||||
|
|
||||||
|
dotIPv4LastDec() {
|
||||||
|
local decimal_ip decimal_mask_inv
|
||||||
|
decimal_ip=$(dotIPv4ToDec "$1")
|
||||||
|
decimal_mask_inv=$((2 ** (32 - $2) - 1))
|
||||||
|
printf "%s\n" "$((decimal_ip | decimal_mask_inv))"
|
||||||
|
}
|
||||||
|
|
||||||
|
decIPv4ToHex() {
|
||||||
|
local hex
|
||||||
|
hex="$(printf "%08x\n" "$1")"
|
||||||
|
quartet_hi=${hex:0:4}
|
||||||
|
quartet_lo=${hex:4:4}
|
||||||
|
# Removes leading zeros from quartets, purely for aesthetic reasons
|
||||||
|
# Source: https://stackoverflow.com/a/19861690
|
||||||
|
leading_zeros_hi="${quartet_hi%%[!0]*}"
|
||||||
|
leading_zeros_lo="${quartet_lo%%[!0]*}"
|
||||||
|
printf "%s:%s\n" "${quartet_hi#"${leading_zeros_hi}"}" "${quartet_lo#"${leading_zeros_lo}"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
cidrToMask() {
|
||||||
|
# Source: https://stackoverflow.com/a/20767392
|
||||||
|
set -- $((5 - (${1} / 8))) \
|
||||||
|
255 255 255 255 \
|
||||||
|
$(((255 << (8 - (${1} % 8))) & 255)) \
|
||||||
|
0 0 0
|
||||||
|
shift "${1}"
|
||||||
|
echo "${1-0}.${2-0}.${3-0}.${4-0}"
|
||||||
|
}
|
||||||
|
|
||||||
setVPNDefaultVars() {
|
setVPNDefaultVars() {
|
||||||
# Allow custom subnetClass via unattend setupVARs file.
|
# Allow custom subnetClass via unattend setupVARs file.
|
||||||
# Use default if not provided.
|
# Use default if not provided.
|
||||||
|
@ -1726,43 +1779,99 @@ setVPNDefaultVars() {
|
||||||
}
|
}
|
||||||
|
|
||||||
generateRandomSubnet() {
|
generateRandomSubnet() {
|
||||||
local MATCHES
|
|
||||||
# Source: https://community.openvpn.net/openvpn/wiki/AvoidRoutingConflicts
|
# Source: https://community.openvpn.net/openvpn/wiki/AvoidRoutingConflicts
|
||||||
declare -a SUBNET_EXCLUDE_LIST
|
declare -a excluded_subnets_dec=(
|
||||||
|
167772160 167772415 # 10.0.0.0/24
|
||||||
|
167772416 167772671 # 10.0.1.0/24
|
||||||
|
167837952 167838207 # 10.1.1.0/24
|
||||||
|
167840256 167840511 # 10.1.10.0/24
|
||||||
|
167903232 167903487 # 10.2.0.0/24
|
||||||
|
168296448 168296703 # 10.8.0.0/24
|
||||||
|
168427776 168428031 # 10.10.1.0/24
|
||||||
|
173693440 173693695 # 10.90.90.0/24
|
||||||
|
174326016 174326271 # 10.100.1.0/24
|
||||||
|
184549120 184549375 # 10.255.255.0/24
|
||||||
|
3232235520 3232235775 # 192.168.0.0/24
|
||||||
|
3232235776 3232236031 # 192.168.1.0/24
|
||||||
|
)
|
||||||
|
|
||||||
SUBNET_EXCLUDE_LIST=(10.0.0.0/24)
|
# Add numeric ranges to the previous array
|
||||||
SUBNET_EXCLUDE_LIST+=(10.0.1.0/24)
|
readarray -t currently_used_subnets <<< "$(ip route show \
|
||||||
SUBNET_EXCLUDE_LIST+=(10.1.1.0/24)
|
|
||||||
SUBNET_EXCLUDE_LIST+=(10.1.10.0/24)
|
|
||||||
SUBNET_EXCLUDE_LIST+=(10.2.0.0/24)
|
|
||||||
SUBNET_EXCLUDE_LIST+=(10.8.0.0/24)
|
|
||||||
SUBNET_EXCLUDE_LIST+=(10.10.1.0/24)
|
|
||||||
SUBNET_EXCLUDE_LIST+=(10.90.90.0/24)
|
|
||||||
SUBNET_EXCLUDE_LIST+=(10.100.1.0/24)
|
|
||||||
SUBNET_EXCLUDE_LIST+=(10.255.255.0/24)
|
|
||||||
|
|
||||||
readarray -t CURRENTLY_USED_SUBNETS <<< "$(ip route show \
|
|
||||||
| grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}')"
|
| grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}')"
|
||||||
SUBNET_EXCLUDE_LIST=("${SUBNET_EXCLUDE_LIST[@]}"
|
|
||||||
"${CURRENTLY_USED_SUBNETS[@]}")
|
|
||||||
|
|
||||||
while true; do
|
local used used_ip used_mask
|
||||||
MATCHES=0
|
for used in "${currently_used_subnets[@]}"; do
|
||||||
pivpnNET="10.$((RANDOM % 256)).$((RANDOM % 256)).0"
|
used_ip="${used%/*}"
|
||||||
|
used_mask="${used##*/}"
|
||||||
|
|
||||||
for SUB in "${SUBNET_EXCLUDE_LIST[@]}"; do
|
excluded_subnets_dec+=("$(dotIPv4FirstDec "$used_ip" "$used_mask")")
|
||||||
if grepcidr "${SUB}" <<< "${pivpnNET}/${subnetClass}" \
|
excluded_subnets_dec+=("$(dotIPv4LastDec "$used_ip" "$used_mask")")
|
||||||
2>&1 > /dev/null; then
|
done
|
||||||
((MATCHES++))
|
|
||||||
|
# Note: excluded_subnets_count array length is twice the number of subnets
|
||||||
|
local excluded_subnets_count="${#excluded_subnets_dec[@]}"
|
||||||
|
|
||||||
|
local source_subnet="$1"
|
||||||
|
local source_ip="${source_subnet%/*}"
|
||||||
|
# shellcheck disable=SC2155
|
||||||
|
local source_ip_dec="$(dotIPv4ToDec "$source_ip")"
|
||||||
|
local source_netmask="${source_subnet##*/}"
|
||||||
|
local source_netmask_dec="$((2 ** 32 - 1 ^ (2 ** (32 - source_netmask) - 1)))"
|
||||||
|
|
||||||
|
local target_netmask="$2"
|
||||||
|
|
||||||
|
local first_ip_target_subnet_dec="$((source_ip_dec & source_netmask_dec))"
|
||||||
|
local total_ips_target_subnet="$((2 ** (32 - target_netmask)))"
|
||||||
|
|
||||||
|
# Picking a random subnet would cause the same subnets to be checked multiple
|
||||||
|
# times shall the number of subnets were small, so instead a random permutation
|
||||||
|
# is scanned to check a subnet only once.
|
||||||
|
local subnets_count="$((2 ** (target_netmask - source_netmask)))"
|
||||||
|
readarray -t random_perm <<< "$(shuf -i 0-"$((subnets_count - 1))")"
|
||||||
|
# random_perm=( 3221 9 8 431 7 [...] )
|
||||||
|
|
||||||
|
# Due to bash performance limitations, it's not pratical to check all subnets.
|
||||||
|
# Taking into account that the install script should not hang for too long even
|
||||||
|
# on a Pi Zero, we avoid doing more than about 5000 iteration.
|
||||||
|
local max_tries="$subnets_count"
|
||||||
|
if [ $((subnets_count * excluded_subnets_count)) -ge 5000 ]; then
|
||||||
|
max_tries="$((5000 / (excluded_subnets_count / 2)))"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local first_ip_subnet_dec last_ip_subnet_dec
|
||||||
|
local first_ip_excluded_subnet_dec last_ip_excluded_subnet_dec
|
||||||
|
local overlap
|
||||||
|
for ((i = 0; i < max_tries; i++)); do
|
||||||
|
|
||||||
|
first_ip_subnet_dec="$((first_ip_target_subnet_dec + total_ips_target_subnet * random_perm[i]))"
|
||||||
|
last_ip_subnet_dec="$((first_ip_subnet_dec + total_ips_target_subnet - 1))"
|
||||||
|
|
||||||
|
overlap=false
|
||||||
|
|
||||||
|
for ((j = 0; j < excluded_subnets_count; j += 2)); do
|
||||||
|
|
||||||
|
first_ip_excluded_subnet_dec="${excluded_subnets_dec[$j]}"
|
||||||
|
last_ip_excluded_subnet_dec="${excluded_subnets_dec[$j + 1]}"
|
||||||
|
|
||||||
|
# |-------------subnet2------------|
|
||||||
|
# |----------subnet1-----------| |
|
||||||
|
# | | | |
|
||||||
|
# first_ip_excluded_subnet_dec | last_ip_excluded_subnet_dec |
|
||||||
|
# | |
|
||||||
|
# first_ip_subnet_dec last_ip_subnet_dec
|
||||||
|
if ((last_ip_excluded_subnet_dec >= first_ip_subnet_dec)) \
|
||||||
|
&& ((first_ip_excluded_subnet_dec <= last_ip_subnet_dec)); then
|
||||||
|
overlap=true
|
||||||
|
break
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ "${MATCHES}" -eq 0 ]]; then
|
if ! "$overlap"; then
|
||||||
|
decIPv4ToDot "$first_ip_subnet_dec"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "${pivpnNET}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setOpenVPNDefaultVars() {
|
setOpenVPNDefaultVars() {
|
||||||
|
@ -1771,10 +1880,31 @@ setOpenVPNDefaultVars() {
|
||||||
# Allow custom NET via unattend setupVARs file.
|
# Allow custom NET via unattend setupVARs file.
|
||||||
# Use default if not provided.
|
# Use default if not provided.
|
||||||
if [[ -z "${pivpnNET}" ]]; then
|
if [[ -z "${pivpnNET}" ]]; then
|
||||||
pivpnNET="$(generateRandomSubnet)"
|
echo "::: Generating random subnet in network 10.0.0.0/8..."
|
||||||
|
pivpnNET="$(generateRandomSubnet "10.0.0.0/8" "$subnetClass")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
vpnGw="$(cut -d '.' -f 1-3 <<< "${pivpnNET}").1"
|
if [[ -z "${pivpnNET}" ]]; then
|
||||||
|
echo "::: Network 10.0.0.0/8 is unavailable, trying 172.16.0.0/12 next..."
|
||||||
|
pivpnNET="$(generateRandomSubnet "172.16.0.0/12" "$subnetClass")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${pivpnNET}" ]]; then
|
||||||
|
echo "::: Network 172.16.0.0/12 is unavailable, trying 192.168.0.0/16 next..."
|
||||||
|
pivpnNET="$(generateRandomSubnet "192.168.0.0/16" "$subnetClass")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${pivpnNET}" ]]; then
|
||||||
|
# This should not happen in practice
|
||||||
|
echo "::: Unable to generate a random subnet for PiVPN. Looks like all private networks are in use."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
pivpnNETdec="$(dotIPv4ToDec "${pivpnNET}")"
|
||||||
|
|
||||||
|
vpnGwdec="$((pivpnNETdec + 1))"
|
||||||
|
vpnGw="$(decIPv4ToDot "${vpnGwdec}")"
|
||||||
|
vpnGwhex="$(decIPv4ToHex "${vpnGwdec}")"
|
||||||
|
|
||||||
if [[ "${pivpnenableipv6}" -eq 1 ]] \
|
if [[ "${pivpnenableipv6}" -eq 1 ]] \
|
||||||
&& [[ -z "${pivpnNETv6}" ]]; then
|
&& [[ -z "${pivpnNETv6}" ]]; then
|
||||||
|
@ -1782,7 +1912,7 @@ setOpenVPNDefaultVars() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${pivpnenableipv6}" -eq 1 ]]; then
|
if [[ "${pivpnenableipv6}" -eq 1 ]]; then
|
||||||
vpnGwv6="${pivpnNETv6}1"
|
vpnGwv6="${pivpnNETv6}${vpnGwhex}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1795,18 +1925,39 @@ setWireguardDefaultVars() {
|
||||||
# Allow custom NET via unattend setupVARs file.
|
# Allow custom NET via unattend setupVARs file.
|
||||||
# Use default if not provided.
|
# Use default if not provided.
|
||||||
if [[ -z "${pivpnNET}" ]]; then
|
if [[ -z "${pivpnNET}" ]]; then
|
||||||
pivpnNET="$(generateRandomSubnet)"
|
echo "::: Generating random subnet in network 10.0.0.0/8..."
|
||||||
|
pivpnNET="$(generateRandomSubnet "10.0.0.0/8" "$subnetClass")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${pivpnNET}" ]]; then
|
||||||
|
echo "::: Network 10.0.0.0/8 is unavailable, trying 172.16.0.0/12 next..."
|
||||||
|
pivpnNET="$(generateRandomSubnet "172.16.0.0/12" "$subnetClass")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${pivpnNET}" ]]; then
|
||||||
|
echo "::: Network 172.16.0.0/12 is unavailable, trying 192.168.0.0/16 next..."
|
||||||
|
pivpnNET="$(generateRandomSubnet "192.168.0.0/16" "$subnetClass")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${pivpnNET}" ]]; then
|
||||||
|
# This should not happen in practice
|
||||||
|
echo "::: Unable to generate a random subnet for PiVPN. Looks like all private networks are in use."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
pivpnNETdec="$(dotIPv4ToDec "${pivpnNET}")"
|
||||||
|
|
||||||
|
vpnGwdec="$((pivpnNETdec + 1))"
|
||||||
|
vpnGw="$(decIPv4ToDot "${vpnGwdec}")"
|
||||||
|
vpnGwhex="$(decIPv4ToHex "${vpnGwdec}")"
|
||||||
|
|
||||||
if [[ "${pivpnenableipv6}" -eq 1 ]] \
|
if [[ "${pivpnenableipv6}" -eq 1 ]] \
|
||||||
&& [[ -z "${pivpnNETv6}" ]]; then
|
&& [[ -z "${pivpnNETv6}" ]]; then
|
||||||
pivpnNETv6="fd11:5ee:bad:c0de::"
|
pivpnNETv6="fd11:5ee:bad:c0de::"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
vpnGw="$(cut -d '.' -f 1-3 <<< "${pivpnNET}").1"
|
|
||||||
|
|
||||||
if [[ "${pivpnenableipv6}" -eq 1 ]]; then
|
if [[ "${pivpnenableipv6}" -eq 1 ]]; then
|
||||||
vpnGwv6="${pivpnNETv6}1"
|
vpnGwv6="${pivpnNETv6}${vpnGwhex}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Allow custom allowed IPs via unattend setupVARs file.
|
# Allow custom allowed IPs via unattend setupVARs file.
|
||||||
|
@ -2715,16 +2866,6 @@ parameters will be generated on your device." "${r}" "${c}"; then
|
||||||
} >> "${tempsetupVarsFile}"
|
} >> "${tempsetupVarsFile}"
|
||||||
}
|
}
|
||||||
|
|
||||||
cidrToMask() {
|
|
||||||
# Source: https://stackoverflow.com/a/20767392
|
|
||||||
set -- $((5 - ($1 / 8))) \
|
|
||||||
255 255 255 255 \
|
|
||||||
$(((255 << (8 - ($1 % 8))) & 255)) \
|
|
||||||
0 0 0
|
|
||||||
shift "${1}"
|
|
||||||
echo "${1-0}.${2-0}.${3-0}.${4-0}"
|
|
||||||
}
|
|
||||||
|
|
||||||
confOpenVPN() {
|
confOpenVPN() {
|
||||||
local sed_pattern file_pattern
|
local sed_pattern file_pattern
|
||||||
|
|
||||||
|
|
54
scripts/ipaddr_utils.sh
Executable file
54
scripts/ipaddr_utils.sh
Executable file
|
@ -0,0 +1,54 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
decIPv4ToDot() {
|
||||||
|
local a b c d
|
||||||
|
a=$((($1 & 4278190080) >> 24))
|
||||||
|
b=$((($1 & 16711680) >> 16))
|
||||||
|
c=$((($1 & 65280) >> 8))
|
||||||
|
d=$(($1 & 255))
|
||||||
|
printf "%s.%s.%s.%s\n" $a $b $c $d
|
||||||
|
}
|
||||||
|
|
||||||
|
dotIPv4ToDec() {
|
||||||
|
local original_ifs=$IFS
|
||||||
|
IFS='.'
|
||||||
|
read -r -a array_ip <<< "$1"
|
||||||
|
IFS=$original_ifs
|
||||||
|
printf "%s\n" $((array_ip[0] * 16777216 + array_ip[1] * 65536 + array_ip[2] * 256 + array_ip[3]))
|
||||||
|
}
|
||||||
|
|
||||||
|
dotIPv4FirstDec() {
|
||||||
|
local decimal_ip decimal_mask
|
||||||
|
decimal_ip=$(dotIPv4ToDec "$1")
|
||||||
|
decimal_mask=$((2 ** 32 - 1 ^ (2 ** (32 - $2) - 1)))
|
||||||
|
printf "%s\n" "$((decimal_ip & decimal_mask))"
|
||||||
|
}
|
||||||
|
|
||||||
|
dotIPv4LastDec() {
|
||||||
|
local decimal_ip decimal_mask_inv
|
||||||
|
decimal_ip=$(dotIPv4ToDec "$1")
|
||||||
|
decimal_mask_inv=$((2 ** (32 - $2) - 1))
|
||||||
|
printf "%s\n" "$((decimal_ip | decimal_mask_inv))"
|
||||||
|
}
|
||||||
|
|
||||||
|
decIPv4ToHex() {
|
||||||
|
local hex
|
||||||
|
hex="$(printf "%08x\n" "$1")"
|
||||||
|
quartet_hi=${hex:0:4}
|
||||||
|
quartet_lo=${hex:4:4}
|
||||||
|
# Removes leading zeros from quartets, purely for aesthetic reasons
|
||||||
|
# Source: https://stackoverflow.com/a/19861690
|
||||||
|
leading_zeros_hi="${quartet_hi%%[!0]*}"
|
||||||
|
leading_zeros_lo="${quartet_lo%%[!0]*}"
|
||||||
|
printf "%s:%s\n" "${quartet_hi#"${leading_zeros_hi}"}" "${quartet_lo#"${leading_zeros_lo}"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
cidrToMask() {
|
||||||
|
# Source: https://stackoverflow.com/a/20767392
|
||||||
|
set -- $((5 - (${1} / 8))) \
|
||||||
|
255 255 255 255 \
|
||||||
|
$(((255 << (8 - (${1} % 8))) & 255)) \
|
||||||
|
0 0 0
|
||||||
|
shift "${1}"
|
||||||
|
echo "${1-0}.${2-0}.${3-0}.${4-0}"
|
||||||
|
}
|
|
@ -14,6 +14,12 @@ INDEX="/etc/openvpn/easy-rsa/pki/index.txt"
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
source "${setupVars}"
|
source "${setupVars}"
|
||||||
|
|
||||||
|
if [ ! -r /opt/pivpn/ipaddr_utils.sh ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source /opt/pivpn/ipaddr_utils.sh
|
||||||
|
|
||||||
# shellcheck disable=SC2154
|
# shellcheck disable=SC2154
|
||||||
userGroup="${install_user}:${install_user}"
|
userGroup="${install_user}:${install_user}"
|
||||||
|
|
||||||
|
@ -162,16 +168,6 @@ keyPASS() {
|
||||||
cd pki || exit
|
cd pki || exit
|
||||||
}
|
}
|
||||||
|
|
||||||
cidrToMask() {
|
|
||||||
# Source: https://stackoverflow.com/a/20767392
|
|
||||||
set -- $((5 - (${1} / 8))) \
|
|
||||||
255 255 255 255 \
|
|
||||||
$(((255 << (8 - (${1} % 8))) & 255)) \
|
|
||||||
0 0 0
|
|
||||||
shift "${1}"
|
|
||||||
echo "${1-0}.${2-0}.${3-0}.${4-0}"
|
|
||||||
}
|
|
||||||
|
|
||||||
### Script
|
### Script
|
||||||
if [[ ! -f "${setupVars}" ]]; then
|
if [[ ! -f "${setupVars}" ]]; then
|
||||||
err "::: Missing setup vars file!"
|
err "::: Missing setup vars file!"
|
||||||
|
@ -293,6 +289,35 @@ if [[ ! -d "${install_home}/ovpns" ]]; then
|
||||||
chmod 0750 "${install_home}/ovpns"
|
chmod 0750 "${install_home}/ovpns"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Exclude first, last and server addresses
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
MAX_CLIENTS="$((2 ** (32 - subnetClass) - 3))"
|
||||||
|
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
FIRST_IPV4_DEC="$(dotIPv4FirstDec "${pivpnNET}" "${subnetClass}")"
|
||||||
|
LAST_IPV4_DEC="$(dotIPv4LastDec "${pivpnNET}" "${subnetClass}")"
|
||||||
|
|
||||||
|
if [ "$(find /etc/openvpn/ccd -type f | wc -l)" -ge "${MAX_CLIENTS}" ]; then
|
||||||
|
echo "::: Can't add any more clients (max. ${MAX_CLIENTS})!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Find an unused address for the client IP
|
||||||
|
for ((ip = FIRST_IPV4_DEC + 2; ip <= LAST_IPV4_DEC - 1; ip++)); do
|
||||||
|
# find returns 0 if the folder is empty, so we create the 'ls -A [...]'
|
||||||
|
# exception to stop at the first static IP (10.8.0.2). Otherwise it would
|
||||||
|
# cycle to the end without finding and available octet.
|
||||||
|
# disabling SC2514, variable sourced externaly
|
||||||
|
ip_dot="$(decIPv4ToDot "${ip}")"
|
||||||
|
|
||||||
|
if [[ -z "$(ls -A /etc/openvpn/ccd)" ]] \
|
||||||
|
|| ! find /etc/openvpn/ccd -type f \
|
||||||
|
-exec grep -q "${ip_dot}" {} +; then
|
||||||
|
UNUSED_IPV4_DOT="${ip_dot}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
#bitWarden
|
#bitWarden
|
||||||
if [[ "${BITWARDEN}" =~ "2" ]]; then
|
if [[ "${BITWARDEN}" =~ "2" ]]; then
|
||||||
useBitwarden
|
useBitwarden
|
||||||
|
@ -469,33 +494,15 @@ if [[ "${iOS}" == 1 ]]; then
|
||||||
printf "========================================================\n\n"
|
printf "========================================================\n\n"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#disabling SC2514, variable sourced externaly
|
echo -n "ifconfig-push ${UNUSED_IPV4_DOT} " >> /etc/openvpn/ccd/"${NAME}"
|
||||||
# shellcheck disable=SC2154
|
# The space after ${UNUSED_IPV4_DOT} is important!
|
||||||
NET_REDUCED="${pivpnNET::-2}"
|
cidrToMask "${subnetClass}" >> /etc/openvpn/ccd/"${NAME}"
|
||||||
|
# the end resuld should be a line like:
|
||||||
# Find an unused number for the last octet of the client IP
|
# ifconfig-push ${UNUSED_IPV4_DOT} ${subnetClass}
|
||||||
for i in {2..254}; do
|
# ifconfig-push 10.205.45.8 255.255.255.0
|
||||||
# find returns 0 if the folder is empty, so we create the 'ls -A [...]'
|
|
||||||
# exception to stop at the first static IP (10.8.0.2). Otherwise it would
|
|
||||||
# cycle to the end without finding and available octet.
|
|
||||||
# disabling SC2514, variable sourced externaly
|
|
||||||
# shellcheck disable=SC2154
|
|
||||||
if [[ -z "$(ls -A /etc/openvpn/ccd)" ]] \
|
|
||||||
|| ! find /etc/openvpn/ccd -type f \
|
|
||||||
-exec grep -q "${NET_REDUCED}.${i}" {} +; then
|
|
||||||
COUNT="${i}"
|
|
||||||
echo -n "ifconfig-push ${NET_REDUCED}.${i} " >> /etc/openvpn/ccd/"${NAME}"
|
|
||||||
# The space after ${i} is important ------^!
|
|
||||||
cidrToMask "${subnetClass}" >> /etc/openvpn/ccd/"${NAME}"
|
|
||||||
# the end resuld should be a line like:
|
|
||||||
# ifconfig-push ${NET_REDUCED}.${i} ${subnetClass}
|
|
||||||
# ifconfig-push 10.205.45.8 255.255.255.0
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ -f /etc/pivpn/hosts.openvpn ]]; then
|
if [[ -f /etc/pivpn/hosts.openvpn ]]; then
|
||||||
echo "${NET_REDUCED}.${COUNT} ${NAME}.pivpn" >> /etc/pivpn/hosts.openvpn
|
echo "${UNUSED_IPV4_DOT} ${NAME}.pivpn" >> /etc/pivpn/hosts.openvpn
|
||||||
|
|
||||||
if killall -SIGHUP pihole-FTL; then
|
if killall -SIGHUP pihole-FTL; then
|
||||||
echo "::: Updated hosts file for Pi-hole"
|
echo "::: Updated hosts file for Pi-hole"
|
||||||
|
|
|
@ -4,9 +4,16 @@
|
||||||
### Constants
|
### Constants
|
||||||
setupVars="/etc/pivpn/openvpn/setupVars.conf"
|
setupVars="/etc/pivpn/openvpn/setupVars.conf"
|
||||||
INDEX="/etc/openvpn/easy-rsa/pki/index.txt"
|
INDEX="/etc/openvpn/easy-rsa/pki/index.txt"
|
||||||
|
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
source "${setupVars}"
|
source "${setupVars}"
|
||||||
|
|
||||||
|
if [ ! -r /opt/pivpn/ipaddr_utils.sh ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source /opt/pivpn/ipaddr_utils.sh
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
err() {
|
err() {
|
||||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
||||||
|
@ -167,10 +174,8 @@ for ((ii = 0; ii < ${#CERTS_TO_REVOKE[@]}; ii++)); do
|
||||||
# Disabling SC2154 $pivpnNET sourced externally
|
# Disabling SC2154 $pivpnNET sourced externally
|
||||||
# shellcheck disable=SC2154
|
# shellcheck disable=SC2154
|
||||||
# Grab the client IP address
|
# Grab the client IP address
|
||||||
NET_REDUCED="${pivpnNET::-2}"
|
|
||||||
STATIC_IP="$(grep -v "^#" /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}" \
|
STATIC_IP="$(grep -v "^#" /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}" \
|
||||||
| grep -w ifconfig-push \
|
| grep -w ifconfig-push | awk '{print $2}')"
|
||||||
| grep -oE "${NET_REDUCED}\.[0-9]{1,3}")"
|
|
||||||
rm -rf /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}"
|
rm -rf /etc/openvpn/ccd/"${CERTS_TO_REVOKE[ii]}"
|
||||||
|
|
||||||
# disablung warning SC2154, $install_home sourced externally
|
# disablung warning SC2154, $install_home sourced externally
|
||||||
|
|
|
@ -10,6 +10,12 @@ setupVars="/etc/pivpn/wireguard/setupVars.conf"
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
source "${setupVars}"
|
source "${setupVars}"
|
||||||
|
|
||||||
|
if [ ! -r /opt/pivpn/ipaddr_utils.sh ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source /opt/pivpn/ipaddr_utils.sh
|
||||||
|
|
||||||
# shellcheck disable=SC2154
|
# shellcheck disable=SC2154
|
||||||
userGroup="${install_user}:${install_user}"
|
userGroup="${install_user}:${install_user}"
|
||||||
|
|
||||||
|
@ -109,6 +115,27 @@ fi
|
||||||
|
|
||||||
cd /etc/wireguard || exit
|
cd /etc/wireguard || exit
|
||||||
|
|
||||||
|
# Exclude first, last and server addresses
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
MAX_CLIENTS="$((2 ** (32 - subnetClass) - 3))"
|
||||||
|
|
||||||
|
if [ "$(wc -l configs/clients.txt | awk '{print $1}')" -ge "${MAX_CLIENTS}" ]; then
|
||||||
|
echo "::: Can't add any more clients (max. ${MAX_CLIENTS})!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
FIRST_IPV4_DEC="$(dotIPv4FirstDec "${pivpnNET}" "${subnetClass}")"
|
||||||
|
LAST_IPV4_DEC="$(dotIPv4LastDec "${pivpnNET}" "${subnetClass}")"
|
||||||
|
|
||||||
|
# Find an unused address for the client IP
|
||||||
|
for ((ip = FIRST_IPV4_DEC + 2; ip <= LAST_IPV4_DEC - 1; ip++)); do
|
||||||
|
if ! grep -q " ${ip}$" configs/clients.txt; then
|
||||||
|
UNUSED_IPV4_DEC="${ip}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
if [[ -z "${CLIENT_NAME}" ]]; then
|
if [[ -z "${CLIENT_NAME}" ]]; then
|
||||||
read -r -p "Enter a Name for the Client: " CLIENT_NAME
|
read -r -p "Enter a Name for the Client: " CLIENT_NAME
|
||||||
checkName
|
checkName
|
||||||
|
@ -122,28 +149,17 @@ wg genkey \
|
||||||
wg genpsk | tee "keys/${CLIENT_NAME}_psk" &> /dev/null
|
wg genpsk | tee "keys/${CLIENT_NAME}_psk" &> /dev/null
|
||||||
echo "::: Client Keys generated"
|
echo "::: Client Keys generated"
|
||||||
|
|
||||||
# Find an unused number for the last octet of the client IP
|
UNUSED_IPV4_DOT="$(decIPv4ToDot "${UNUSED_IPV4_DEC}")"
|
||||||
for i in {2..254}; do
|
UNUSED_IPV4_HEX="$(decIPv4ToHex "${UNUSED_IPV4_DEC}")"
|
||||||
if ! grep -q " ${i}$" configs/clients.txt; then
|
|
||||||
COUNT="${i}"
|
|
||||||
echo "${CLIENT_NAME} $(< keys/"${CLIENT_NAME}"_pub) $(date +%s) ${COUNT}" \
|
|
||||||
| tee -a configs/clients.txt > /dev/null
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Disabling SC2154, variables sourced externaly
|
|
||||||
# shellcheck disable=SC2154
|
|
||||||
NET_REDUCED="${pivpnNET::-2}"
|
|
||||||
|
|
||||||
# shellcheck disable=SC2154
|
# shellcheck disable=SC2154
|
||||||
{
|
{
|
||||||
echo '[Interface]'
|
echo '[Interface]'
|
||||||
echo "PrivateKey = $(cat "keys/${CLIENT_NAME}_priv")"
|
echo "PrivateKey = $(cat "keys/${CLIENT_NAME}_priv")"
|
||||||
echo -n "Address = ${NET_REDUCED}.${COUNT}/${subnetClass}"
|
echo -n "Address = ${UNUSED_IPV4_DOT}/${subnetClass}"
|
||||||
|
|
||||||
if [[ "${pivpnenableipv6}" == 1 ]]; then
|
if [[ "${pivpnenableipv6}" == 1 ]]; then
|
||||||
echo ",${pivpnNETv6}${COUNT}/${subnetClassv6}"
|
echo ",${pivpnNETv6}${UNUSED_IPV4_HEX}/${subnetClassv6}"
|
||||||
else
|
else
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
@ -175,10 +191,10 @@ echo "::: Client config generated"
|
||||||
echo '[Peer]'
|
echo '[Peer]'
|
||||||
echo "PublicKey = $(cat "keys/${CLIENT_NAME}_pub")"
|
echo "PublicKey = $(cat "keys/${CLIENT_NAME}_pub")"
|
||||||
echo "PresharedKey = $(cat "keys/${CLIENT_NAME}_psk")"
|
echo "PresharedKey = $(cat "keys/${CLIENT_NAME}_psk")"
|
||||||
echo -n "AllowedIPs = ${NET_REDUCED}.${COUNT}/32"
|
echo -n "AllowedIPs = ${UNUSED_IPV4_DOT}/32"
|
||||||
|
|
||||||
if [[ "${pivpnenableipv6}" == 1 ]]; then
|
if [[ "${pivpnenableipv6}" == 1 ]]; then
|
||||||
echo ",${pivpnNETv6}${COUNT}/128"
|
echo ",${pivpnNETv6}${UNUSED_IPV4_HEX}/128"
|
||||||
else
|
else
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
@ -188,12 +204,15 @@ echo "::: Client config generated"
|
||||||
|
|
||||||
echo "::: Updated server config"
|
echo "::: Updated server config"
|
||||||
|
|
||||||
|
echo "${CLIENT_NAME} $(< keys/"${CLIENT_NAME}"_pub) $(date +%s) ${UNUSED_IPV4_DEC}" \
|
||||||
|
| tee -a configs/clients.txt > /dev/null
|
||||||
|
|
||||||
if [[ -f /etc/pivpn/hosts.wireguard ]]; then
|
if [[ -f /etc/pivpn/hosts.wireguard ]]; then
|
||||||
echo "${NET_REDUCED}.${COUNT} ${CLIENT_NAME}.pivpn" \
|
echo "${UNUSED_IPV4_DOT} ${CLIENT_NAME}.pivpn" \
|
||||||
| tee -a /etc/pivpn/hosts.wireguard > /dev/null
|
| tee -a /etc/pivpn/hosts.wireguard > /dev/null
|
||||||
|
|
||||||
if [[ "${pivpnenableipv6}" == 1 ]]; then
|
if [[ "${pivpnenableipv6}" == 1 ]]; then
|
||||||
echo "${pivpnNETv6}${COUNT} ${CLIENT_NAME}.pivpn" \
|
echo "${pivpnNETv6}${UNUSED_IPV4_HEX} ${CLIENT_NAME}.pivpn" \
|
||||||
| tee -a /etc/pivpn/hosts.wireguard > /dev/null
|
| tee -a /etc/pivpn/hosts.wireguard > /dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@ setupVars="/etc/pivpn/wireguard/setupVars.conf"
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
source "${setupVars}"
|
source "${setupVars}"
|
||||||
|
|
||||||
|
if [ ! -r /opt/pivpn/ipaddr_utils.sh ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source /opt/pivpn/ipaddr_utils.sh
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
err() {
|
err() {
|
||||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
|
||||||
|
@ -100,8 +106,8 @@ for CLIENT_NAME in "${CLIENTS_TO_REMOVE[@]}"; do
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
|
if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
|
||||||
# Grab the least significant octed of the client IP address
|
# Grab the decimal representation of the client IP address
|
||||||
COUNT="$(grep "^${CLIENT_NAME} " configs/clients.txt | awk '{print $4}')"
|
IPV4_DEC="$(grep "^${CLIENT_NAME} " configs/clients.txt | awk '{print $4}')"
|
||||||
# The creation date of the client
|
# The creation date of the client
|
||||||
CREATION_DATE="$(grep "^${CLIENT_NAME} " configs/clients.txt \
|
CREATION_DATE="$(grep "^${CLIENT_NAME} " configs/clients.txt \
|
||||||
| awk '{print $3}')"
|
| awk '{print $3}')"
|
||||||
|
@ -111,7 +117,7 @@ for CLIENT_NAME in "${CLIENTS_TO_REMOVE[@]}"; do
|
||||||
|
|
||||||
# Then remove the client matching the variables above
|
# Then remove the client matching the variables above
|
||||||
sed \
|
sed \
|
||||||
-e "\#${CLIENT_NAME} ${PUBLIC_KEY} ${CREATION_DATE} ${COUNT}#d" \
|
-e "\#${CLIENT_NAME} ${PUBLIC_KEY} ${CREATION_DATE} ${IPV4_DEC}#d" \
|
||||||
-i configs/clients.txt
|
-i configs/clients.txt
|
||||||
|
|
||||||
# Remove the peer section from the server config
|
# Remove the peer section from the server config
|
||||||
|
@ -147,10 +153,11 @@ for CLIENT_NAME in "${CLIENTS_TO_REMOVE[@]}"; do
|
||||||
# Disabling SC2154, variable sourced externaly and may vary
|
# Disabling SC2154, variable sourced externaly and may vary
|
||||||
# shellcheck disable=SC2154
|
# shellcheck disable=SC2154
|
||||||
if [[ -f /etc/pivpn/hosts.wireguard ]]; then
|
if [[ -f /etc/pivpn/hosts.wireguard ]]; then
|
||||||
NET_REDUCED="${pivpnNET::-2}"
|
IPV4_DOT="$(decIPv4ToDot "${IPV4_DEC}")"
|
||||||
|
IPV4_HEX="$(decIPv4ToHex "${IPV4_DEC}")"
|
||||||
sed \
|
sed \
|
||||||
-e "\#${NET_REDUCED}.${COUNT} ${CLIENT_NAME}.pivpn#d" \
|
-e "\#${IPV4_DOT} ${CLIENT_NAME}.pivpn#d" \
|
||||||
-e "\#${pivpnNETv6}${COUNT} ${CLIENT_NAME}.pivpn#d" \
|
-e "\#${pivpnNETv6}${IPV4_HEX} ${CLIENT_NAME}.pivpn#d" \
|
||||||
-i /etc/pivpn/hosts.wireguard
|
-i /etc/pivpn/hosts.wireguard
|
||||||
|
|
||||||
if killall -SIGHUP pihole-FTL; then
|
if killall -SIGHUP pihole-FTL; then
|
||||||
|
|
Loading…
Reference in a new issue