Improve VPN script

- Refactor the script into Bash functions for improved organization
  and readability.
This commit is contained in:
hwdsl2 2024-06-16 22:21:37 -05:00
parent fafb5b9e49
commit f4b053d673

View File

@ -21,6 +21,26 @@ check_ip() {
printf '%s' "$1" | tr -d '\n' | grep -Eq "$IP_REGEX"
}
check_root() {
if [ "$(id -u)" != 0 ]; then
exiterr "This installer must be run as root. Try 'sudo bash $0'"
fi
}
check_shell() {
# Detect Debian users running the script with "sh" instead of bash
if readlink /proc/$$/exe | grep -q "dash"; then
exiterr 'This installer needs to be run with "bash", not "sh".'
fi
}
check_kernel() {
# Detect OpenVZ 6
if [[ $(uname -r | cut -d "." -f 1) -eq 2 ]]; then
exiterr "The system is running an old kernel, which is incompatible with this installer."
fi
}
check_os() {
if grep -qs "ubuntu" /etc/os-release; then
os="ubuntu"
@ -71,6 +91,30 @@ This version of CentOS is too old and unsupported."
fi
}
check_tun() {
if [[ ! -e /dev/net/tun ]] || ! ( exec 7<>/dev/net/tun ) 2>/dev/null; then
exiterr "The system does not have the TUN device available.
TUN needs to be enabled before running this installer."
fi
}
parse_args() {
while [ "$#" -gt 0 ]; do
case $1 in
--auto)
auto=1
shift
;;
-h|--help)
show_usage
;;
*)
show_usage "Unknown parameter: $1"
;;
esac
done
}
check_nftables() {
if [ "$os" = "centos" ]; then
if grep -qs "hwdsl2 VPN script" /etc/sysconfig/nftables.conf \
@ -403,6 +447,305 @@ confirm_setup() {
fi
}
disable_limitnproc() {
# If running inside a container, disable LimitNPROC to prevent conflicts
if systemd-detect-virt -cq; then
mkdir /etc/systemd/system/openvpn-server@server.service.d/ 2>/dev/null
echo "[Service]
LimitNPROC=infinity" > /etc/systemd/system/openvpn-server@server.service.d/disable-limitnproc.conf
fi
}
install_pkgs() {
if [[ "$os" = "debian" || "$os" = "ubuntu" ]]; then
export DEBIAN_FRONTEND=noninteractive
(
set -x
apt-get -yqq update || apt-get -yqq update
apt-get -yqq --no-install-recommends install openvpn >/dev/null
) || exiterr2
(
set -x
apt-get -yqq install openssl ca-certificates $firewall >/dev/null
) || exiterr2
elif [[ "$os" = "centos" ]]; then
if grep -qs "Amazon Linux release 2 " /etc/system-release; then
(
set -x
amazon-linux-extras install epel -y >/dev/null
) || exit 1
else
(
set -x
yum -y -q install epel-release >/dev/null
) || exiterr3
fi
(
set -x
yum -y -q install openvpn openssl ca-certificates tar $firewall >/dev/null 2>&1
) || exiterr3
elif [[ "$os" = "fedora" ]]; then
(
set -x
dnf install -y openvpn openssl ca-certificates tar $firewall >/dev/null
) || exiterr "'dnf install' failed."
else
# Else, OS must be openSUSE
(
set -x
zypper install -y openvpn openssl ca-certificates tar $firewall >/dev/null
) || exiterr4
fi
# If firewalld was just installed, enable it
if [[ "$firewall" == "firewalld" ]]; then
(
set -x
systemctl enable --now firewalld.service >/dev/null 2>&1
)
fi
}
remove_pkgs() {
if [[ "$os" = "debian" || "$os" = "ubuntu" ]]; then
(
set -x
rm -rf /etc/openvpn/server
apt-get remove --purge -y openvpn >/dev/null
)
elif [[ "$os" = "openSUSE" ]]; then
(
set -x
zypper remove -y openvpn >/dev/null
rm -rf /etc/openvpn/server
)
rm -f /etc/openvpn/ipp.txt
else
# Else, OS must be CentOS or Fedora
(
set -x
yum -y -q remove openvpn >/dev/null
rm -rf /etc/openvpn/server
)
fi
}
create_firewall_rules() {
if systemctl is-active --quiet firewalld.service; then
# Using both permanent and not permanent rules to avoid a firewalld
# reload.
# We don't use --add-service=openvpn because that would only work with
# the default port and protocol.
firewall-cmd -q --add-port="$port"/"$protocol"
firewall-cmd -q --zone=trusted --add-source=10.8.0.0/24
firewall-cmd -q --permanent --add-port="$port"/"$protocol"
firewall-cmd -q --permanent --zone=trusted --add-source=10.8.0.0/24
# Set NAT for the VPN subnet
firewall-cmd -q --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
firewall-cmd -q --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
if [[ -n "$ip6" ]]; then
firewall-cmd -q --zone=trusted --add-source=fddd:1194:1194:1194::/64
firewall-cmd -q --permanent --zone=trusted --add-source=fddd:1194:1194:1194::/64
firewall-cmd -q --direct --add-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
firewall-cmd -q --permanent --direct --add-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
fi
else
# Create a service to set up persistent iptables rules
iptables_path=$(command -v iptables)
ip6tables_path=$(command -v ip6tables)
# nf_tables is not available as standard in OVZ kernels. So use iptables-legacy
# if we are in OVZ, with a nf_tables backend and iptables-legacy is available.
if [[ $(systemd-detect-virt) == "openvz" ]] && readlink -f "$(command -v iptables)" | grep -q "nft" && hash iptables-legacy 2>/dev/null; then
iptables_path=$(command -v iptables-legacy)
ip6tables_path=$(command -v ip6tables-legacy)
fi
echo "[Unit]
Before=network.target
[Service]
Type=oneshot
ExecStart=$iptables_path -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
ExecStart=$iptables_path -I INPUT -p $protocol --dport $port -j ACCEPT
ExecStart=$iptables_path -I FORWARD -s 10.8.0.0/24 -j ACCEPT
ExecStart=$iptables_path -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
ExecStop=$iptables_path -t nat -D POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
ExecStop=$iptables_path -D INPUT -p $protocol --dport $port -j ACCEPT
ExecStop=$iptables_path -D FORWARD -s 10.8.0.0/24 -j ACCEPT
ExecStop=$iptables_path -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" > /etc/systemd/system/openvpn-iptables.service
if [[ -n "$ip6" ]]; then
echo "ExecStart=$ip6tables_path -t nat -A POSTROUTING -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
ExecStart=$ip6tables_path -I FORWARD -s fddd:1194:1194:1194::/64 -j ACCEPT
ExecStart=$ip6tables_path -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
ExecStop=$ip6tables_path -t nat -D POSTROUTING -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
ExecStop=$ip6tables_path -D FORWARD -s fddd:1194:1194:1194::/64 -j ACCEPT
ExecStop=$ip6tables_path -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" >> /etc/systemd/system/openvpn-iptables.service
fi
echo "RemainAfterExit=yes
[Install]
WantedBy=multi-user.target" >> /etc/systemd/system/openvpn-iptables.service
(
set -x
systemctl enable --now openvpn-iptables.service >/dev/null 2>&1
)
fi
}
remove_firewall_rules() {
port=$(grep '^port ' "$OVPN_CONF" | cut -d " " -f 2)
protocol=$(grep '^proto ' "$OVPN_CONF" | cut -d " " -f 2)
if systemctl is-active --quiet firewalld.service; then
ip=$(firewall-cmd --direct --get-rules ipv4 nat POSTROUTING | grep '\-s 10.8.0.0/24 '"'"'!'"'"' -d 10.8.0.0/24' | grep -oE '[^ ]+$')
# Using both permanent and not permanent rules to avoid a firewalld reload.
firewall-cmd -q --remove-port="$port"/"$protocol"
firewall-cmd -q --zone=trusted --remove-source=10.8.0.0/24
firewall-cmd -q --permanent --remove-port="$port"/"$protocol"
firewall-cmd -q --permanent --zone=trusted --remove-source=10.8.0.0/24
firewall-cmd -q --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
firewall-cmd -q --permanent --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
if grep -qs "server-ipv6" "$OVPN_CONF"; then
ip6=$(firewall-cmd --direct --get-rules ipv6 nat POSTROUTING | grep '\-s fddd:1194:1194:1194::/64 '"'"'!'"'"' -d fddd:1194:1194:1194::/64' | grep -oE '[^ ]+$')
firewall-cmd -q --zone=trusted --remove-source=fddd:1194:1194:1194::/64
firewall-cmd -q --permanent --zone=trusted --remove-source=fddd:1194:1194:1194::/64
firewall-cmd -q --direct --remove-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
firewall-cmd -q --permanent --direct --remove-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
fi
else
systemctl disable --now openvpn-iptables.service
rm -f /etc/systemd/system/openvpn-iptables.service
fi
if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$port" != 1194 ]]; then
semanage port -d -t openvpn_port_t -p "$protocol" "$port"
fi
}
install_easyrsa() {
# Get easy-rsa
easy_rsa_url='https://github.com/OpenVPN/easy-rsa/releases/download/v3.2.0/EasyRSA-3.2.0.tgz'
mkdir -p /etc/openvpn/server/easy-rsa/
{ wget -t 3 -T 30 -qO- "$easy_rsa_url" 2>/dev/null || curl -m 30 -sL "$easy_rsa_url" ; } | tar xz -C /etc/openvpn/server/easy-rsa/ --strip-components 1
if [ ! -f /etc/openvpn/server/easy-rsa/easyrsa ]; then
exiterr "Failed to download EasyRSA from $easy_rsa_url."
fi
chown -R root:root /etc/openvpn/server/easy-rsa/
}
create_pki_and_certs() {
cd /etc/openvpn/server/easy-rsa/ || exit 1
(
set -x
# Create the PKI, set up the CA and the server and client certificates
./easyrsa --batch init-pki >/dev/null
./easyrsa --batch build-ca nopass >/dev/null 2>&1
./easyrsa --batch --days=3650 build-server-full server nopass >/dev/null 2>&1
./easyrsa --batch --days=3650 build-client-full "$client" nopass >/dev/null 2>&1
./easyrsa --batch --days=3650 gen-crl >/dev/null 2>&1
)
# Move the stuff we need
cp pki/ca.crt pki/private/ca.key pki/issued/server.crt pki/private/server.key pki/crl.pem /etc/openvpn/server
# CRL is read with each client connection, while OpenVPN is dropped to nobody
chown nobody:"$group_name" /etc/openvpn/server/crl.pem
# Without +x in the directory, OpenVPN can't run a stat() on the CRL file
chmod o+x /etc/openvpn/server/
(
set -x
# Generate key for tls-crypt
openvpn --genkey --secret /etc/openvpn/server/tc.key >/dev/null
)
# Create the DH parameters file using the predefined ffdhe2048 group
echo '-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS-----' > /etc/openvpn/server/dh.pem
}
create_dns_config() {
case "$dns" in
1)
# Locate the proper resolv.conf
# Needed for systems running systemd-resolved
if grep '^nameserver' "/etc/resolv.conf" | grep -qv '127.0.0.53' ; then
resolv_conf="/etc/resolv.conf"
else
resolv_conf="/run/systemd/resolve/resolv.conf"
fi
# Obtain the resolvers from resolv.conf and use them for OpenVPN
grep -v '^#\|^;' "$resolv_conf" | grep '^nameserver' | grep -v '127.0.0.53' | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' | while read line; do
echo "push \"dhcp-option DNS $line\"" >> "$OVPN_CONF"
done
;;
2|"")
echo 'push "dhcp-option DNS 8.8.8.8"' >> "$OVPN_CONF"
echo 'push "dhcp-option DNS 8.8.4.4"' >> "$OVPN_CONF"
;;
3)
echo 'push "dhcp-option DNS 1.1.1.1"' >> "$OVPN_CONF"
echo 'push "dhcp-option DNS 1.0.0.1"' >> "$OVPN_CONF"
;;
4)
echo 'push "dhcp-option DNS 208.67.222.222"' >> "$OVPN_CONF"
echo 'push "dhcp-option DNS 208.67.220.220"' >> "$OVPN_CONF"
;;
5)
echo 'push "dhcp-option DNS 9.9.9.9"' >> "$OVPN_CONF"
echo 'push "dhcp-option DNS 149.112.112.112"' >> "$OVPN_CONF"
;;
6)
echo 'push "dhcp-option DNS 94.140.14.14"' >> "$OVPN_CONF"
echo 'push "dhcp-option DNS 94.140.15.15"' >> "$OVPN_CONF"
;;
7)
echo "push \"dhcp-option DNS $dns1\"" >> "$OVPN_CONF"
if [ -n "$dns2" ]; then
echo "push \"dhcp-option DNS $dns2\"" >> "$OVPN_CONF"
fi
;;
esac
}
create_server_config() {
# Generate server.conf
echo "local $ip
port $port
proto $protocol
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh.pem
auth SHA256
tls-crypt tc.key
topology subnet
server 10.8.0.0 255.255.255.0" > "$OVPN_CONF"
# IPv6
if [[ -z "$ip6" ]]; then
echo 'push "block-ipv6"' >> "$OVPN_CONF"
echo 'push "ifconfig-ipv6 fddd:1194:1194:1194::2/64 fddd:1194:1194:1194::1"' >> "$OVPN_CONF"
else
echo 'server-ipv6 fddd:1194:1194:1194::/64' >> "$OVPN_CONF"
fi
echo 'push "redirect-gateway def1 ipv6 bypass-dhcp"' >> "$OVPN_CONF"
echo 'ifconfig-pool-persist ipp.txt' >> "$OVPN_CONF"
create_dns_config
echo 'push "block-outside-dns"' >> "$OVPN_CONF"
echo "keepalive 10 120
cipher AES-128-GCM
user nobody
group $group_name
persist-key
persist-tun
verb 3
crl-verify crl.pem" >> "$OVPN_CONF"
if [[ "$protocol" = "udp" ]]; then
echo "explicit-exit-notify" >> "$OVPN_CONF"
fi
}
show_clients() {
tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
}
get_export_dir() {
export_to_home_dir=0
export_dir=~/
@ -491,6 +834,70 @@ EOF
fi
}
update_selinux() {
# If SELinux is enabled and a custom port was selected, we need this
if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$port" != 1194 ]]; then
# Install semanage if not already present
if ! hash semanage 2>/dev/null; then
if [[ "$os_version" -eq 7 ]]; then
# Centos 7
(
set -x
yum -y -q install policycoreutils-python >/dev/null
) || exiterr3
else
# CentOS 8/9 or Fedora
(
set -x
dnf install -y policycoreutils-python-utils >/dev/null
) || exiterr "'dnf install' failed."
fi
fi
semanage port -a -t openvpn_port_t -p "$protocol" "$port"
fi
}
create_client_common() {
# client-common.txt is created so we have a template to add further users later
echo "client
dev tun
proto $protocol
remote $ip $port
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
auth SHA256
cipher AES-128-GCM
ignore-unknown-option block-outside-dns block-ipv6
verb 3" > /etc/openvpn/server/client-common.txt
}
start_openvpn_service() {
# Enable and start the OpenVPN service
if [ "$os" != "openSUSE" ]; then
(
set -x
systemctl enable --now openvpn-server@server.service >/dev/null 2>&1
)
else
ln -s /etc/openvpn/server/* /etc/openvpn >/dev/null 2>&1
(
set -x
systemctl enable --now openvpn@server.service >/dev/null 2>&1
)
fi
}
finish_setup() {
echo
echo "Finished!"
echo
echo "The client configuration is available in: $export_dir$client.ovpn"
echo "New clients can be added by running this script again."
}
show_header() {
cat <<'EOF'
@ -507,6 +914,24 @@ Copyright (c) 2013-2023 Nyr
EOF
}
select_menu_option() {
echo
echo "OpenVPN is already installed."
echo
echo "Select an option:"
echo " 1) Add a new client"
echo " 2) Export config for an existing client"
echo " 3) List existing clients"
echo " 4) Revoke an existing client"
echo " 5) Remove OpenVPN"
echo " 6) Exit"
read -rp "Option: " option
until [[ "$option" =~ ^[1-6]$ ]]; do
echo "$option: invalid selection."
read -rp "Option: " option
done
}
show_usage() {
if [ -n "$1" ]; then
echo "Error: $1" >&2
@ -530,45 +955,19 @@ ovpnsetup() {
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
if [ "$(id -u)" != 0 ]; then
exiterr "This installer must be run as root. Try 'sudo bash $0'"
fi
# Detect Debian users running the script with "sh" instead of bash
if readlink /proc/$$/exe | grep -q "dash"; then
exiterr 'This installer needs to be run with "bash", not "sh".'
fi
# Detect OpenVZ 6
if [[ $(uname -r | cut -d "." -f 1) -eq 2 ]]; then
exiterr "The system is running an old kernel, which is incompatible with this installer."
fi
check_root
check_shell
check_kernel
check_os
check_os_ver
check_tun
if [[ ! -e /dev/net/tun ]] || ! ( exec 7<>/dev/net/tun ) 2>/dev/null; then
exiterr "The system does not have the TUN device available.
TUN needs to be enabled before running this installer."
fi
OVPN_CONF="/etc/openvpn/server/server.conf"
auto=0
if [[ ! -e /etc/openvpn/server/server.conf ]]; then
if [[ ! -e "$OVPN_CONF" ]]; then
check_nftables
while [ "$#" -gt 0 ]; do
case $1 in
--auto)
auto=1
shift
;;
-h|--help)
show_usage
;;
*)
show_usage "Unknown parameter: $1"
;;
esac
done
parse_args "$@"
install_wget
install_iproute
show_start_setup
@ -593,305 +992,26 @@ if [[ ! -e /etc/openvpn/server/server.conf ]]; then
confirm_setup
echo
echo "Installing OpenVPN, please wait..."
# If running inside a container, disable LimitNPROC to prevent conflicts
if systemd-detect-virt -cq; then
mkdir /etc/systemd/system/openvpn-server@server.service.d/ 2>/dev/null
echo "[Service]
LimitNPROC=infinity" > /etc/systemd/system/openvpn-server@server.service.d/disable-limitnproc.conf
fi
if [[ "$os" = "debian" || "$os" = "ubuntu" ]]; then
export DEBIAN_FRONTEND=noninteractive
(
set -x
apt-get -yqq update || apt-get -yqq update
apt-get -yqq --no-install-recommends install openvpn >/dev/null
) || exiterr2
(
set -x
apt-get -yqq install openssl ca-certificates $firewall >/dev/null
) || exiterr2
elif [[ "$os" = "centos" ]]; then
if grep -qs "Amazon Linux release 2 " /etc/system-release; then
(
set -x
amazon-linux-extras install epel -y >/dev/null
) || exit 1
else
(
set -x
yum -y -q install epel-release >/dev/null
) || exiterr3
fi
(
set -x
yum -y -q install openvpn openssl ca-certificates tar $firewall >/dev/null 2>&1
) || exiterr3
elif [[ "$os" = "fedora" ]]; then
(
set -x
dnf install -y openvpn openssl ca-certificates tar $firewall >/dev/null
) || exiterr "'dnf install' failed."
else
# Else, OS must be openSUSE
(
set -x
zypper install -y openvpn openssl ca-certificates tar $firewall >/dev/null
) || exiterr4
fi
# If firewalld was just installed, enable it
if [[ "$firewall" == "firewalld" ]]; then
(
set -x
systemctl enable --now firewalld.service >/dev/null 2>&1
)
fi
# Get easy-rsa
easy_rsa_url='https://github.com/OpenVPN/easy-rsa/releases/download/v3.2.0/EasyRSA-3.2.0.tgz'
mkdir -p /etc/openvpn/server/easy-rsa/
{ wget -t 3 -T 30 -qO- "$easy_rsa_url" 2>/dev/null || curl -m 30 -sL "$easy_rsa_url" ; } | tar xz -C /etc/openvpn/server/easy-rsa/ --strip-components 1
if [ ! -f /etc/openvpn/server/easy-rsa/easyrsa ]; then
exiterr "Failed to download EasyRSA from $easy_rsa_url."
fi
chown -R root:root /etc/openvpn/server/easy-rsa/
cd /etc/openvpn/server/easy-rsa/ || exit 1
(
set -x
# Create the PKI, set up the CA and the server and client certificates
./easyrsa --batch init-pki >/dev/null
./easyrsa --batch build-ca nopass >/dev/null 2>&1
./easyrsa --batch --days=3650 build-server-full server nopass >/dev/null 2>&1
./easyrsa --batch --days=3650 build-client-full "$client" nopass >/dev/null 2>&1
./easyrsa --batch --days=3650 gen-crl >/dev/null 2>&1
)
# Move the stuff we need
cp pki/ca.crt pki/private/ca.key pki/issued/server.crt pki/private/server.key pki/crl.pem /etc/openvpn/server
# CRL is read with each client connection, while OpenVPN is dropped to nobody
chown nobody:"$group_name" /etc/openvpn/server/crl.pem
# Without +x in the directory, OpenVPN can't run a stat() on the CRL file
chmod o+x /etc/openvpn/server/
(
set -x
# Generate key for tls-crypt
openvpn --genkey --secret /etc/openvpn/server/tc.key >/dev/null
)
# Create the DH parameters file using the predefined ffdhe2048 group
echo '-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
-----END DH PARAMETERS-----' > /etc/openvpn/server/dh.pem
# Generate server.conf
echo "local $ip
port $port
proto $protocol
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh.pem
auth SHA256
tls-crypt tc.key
topology subnet
server 10.8.0.0 255.255.255.0" > /etc/openvpn/server/server.conf
# IPv6
if [[ -z "$ip6" ]]; then
echo 'push "block-ipv6"' >> /etc/openvpn/server/server.conf
echo 'push "ifconfig-ipv6 fddd:1194:1194:1194::2/64 fddd:1194:1194:1194::1"' >> /etc/openvpn/server/server.conf
else
echo 'server-ipv6 fddd:1194:1194:1194::/64' >> /etc/openvpn/server/server.conf
fi
echo 'push "redirect-gateway def1 ipv6 bypass-dhcp"' >> /etc/openvpn/server/server.conf
echo 'ifconfig-pool-persist ipp.txt' >> /etc/openvpn/server/server.conf
# DNS
case "$dns" in
1)
# Locate the proper resolv.conf
# Needed for systems running systemd-resolved
if grep '^nameserver' "/etc/resolv.conf" | grep -qv '127.0.0.53' ; then
resolv_conf="/etc/resolv.conf"
else
resolv_conf="/run/systemd/resolve/resolv.conf"
fi
# Obtain the resolvers from resolv.conf and use them for OpenVPN
grep -v '^#\|^;' "$resolv_conf" | grep '^nameserver' | grep -v '127.0.0.53' | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' | while read line; do
echo "push \"dhcp-option DNS $line\"" >> /etc/openvpn/server/server.conf
done
;;
2|"")
echo 'push "dhcp-option DNS 8.8.8.8"' >> /etc/openvpn/server/server.conf
echo 'push "dhcp-option DNS 8.8.4.4"' >> /etc/openvpn/server/server.conf
;;
3)
echo 'push "dhcp-option DNS 1.1.1.1"' >> /etc/openvpn/server/server.conf
echo 'push "dhcp-option DNS 1.0.0.1"' >> /etc/openvpn/server/server.conf
;;
4)
echo 'push "dhcp-option DNS 208.67.222.222"' >> /etc/openvpn/server/server.conf
echo 'push "dhcp-option DNS 208.67.220.220"' >> /etc/openvpn/server/server.conf
;;
5)
echo 'push "dhcp-option DNS 9.9.9.9"' >> /etc/openvpn/server/server.conf
echo 'push "dhcp-option DNS 149.112.112.112"' >> /etc/openvpn/server/server.conf
;;
6)
echo 'push "dhcp-option DNS 94.140.14.14"' >> /etc/openvpn/server/server.conf
echo 'push "dhcp-option DNS 94.140.15.15"' >> /etc/openvpn/server/server.conf
;;
7)
echo "push \"dhcp-option DNS $dns1\"" >> /etc/openvpn/server/server.conf
if [ -n "$dns2" ]; then
echo "push \"dhcp-option DNS $dns2\"" >> /etc/openvpn/server/server.conf
fi
;;
esac
echo 'push "block-outside-dns"' >> /etc/openvpn/server/server.conf
echo "keepalive 10 120
cipher AES-128-GCM
user nobody
group $group_name
persist-key
persist-tun
verb 3
crl-verify crl.pem" >> /etc/openvpn/server/server.conf
if [[ "$protocol" = "udp" ]]; then
echo "explicit-exit-notify" >> /etc/openvpn/server/server.conf
fi
disable_limitnproc
install_pkgs
install_easyrsa
create_pki_and_certs
create_server_config
update_sysctl
if systemctl is-active --quiet firewalld.service; then
# Using both permanent and not permanent rules to avoid a firewalld
# reload.
# We don't use --add-service=openvpn because that would only work with
# the default port and protocol.
firewall-cmd -q --add-port="$port"/"$protocol"
firewall-cmd -q --zone=trusted --add-source=10.8.0.0/24
firewall-cmd -q --permanent --add-port="$port"/"$protocol"
firewall-cmd -q --permanent --zone=trusted --add-source=10.8.0.0/24
# Set NAT for the VPN subnet
firewall-cmd -q --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
firewall-cmd -q --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
if [[ -n "$ip6" ]]; then
firewall-cmd -q --zone=trusted --add-source=fddd:1194:1194:1194::/64
firewall-cmd -q --permanent --zone=trusted --add-source=fddd:1194:1194:1194::/64
firewall-cmd -q --direct --add-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
firewall-cmd -q --permanent --direct --add-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
fi
else
# Create a service to set up persistent iptables rules
iptables_path=$(command -v iptables)
ip6tables_path=$(command -v ip6tables)
# nf_tables is not available as standard in OVZ kernels. So use iptables-legacy
# if we are in OVZ, with a nf_tables backend and iptables-legacy is available.
if [[ $(systemd-detect-virt) == "openvz" ]] && readlink -f "$(command -v iptables)" | grep -q "nft" && hash iptables-legacy 2>/dev/null; then
iptables_path=$(command -v iptables-legacy)
ip6tables_path=$(command -v ip6tables-legacy)
fi
echo "[Unit]
Before=network.target
[Service]
Type=oneshot
ExecStart=$iptables_path -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
ExecStart=$iptables_path -I INPUT -p $protocol --dport $port -j ACCEPT
ExecStart=$iptables_path -I FORWARD -s 10.8.0.0/24 -j ACCEPT
ExecStart=$iptables_path -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
ExecStop=$iptables_path -t nat -D POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
ExecStop=$iptables_path -D INPUT -p $protocol --dport $port -j ACCEPT
ExecStop=$iptables_path -D FORWARD -s 10.8.0.0/24 -j ACCEPT
ExecStop=$iptables_path -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" > /etc/systemd/system/openvpn-iptables.service
if [[ -n "$ip6" ]]; then
echo "ExecStart=$ip6tables_path -t nat -A POSTROUTING -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
ExecStart=$ip6tables_path -I FORWARD -s fddd:1194:1194:1194::/64 -j ACCEPT
ExecStart=$ip6tables_path -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
ExecStop=$ip6tables_path -t nat -D POSTROUTING -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
ExecStop=$ip6tables_path -D FORWARD -s fddd:1194:1194:1194::/64 -j ACCEPT
ExecStop=$ip6tables_path -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT" >> /etc/systemd/system/openvpn-iptables.service
fi
echo "RemainAfterExit=yes
[Install]
WantedBy=multi-user.target" >> /etc/systemd/system/openvpn-iptables.service
(
set -x
systemctl enable --now openvpn-iptables.service >/dev/null 2>&1
)
fi
create_firewall_rules
if [ "$os" != "openSUSE" ]; then
update_rclocal
fi
# If SELinux is enabled and a custom port was selected, we need this
if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$port" != 1194 ]]; then
# Install semanage if not already present
if ! hash semanage 2>/dev/null; then
if [[ "$os_version" -eq 7 ]]; then
# Centos 7
(
set -x
yum -y -q install policycoreutils-python >/dev/null
) || exiterr3
else
# CentOS 8/9 or Fedora
(
set -x
dnf install -y policycoreutils-python-utils >/dev/null
) || exiterr "'dnf install' failed."
fi
fi
semanage port -a -t openvpn_port_t -p "$protocol" "$port"
fi
update_selinux
# If the server is behind NAT, use the correct IP address
[[ -n "$public_ip" ]] && ip="$public_ip"
# client-common.txt is created so we have a template to add further users later
echo "client
dev tun
proto $protocol
remote $ip $port
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
auth SHA256
cipher AES-128-GCM
ignore-unknown-option block-outside-dns block-ipv6
verb 3" > /etc/openvpn/server/client-common.txt
# Enable and start the OpenVPN service
if [ "$os" != "openSUSE" ]; then
(
set -x
systemctl enable --now openvpn-server@server.service >/dev/null 2>&1
)
else
ln -s /etc/openvpn/server/* /etc/openvpn >/dev/null 2>&1
(
set -x
systemctl enable --now openvpn@server.service >/dev/null 2>&1
)
fi
# Generates the custom client.ovpn
create_client_common
start_openvpn_service
new_client
echo
echo "Finished!"
echo
echo "The client configuration is available in: $export_dir$client.ovpn"
echo "New clients can be added by running this script again."
finish_setup
else
show_header
echo
echo "OpenVPN is already installed."
echo
echo "Select an option:"
echo " 1) Add a new client"
echo " 2) Export config for an existing client"
echo " 3) List existing clients"
echo " 4) Revoke an existing client"
echo " 5) Remove OpenVPN"
echo " 6) Exit"
read -rp "Option: " option
until [[ "$option" =~ ^[1-6]$ ]]; do
echo "$option: invalid selection."
read -rp "Option: " option
done
select_menu_option
case "$option" in
1)
echo
@ -925,7 +1045,7 @@ else
fi
echo
echo "Select the client to export:"
tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
show_clients
read -rp "Client: " client_num
[ -z "$client_num" ] && abort_and_exit
until [[ "$client_num" =~ ^[0-9]+$ && "$client_num" -le "$num_of_clients" ]]; do
@ -949,7 +1069,7 @@ else
exit
fi
echo
tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
show_clients
if [ "$num_of_clients" = 1 ]; then
printf '\n%s\n' "Total: 1 client"
elif [ -n "$num_of_clients" ]; then
@ -966,7 +1086,7 @@ else
fi
echo
echo "Select the client to revoke:"
tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | nl -s ') '
show_clients
read -rp "Client: " client_num
[ -z "$client_num" ] && abort_and_exit
until [[ "$client_num" =~ ^[0-9]+$ && "$client_num" -le "$num_of_clients" ]]; do
@ -1018,31 +1138,7 @@ else
if [[ "$remove" =~ ^[yY]$ ]]; then
echo
echo "Removing OpenVPN, please wait..."
port=$(grep '^port ' /etc/openvpn/server/server.conf | cut -d " " -f 2)
protocol=$(grep '^proto ' /etc/openvpn/server/server.conf | cut -d " " -f 2)
if systemctl is-active --quiet firewalld.service; then
ip=$(firewall-cmd --direct --get-rules ipv4 nat POSTROUTING | grep '\-s 10.8.0.0/24 '"'"'!'"'"' -d 10.8.0.0/24' | grep -oE '[^ ]+$')
# Using both permanent and not permanent rules to avoid a firewalld reload.
firewall-cmd -q --remove-port="$port"/"$protocol"
firewall-cmd -q --zone=trusted --remove-source=10.8.0.0/24
firewall-cmd -q --permanent --remove-port="$port"/"$protocol"
firewall-cmd -q --permanent --zone=trusted --remove-source=10.8.0.0/24
firewall-cmd -q --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
firewall-cmd -q --permanent --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j MASQUERADE
if grep -qs "server-ipv6" /etc/openvpn/server/server.conf; then
ip6=$(firewall-cmd --direct --get-rules ipv6 nat POSTROUTING | grep '\-s fddd:1194:1194:1194::/64 '"'"'!'"'"' -d fddd:1194:1194:1194::/64' | grep -oE '[^ ]+$')
firewall-cmd -q --zone=trusted --remove-source=fddd:1194:1194:1194::/64
firewall-cmd -q --permanent --zone=trusted --remove-source=fddd:1194:1194:1194::/64
firewall-cmd -q --direct --remove-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
firewall-cmd -q --permanent --direct --remove-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j MASQUERADE
fi
else
systemctl disable --now openvpn-iptables.service
rm -f /etc/systemd/system/openvpn-iptables.service
fi
if sestatus 2>/dev/null | grep "Current mode" | grep -q "enforcing" && [[ "$port" != 1194 ]]; then
semanage port -d -t openvpn_port_t -p "$protocol" "$port"
fi
remove_firewall_rules
if [ "$os" != "openSUSE" ]; then
systemctl disable --now openvpn-server@server.service
else
@ -1059,27 +1155,7 @@ else
if grep -qs "$ipt_cmd" /etc/rc.local; then
sed --follow-symlinks -i "/^$ipt_cmd/d" /etc/rc.local
fi
if [[ "$os" = "debian" || "$os" = "ubuntu" ]]; then
(
set -x
rm -rf /etc/openvpn/server
apt-get remove --purge -y openvpn >/dev/null
)
elif [[ "$os" = "openSUSE" ]]; then
(
set -x
zypper remove -y openvpn >/dev/null
rm -rf /etc/openvpn/server
)
rm -f /etc/openvpn/ipp.txt
else
# Else, OS must be CentOS or Fedora
(
set -x
yum -y -q remove openvpn >/dev/null
rm -rf /etc/openvpn/server
)
fi
remove_pkgs
echo
echo "OpenVPN removed!"
else