mirror of
https://github.com/Nyr/openvpn-install.git
synced 2025-04-12 21:40:57 +00:00
Thanks to @nyr for the best script. Just added a few touches as a Kali Debian user, as well as the introduction of duplicate-cn in the server.conf This helps to add Kali support (but breaks Pre Debian 9, so be careful. Ideally, We are well past using Debian 8 or lower though, all honesty. We could almost call it deprecated except for the backwards compatibility, so be forewarned. The duplicate-cn in servers.conf is something that should be there anyway, I don't see the average person only wishing to make a single connection without breaking the rest of their connections. If I try to add this to a second device, I can block the original from using the tunnel. While we can create separate tunnels, this one flag is sufficient to allow the multiple connections we need from other locations. Obviously that is bad for IPsec, because anyone that gets ahold of the servers.conf can have open access to your server of linux host. That is the case anyway, so you really don't want to let your .ovpn get out of your hands. Adding multiple connection effectively broadens the ability for this leaks to become threatening. Personally, I trust how I store this information, and handle it very carefully, where it isn't already well place in the /root directory anyway. I transfer the .ovpn over an SFTP tunnel, and store it on an encrypted drive in case I need it later. Absolutely wonderful to have this script!! I am able to use this server's IP address and tunnel other servers' outbound traffic while also use the same VPN at home. I don't pay for a VPN anymore, but being able to use it and also re-use it simultaneously is, well, amazing. MY server is a 64GB RAM 12 CPU, and is now my beautiful security OS (Kali, with a lot of custom fireballing, etc) and I can traffic all my connection to my 'work' IP address when desired. This script worked well in comparison to some other examples I tried. I can install it on a VPN router and select devices to traffic to work. And my other server also can reuse it, to proxy one server connection as another, while still being able to have the VPN at home on our router. I hope these changes were helpful. @SatoriHoshiAiko
577 lines
24 KiB
Bash
577 lines
24 KiB
Bash
#!/bin/bash
|
||
#
|
||
# https://github.com/Nyr/openvpn-install
|
||
#
|
||
# Copyright (c) 2013 Nyr. Released under the MIT License.
|
||
|
||
|
||
# Detect Debian users running the script with "sh" instead of bash
|
||
if readlink /proc/$$/exe | grep -q "dash"; then
|
||
echo 'This installer needs to be run with "bash", not "sh".'
|
||
exit
|
||
fi
|
||
|
||
# Discard stdin. Needed when running from an one-liner which includes a newline
|
||
read -N 999999 -t 0.001
|
||
|
||
# Detect OpenVZ 6
|
||
if [[ $(uname -r | cut -d "." -f 1) -eq 2 ]]; then
|
||
echo "The system is running an old kernel, which is incompatible with this installer."
|
||
exit
|
||
fi
|
||
|
||
# Detect OS
|
||
# $os_version variables aren't always in use, but are kept here for convenience
|
||
if grep -qs "ubuntu" /etc/os-release; then
|
||
os="ubuntu"
|
||
os_version=$(grep 'VERSION_ID' /etc/os-release | cut -d '"' -f 2 | tr -d '.')
|
||
group_name="nogroup"
|
||
elif [[ -e /etc/debian_version ]]; then
|
||
os="debian"
|
||
os_version=$(grep -oE '[0-9]+' /etc/debian_version | head -1)
|
||
group_name="nogroup"
|
||
elif [[ -e /etc/almalinux-release || -e /etc/rocky-release || -e /etc/centos-release ]]; then
|
||
os="centos"
|
||
os_version=$(grep -shoE '[0-9]+' /etc/almalinux-release /etc/rocky-release /etc/centos-release | head -1)
|
||
group_name="nobody"
|
||
elif [[ -e /etc/fedora-release ]]; then
|
||
os="fedora"
|
||
os_version=$(grep -oE '[0-9]+' /etc/fedora-release | head -1)
|
||
group_name="nobody"
|
||
else
|
||
echo "This installer seems to be running on an unsupported distribution.
|
||
Supported distros are Ubuntu, Debian, AlmaLinux, Rocky Linux, CentOS and Fedora."
|
||
exit
|
||
fi
|
||
|
||
if [[ "$os" == "ubuntu" && "$os_version" -lt 1804 ]]; then
|
||
echo "Ubuntu 18.04 or higher is required to use this installer.
|
||
This version of Ubuntu is too old and unsupported."
|
||
exit
|
||
fi
|
||
################################################################################################################
|
||
# WE COMMENTED OUT THIS LINE TO BYPASS DEBIAN VERSION CHECKS THAT KALI DOESN'T MATCH (IT STILL WORKS THE SAME) #
|
||
################################################################################################################
|
||
#if [[ "$os" == "debian" && "$os_version" -lt 9 ]]; then
|
||
# echo "Debian 9 or higher is required to use this installer.
|
||
#This version of Debian is too old and unsupported."
|
||
# exit
|
||
#fi
|
||
|
||
if [[ "$os" == "centos" && "$os_version" -lt 7 ]]; then
|
||
echo "CentOS 7 or higher is required to use this installer.
|
||
This version of CentOS is too old and unsupported."
|
||
exit
|
||
fi
|
||
|
||
# Detect environments where $PATH does not include the sbin directories
|
||
if ! grep -q sbin <<< "$PATH"; then
|
||
echo '$PATH does not include sbin. Try using "su -" instead of "su".'
|
||
exit
|
||
fi
|
||
|
||
if [[ "$EUID" -ne 0 ]]; then
|
||
echo "This installer needs to be run with superuser privileges."
|
||
exit
|
||
fi
|
||
|
||
if [[ ! -e /dev/net/tun ]] || ! ( exec 7<>/dev/net/tun ) 2>/dev/null; then
|
||
echo "The system does not have the TUN device available.
|
||
TUN needs to be enabled before running this installer."
|
||
exit
|
||
fi
|
||
|
||
new_client () {
|
||
# Generates the custom client.ovpn
|
||
{
|
||
cat /etc/openvpn/server/client-common.txt
|
||
echo "<ca>"
|
||
cat /etc/openvpn/server/easy-rsa/pki/ca.crt
|
||
echo "</ca>"
|
||
echo "<cert>"
|
||
sed -ne '/BEGIN CERTIFICATE/,$ p' /etc/openvpn/server/easy-rsa/pki/issued/"$client".crt
|
||
echo "</cert>"
|
||
echo "<key>"
|
||
cat /etc/openvpn/server/easy-rsa/pki/private/"$client".key
|
||
echo "</key>"
|
||
echo "<tls-crypt>"
|
||
sed -ne '/BEGIN OpenVPN Static key/,$ p' /etc/openvpn/server/tc.key
|
||
echo "</tls-crypt>"
|
||
} > ~/"$client".ovpn
|
||
}
|
||
|
||
if [[ ! -e /etc/openvpn/server/server.conf ]]; then
|
||
# Detect some Debian minimal setups where neither wget nor curl are installed
|
||
if ! hash wget 2>/dev/null && ! hash curl 2>/dev/null; then
|
||
echo "Wget is required to use this installer."
|
||
read -n1 -r -p "Press any key to install Wget and continue..."
|
||
apt-get update
|
||
apt-get install -y wget
|
||
fi
|
||
clear
|
||
echo 'Welcome to this OpenVPN road warrior installer!'
|
||
# If system has a single IPv4, it is selected automatically. Else, ask the user
|
||
if [[ $(ip -4 addr | grep inet | grep -vEc '127(\.[0-9]{1,3}){3}') -eq 1 ]]; then
|
||
ip=$(ip -4 addr | grep inet | grep -vE '127(\.[0-9]{1,3}){3}' | cut -d '/' -f 1 | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}')
|
||
else
|
||
number_of_ip=$(ip -4 addr | grep inet | grep -vEc '127(\.[0-9]{1,3}){3}')
|
||
echo
|
||
echo "Which IPv4 address should be used?"
|
||
ip -4 addr | grep inet | grep -vE '127(\.[0-9]{1,3}){3}' | cut -d '/' -f 1 | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' | nl -s ') '
|
||
read -p "IPv4 address [1]: " ip_number
|
||
until [[ -z "$ip_number" || "$ip_number" =~ ^[0-9]+$ && "$ip_number" -le "$number_of_ip" ]]; do
|
||
echo "$ip_number: invalid selection."
|
||
read -p "IPv4 address [1]: " ip_number
|
||
done
|
||
[[ -z "$ip_number" ]] && ip_number="1"
|
||
ip=$(ip -4 addr | grep inet | grep -vE '127(\.[0-9]{1,3}){3}' | cut -d '/' -f 1 | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' | sed -n "$ip_number"p)
|
||
fi
|
||
# If $ip is a private IP address, the server must be behind NAT
|
||
if echo "$ip" | grep -qE '^(10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|192\.168)'; then
|
||
echo
|
||
echo "This server is behind NAT. What is the public IPv4 address or hostname?"
|
||
# Get public IP and sanitize with grep
|
||
get_public_ip=$(grep -m 1 -oE '^[0-9]{1,3}(\.[0-9]{1,3}){3}$' <<< "$(wget -T 10 -t 1 -4qO- "http://ip1.dynupdate.no-ip.com/" || curl -m 10 -4Ls "http://ip1.dynupdate.no-ip.com/")")
|
||
read -p "Public IPv4 address / hostname [$get_public_ip]: " public_ip
|
||
# If the checkip service is unavailable and user didn't provide input, ask again
|
||
until [[ -n "$get_public_ip" || -n "$public_ip" ]]; do
|
||
echo "Invalid input."
|
||
read -p "Public IPv4 address / hostname: " public_ip
|
||
done
|
||
[[ -z "$public_ip" ]] && public_ip="$get_public_ip"
|
||
fi
|
||
# If system has a single IPv6, it is selected automatically
|
||
if [[ $(ip -6 addr | grep -c 'inet6 [23]') -eq 1 ]]; then
|
||
ip6=$(ip -6 addr | grep 'inet6 [23]' | cut -d '/' -f 1 | grep -oE '([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}')
|
||
fi
|
||
# If system has multiple IPv6, ask the user to select one
|
||
if [[ $(ip -6 addr | grep -c 'inet6 [23]') -gt 1 ]]; then
|
||
number_of_ip6=$(ip -6 addr | grep -c 'inet6 [23]')
|
||
echo
|
||
echo "Which IPv6 address should be used?"
|
||
ip -6 addr | grep 'inet6 [23]' | cut -d '/' -f 1 | grep -oE '([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}' | nl -s ') '
|
||
read -p "IPv6 address [1]: " ip6_number
|
||
until [[ -z "$ip6_number" || "$ip6_number" =~ ^[0-9]+$ && "$ip6_number" -le "$number_of_ip6" ]]; do
|
||
echo "$ip6_number: invalid selection."
|
||
read -p "IPv6 address [1]: " ip6_number
|
||
done
|
||
[[ -z "$ip6_number" ]] && ip6_number="1"
|
||
ip6=$(ip -6 addr | grep 'inet6 [23]' | cut -d '/' -f 1 | grep -oE '([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}' | sed -n "$ip6_number"p)
|
||
fi
|
||
echo
|
||
echo "Which protocol should OpenVPN use?"
|
||
echo " 1) UDP (recommended)"
|
||
echo " 2) TCP"
|
||
read -p "Protocol [1]: " protocol
|
||
until [[ -z "$protocol" || "$protocol" =~ ^[12]$ ]]; do
|
||
echo "$protocol: invalid selection."
|
||
read -p "Protocol [1]: " protocol
|
||
done
|
||
case "$protocol" in
|
||
1|"")
|
||
protocol=udp
|
||
;;
|
||
2)
|
||
protocol=tcp
|
||
;;
|
||
esac
|
||
echo
|
||
echo "What port should OpenVPN listen to?"
|
||
read -p "Port [1194]: " port
|
||
until [[ -z "$port" || "$port" =~ ^[0-9]+$ && "$port" -le 65535 ]]; do
|
||
echo "$port: invalid port."
|
||
read -p "Port [1194]: " port
|
||
done
|
||
[[ -z "$port" ]] && port="1194"
|
||
echo
|
||
echo "Select a DNS server for the clients:"
|
||
echo " 1) Current system resolvers"
|
||
echo " 2) Google"
|
||
echo " 3) 1.1.1.1"
|
||
echo " 4) OpenDNS"
|
||
echo " 5) Quad9"
|
||
echo " 6) AdGuard"
|
||
read -p "DNS server [1]: " dns
|
||
until [[ -z "$dns" || "$dns" =~ ^[1-6]$ ]]; do
|
||
echo "$dns: invalid selection."
|
||
read -p "DNS server [1]: " dns
|
||
done
|
||
echo
|
||
echo "Enter a name for the first client:"
|
||
read -p "Name [client]: " unsanitized_client
|
||
# Allow a limited set of characters to avoid conflicts
|
||
client=$(sed 's/[^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-]/_/g' <<< "$unsanitized_client")
|
||
[[ -z "$client" ]] && client="client"
|
||
echo
|
||
echo "OpenVPN installation is ready to begin."
|
||
# Install a firewall if firewalld or iptables are not already available
|
||
if ! systemctl is-active --quiet firewalld.service && ! hash iptables 2>/dev/null; then
|
||
if [[ "$os" == "centos" || "$os" == "fedora" ]]; then
|
||
firewall="firewalld"
|
||
# We don't want to silently enable firewalld, so we give a subtle warning
|
||
# If the user continues, firewalld will be installed and enabled during setup
|
||
echo "firewalld, which is required to manage routing tables, will also be installed."
|
||
elif [[ "$os" == "debian" || "$os" == "ubuntu" ]]; then
|
||
# iptables is way less invasive than firewalld so no warning is given
|
||
firewall="iptables"
|
||
fi
|
||
fi
|
||
read -n1 -r -p "Press any key to continue..."
|
||
# 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
|
||
apt-get update
|
||
apt-get install -y openvpn openssl ca-certificates $firewall
|
||
elif [[ "$os" = "centos" ]]; then
|
||
yum install -y epel-release
|
||
yum install -y openvpn openssl ca-certificates tar $firewall
|
||
else
|
||
# Else, OS must be Fedora
|
||
dnf install -y openvpn openssl ca-certificates tar $firewall
|
||
fi
|
||
# If firewalld was just installed, enable it
|
||
if [[ "$firewall" == "firewalld" ]]; then
|
||
systemctl enable --now firewalld.service
|
||
fi
|
||
# Get easy-rsa
|
||
easy_rsa_url='https://github.com/OpenVPN/easy-rsa/releases/download/v3.1.0/EasyRSA-3.1.0.tgz'
|
||
mkdir -p /etc/openvpn/server/easy-rsa/
|
||
{ wget -qO- "$easy_rsa_url" 2>/dev/null || curl -sL "$easy_rsa_url" ; } | tar xz -C /etc/openvpn/server/easy-rsa/ --strip-components 1
|
||
chown -R root:root /etc/openvpn/server/easy-rsa/
|
||
cd /etc/openvpn/server/easy-rsa/
|
||
# Create the PKI, set up the CA and the server and client certificates
|
||
./easyrsa init-pki
|
||
./easyrsa --batch build-ca nopass
|
||
EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-server-full server nopass
|
||
EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-client-full "$client" nopass
|
||
EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
|
||
# 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/
|
||
# Generate key for tls-crypt
|
||
openvpn --genkey --secret /etc/openvpn/server/tc.key
|
||
# 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
|
||
|
||
################################################################
|
||
# HERE WE ADDED "duplicate-cn" TO PREVENT EXTRA CLIENTS FROM #
|
||
# CAUSING THE ORIGINAL CONNECTION TO DROP. "duplicate-cn" in #
|
||
# THE Server.conf HELP TO VERIFY MULTIPLE CLIENTS AS PER THE. #
|
||
# STANDARD OpenVPN USAGE. JUST ONE LINE LET'S YOU MAKE SEVERAL #
|
||
# CONNECTIONS, Home, Work, Office, Router, Phone, etc. ENJOY! #
|
||
################################################################
|
||
# 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 SHA512
|
||
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 "redirect-gateway def1 bypass-dhcp"' >> /etc/openvpn/server/server.conf
|
||
else
|
||
echo 'server-ipv6 fddd:1194:1194:1194::/64' >> /etc/openvpn/server/server.conf
|
||
echo 'push "redirect-gateway def1 ipv6 bypass-dhcp"' >> /etc/openvpn/server/server.conf
|
||
fi
|
||
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
|
||
;;
|
||
esac
|
||
echo 'push "block-outside-dns"' >> /etc/openvpn/server/server.conf
|
||
echo "keepalive 10 120
|
||
cipher AES-256-CBC
|
||
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
|
||
# Enable net.ipv4.ip_forward for the system
|
||
echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-openvpn-forward.conf
|
||
# Enable without waiting for a reboot or service restart
|
||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||
if [[ -n "$ip6" ]]; then
|
||
# Enable net.ipv6.conf.all.forwarding for the system
|
||
echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.d/99-openvpn-forward.conf
|
||
# Enable without waiting for a reboot or service restart
|
||
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
|
||
fi
|
||
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 --add-port="$port"/"$protocol"
|
||
firewall-cmd --zone=trusted --add-source=10.8.0.0/24
|
||
firewall-cmd --permanent --add-port="$port"/"$protocol"
|
||
firewall-cmd --permanent --zone=trusted --add-source=10.8.0.0/24
|
||
# Set NAT for the VPN subnet
|
||
firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to "$ip"
|
||
firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to "$ip"
|
||
if [[ -n "$ip6" ]]; then
|
||
firewall-cmd --zone=trusted --add-source=fddd:1194:1194:1194::/64
|
||
firewall-cmd --permanent --zone=trusted --add-source=fddd:1194:1194:1194::/64
|
||
firewall-cmd --direct --add-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to "$ip6"
|
||
firewall-cmd --permanent --direct --add-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to "$ip6"
|
||
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 SNAT --to $ip
|
||
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 SNAT --to $ip
|
||
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 SNAT --to $ip6
|
||
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 SNAT --to $ip6
|
||
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
|
||
systemctl enable --now openvpn-iptables.service
|
||
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
|
||
yum install -y policycoreutils-python
|
||
else
|
||
# CentOS 8 or Fedora
|
||
dnf install -y policycoreutils-python-utils
|
||
fi
|
||
fi
|
||
semanage port -a -t openvpn_port_t -p "$protocol" "$port"
|
||
fi
|
||
# 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 SHA512
|
||
cipher AES-256-CBC
|
||
ignore-unknown-option block-outside-dns
|
||
verb 3" > /etc/openvpn/server/client-common.txt
|
||
# Enable and start the OpenVPN service
|
||
systemctl enable --now openvpn-server@server.service
|
||
# Generates the custom client.ovpn
|
||
new_client
|
||
echo
|
||
echo "Finished!"
|
||
echo
|
||
echo "The client configuration is available in:" ~/"$client.ovpn"
|
||
echo "New clients can be added by running this script again."
|
||
else
|
||
clear
|
||
echo "OpenVPN is already installed."
|
||
echo
|
||
echo "Select an option:"
|
||
echo " 1) Add a new client"
|
||
echo " 2) Revoke an existing client"
|
||
echo " 3) Remove OpenVPN"
|
||
echo " 4) Exit"
|
||
read -p "Option: " option
|
||
until [[ "$option" =~ ^[1-4]$ ]]; do
|
||
echo "$option: invalid selection."
|
||
read -p "Option: " option
|
||
done
|
||
case "$option" in
|
||
1)
|
||
echo
|
||
echo "Provide a name for the client:"
|
||
read -p "Name: " unsanitized_client
|
||
client=$(sed 's/[^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-]/_/g' <<< "$unsanitized_client")
|
||
while [[ -z "$client" || -e /etc/openvpn/server/easy-rsa/pki/issued/"$client".crt ]]; do
|
||
echo "$client: invalid name."
|
||
read -p "Name: " unsanitized_client
|
||
client=$(sed 's/[^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-]/_/g' <<< "$unsanitized_client")
|
||
done
|
||
cd /etc/openvpn/server/easy-rsa/
|
||
EASYRSA_CERT_EXPIRE=3650 ./easyrsa build-client-full "$client" nopass
|
||
# Generates the custom client.ovpn
|
||
new_client
|
||
echo
|
||
echo "$client added. Configuration available in:" ~/"$client.ovpn"
|
||
exit
|
||
;;
|
||
2)
|
||
# This option could be documented a bit better and maybe even be simplified
|
||
# ...but what can I say, I want some sleep too
|
||
number_of_clients=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep -c "^V")
|
||
if [[ "$number_of_clients" = 0 ]]; then
|
||
echo
|
||
echo "There are no existing clients!"
|
||
exit
|
||
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 ') '
|
||
read -p "Client: " client_number
|
||
until [[ "$client_number" =~ ^[0-9]+$ && "$client_number" -le "$number_of_clients" ]]; do
|
||
echo "$client_number: invalid selection."
|
||
read -p "Client: " client_number
|
||
done
|
||
client=$(tail -n +2 /etc/openvpn/server/easy-rsa/pki/index.txt | grep "^V" | cut -d '=' -f 2 | sed -n "$client_number"p)
|
||
echo
|
||
read -p "Confirm $client revocation? [y/N]: " revoke
|
||
until [[ "$revoke" =~ ^[yYnN]*$ ]]; do
|
||
echo "$revoke: invalid selection."
|
||
read -p "Confirm $client revocation? [y/N]: " revoke
|
||
done
|
||
if [[ "$revoke" =~ ^[yY]$ ]]; then
|
||
cd /etc/openvpn/server/easy-rsa/
|
||
./easyrsa --batch revoke "$client"
|
||
EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
|
||
rm -f /etc/openvpn/server/crl.pem
|
||
cp /etc/openvpn/server/easy-rsa/pki/crl.pem /etc/openvpn/server/crl.pem
|
||
# CRL is read with each client connection, when OpenVPN is dropped to nobody
|
||
chown nobody:"$group_name" /etc/openvpn/server/crl.pem
|
||
echo
|
||
echo "$client revoked!"
|
||
else
|
||
echo
|
||
echo "$client revocation aborted!"
|
||
fi
|
||
exit
|
||
;;
|
||
3)
|
||
echo
|
||
read -p "Confirm OpenVPN removal? [y/N]: " remove
|
||
until [[ "$remove" =~ ^[yYnN]*$ ]]; do
|
||
echo "$remove: invalid selection."
|
||
read -p "Confirm OpenVPN removal? [y/N]: " remove
|
||
done
|
||
if [[ "$remove" =~ ^[yY]$ ]]; then
|
||
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 --remove-port="$port"/"$protocol"
|
||
firewall-cmd --zone=trusted --remove-source=10.8.0.0/24
|
||
firewall-cmd --permanent --remove-port="$port"/"$protocol"
|
||
firewall-cmd --permanent --zone=trusted --remove-source=10.8.0.0/24
|
||
firewall-cmd --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to "$ip"
|
||
firewall-cmd --permanent --direct --remove-rule ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to "$ip"
|
||
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 --zone=trusted --remove-source=fddd:1194:1194:1194::/64
|
||
firewall-cmd --permanent --zone=trusted --remove-source=fddd:1194:1194:1194::/64
|
||
firewall-cmd --direct --remove-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to "$ip6"
|
||
firewall-cmd --permanent --direct --remove-rule ipv6 nat POSTROUTING 0 -s fddd:1194:1194:1194::/64 ! -d fddd:1194:1194:1194::/64 -j SNAT --to "$ip6"
|
||
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
|
||
systemctl disable --now openvpn-server@server.service
|
||
rm -f /etc/systemd/system/openvpn-server@server.service.d/disable-limitnproc.conf
|
||
rm -f /etc/sysctl.d/99-openvpn-forward.conf
|
||
if [[ "$os" = "debian" || "$os" = "ubuntu" ]]; then
|
||
rm -rf /etc/openvpn/server
|
||
apt-get remove --purge -y openvpn
|
||
else
|
||
# Else, OS must be CentOS or Fedora
|
||
yum remove -y openvpn
|
||
rm -rf /etc/openvpn/server
|
||
fi
|
||
echo
|
||
echo "OpenVPN removed!"
|
||
else
|
||
echo
|
||
echo "OpenVPN removal aborted!"
|
||
fi
|
||
exit
|
||
;;
|
||
4)
|
||
exit
|
||
;;
|
||
esac
|
||
fi
|