wireguard.sh 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. #!/usr/bin/env bash
  2. #
  3. # This is a Shell script for configure and start WireGuard VPN server.
  4. #
  5. # Copyright (C) 2019 Teddysun <[email protected]>
  6. #
  7. # Reference URL:
  8. # https://www.wireguard.com
  9. # https://git.zx2c4.com/WireGuard
  10. trap _exit INT QUIT TERM
  11. _red() {
  12. printf '\033[1;31;31m%b\033[0m' "$1"
  13. }
  14. _green() {
  15. printf '\033[1;31;32m%b\033[0m' "$1"
  16. }
  17. _yellow() {
  18. printf '\033[1;31;33m%b\033[0m' "$1"
  19. }
  20. _printargs() {
  21. printf -- "%s" "[$(date)] "
  22. printf -- "%s" "$1"
  23. printf "\n"
  24. }
  25. _info() {
  26. _printargs "$@"
  27. }
  28. _warn() {
  29. printf -- "%s" "[$(date)] "
  30. _yellow "$1"
  31. printf "\n"
  32. }
  33. _error() {
  34. printf -- "%s" "[$(date)] "
  35. _red "$1"
  36. printf "\n"
  37. exit 2
  38. }
  39. _exit() {
  40. printf "\n"
  41. _red "$0 has been terminated."
  42. printf "\n"
  43. exit 1
  44. }
  45. _exists() {
  46. local cmd="$1"
  47. if eval type type > /dev/null 2>&1; then
  48. eval type "$cmd" > /dev/null 2>&1
  49. elif command > /dev/null 2>&1; then
  50. command -v "$cmd" > /dev/null 2>&1
  51. else
  52. which "$cmd" > /dev/null 2>&1
  53. fi
  54. rt="$?"
  55. return ${rt}
  56. }
  57. _ipv4() {
  58. local ipv4="$( ip addr | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | \
  59. egrep -v "^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\.|^0\.|^169\.254\." | head -n 1 )"
  60. [ -z "${ipv4}" ] && ipv4="$( wget -qO- -t1 -T2 ipv4.icanhazip.com )"
  61. [ -z "${ipv4}" ] && ipv4="$( wget -qO- -t1 -T2 ipinfo.io/ip )"
  62. printf -- "%s" "${ipv4}"
  63. }
  64. _ipv6() {
  65. local ipv6=""
  66. ipv6="$(wget -qO- -t1 -T2 ipv6.icanhazip.com)"
  67. printf -- "%s" "${ipv6}"
  68. }
  69. _nic() {
  70. local nic=""
  71. nic="$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)"
  72. printf -- "%s" "${nic}"
  73. }
  74. _port() {
  75. local port="$(shuf -i 1024-20480 -n 1)"
  76. while true
  77. do
  78. if _exists "netstat" && netstat -tunlp | grep -w "${port}" > /dev/null 2>&1; then
  79. port="$(shuf -i 1024-20480 -n 1)"
  80. else
  81. break
  82. fi
  83. done
  84. printf -- "%s" "${port}"
  85. }
  86. _os() {
  87. local os=""
  88. [ -f "/etc/debian_version" ] && source /etc/os-release && os="${ID}" && printf -- "%s" "${os}" && return
  89. [ -f "/etc/fedora-release" ] && os="fedora" && printf -- "%s" "${os}" && return
  90. [ -f "/etc/redhat-release" ] && os="centos" && printf -- "%s" "${os}" && return
  91. }
  92. _os_full() {
  93. [ -f /etc/redhat-release ] && awk '{print ($1,$3~/^[0-9]/?$3:$4)}' /etc/redhat-release && return
  94. [ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return
  95. [ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return
  96. }
  97. _os_ver() {
  98. local main_ver="$( echo $(_os_full) | grep -oE "[0-9.]+")"
  99. printf -- "%s" "${main_ver%%.*}"
  100. }
  101. _error_detect() {
  102. local cmd="$1"
  103. _info "${cmd}"
  104. eval ${cmd} 1> /dev/null
  105. if [ $? -ne 0 ]; then
  106. _error "Execution command (${cmd}) failed, please check it and try again."
  107. fi
  108. }
  109. _version_gt(){
  110. test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"
  111. }
  112. _is_installed() {
  113. if _exists "wg" && _exists "wg-quick"; then
  114. if [ -s "/lib/modules/$(uname -r)/extra/wireguard.ko" ] || [ -s "/lib/modules/$(uname -r)/extra/wireguard.ko.xz" ] \
  115. || [ -s "/lib/modules/$(uname -r)/updates/dkms/wireguard.ko" ]; then
  116. return 0
  117. else
  118. return 1
  119. fi
  120. else
  121. return 2
  122. fi
  123. }
  124. _get_latest_ver() {
  125. wireguard_ver="$(wget --no-check-certificate -qO- https://api.github.com/repos/WireGuard/WireGuard/tags | grep 'name' | head -1 | cut -d\" -f4)"
  126. if [ -z "${wireguard_ver}" ]; then
  127. wireguard_ver="$(curl -Lso- https://api.github.com/repos/WireGuard/WireGuard/tags | grep 'name' | head -1 | cut -d\" -f4)"
  128. fi
  129. [ -z "${wireguard_ver}" ] && _error "Failed to get wireguard latest version from github"
  130. }
  131. # Check OS version
  132. check_os() {
  133. _info "Check OS version"
  134. if _exists "virt-what"; then
  135. virt="$(virt-what)"
  136. elif _exists "systemd-detect-virt"; then
  137. virt="$(systemd-detect-virt)"
  138. fi
  139. if [ -n "${virt}" -a "${virt}" = "lxc" ]; then
  140. _error "Virtualization method is LXC, which is not supported."
  141. fi
  142. if [ -n "${virt}" -a "${virt}" = "openvz" ] || [ -d "/proc/vz" ]; then
  143. _error "Virtualization method is OpenVZ, which is not supported."
  144. fi
  145. [ -z "$(_os)" ] && _error "Not supported OS"
  146. case "$(_os)" in
  147. ubuntu)
  148. [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 16 ] && _error "Not supported OS, please change to Ubuntu 16+ and try again."
  149. ;;
  150. debian|raspbian)
  151. [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 8 ] && _error "Not supported OS, please change to De(Rasp)bian 8+ and try again."
  152. ;;
  153. fedora)
  154. [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 29 ] && _error "Not supported OS, please change to Fedora 29+ and try again."
  155. ;;
  156. centos)
  157. [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 7 ] && _error "Not supported OS, please change to CentOS 7+ and try again."
  158. ;;
  159. *)
  160. _error "Not supported OS"
  161. ;;
  162. esac
  163. }
  164. # Install from repository
  165. install_wg_1() {
  166. _info "Install wireguard from repository"
  167. case "$(_os)" in
  168. ubuntu)
  169. _error_detect "add-apt-repository ppa:wireguard/wireguard"
  170. _error_detect "apt-get update"
  171. _error_detect "apt-get -y install linux-headers-$(uname -r)"
  172. _error_detect "apt-get -y install qrencode"
  173. _error_detect "apt-get -y install iptables"
  174. _error_detect "apt-get -y install wireguard"
  175. ;;
  176. debian)
  177. echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list
  178. printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable
  179. _error_detect "apt-get update"
  180. _error_detect "apt-get -y install linux-headers-$(uname -r)"
  181. _error_detect "apt-get -y install qrencode"
  182. _error_detect "apt-get -y install iptables"
  183. _error_detect "apt-get -y install wireguard"
  184. ;;
  185. fedora)
  186. _error_detect "dnf -y copr enable jdoss/wireguard"
  187. _error_detect "dnf -y install kernel-devel"
  188. _error_detect "dnf -y install kernel-headers"
  189. _error_detect "dnf -y install qrencode"
  190. _error_detect "dnf -y install wireguard-dkms wireguard-tools"
  191. ;;
  192. centos)
  193. _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"
  194. _error_detect "yum -y install epel-release"
  195. _error_detect "yum -y install kernel-devel"
  196. _error_detect "yum -y install kernel-headers"
  197. _error_detect "yum -y install qrencode"
  198. _error_detect "yum -y install wireguard-dkms wireguard-tools"
  199. ;;
  200. *)
  201. ;; # do nothing
  202. esac
  203. if ! _is_installed; then
  204. _error "Failed to install wireguard, the kernel is most likely not configured correctly"
  205. fi
  206. }
  207. # Install from source
  208. install_wg_2() {
  209. _info "Install wireguard from source"
  210. case "$(_os)" in
  211. ubuntu|debian|raspbian)
  212. _error_detect "apt-get update"
  213. if [ ! -d "/usr/src/linux-headers-$(uname -r)" ]; then
  214. if [ "$(_os)" = "raspbian" ]; then
  215. _error_detect "apt-get -y install raspberrypi-kernel-headers"
  216. else
  217. _error_detect "apt-get -y install linux-headers-$(uname -r)"
  218. fi
  219. fi
  220. _error_detect "apt-get -y install qrencode"
  221. _error_detect "apt-get -y install iptables"
  222. _error_detect "apt-get -y install bc"
  223. _error_detect "apt-get -y install gcc"
  224. _error_detect "apt-get -y install make"
  225. _error_detect "apt-get -y install libmnl-dev"
  226. ;;
  227. fedora)
  228. [ ! -d "/usr/src/kernels/$(uname -r)" ] && _error_detect "dnf -y install kernel-headers" && _error_detect "dnf -y install kernel-devel"
  229. _error_detect "dnf -y install qrencode"
  230. _error_detect "dnf -y install bc"
  231. _error_detect "dnf -y install gcc"
  232. _error_detect "dnf -y install make"
  233. _error_detect "dnf -y install libmnl-devel"
  234. ;;
  235. centos)
  236. _error_detect "yum -y install epel-release"
  237. [ ! -d "/usr/src/kernels/$(uname -r)" ] && _error_detect "yum -y install kernel-headers" && _error_detect "yum -y install kernel-devel"
  238. _error_detect "yum -y install qrencode"
  239. _error_detect "yum -y install bc"
  240. _error_detect "yum -y install gcc"
  241. _error_detect "yum -y install make"
  242. _error_detect "yum -y install libmnl-devel"
  243. ;;
  244. *)
  245. ;; # do nothing
  246. esac
  247. _get_latest_ver
  248. wireguard_name="WireGuard-${wireguard_ver}"
  249. wireguard_url="https://github.com/WireGuard/WireGuard/archive/${wireguard_ver}.tar.gz"
  250. _error_detect "wget --no-check-certificate -qO ${wireguard_name}.tar.gz ${wireguard_url}"
  251. _error_detect "tar zxf ${wireguard_name}.tar.gz"
  252. _error_detect "cd ${wireguard_name}/src"
  253. _error_detect "make tools"
  254. _error_detect "make module"
  255. _error_detect "make install"
  256. _error_detect "cd ${cur_dir} && rm -fr ${wireguard_name}.tar.gz ${wireguard_name}"
  257. if ! _is_installed; then
  258. _error "Failed to install wireguard, the kernel is most likely not configured correctly"
  259. fi
  260. }
  261. # Uninstall WireGuard
  262. uninstall_wg() {
  263. if ! _is_installed; then
  264. _error "WireGuard is not installed"
  265. fi
  266. _info "Uninstall WireGuard start"
  267. # stop wireguard at first
  268. _error_detect "systemctl stop wg-quick@${SERVER_WG_NIC}"
  269. _error_detect "systemctl disable wg-quick@${SERVER_WG_NIC}"
  270. # if wireguard has been installed from repository
  271. if _exists "yum" && _exists "rpm"; then
  272. if rpm -qa | grep -q wireguard; then
  273. _error_detect "yum -y remove wireguard-dkms wireguard-tools"
  274. fi
  275. elif _exists "apt" && _exists "apt-get"; then
  276. if apt list --installed | grep -q wireguard; then
  277. _error_detect "apt-get -y remove wireguard"
  278. fi
  279. fi
  280. # if wireguard has been installed from source
  281. if _is_installed; then
  282. _error_detect "rm -f /usr/bin/wg"
  283. _error_detect "rm -f /usr/bin/wg-quick"
  284. _error_detect "rm -f /usr/share/man/man8/wg.8"
  285. _error_detect "rm -f /usr/share/man/man8/wg-quick.8"
  286. _exists "modprobe" && _error_detect "modprobe -r wireguard"
  287. fi
  288. [ -d "/etc/wireguard" ] && _error_detect "rm -fr /etc/wireguard"
  289. _info "Uninstall WireGuard completed"
  290. }
  291. # Create server interface
  292. create_server_if() {
  293. SERVER_PRIVATE_KEY="$(wg genkey)"
  294. SERVER_PUBLIC_KEY="$(echo ${SERVER_PRIVATE_KEY} | wg pubkey)"
  295. CLIENT_PRIVATE_KEY="$(wg genkey)"
  296. CLIENT_PUBLIC_KEY="$(echo ${CLIENT_PRIVATE_KEY} | wg pubkey)"
  297. CLIENT_PRE_SHARED_KEY="$( wg genpsk )"
  298. _info "Create server interface: /etc/wireguard/${SERVER_WG_NIC}.conf"
  299. [ ! -d "/etc/wireguard" ] && mkdir -p "/etc/wireguard"
  300. if [ -n "${SERVER_PUB_IPV6}" ]; then
  301. cat > /etc/wireguard/${SERVER_WG_NIC}.conf <<EOF
  302. [Interface]
  303. Address = ${SERVER_WG_IPV4}/24,${SERVER_WG_IPV6}/64
  304. ListenPort = ${SERVER_WG_PORT}
  305. PrivateKey = ${SERVER_PRIVATE_KEY}
  306. [Peer]
  307. PublicKey = ${CLIENT_PUBLIC_KEY}
  308. AllowedIPs = ${CLIENT_WG_IPV4}/32,${CLIENT_WG_IPV6}/128
  309. PresharedKey = ${CLIENT_PRE_SHARED_KEY}
  310. EOF
  311. else
  312. cat > /etc/wireguard/${SERVER_WG_NIC}.conf <<EOF
  313. [Interface]
  314. Address = ${SERVER_WG_IPV4}/24
  315. ListenPort = ${SERVER_WG_PORT}
  316. PrivateKey = ${SERVER_PRIVATE_KEY}
  317. [Peer]
  318. PublicKey = ${CLIENT_PUBLIC_KEY}
  319. AllowedIPs = ${CLIENT_WG_IPV4}/32
  320. PresharedKey = ${CLIENT_PRE_SHARED_KEY}
  321. EOF
  322. fi
  323. chmod 600 /etc/wireguard/${SERVER_WG_NIC}.conf
  324. }
  325. # Create client interface
  326. create_client_if() {
  327. _info "Create client interface: /etc/wireguard/${SERVER_WG_NIC}_client"
  328. if [ -n "${SERVER_PUB_IPV6}" ]; then
  329. cat > /etc/wireguard/${SERVER_WG_NIC}_client <<EOF
  330. [Interface]
  331. Address = ${CLIENT_WG_IPV4}/24,${CLIENT_WG_IPV6}/64
  332. PrivateKey = ${CLIENT_PRIVATE_KEY}
  333. DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2}
  334. [Peer]
  335. PublicKey = ${SERVER_PUBLIC_KEY}
  336. Endpoint = ${SERVER_PUB_IPV4}:${SERVER_WG_PORT}
  337. AllowedIPs = 0.0.0.0/0,::/0
  338. PresharedKey = ${CLIENT_PRE_SHARED_KEY}
  339. EOF
  340. else
  341. cat > /etc/wireguard/${SERVER_WG_NIC}_client <<EOF
  342. [Interface]
  343. Address = ${CLIENT_WG_IPV4}/24
  344. PrivateKey = ${CLIENT_PRIVATE_KEY}
  345. DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2}
  346. [Peer]
  347. PublicKey = ${SERVER_PUBLIC_KEY}
  348. Endpoint = ${SERVER_PUB_IPV4}:${SERVER_WG_PORT}
  349. AllowedIPs = 0.0.0.0/0
  350. PresharedKey = ${CLIENT_PRE_SHARED_KEY}
  351. EOF
  352. fi
  353. chmod 600 /etc/wireguard/${SERVER_WG_NIC}_client
  354. }
  355. # Generate a QR Code picture with default client interface
  356. generate_qr() {
  357. _info "Generate a QR Code picture with client interface"
  358. _error_detect "qrencode -s8 -o /etc/wireguard/${SERVER_WG_NIC}_client.png < /etc/wireguard/${SERVER_WG_NIC}_client"
  359. }
  360. # Enable IP forwarding
  361. enable_ip_forward() {
  362. _info "Enable IP forward"
  363. sed -i '/net.ipv4.ip_forward/d' /etc/sysctl.conf
  364. [ -n "${SERVER_PUB_IPV6}" ] && sed -i '/net.ipv6.conf.all.forwarding/d' /etc/sysctl.conf
  365. echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
  366. [ -n "${SERVER_PUB_IPV6}" ] && echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf
  367. sysctl -p >/dev/null 2>&1
  368. }
  369. # Set firewall rules
  370. set_firewall() {
  371. _info "Setting firewall rules"
  372. if _exists "firewall-cmd"; then
  373. if [ "$(firewall-cmd --state | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g")" = "running" ]; then
  374. default_zone="$(firewall-cmd --get-default-zone)"
  375. if [ "$(firewall-cmd --zone=${default_zone} --query-masquerade)" = "no" ]; then
  376. _error_detect "firewall-cmd --permanent --zone=${default_zone} --add-masquerade"
  377. fi
  378. if ! firewall-cmd --list-ports | grep -qw "${SERVER_WG_PORT}/udp"; then
  379. _error_detect "firewall-cmd --permanent --zone=${default_zone} --add-port=${SERVER_WG_PORT}/udp"
  380. fi
  381. _error_detect "firewall-cmd --reload"
  382. else
  383. _warn "Firewalld looks like not running, please start it and manually set"
  384. fi
  385. else
  386. if _exists "iptables"; then
  387. iptables -A INPUT -p udp --dport ${SERVER_WG_PORT} -j ACCEPT
  388. iptables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT
  389. iptables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE
  390. iptables-save > /etc/iptables.rules
  391. if [ -d "/etc/network/if-up.d" ]; then
  392. cat > /etc/network/if-up.d/iptables <<EOF
  393. #!/bin/sh
  394. /sbin/iptables-restore < /etc/iptables.rules
  395. EOF
  396. chmod +x /etc/network/if-up.d/iptables
  397. fi
  398. fi
  399. if _exists "ip6tables"; then
  400. ip6tables -A INPUT -p udp --dport ${SERVER_WG_PORT} -j ACCEPT
  401. ip6tables -A FORWARD -i ${SERVER_WG_NIC} -j ACCEPT
  402. ip6tables -t nat -A POSTROUTING -o ${SERVER_PUB_NIC} -j MASQUERADE
  403. ip6tables-save > /etc/ip6tables.rules
  404. if [ -d "/etc/network/if-up.d" ]; then
  405. cat > /etc/network/if-up.d/ip6tables <<EOF
  406. #!/bin/sh
  407. /sbin/ip6tables-restore < /etc/ip6tables.rules
  408. EOF
  409. chmod +x /etc/network/if-up.d/ip6tables
  410. fi
  411. fi
  412. fi
  413. }
  414. # WireGuard installation completed
  415. install_completed() {
  416. _info "Starting WireGuard via wg-quick for ${SERVER_WG_NIC}"
  417. _error_detect "systemctl daemon-reload"
  418. _error_detect "systemctl start wg-quick@${SERVER_WG_NIC}"
  419. _error_detect "systemctl enable wg-quick@${SERVER_WG_NIC}"
  420. _info "WireGuard VPN Server installation completed"
  421. _info "WireGuard VPN default client file is below:"
  422. _info "$(_green "/etc/wireguard/${SERVER_WG_NIC}_client")"
  423. _info "WireGuard VPN default client QR Code is below:"
  424. _info "$(_green "/etc/wireguard/${SERVER_WG_NIC}_client.png")"
  425. _info "Download and scan this QR Code with your phone, enjoy it"
  426. }
  427. add_client() {
  428. if ! _is_installed; then
  429. _red "WireGuard was not installed, please install it and try again\n" && exit 1
  430. fi
  431. default_server_if="/etc/wireguard/${SERVER_WG_NIC}.conf"
  432. default_client_if="/etc/wireguard/${SERVER_WG_NIC}_client"
  433. [ ! -s "${default_server_if}" ] && echo "The default server interface ($(_red ${default_server_if})) does not exists" && exit 1
  434. [ ! -s "${default_client_if}" ] && echo "The default client interface ($(_red ${default_client_if})) does not exists" && exit 1
  435. while true
  436. do
  437. read -p "Please enter a client name (for example: wg1):" client
  438. if [ -z "${client}" ]; then
  439. _red "Client name can not be empty\n"
  440. else
  441. new_client_if="/etc/wireguard/${client}_client"
  442. if [ "${client}" = "${SERVER_WG_NIC}" ]; then
  443. echo "The default client ($(_yellow ${client})) already exists. Please re-enter it"
  444. elif [ -s "${new_client_if}" ]; then
  445. echo "The client ($(_yellow ${client})) already exists. Please re-enter it"
  446. else
  447. break
  448. fi
  449. fi
  450. done
  451. # Get information from default interface file
  452. client_files=($(find /etc/wireguard -name "*_client" | sort))
  453. client_ipv4=()
  454. client_ipv6=()
  455. for ((i=0; i<${#client_files[@]}; i++)); do
  456. tmp_ipv4="$(grep -w "Address" ${client_files[$i]} | awk '{print $3}' | cut -d\/ -f1 )"
  457. tmp_ipv6="$(grep -w "Address" ${client_files[$i]} | awk '{print $3}' | awk -F, '{print $2}' | cut -d\/ -f1 )"
  458. client_ipv4=(${client_ipv4[@]} ${tmp_ipv4})
  459. client_ipv6=(${client_ipv6[@]} ${tmp_ipv6})
  460. done
  461. # Sort array
  462. client_ipv4_sorted=($(printf '%s\n' "${client_ipv4[@]}" | sort))
  463. index=$(expr ${#client_ipv4[@]} - 1)
  464. last_ip=$(echo ${client_ipv4_sorted[$index]} | cut -d. -f4)
  465. issue_ip_last=$(expr ${last_ip} + 1)
  466. [ ${issue_ip_last} -gt 254 ] && _red "Too many client, IP addresses might not be enough\n" && exit 1
  467. ipv4_comm=$(echo ${client_ipv4[$index]} | cut -d. -f1-3)
  468. ipv6_comm=$(echo ${client_ipv6[$index]} | awk -F: '{print $1":"$2":"$3":"$4}')
  469. CLIENT_PRIVATE_KEY="$(wg genkey)"
  470. CLIENT_PUBLIC_KEY="$(echo ${CLIENT_PRIVATE_KEY} | wg pubkey)"
  471. SERVER_PUBLIC_KEY="$(grep -w "PublicKey" ${default_client_if} | awk '{print $3}')"
  472. CLIENT_ENDPOINT="$(grep -w "Endpoint" ${default_client_if} | awk '{print $3}')"
  473. CLIENT_PRE_SHARED_KEY="$(grep -w "PresharedKey" ${default_client_if} | awk '{print $3}')"
  474. CLIENT_WG_IPV4="${ipv4_comm}.${issue_ip_last}"
  475. CLIENT_WG_IPV6="${ipv6_comm}:${issue_ip_last}"
  476. # Create a new client interface
  477. if [ -n "${SERVER_PUB_IPV6}" ]; then
  478. cat > ${new_client_if} <<EOF
  479. [Interface]
  480. Address = ${CLIENT_WG_IPV4}/24,${CLIENT_WG_IPV6}/64
  481. PrivateKey = ${CLIENT_PRIVATE_KEY}
  482. DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2}
  483. [Peer]
  484. PublicKey = ${SERVER_PUBLIC_KEY}
  485. Endpoint = ${CLIENT_ENDPOINT}
  486. AllowedIPs = 0.0.0.0/0,::/0
  487. PresharedKey = ${CLIENT_PRE_SHARED_KEY}
  488. EOF
  489. # Add a new client to default server interface
  490. cat >> ${default_server_if} <<EOF
  491. [Peer]
  492. PublicKey = ${CLIENT_PUBLIC_KEY}
  493. AllowedIPs = ${CLIENT_WG_IPV4}/32,${CLIENT_WG_IPV6}/128
  494. PresharedKey = ${CLIENT_PRE_SHARED_KEY}
  495. EOF
  496. else
  497. cat > ${new_client_if} <<EOF
  498. [Interface]
  499. Address = ${CLIENT_WG_IPV4}/24
  500. PrivateKey = ${CLIENT_PRIVATE_KEY}
  501. DNS = ${CLIENT_DNS_1},${CLIENT_DNS_2}
  502. [Peer]
  503. PublicKey = ${SERVER_PUBLIC_KEY}
  504. Endpoint = ${CLIENT_ENDPOINT}
  505. AllowedIPs = 0.0.0.0/0
  506. PresharedKey = ${CLIENT_PRE_SHARED_KEY}
  507. EOF
  508. cat >> ${default_server_if} <<EOF
  509. [Peer]
  510. PublicKey = ${CLIENT_PUBLIC_KEY}
  511. AllowedIPs = ${CLIENT_WG_IPV4}/32
  512. PresharedKey = ${CLIENT_PRE_SHARED_KEY}
  513. EOF
  514. fi
  515. chmod 600 ${new_client_if}
  516. echo "Add a WireGuard client ($(_green ${client})) completed"
  517. systemctl restart wg-quick@${SERVER_WG_NIC}
  518. # Generate a new QR Code picture
  519. qrencode -s8 -o ${new_client_if}.png < ${new_client_if}
  520. echo "Generate a QR Code picture with new client ($(_green ${client})) completed"
  521. echo
  522. echo "WireGuard VPN new client ($(_green ${client})) file is below:"
  523. _green "/etc/wireguard/${client}_client\n"
  524. echo
  525. echo "WireGuard VPN new client ($(_green ${client})) QR Code is below:"
  526. _green "/etc/wireguard/${client}_client.png\n"
  527. echo "Download and scan this QR Code with your phone, enjoy it"
  528. }
  529. remove_client() {
  530. if ! _is_installed; then
  531. _red "WireGuard was not installed, please install it and try again\n" && exit 1
  532. fi
  533. default_server_if="/etc/wireguard/${SERVER_WG_NIC}.conf"
  534. [ ! -s "${default_server_if}" ] && echo "The default server interface ($(_red ${default_server_if})) does not exists" && exit 1
  535. while true
  536. do
  537. read -p "Please enter a client name you want to delete it (for example: wg1):" client
  538. if [ -z "${client}" ]; then
  539. _red "Client name can not be empty\n"
  540. else
  541. if [ "${client}" = "${SERVER_WG_NIC}" ]; then
  542. echo "The default client ($(_yellow ${client})) can not be delete"
  543. else
  544. break
  545. fi
  546. fi
  547. done
  548. client_if="/etc/wireguard/${client}_client"
  549. [ ! -s "${client_if}" ] && echo "The client file ($(_red ${client_if})) does not exists" && exit 1
  550. tmp_tag="$(grep -w "Address" ${client_if} | awk '{print $3}' | cut -d\/ -f1 )"
  551. [ -n "${tmp_tag}" ] && sed -i '/'"$tmp_tag"'/,+1d;:a;1,3!{P;$!N;D};N;ba' ${default_server_if}
  552. # Delete client interface file
  553. rm -f ${client_if}
  554. [ -s "/etc/wireguard/${client}_client.png" ] && rm -f /etc/wireguard/${client}_client.png
  555. systemctl restart wg-quick@${SERVER_WG_NIC}
  556. echo "The client name ($(_green ${client})) has been deleted"
  557. }
  558. list_clients() {
  559. if ! _is_installed; then
  560. _red "WireGuard was not installed, please install it and try again\n" && exit 1
  561. fi
  562. default_server_if="/etc/wireguard/${SERVER_WG_NIC}.conf"
  563. [ ! -s "${default_server_if}" ] && echo "The default server interface ($(_red ${default_server_if})) does not exists" && exit 1
  564. local line="+-------------------------------------------------------------------------+\n"
  565. local string=%-35s
  566. printf "${line}|${string} |${string} |\n${line}" " Client Interface" " Client's IP"
  567. client_files=($(find /etc/wireguard -name "*_client" | sort))
  568. ips=($(grep -w "AllowedIPs" ${default_server_if} | awk '{print $3}'))
  569. [ ${#client_files[@]} -ne ${#ips[@]} ] && echo "One or more client interface file is missing in /etc/wireguard" && exit 1
  570. for ((i=0; i<${#ips[@]}; i++)); do
  571. tmp_ipv4="$(echo ${ips[$i]} | cut -d\/ -f1)"
  572. for ((j=0; j<${#client_files[@]}; j++)); do
  573. if grep -qw "${tmp_ipv4}" "${client_files[$j]}"; then
  574. printf "|${string} |${string} |\n" " ${client_files[$j]}" " ${ips[$i]}"
  575. break
  576. fi
  577. done
  578. done
  579. printf ${line}
  580. }
  581. check_version() {
  582. _is_installed
  583. rt=$?
  584. if [ ${rt} -eq 0 ]; then
  585. _exists "modinfo" && installed_wg_ver="$(modinfo -F version wireguard)"
  586. [ -n "${installed_wg_ver}" ] && echo "WireGuard version: $(_green ${installed_wg_ver})" && return 0
  587. elif [ ${rt} -eq 1 ]; then
  588. _red "WireGuard kernel module does not exists\n" && return 1
  589. elif [ ${rt} -eq 2 ]; then
  590. _red "WireGuard was not installed\n" && return 2
  591. fi
  592. }
  593. show_help() {
  594. printf "
  595. Usage : $0 [Options]
  596. Options:
  597. -h, --help Print this help text and exit
  598. -r, --repo Install WireGuard from repository
  599. -s, --source Install WireGuard from source
  600. -u, --update Upgrade WireGuard from source
  601. -v, --version Print WireGuard version if installed
  602. -a, --add Add a WireGuard client
  603. -d, --del Delete a WireGuard client
  604. -l, --list List all WireGuard client's IP
  605. -n, --uninstall Uninstall WireGuard
  606. "
  607. }
  608. install_from_repo() {
  609. _is_installed && check_version && _red "WireGuard was already installed\n" && exit 0
  610. check_os
  611. install_wg_1
  612. create_server_if
  613. create_client_if
  614. generate_qr
  615. enable_ip_forward
  616. set_firewall
  617. install_completed
  618. }
  619. install_from_source() {
  620. _is_installed && check_version && _red "WireGuard was already installed\n" && exit 0
  621. check_os
  622. install_wg_2
  623. create_server_if
  624. create_client_if
  625. generate_qr
  626. enable_ip_forward
  627. set_firewall
  628. install_completed
  629. }
  630. update_from_source() {
  631. if check_version > /dev/null 2>&1; then
  632. _get_latest_ver
  633. _info "WireGuard version: $(_green ${installed_wg_ver})"
  634. _info "WireGuard latest version: $(_green ${wireguard_ver})"
  635. if _version_gt "${wireguard_ver}" "${installed_wg_ver}"; then
  636. _info "Starting upgrade WireGuard"
  637. install_wg_2
  638. _error_detect "systemctl daemon-reload"
  639. _error_detect "systemctl restart wg-quick@${SERVER_WG_NIC}"
  640. _info "Update WireGuard completed"
  641. else
  642. _info "There is no update available for WireGuard"
  643. fi
  644. else
  645. _red "WireGuard was not installed, maybe you need to install it at first\n"
  646. fi
  647. }
  648. cur_dir="$(pwd)"
  649. [ ${EUID} -ne 0 ] && _red "This script must be run as root\n" && exit 1
  650. SERVER_PUB_IPV4="${VPN_SERVER_PUB_IPV4:-$(_ipv4)}"
  651. SERVER_PUB_IPV6="${VPN_SERVER_PUB_IPV6:-$(_ipv6)}"
  652. SERVER_PUB_NIC="${VPN_SERVER_PUB_NIC:-$(_nic)}"
  653. SERVER_WG_NIC="${VPN_SERVER_WG_NIC:-wg0}"
  654. SERVER_WG_IPV4="${VPN_SERVER_WG_IPV4:-10.88.88.1}"
  655. SERVER_WG_IPV6="${VPN_SERVER_WG_IPV6:-fd88:88:88::1}"
  656. SERVER_WG_PORT="${VPN_SERVER_WG_PORT:-$(_port)}"
  657. CLIENT_WG_IPV4="${VPN_CLIENT_WG_IPV4:-10.88.88.2}"
  658. CLIENT_WG_IPV6="${VPN_CLIENT_WG_IPV6:-fd88:88:88::2}"
  659. CLIENT_DNS_1="${VPN_CLIENT_DNS_1:-1.1.1.1}"
  660. CLIENT_DNS_2="${VPN_CLIENT_DNS_2:-8.8.8.8}"
  661. main() {
  662. action="$1"
  663. [ -z "${action}" ] && show_help && exit 0
  664. case "${action}" in
  665. -h|--help)
  666. show_help
  667. ;;
  668. -r|--repo)
  669. install_from_repo
  670. ;;
  671. -s|--source)
  672. install_from_source
  673. ;;
  674. -u|--update)
  675. update_from_source
  676. ;;
  677. -v|--version)
  678. check_version
  679. ;;
  680. -a|--add)
  681. add_client
  682. ;;
  683. -d|--del)
  684. remove_client
  685. ;;
  686. -l|--list)
  687. list_clients
  688. ;;
  689. -n|--uninstall)
  690. uninstall_wg
  691. ;;
  692. *)
  693. show_help
  694. ;;
  695. esac
  696. }
  697. main "$@"