forked from wiorca/docker-pia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinstall.sh
executable file
·498 lines (431 loc) · 17.7 KB
/
install.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
#!/bin/bash
set -e
# Overwrite PATH with known safe defaults
PATH="/usr/bin:/usr/sbin:/bin:/sbin"
root=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
logFile="/dev/null"
readonly appName="Private Internet Access"
readonly brandCode="pia"
readonly installDir="/opt/${brandCode}vpn"
readonly daemonSettingsPath="$installDir/etc"
readonly daemonDataPath="$installDir/var"
readonly oldSettingsPath="/$HOME/.pia_manager/data"
readonly systemdServiceLocation="/etc/systemd/system/${brandCode}vpn.service"
readonly sysvinitServiceLocation="/etc/init.d/${brandCode}vpn"
readonly openrcServiceLocation="/etc/init.d/${brandCode}vpn"
readonly serviceName="${brandCode}vpn"
readonly groupName="${brandCode}vpn"
readonly hnsdGroupName="${brandCode}hnsd" # The group used by the Handshake DNS service
readonly routingTableName="${serviceName}rt" # for split tunnel
readonly vpnOnlyroutingTableName="${serviceName}Onlyrt" # for inverse split tunnel
readonly wireguardRoutingTableName="${serviceName}Wgrt"
readonly forwardedRoutingTableName="${serviceName}Fwdrt" # For forwarded packets
readonly ctlExecutableName="piactl"
readonly ctlExecutablePath="${installDir}/bin/${ctlExecutableName}"
readonly ctlSymlinkPath="/usr/local/bin/${ctlExecutableName}"
readonly wgIfPrefix="wg${brandCode}" # WireGuard interface prefix, e.g wgpia
readonly nmConfigDir="/etc/NetworkManager/conf.d"
readonly nmConfigPath="${nmConfigDir}/${wgIfPrefix}.conf" # Our custom NetworkManager config
echo ""
echo "================================="
echo "$appName Installer"
echo "================================="
echo ""
function enableLogging() {
logFile="/tmp/pia_install.log"
}
function echoPass() {
printf '\e[92m\xE2\x9C\x94\e[0m %s\n' "$@"
echo "$(date +"[%Y-%m-%d %H:%M:%S]") [ OK ]" "$@" >> "$logFile" || true
}
function echoFail() {
printf '\e[91m\xE2\x9C\x98\e[0m %s\n' "$@"
echo "$(date +"[%Y-%m-%d %H:%M:%S]") [FAIL]" "$@" >> "$logFile" || true
}
function fail() {
echoFail "$@"
exit 1
}
# This ensures that NetworkManager does not remove DNS settings from the wireguard interface when
# the user changes network.
function wireguardUnmanaged() {
if [ -d "$nmConfigDir" ] && [ ! -f "$nmConfigPath" ]; then
echo -e "[keyfile]\nunmanaged-devices=interface-name:${wgIfPrefix}*" | tee "$nmConfigPath" > /dev/null
echoPass "Set $wgIfPrefix interface to be unmanaged"
fi
}
function startClient() {
# Change directory before starting the client; don't start it from a
# directory that's about to be deleted.
# The PIA client doesn't really care, but some of the programs it starts
# might (in particular, Terminator does, and it might be the user's
# preferred terminal emulator for updates / installation)
pushd "$installDir/bin/" > /dev/null 2>&1
"$installDir/bin/${brandCode}-client" > /dev/null 2>&1 & disown
popd > /dev/null 2>&1
true
}
function configureSystemd() {
# install the service
cp "$root/installfiles/piavpn.service" "$systemdServiceLocation"
echoPass "Created $serviceName service"
systemctl daemon-reload
systemctl enable "$serviceName"
systemctl restart "$serviceName"
echoPass "Started $serviceName service"
startClient
}
function configureSysvinit() {
cp "$root/installfiles/piavpn.sysvinit.service" "$sysvinitServiceLocation"
chmod 755 "$sysvinitServiceLocation"
update-rc.d "$serviceName" defaults
service "$serviceName" start
echoPass "Created $serviceName sysvinit service"
startClient
}
function configureOpenrc() {
cp "$root/installfiles/piavpn.openrc.service" "$openrcServiceLocation"
chmod 755 "$openrcServiceLocation"
rc-update add $serviceName default
rc-service $serviceName start
echoPass "Created $serviceName openrc service"
startClient
}
function exemptFromApport() {
# exempt piavpn from apport blacklist
if [ -d /etc/apport/blacklist.d ]; then
tee "/etc/apport/blacklist.d/${brandCode}vpn" > /dev/null << EOF
$installDir/bin/${brandCode}-client
$installDir/bin/${brandCode}-daemon
EOF
systemctl is-active --quiet apport && service apport restart
fi
true
}
function removeLegacyPia() {
if [[ -d "/opt/pia/" ]]; then
# Show a disclaimer about replacing older version of PIA
echo "This will replace your existing installation of $appName."
requestConfirmation "Downgrading afterwards will require a clean reinstall. Do you wish to continue?"
while pgrep -f "/opt/pia/" > /dev/null; do
read -rsn1 -p"Please exit Private Internet Access and press any key to continue."
echo ""
done
rm -rf /opt/pia
[ -f "$HOME/pia.sh" ] && rm "$HOME/pia.sh"
[ -f "$HOME/.local/share/applications/pia_manager.desktop" ] && rm "$HOME/.local/share/applications/pia_manager.desktop"
echoPass "Uninstalled $appName"
fi
true
}
# Test whether dependencies are present. Returns nonzero if any dependency is
# missing.
function hasDependencies() {
# Check for ifconfig, libxkbcommon-x11, libxkbcommon, and libxcb-xkb
# Note that ifconfig must be at /sbin/ifconfig since OpenVPN finds the
# absolute path to ifconfig at build time.
# Wrap each test in `if ...; then return 1; fi` to play nicely with set -e
if ! [ -x /sbin/ifconfig ]; then return 1; fi
if ! ldconfig -p | grep -q libxkbcommon.so.0; then return 1; fi
if ! ldconfig -p | grep -q libxkbcommon-x11.so.0; then return 1; fi
if ! ldconfig -p | grep -q libxcb-xkb.so.1; then return 1; fi
if ! ldconfig -p | grep -q libxcb-xinerama.so.0; then return 1; fi
if ! ldconfig -p | grep -q libxcb-icccm.so.4; then return 1; fi
if ! ldconfig -p | grep -q libxcb-image.so.0; then return 1; fi
if ! ldconfig -p | grep -q libxcb-keysyms.so.1; then return 1; fi
if ! ldconfig -p | grep -q libxcb-randr.so.0; then return 1; fi
if ! ldconfig -p | grep -q libxcb-render-util.so.0; then return 1; fi
if ! ldconfig -p | grep -q libnl-3.so.200; then return 1; fi
if ! ldconfig -p | grep -q libnl-route-3.so.200; then return 1; fi
if ! ldconfig -p | grep -q libnl-genl-3.so.200; then return 1; fi
return 0
}
function promptNetTools() {
echo "Could not install package 'net-tools'."
echo "Please install the package manually and ensure 'ifconfig' command exists."
}
function promptManualDependencies() {
echo "Could not install dependencies. Please install these packages:"
echo " - net-tools (ifconfig)"
echo " - libxkbcommon-x11 (libxkbcommon-x11.so.0, libxkbcommon.so.0)"
echo " - libxcb (libxcb.so.1)"
echo " - libxcb-xkb (libxcb-xkb.so.1, may be included in libxcb)"
echo " - libxcb-xinerama (libxcb-xinerama.so.0, may be included in libxcb)"
echo " - libxcb-icccm (libxcb-icccm.so.4, may be included in libxcb)"
echo " - libxcb-image (libxcb-image.so.0, may be included in libxcb)"
echo " - libxcb-keysyms (libxcb-keysyms.so.1, may be included in libxcb)"
echo " - libxcb-randr (libxcb-randr.so.0, may be included in libxcb)"
echo " - libxcb-render-util (libxcb-render-util.so.0, may be included in libxcb)"
echo " - libnl-3-200"
echo " - libnl-route-3-200, libnl-genl-3-200 (may be included in libnl-3-200)"
requestConfirmation "Continue with installation?"
}
function installDependencies() {
# If all dependencies are present, don't do anything, don't try to detect
# package manager, etc.
if hasDependencies; then return 0; fi
if hash yum 2>/dev/null; then
# Fedora and relatives put all xcb libs in libxcb
yum -y install net-tools libxkbcommon-x11 libxcb libnl3 xcb-util-wm xcb-util-image xcb-util-keysyms xcb-util-renderutil
elif hash pacman 2>/dev/null; then
# Arch puts all xcb libs in the libxcb package.
pacman -S --noconfirm net-tools libxkbcommon-x11 libxcb libnl xcb-util-wm xcb-util-image xcb-util-keysyms xcb-util-renderutil
elif hash zypper 2>/dev/null; then
# openSUSE splits up xcb
zypper install libxkbcommon-x11-0 libxcb1 libxcb-xkb1 libxcb-xinerama0 libnl3-200 \
libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0
# We can't set up ifconfig on openSUSE; our OpenVPN build has a
# hard-coded path to /sbin/ifconfig, but openSUSE installs it to
# /usr/bin/ifconfig. We don't want to mess with the user's sbin
# directory, the user will have to make the symlink themselves.
echoFail "ifconfig not installed - please ensure net-tools-deprecated is installed and symlink ifconfig to /sbin/ifconfig"
# Check for apt-get last. Apparently some RPM-based distributions (such as
# openSUSE) have an RPM port of apt in addition to their preferred package
# manager. This check uses Debian package names though that aren't
# necessarily the same on other distributions.
elif hash apt-get 2>/dev/null; then
# Debian splits up the xcb libs
APT_PKGS="libxkbcommon-x11-0 libxcb1 libxcb-xkb1 libxcb-xinerama0 \
libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \
libnl-3-200 libnl-route-3-200"
# A few releases do not have the net-tools package at all, still try to
# install other dependencies
if [[ $(apt-cache search --names-only net-tools) ]]; then
echo "Skipped"
# apt-get install --yes net-tools $APT_PKGS
else
# apt-get install --yes $APT_PKGS
promptNetTools
fi
else
promptManualDependencies
return 0 # Skip "installed packages" output
fi
echoPass "Installed packages"
}
function addGroups() {
for group in "$@"; do
if ! grep -q $group /etc/group; then
groupadd $group || true
echoPass "Added group $group"
fi
done
true
}
function addRoutingTable() {
local highestIndex=$(awk '/^[0-9]/{print $1}' /etc/iproute2/rt_tables | sort -n | tail -1)
local newIndex=$(($highestIndex + 1))
local routingTable="$1"
local routesLocation=/etc/iproute2/rt_tables
if [[ -f $routesLocation ]] && ! grep -q "$routingTable" $routesLocation; then
echo -e "$newIndex\t$routingTable" | tee -a $routesLocation > /dev/null
echoPass "Added $routingTable routing table"
fi
true
}
function installPia() {
addGroups $groupName $hnsdGroupName
mkdir -p $installDir
if [[ $(pgrep "${brandCode}-client") ]]; then
killall "${brandCode}-client"
sleep 2
echoPass "Closed running $appName client"
fi
# Clear old PIA files if existing
# We are deleting specific folders rather than the alternative (remove all but exclude data dir)
rm -rf "$installDir/bin"
rm -rf "$installDir/lib"
rm -rf "$installDir/plugins"
rm -rf "$installDir/qml"
# Use /bin/cp and not 'cp' since 'cp' might be aliased
/bin/cp -rf "$root/piafiles/"* $installDir/
/bin/cp "$root/installfiles/"*.sh "$installDir/bin/"
chmod +x "$installDir/bin/"*.sh
echoPass "Copied $appName files"
# Allow us to run unbound without root
if setcap 'cap_net_bind_service=+ep' "$installDir/bin/pia-unbound" 2>/dev/null; then
echoPass "Allow non-root $installDir/bin/pia-unbound to bind to privileged ports"
fi
mkdir -p "$daemonDataPath"
echoPass "Created var folder"
# Ideally we don't want to put them in pixmaps but this seems to be the
# best place for cross platform usage, and is part of the XDG spec
# Some platforms like Arch do't have this path
#if [ ! -d "/usr/share/pixmaps" ]; then
# mkdir -p /usr/share/pixmaps/
#fi
#cp "$root/installfiles/app.png" "/usr/share/pixmaps/${brandCode}.png"
#echoPass "Installed icon"
#if [ ! -d "/usr/share/applications" ]; then
# mkdir -p /usr/share/applications/
#fi
#cp "$root/installfiles/piavpn.desktop" "/usr/share/applications/${brandCode}vpn.desktop"
#if hash update-desktop-database 2>/dev/null; then
# update-desktop-database
#fi
#echoPass "Created desktop entry"
# Create routing tables for split-tunneling
addRoutingTable $routingTableName
addRoutingTable $vpnOnlyroutingTableName
addRoutingTable $wireguardRoutingTableName
addRoutingTable $forwardedRoutingTableName
# Instruct NetworkManager not to interfere with DNS on the wireguard interface
wireguardUnmanaged
# Link piactl into /usr/local/bin if it's not already there. If it's there,
# either it's ours and doesn't need to be updated, or it's something else
# and we shouldn't touch it.?
if [ ! -L "${ctlSymlinkPath}" ] && [ ! -e "${ctlSymlinkPath}" ]; then
# This is allowed to fail if /usr/bin doesn't exist for some reason,
# etc. - just ignore it
ln -s "${ctlExecutablePath}" "${ctlSymlinkPath}" || true
fi
# Link piactl into /usr/local/bin if it's not already there. If it's there,
# either it's ours and doesn't need to be updated, or it's something else
# and we shouldn't touch it.?
if [ ! -L "${ctlSymlinkPath}" ] && [ ! -e "${ctlSymlinkPath}" ]; then
# This is allowed to fail if /usr/bin doesn't exist for some reason,
# etc. - just ignore it
ln -s "${ctlExecutablePath}" "${ctlSymlinkPath}" || true
fi
true
}
function migrateLegacySettings() {
if [ -f "$oldSettingsPath/settings.json" ] && [ ! -f "$daemonSettingsPath/settings.json" ]; then
if echo "{\"legacy\":$(cat "$oldSettingsPath/settings.json")}" | tee "$daemonSettingsPath/settings.json" > /dev/null; then
echoPass "Migrated old settings"
else
echoFail "Old settings not migrated"
fi
fi
# Clean up files after legacy settings migrated
[ -e "$HOME/.pia_manager" ] && rm -rf "$HOME/.pia_manager"
[ -e "$HOME/.com.privateinternetaccess.vpn" ] && rm -rf "$HOME/.com.privateinternetaccess.vpn"
true
}
function autoDetectSystem() {
# ignore "ps | grep" warning (below in elif) pgrep cannot check a specific PID
# shellcheck disable=SC2009
# if prior systemd install exists, assume systemd
if [ -f "$systemdServiceLocation" ]; then
echo "Detected a previous systemd install - assuming systemd"
BOOT_MANAGER=systemd
# openrcServiceLocation is set to the same file as sysvinitServiceLocation so we need the extra rc-status check
# to distinguish it from a sysvinit system
elif rc-status > /dev/null 2>&1 && [ -f "$openrcServiceLocation" ]; then
echo "Detected a previous openrc install - assuming openrc"
BOOT_MANAGER=openrc
# if prior sysvinit install exists, assume sysvinit
elif [ -f "$sysvinitServiceLocation" ]; then
echo "Detected a previous sysvinit install - assuming sysvinit"
BOOT_MANAGER=sysvinit
# pia is installed but no service detected, assume "none"
elif [ -f "$installDir/bin/${brandCode}-daemon" ]; then
echo "Detected a previous install but no service installed - assuming no service should be configured"
BOOT_MANAGER=none
# rc-status command should only exist on openrc systems
elif rc-status > /dev/null 2>&1; then
BOOT_MANAGER=openrc
# make best guess at the system type
elif ps -p 1 | grep -q init; then
BOOT_MANAGER=sysvinit
else
# fall-back to systemd if it's not sysvinit
BOOT_MANAGER=systemd
fi
true
}
function processOpts() {
case "$1" in
--sysvinit)
BOOT_MANAGER=sysvinit
;;
--systemd)
BOOT_MANAGER=systemd
;;
--openrc)
BOOT_MANAGER=openrc
;;
--skip-service)
BOOT_MANAGER=none
;;
-h|--help)
echo "Usage: $brandCode-linux-<version>.run -- <install-options>"
echo "Install options:"
echo " --systemd to setup a systemd service on boot"
echo " --sysvinit to setup a sysvinit service on boot"
echo " --skip-service to skip setting up a service"
exit 0
;;
*)
echo "Unrecognized option: '$1'"
echo "Type: 'pia-linux-<version>.run -- -h' to see the available options."
exit 1
;;
esac
true
}
function requestConfirmation() {
read -r -p "$1 [y/N] " input
case $input in
[yY][eE][sS]|[yY])
;;
[nN][oO]|[nN])
exit 1
;;
*)
exit 1
;;
esac
}
#if [[ $EUID -eq 0 ]]; then
# echo "This script must be run as a normal user, not root."
# exit 1
#fi
# process command line options and figure out the system type (e.g systemd vs sysvinit)
if [[ $# -eq 0 ]]; then
autoDetectSystem
else
processOpts "$1"
fi
# early-exit in our default case (systemd) if systemd is not installed
if [[ $BOOT_MANAGER == systemd ]] && ! hash systemctl 2>/dev/null; then
echo "systemd installation was selected, but systemctl was not found."
echo "Use ${brandCode}-linux-<version>.run -- --help for options to select a different installation."
exit 1
fi
ORIG_UMASK=$(umask)
# Ensure that all files are world readable
umask 022
if [ $brandCode = "pia" ]; then
removeLegacyPia
fi
installDependencies
installPia
if [ $brandCode = "pia" ]; then
migrateLegacySettings
fi
# If the installing user has a .pia-early-debug file, create .pia-early-debug in
# the daemon data directory, so it will enable tracing early in startup
if [ -e "$HOME/.$brandCode-early-debug" ]; then
touch "$daemonDataPath/.$brandCode-early-debug"
fi
case "$BOOT_MANAGER" in
systemd)
exemptFromApport
configureSystemd
;;
sysvinit)
configureSysvinit
;;
openrc)
configureOpenrc
;;
none)
echoPass "Finished. You will need to manually configure ${installDir}/bin/${brandCode}-daemon to start at boot."
;;
*)
echoFail "Error: BOOT_MANAGER had unexpected value, got $BOOT_MANAGER"
;;
esac
# Restore the original umask
umask "$ORIG_UMASK"