Browse Source

Added wireguard.sh
This is a Shell script for configure and start WireGuard VPN server

Signed-off-by: Teddysun <[email protected]>

Teddysun 6 years ago
parent
commit
2695401bc9
1 changed files with 651 additions and 0 deletions
  1. 651 0
      wireguard.sh

+ 651 - 0
wireguard.sh

@@ -0,0 +1,651 @@
+#!/usr/bin/env bash
+#
+# This is a Shell script for configure and start WireGuard VPN server.
+#
+# Copyright (C) 2019 Teddysun <[email protected]>
+#
+# Reference URL:
+# https://www.wireguard.com
+# https://git.zx2c4.com/WireGuard
+
+trap _exit INT QUIT TERM
+
+_red() {
+    printf '\033[1;31;31m%b\033[0m' "$1"
+}
+
+_green() {
+    printf '\033[1;31;32m%b\033[0m' "$1"
+}
+
+_yellow() {
+    printf '\033[1;31;33m%b\033[0m' "$1"
+}
+
+_printargs() {
+    printf -- "%s" "[$(date)] "
+    printf -- "%s" "$1"
+    printf "\n"
+}
+
+_info() {
+    _printargs "$@"
+}
+
+_warn() {
+    printf -- "%s" "[$(date)] "
+    _yellow "$1"
+    printf "\n"
+}
+
+_error() {
+    printf -- "%s" "[$(date)] "
+    _red "$1"
+    printf "\n"
+    exit 2
+}
+
+_exit() {
+    printf "\n"
+    _red "$0 has been terminated."
+    printf "\n"
+    exit 1
+}
+
+_exists() {
+    local cmd="$1"
+    if eval type type > /dev/null 2>&1; then
+        eval type "$cmd" > /dev/null 2>&1
+    elif command > /dev/null 2>&1; then
+        command -v "$cmd" > /dev/null 2>&1
+    else
+        which "$cmd" > /dev/null 2>&1
+    fi
+    rt="$?"
+    return ${rt}
+}
+
+_ipv4() {
+    local ipv4="$( ip addr | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | \
+                   egrep -v "^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\.|^0\." | head -n 1 )"
+    [ -z "${ipv4}" ] && ipv4="$( wget -qO- -t1 -T2 ipv4.icanhazip.com )"
+    [ -z "${ipv4}" ] && ipv4="$( wget -qO- -t1 -T2 ipinfo.io/ip )"
+    printf -- "%s" "${ipv4}"
+}
+
+_ipv6() {
+    local ipv6=""
+    ipv6="$(wget -qO- -t1 -T2 ipv6.icanhazip.com)"
+    printf -- "%s" "${ipv6}"
+}
+
+_nic() {
+    local nic=""
+    nic="$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)"
+    printf -- "%s" "${nic}"
+}
+
+_port() {
+    local port="$(shuf -i 1024-20480 -n 1)"
+    while true
+    do
+        if _exists "netstat" && netstat -tunlp | grep -w "${port}" > /dev/null 2>&1; then
+            port="$(shuf -i 1024-20480 -n 1)"
+        else
+            break
+        fi
+    done
+    printf -- "%s" "${port}"
+}
+
+_os() {
+    local os=""
+    [ -f "/etc/debian_version" ] && source /etc/os-release && os="${ID}" && printf -- "%s" "${os}" && return
+    [ -f "/etc/fedora-release" ] && os="fedora" && printf -- "%s" "${os}" && return
+    [ -f "/etc/redhat-release" ] && os="centos" && printf -- "%s" "${os}" && return
+}
+
+_os_full() {
+    [ -f /etc/redhat-release ] && awk '{print ($1,$3~/^[0-9]/?$3:$4)}' /etc/redhat-release && return
+    [ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return
+    [ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return
+}
+
+_os_ver() {
+    local main_ver="$( echo $(_os_full) | grep -oE  "[0-9.]+")"
+    printf -- "%s" "${main_ver%%.*}"
+}
+
+_error_detect() {
+    local cmd="$1"
+    _info "${cmd}"
+    eval ${cmd} 1> /dev/null
+    if [ $? -ne 0 ]; then
+        _error "Execution command (${cmd}) failed, please check it and try again."
+    fi
+}
+
+# Check OS version
+check_os() {
+    _info "Check OS version"
+    if _exists "virt-what"; then
+        virt="$(virt-what)"
+    elif _exists "systemd-detect-virt"; then
+        virt="$(systemd-detect-virt)"
+    fi
+    if [ -n "${virt}" -a "${virt}" = "lxc" ]; then
+        _error "Virtualization method is LXC, which is not supported."
+    fi
+    if [ -n "${virt}" -a "${virt}" = "openvz" ] || [ -d "/proc/vz" ]; then
+        _error "Virtualization method is OpenVZ, which is not supported."
+    fi
+    [ -z "$(_os)" ] && _error "Not supported OS."
+    case "$(_os)" in
+        ubuntu)
+            [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 16 ] && _error "Not supported OS, please change to Ubuntu 16+ and try again."
+            ;;
+        debian)
+            [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 8 ] &&  _error "Not supported OS, please change to Debian 8+ and try again."
+            ;;
+        fedora)
+            [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 29 ] && _error "Not supported OS, please change to Fedora 29+ and try again."
+            ;;
+        centos)
+            [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 7 ] &&  _error "Not supported OS, please change to CentOS 7+ and try again."
+            ;;
+        *)
+            ;; # do nothing
+    esac
+}
+
+# Install from repository
+install_wg_1() {
+    _info "Install wireguard from repository"
+    case "$(_os)" in
+        ubuntu)
+            _error_detect "add-apt-repository ppa:wireguard/wireguard"
+            _error_detect "apt-get update"
+            _error_detect "apt-get -y install linux-headers-$(uname -r)"
+            _error_detect "apt-get -y install qrencode"
+            _error_detect "apt-get -y install iptables"
+            _error_detect "apt-get -y install wireguard"
+            ;;
+        debian)
+            echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list
+            printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable
+            _error_detect "apt-get update"
+            _error_detect "apt-get -y install linux-headers-$(uname -r)"
+            _error_detect "apt-get -y install qrencode"
+            _error_detect "apt-get -y install iptables"
+            _error_detect "apt-get -y install wireguard"
+            ;;
+        fedora)
+            _error_detect "dnf -y copr enable jdoss/wireguard"
+            _error_detect "dnf -y install kernel-devel"
+            _error_detect "dnf -y install kernel-headers"
+            _error_detect "dnf -y install qrencode"
+            _error_detect "dnf -y install wireguard-dkms wireguard-tools"
+            ;;
+        centos)
+            _error_detect "curl -Lso /etc/yum.repos.d/wireguard.repo https://copr.fedorainfracloud.org/coprs/jdoss/wireguard/repo/epel-7/jdoss-wireguard-epel-7.repo"
+            _error_detect "yum -y install epel-release"
+            _error_detect "yum -y install kernel-devel"
+            _error_detect "yum -y install kernel-headers"
+            _error_detect "yum -y install qrencode"
+            _error_detect "yum -y install wireguard-dkms wireguard-tools"
+            ;;
+        *)
+            ;; # do nothing
+    esac
+}
+
+# Install from source
+install_wg_2() {
+    _info "Install wireguard from source"
+    wireguard_ver="$(wget --no-check-certificate -qO- https://api.github.com/repos/WireGuard/WireGuard/tags | grep 'name' | head -1 | cut -d\" -f4)"
+    if [ -z "${wireguard_ver}" ]; then
+        wireguard_ver="$(curl -Lso- https://api.github.com/repos/WireGuard/WireGuard/tags | grep 'name' | head -1 | cut -d\" -f4)"
+    fi
+    [ -z "${wireguard_ver}" ] && _error "Failed to get wireguard latest version from github."
+    wireguard_name="WireGuard-${wireguard_ver}"
+    wireguard_url="https://github.com/WireGuard/WireGuard/archive/${wireguard_ver}.tar.gz"
+    case "$(_os)" in
+        ubuntu|debian)
+            _error_detect "apt-get update"
+            [ ! -d "/usr/src/linux-headers-$(uname -r)" ] && _error_detect "apt-get -y install linux-headers-$(uname -r)"
+            _error_detect "apt-get -y install qrencode"
+            _error_detect "apt-get -y install iptables"
+            _error_detect "apt-get -y install bc"
+            _error_detect "apt-get -y install gcc"
+            _error_detect "apt-get -y install make"
+            _error_detect "apt-get -y install libmnl-dev"
+            ;;
+        fedora)
+            [ ! -d "/usr/src/kernels/$(uname -r)" ] && _error_detect "dnf -y install kernel-headers" && _error_detect "dnf -y install kernel-devel"
+            _error_detect "dnf -y install qrencode"
+            _error_detect "dnf -y install bc"
+            _error_detect "dnf -y install gcc"
+            _error_detect "dnf -y install make"
+            _error_detect "dnf -y install libmnl-devel"
+            ;;
+        centos)
+            _error_detect "yum -y install epel-release"
+            [ ! -d "/usr/src/kernels/$(uname -r)" ] && _error_detect "yum -y install kernel-headers" && _error_detect "yum -y install kernel-devel"
+            _error_detect "yum -y install qrencode"
+            _error_detect "yum -y install bc"
+            _error_detect "yum -y install gcc"
+            _error_detect "yum -y install make"
+            _error_detect "yum -y install libmnl-devel"
+            ;;
+        *)
+            ;; # do nothing
+    esac
+    _error_detect "wget --no-check-certificate -qO ${wireguard_name}.tar.gz ${wireguard_url}"
+    _error_detect "tar zxf ${wireguard_name}.tar.gz"
+    _error_detect "cd ${wireguard_name}/src"
+    _error_detect "make tools"
+    _error_detect "make module"
+    _error_detect "make install"
+    _error_detect "cd ${cur_dir} && rm -fr ${wireguard_name}.tar.gz ${wireguard_name}"
+}
+
+# Create server interface
+create_server_if() {
+    SERVER_PRIVATE_KEY="$(wg genkey)"
+    SERVER_PUBLIC_KEY="$(echo ${SERVER_PRIVATE_KEY} | wg pubkey)"
+    CLIENT_PRIVATE_KEY="$(wg genkey)"
+    CLIENT_PUBLIC_KEY="$(echo ${CLIENT_PRIVATE_KEY} | wg pubkey)"
+    CLIENT_PRE_SHARED_KEY="$( wg genpsk )"
+    _info "Create server interface: /etc/wireguard/${SERVER_WG_NIC}.conf"
+    [ ! -d "/etc/wireguard" ] && mkdir -p "/etc/wireguard"
+    if [ -n "${SERVER_PUB_IPV6}" ]; then
+        cat > /etc/wireguard/${SERVER_WG_NIC}.conf <<EOF
+[Interface]
+Address = ${SERVER_WG_IPV4}/24,${SERVER_WG_IPV6}/64
+ListenPort = ${SERVER_WG_PORT}
+PrivateKey = ${SERVER_PRIVATE_KEY}
+
+[Peer]
+PublicKey = ${CLIENT_PUBLIC_KEY}
+AllowedIPs = ${CLIENT_WG_IPV4}/32,${CLIENT_WG_IPV6}/128
+PresharedKey = ${CLIENT_PRE_SHARED_KEY}
+EOF
+    else
+        cat > /etc/wireguard/${SERVER_WG_NIC}.conf <<EOF
+[Interface]
+Address = ${SERVER_WG_IPV4}/24
+ListenPort = ${SERVER_WG_PORT}
+PrivateKey = ${SERVER_PRIVATE_KEY}
+
+[Peer]
+PublicKey = ${CLIENT_PUBLIC_KEY}
+AllowedIPs = ${CLIENT_WG_IPV4}/32
+PresharedKey = ${CLIENT_PRE_SHARED_KEY}
+EOF
+    fi
+    chmod 600 /etc/wireguard/${SERVER_WG_NIC}.conf
+}
+
+# Create client interface
+create_client_if() {
+    _info "Create client interface: /etc/wireguard/${SERVER_WG_NIC}_client"
+    if [ -n "${SERVER_PUB_IPV6}" ]; then
+        cat > /etc/wireguard/${SERVER_WG_NIC}_client <<EOF
+[Interface]
+Address = ${CLIENT_WG_IPV4}/24,${CLIENT_WG_IPV6}/64
+PrivateKey = ${CLIENT_PRIVATE_KEY}
+DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2}
+
+[Peer]
+PublicKey = ${SERVER_PUBLIC_KEY}
+Endpoint = ${SERVER_PUB_IPV4}:${SERVER_WG_PORT}
+AllowedIPs = 0.0.0.0/0,::/0
+PresharedKey = ${CLIENT_PRE_SHARED_KEY}
+EOF
+    else
+        cat > /etc/wireguard/${SERVER_WG_NIC}_client <<EOF
+[Interface]
+Address = ${CLIENT_WG_IPV4}/24
+PrivateKey = ${CLIENT_PRIVATE_KEY}
+DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2}
+
+[Peer]
+PublicKey = ${SERVER_PUBLIC_KEY}
+Endpoint = ${SERVER_PUB_IPV4}:${SERVER_WG_PORT}
+AllowedIPs = 0.0.0.0/0
+PresharedKey = ${CLIENT_PRE_SHARED_KEY}
+EOF
+    fi
+    chmod 600 /etc/wireguard/${SERVER_WG_NIC}_client
+}
+
+# Generate a QR Code picture with default client interface
+generate_qr() {
+    _info "Generate a QR Code picture with client interface"
+    _error_detect "qrencode -s8 -o /etc/wireguard/${SERVER_WG_NIC}_client.png < /etc/wireguard/${SERVER_WG_NIC}_client"
+}
+
+# Enable IP forwarding
+enable_ip_forward() {
+    _info "Enable IP forward"
+    sed -i '/net.ipv4.ip_forward/d' /etc/sysctl.conf
+    [ -n "${SERVER_PUB_IPV6}" ] && sed -i '/net.ipv6.conf.all.forwarding/d' /etc/sysctl.conf
+    echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
+    [ -n "${SERVER_PUB_IPV6}" ] && echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf
+    sysctl -p >/dev/null 2>&1
+}
+
+# Set firewall rules
+set_firewall() {
+    _info "Setting firewall rules"
+    if _exists "firewall-cmd"; then
+        if [ "$(firewall-cmd --state)" = "running" ]; then
+            default_zone="$(firewall-cmd --get-default-zone)"
+            if [ "$(firewall-cmd --zone=${default_zone} --query-masquerade)" = "no" ]; then
+                _error_detect "firewall-cmd --zone=${default_zone} --add-masquerade"
+            fi
+            if ! firewall-cmd --list-ports | grep -qw "${SERVER_WG_PORT}/udp"; then
+                _error_detect "firewall-cmd --permanent --zone=${default_zone} --add-port=${SERVER_WG_PORT}/udp"
+            fi
+            _error_detect "firewall-cmd --reload"
+        else
+            _warn "Firewalld looks like not running, please start it and manually set"
+        fi
+    else
+        if _exists "iptables"; then
+            iptables -A INPUT -p udp --dport ${SERVER_WG_PORT} -j ACCEPT
+            iptables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT
+            iptables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE
+            iptables-save > /etc/iptables.rules
+            if [ -d "/etc/network/if-up.d" ]; then
+                cat > /etc/network/if-up.d/iptables <<EOF
+#!/bin/sh
+/sbin/iptables-restore < /etc/iptables.rules
+EOF
+                chmod +x /etc/network/if-up.d/iptables
+            fi
+        fi
+        if _exists "ip6tables"; then
+            ip6tables -A INPUT -p udp --dport ${SERVER_WG_PORT} -j ACCEPT
+            ip6tables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT
+            ip6tables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE
+            ip6tables-save > /etc/ip6tables.rules
+            if [ -d "/etc/network/if-up.d" ]; then
+                cat > /etc/network/if-up.d/ip6tables <<EOF
+#!/bin/sh
+/sbin/ip6tables-restore < /etc/ip6tables.rules
+EOF
+                chmod +x /etc/network/if-up.d/ip6tables
+            fi
+        fi
+    fi
+}
+
+# WireGuard installation completed
+install_completed() {
+    _info "Starting WireGuard via wg-quick for ${SERVER_WG_NIC}"
+    _error_detect "systemctl daemon-reload"
+    _error_detect "systemctl start wg-quick@${SERVER_WG_NIC}"
+    _error_detect "systemctl enable wg-quick@${SERVER_WG_NIC}"
+    _info "WireGuard VPN Server installation completed"
+    _info "WireGuard VPN default client file is below:"
+    _info "$(_green "/etc/wireguard/${SERVER_WG_NIC}_client")"
+    _info "WireGuard VPN default client QR Code is below:"
+    _info "$(_green "/etc/wireguard/${SERVER_WG_NIC}_client.png")"
+    _info "Download and scan this QR Code with your phone, enjoy it"
+}
+
+add_client() {
+    if ! _exists "wg" || ! _exists "wg-quick"; then
+        _red "WireGuard looks like not installed, please installed it try again\n" && exit 1
+    fi
+    default_server_if="/etc/wireguard/${SERVER_WG_NIC}.conf"
+    default_client_if="/etc/wireguard/${SERVER_WG_NIC}_client"
+    [ ! -s "${default_server_if}" ] && echo "The default server interface ($(_red ${default_server_if})) does not exists" && exit 1
+    [ ! -s "${default_client_if}" ] && echo "The default client interface ($(_red ${default_client_if})) does not exists" && exit 1
+    while true
+    do
+        read -p "Please enter a client name (for example: wg1):" client
+        if [ -z "${client}" ]; then
+            _red "Client name can not be empty\n"
+        else
+            new_client_if="/etc/wireguard/${client}_client"
+            if [ "${client}" = "${SERVER_WG_NIC}" ]; then
+                echo "The default client ($(_yellow ${client})) already exists. Please re-enter it"
+            elif [ -s "${new_client_if}" ]; then
+                echo "The client ($(_yellow ${client})) already exists. Please re-enter it"
+            else
+                break
+            fi
+        fi
+    done
+    # Get information from default interface file
+    client_files=($(find /etc/wireguard -name "*_client" | sort))
+    client_ipv4=()
+    client_ipv6=()
+    for ((i=0; i<${#client_files[@]}; i++)); do
+        tmp_ipv4="$(grep -w "Address" ${client_files[$i]} | awk '{print $3}' | cut -d\/ -f1 )"
+        tmp_ipv6="$(grep -w "Address" ${client_files[$i]} | awk '{print $3}' | awk -F, '{print $2}' | cut -d\/ -f1 )"
+        client_ipv4=(${client_ipv4[@]} ${tmp_ipv4})
+        client_ipv6=(${client_ipv6[@]} ${tmp_ipv6})
+    done
+    # Sort array
+    client_ipv4_sorted=($(printf '%s\n' "${client_ipv4[@]}" | sort))
+    index=$(expr ${#client_ipv4[@]} - 1)
+    last_ip=$(echo ${client_ipv4_sorted[$index]} | cut -d. -f4)
+    issue_ip_last=$(expr ${last_ip} + 1)
+    [ ${issue_ip_last} -gt 254 ] && _red "Too many client, IP addresses might not be enough\n" && exit 1
+    ipv4_comm=$(echo ${client_ipv4[$index]} | cut -d. -f1-3)
+    ipv6_comm=$(echo ${client_ipv6[$index]} | awk -F: '{print $1":"$2":"$3":"$4}')
+    CLIENT_PRIVATE_KEY="$(wg genkey)"
+    CLIENT_PUBLIC_KEY="$(echo ${CLIENT_PRIVATE_KEY} | wg pubkey)"
+    SERVER_PUBLIC_KEY="$(grep -w "PublicKey" ${default_client_if} | awk '{print $3}')"
+    CLIENT_ENDPOINT="$(grep -w "Endpoint" ${default_client_if} | awk '{print $3}')"
+    CLIENT_PRE_SHARED_KEY="$(grep -w "PresharedKey" ${default_client_if} | awk '{print $3}')"
+    CLIENT_WG_IPV4="${ipv4_comm}.${issue_ip_last}"
+    CLIENT_WG_IPV6="${ipv6_comm}:${issue_ip_last}"
+    # Create a new client interface
+    if [ -n "${SERVER_PUB_IPV6}" ]; then
+        cat > ${new_client_if} <<EOF
+[Interface]
+Address = ${CLIENT_WG_IPV4}/24,${CLIENT_WG_IPV6}/64
+PrivateKey = ${CLIENT_PRIVATE_KEY}
+DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2}
+
+[Peer]
+PublicKey = ${SERVER_PUBLIC_KEY}
+Endpoint = ${CLIENT_ENDPOINT}
+AllowedIPs = 0.0.0.0/0,::/0
+PresharedKey = ${CLIENT_PRE_SHARED_KEY}
+EOF
+        # Add a new client to default server interface
+        cat >> ${default_server_if} <<EOF
+
+[Peer]
+PublicKey = ${CLIENT_PUBLIC_KEY}
+AllowedIPs = ${CLIENT_WG_IPV4}/32,${CLIENT_WG_IPV6}/128
+PresharedKey = ${CLIENT_PRE_SHARED_KEY}
+EOF
+    else
+        cat > ${new_client_if} <<EOF
+[Interface]
+Address = ${CLIENT_WG_IPV4}/24
+PrivateKey = ${CLIENT_PRIVATE_KEY}
+DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2}
+
+[Peer]
+PublicKey = ${SERVER_PUBLIC_KEY}
+Endpoint = ${CLIENT_ENDPOINT}
+AllowedIPs = 0.0.0.0/0
+PresharedKey = ${CLIENT_PRE_SHARED_KEY}
+EOF
+        cat >> ${default_server_if} <<EOF
+
+[Peer]
+PublicKey = ${CLIENT_PUBLIC_KEY}
+AllowedIPs = ${CLIENT_WG_IPV4}/32
+PresharedKey = ${CLIENT_PRE_SHARED_KEY}
+EOF
+    fi
+    chmod 600 ${new_client_if}
+    echo "Add a WireGuard client ($(_green ${client})) completed"
+    systemctl restart wg-quick@${SERVER_WG_NIC}
+    # Generate a new QR Code picture
+    qrencode -s8 -o ${new_client_if}.png < ${new_client_if}
+    echo "Generate a QR Code picture with new client ($(_green ${client})) completed"
+    echo
+    echo "WireGuard VPN new client ($(_green ${client})) file is below:"
+    _green "/etc/wireguard/${client}_client\n"
+    echo
+    echo "WireGuard VPN new client ($(_green ${client})) QR Code is below:"
+    _green "/etc/wireguard/${client}_client.png\n"
+    echo "Download and scan this QR Code with your phone, enjoy it"
+}
+
+remove_client() {
+    default_server_if="/etc/wireguard/${SERVER_WG_NIC}.conf"
+    [ ! -s "${default_server_if}" ] && echo "The default server interface ($(_red ${default_server_if})) does not exists" && exit 1
+    while true
+    do
+        read -p "Please enter a client name you want to delete it (for example: wg1):" client
+        if [ -z "${client}" ]; then
+            _red "Client name can not be empty\n"
+        else
+            if [ "${client}" = "${SERVER_WG_NIC}" ]; then
+                echo "The default client ($(_yellow ${client})) can not be delete"
+            else
+                break
+            fi
+        fi
+    done
+    client_if="/etc/wireguard/${client}_client"
+    [ ! -s "${client_if}" ] && echo "The client file ($(_red ${client_if})) does not exists" && exit 1
+    tmp_tag="$(grep -w "Address" ${client_if} | awk '{print $3}' | cut -d\/ -f1 )"
+    [ -n "${tmp_tag}" ] && sed -i '/'"$tmp_tag"'/,+1d;:a;1,3!{P;$!N;D};N;ba' ${default_server_if}
+    # Delete client interface file
+    rm -f ${client_if}
+    [ -s "/etc/wireguard/${client}_client.png" ] && rm -f /etc/wireguard/${client}_client.png
+    systemctl restart wg-quick@${SERVER_WG_NIC}
+    echo "The client name ($(_green ${client})) has been deleted"
+}
+
+list_clients() {
+    default_server_if="/etc/wireguard/${SERVER_WG_NIC}.conf"
+    [ ! -s "${default_server_if}" ] && echo "The default server interface ($(_red ${default_server_if})) does not exists" && exit 1
+    local line="+-------------------------------------------------------------------------+\n"
+    local string=%-35s
+    printf "${line}|${string} |${string} |\n${line}" " Client Interface" " Client's IP"
+    client_files=($(find /etc/wireguard -name "*_client" | sort))
+    ips=($(grep -w "AllowedIPs" ${default_server_if} | awk '{print $3}'))
+    [ ${#client_files[@]} -ne ${#ips[@]} ] && echo "One or more client interface file is missing in /etc/wireguard" && exit 1
+    for ((i=0; i<${#ips[@]}; i++)); do
+        tmp_ipv4="$(echo ${ips[$i]} | cut -d\/ -f1)"
+        for ((j=0; j<${#client_files[@]}; j++)); do
+            if grep -qw "${tmp_ipv4}" "${client_files[$j]}"; then
+                printf "|${string} |${string} |\n" " ${client_files[$j]}" " ${ips[$i]}"
+                break
+            fi
+        done
+    done
+    printf ${line}
+}
+
+version() {
+    if _exists "wg" && _exists "wg-quick"; then
+        if [ -s "/lib/modules/$(uname -r)/extra/wireguard.ko" ] || [ -s "/lib/modules/$(uname -r)/extra/wireguard.ko.xz" ] \
+           || [ -s "/lib/modules/$(uname -r)/updates/dkms/" ]; then
+            _exists "modinfo" && installed_wg_ver="$(modinfo -F version wireguard)"
+            [ -n "${installed_wg_ver}" ] && echo "WireGuard version: $(_green ${installed_wg_ver})"
+        else
+            _red "WireGuard kernel module does not exists\n"
+        fi
+    else
+        _red "WireGuard is not installed\n"
+    fi
+}
+
+show_help() {
+    printf "
+Usage: $0 [Options]
+Options:
+-h, --help       Print this help text and exit
+-r, --repo       Install WireGuard from repository
+-s, --source     Install WireGuard from source
+-v, --version    Print WireGuard version if installed
+-a, --add        Add a WireGuard client
+-d, --del        Delete a WireGuard client
+-l, --list       List all WireGuard client's IP
+
+"
+}
+
+install_from_repo() {
+    check_os
+    install_wg_1
+    create_server_if
+    create_client_if
+    generate_qr
+    enable_ip_forward
+    set_firewall
+    install_completed
+}
+
+install_from_source() {
+    check_os
+    install_wg_2
+    create_server_if
+    create_client_if
+    generate_qr
+    enable_ip_forward
+    set_firewall
+    install_completed
+}
+
+cur_dir="$(pwd)"
+
+[ ${EUID} -ne 0 ] && _error "This script must be run as root"
+
+SERVER_PUB_IPV4="${VPN_SERVER_PUB_IPV4:-$(_ipv4)}"
+SERVER_PUB_IPV6="${VPN_SERVER_PUB_IPV6:-$(_ipv6)}"
+SERVER_PUB_NIC="${VPN_SERVER_PUB_NIC:-$(_nic)}"
+SERVER_WG_NIC="${VPN_SERVER_WG_NIC:-wg0}"
+SERVER_WG_IPV4="${VPN_SERVER_WG_IPV4:-10.88.88.1}"
+SERVER_WG_IPV6="${VPN_SERVER_WG_IPV6:-fd88:88:88::1}"
+SERVER_WG_PORT="${VPN_SERVER_WG_PORT:-$(_port)}"
+CLIENT_WG_IPV4="${VPN_CLIENT_WG_IPV4:-10.88.88.2}"
+CLIENT_WG_IPV6="${VPN_CLIENT_WG_IPV6:-fd88:88:88::2}"
+CLIENT_DNS_1="${VPN_CLIENT_DNS_1:-1.1.1.1}"
+CLIENT_DNS_2="${VPN_CLIENT_DNS_2:-8.8.8.8}"
+
+main() {
+    action="$1"
+    [ -z "${action}" ] && show_help && exit 0
+    case "${action}" in
+        -h|--help)
+            show_help
+            ;;
+        -r|--repo)
+            install_from_repo
+            ;;
+        -s|--source)
+            install_from_source
+            ;;
+        -v|--version)
+            version
+            ;;
+        -a|--add)
+            add_client
+            ;;
+        -d|--del)
+            remove_client
+            ;;
+        -l|--list)
+            list_clients
+            ;;
+        *)
+            show_help
+            ;;
+    esac
+}
+
+main "$@"