mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-06-02 05:44:03 +02:00
Merge pull request #2399 from litinoveweedle/qbittorrent_vpn_overhaul
Qbittorrent vpn overhaul
This commit is contained in:
@@ -1,15 +1,27 @@
|
|||||||
{
|
{
|
||||||
"name": "Example devcontainer for add-on repositories",
|
"name": "Example devcontainer for add-on repositories",
|
||||||
"image": "ghcr.io/home-assistant/devcontainer:addons",
|
"image": "ghcr.io/home-assistant/devcontainer:2-addons",
|
||||||
"appPort": ["7123:8123", "7357:4357"],
|
"appPort": [
|
||||||
"postStartCommand": "sudo -E bash devcontainer_bootstrap",
|
"7123:8123",
|
||||||
"runArgs": ["-e", "GIT_EDITOR=code --wait", "--privileged"],
|
"7357:4357"
|
||||||
|
],
|
||||||
|
"postStartCommand": "bash devcontainer_bootstrap",
|
||||||
|
"runArgs": [
|
||||||
|
"-e",
|
||||||
|
"GIT_EDITOR=code --wait",
|
||||||
|
"--privileged"
|
||||||
|
],
|
||||||
|
"workspaceFolder": "/mnt/supervisor/addons/local/${localWorkspaceFolderBasename}",
|
||||||
|
"workspaceMount": "source=${localWorkspaceFolder},target=${containerWorkspaceFolder},type=bind,consistency=cached",
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
|
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
|
||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"extensions": ["timonwong.shellcheck", "esbenp.prettier-vscode"],
|
"extensions": [
|
||||||
|
"timonwong.shellcheck",
|
||||||
|
"esbenp.prettier-vscode"
|
||||||
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"terminal.integrated.profiles.linux": {
|
"terminal.integrated.profiles.linux": {
|
||||||
"zsh": {
|
"zsh": {
|
||||||
@@ -24,5 +36,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mounts": [ "type=volume,target=/var/lib/docker" ]
|
"mounts": [
|
||||||
}
|
"type=volume,target=/var/lib/docker",
|
||||||
|
"type=volume,target=/mnt/supervisor"
|
||||||
|
]
|
||||||
|
}
|
||||||
4
.vscode/tasks.json
vendored
4
.vscode/tasks.json
vendored
@@ -4,7 +4,7 @@
|
|||||||
{
|
{
|
||||||
"label": "Start Home Assistant",
|
"label": "Start Home Assistant",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "sudo chmod a+x /usr/bin/supervisor* && sudo -E supervisor_run",
|
"command": "supervisor_run",
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "test",
|
"kind": "test",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
@@ -16,4 +16,4 @@
|
|||||||
"problemMatcher": []
|
"problemMatcher": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
- Rewrite the openvpn and wireguard scripts in order to make them more robust, secure, and compatible with more suppliers @litinoveweedle
|
||||||
|
|
||||||
## 5.1.4-6 (03-02-2026)
|
## 5.1.4-6 (03-02-2026)
|
||||||
- Minor bugs fixed
|
- Minor bugs fixed
|
||||||
## 5.1.4-5 (23-01-2026)
|
## 5.1.4-5 (23-01-2026)
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ RUN \
|
|||||||
# Copy local files
|
# Copy local files
|
||||||
COPY rootfs/ /
|
COPY rootfs/ /
|
||||||
RUN find /etc -type f \( -name "*.sh" -o -name "run" -o -name "finish" \) -exec chmod +x {} +
|
RUN find /etc -type f \( -name "*.sh" -o -name "run" -o -name "finish" \) -exec chmod +x {} +
|
||||||
|
RUN chmod +x /usr/local/sbin/vpn
|
||||||
|
|
||||||
# Uses /bin for compatibility purposes
|
# Uses /bin for compatibility purposes
|
||||||
# hadolint ignore=DL4005
|
# hadolint ignore=DL4005
|
||||||
@@ -112,7 +113,7 @@ RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_auto
|
|||||||
# && chmod a+x /etc/s6-overlay/s6-rc.d/$SCRIPTSNAME/* ; done; fi
|
# && chmod a+x /etc/s6-overlay/s6-rc.d/$SCRIPTSNAME/* ; done; fi
|
||||||
|
|
||||||
# Manual apps
|
# Manual apps
|
||||||
ARG PACKAGES="wireguard-tools iptables ip6tables iptables-legacy"
|
ARG PACKAGES="ipcalc wireguard-tools"
|
||||||
|
|
||||||
# Automatic apps & bashio
|
# Automatic apps & bashio
|
||||||
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_autoapps.sh" "/ha_autoapps.sh"
|
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_autoapps.sh" "/ha_autoapps.sh"
|
||||||
@@ -126,8 +127,6 @@ RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" && rm /ha_autoapps.
|
|||||||
# 4 Entrypoint #
|
# 4 Entrypoint #
|
||||||
################
|
################
|
||||||
|
|
||||||
RUN chmod +x /usr/local/bin/* /usr/local/sbin/*
|
|
||||||
|
|
||||||
# Add entrypoint
|
# Add entrypoint
|
||||||
ENV S6_STAGE2_HOOK=/ha_entrypoint.sh
|
ENV S6_STAGE2_HOOK=/ha_entrypoint.sh
|
||||||
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_entrypoint.sh" "/ha_entrypoint.sh"
|
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_entrypoint.sh" "/ha_entrypoint.sh"
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ map:
|
|||||||
- ssl
|
- ssl
|
||||||
name: qBittorrent
|
name: qBittorrent
|
||||||
options:
|
options:
|
||||||
|
log_level: info
|
||||||
env_vars: []
|
env_vars: []
|
||||||
DNS_server: 8.8.8.8,1.1.1.1
|
DNS_server: 8.8.8.8,1.1.1.1
|
||||||
PGID: "0"
|
PGID: "0"
|
||||||
@@ -88,10 +89,7 @@ options:
|
|||||||
certfile: fullchain.pem
|
certfile: fullchain.pem
|
||||||
customUI: vuetorrent
|
customUI: vuetorrent
|
||||||
keyfile: privkey.pem
|
keyfile: privkey.pem
|
||||||
qbit_manage: false
|
|
||||||
ssl: false
|
ssl: false
|
||||||
wireguard_enabled: false
|
|
||||||
wireguard_config: ""
|
|
||||||
whitelist: localhost,127.0.0.1,172.30.0.0/16,192.168.0.0/16
|
whitelist: localhost,127.0.0.1,172.30.0.0/16,192.168.0.0/16
|
||||||
panel_admin: false
|
panel_admin: false
|
||||||
panel_icon: mdi:progress-download
|
panel_icon: mdi:progress-download
|
||||||
@@ -112,6 +110,7 @@ privileged:
|
|||||||
- DAC_READ_SEARCH
|
- DAC_READ_SEARCH
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
schema:
|
schema:
|
||||||
|
log_level: list(trace|debug|info|notice|warning|error|fatal)?
|
||||||
env_vars:
|
env_vars:
|
||||||
- name: match(^[A-Za-z0-9_]+$)
|
- name: match(^[A-Za-z0-9_]+$)
|
||||||
value: str?
|
value: str?
|
||||||
@@ -129,8 +128,7 @@ schema:
|
|||||||
keyfile: str
|
keyfile: str
|
||||||
localdisks: str?
|
localdisks: str?
|
||||||
networkdisks: str?
|
networkdisks: str?
|
||||||
openvpn_alt_mode: bool?
|
openvpn_config: match(^\w+\.(ovpn|conf)$)?
|
||||||
openvpn_config: str?
|
|
||||||
openvpn_enabled: bool?
|
openvpn_enabled: bool?
|
||||||
openvpn_password: str?
|
openvpn_password: str?
|
||||||
openvpn_username: str?
|
openvpn_username: str?
|
||||||
@@ -138,10 +136,10 @@ schema:
|
|||||||
run_duration: str?
|
run_duration: str?
|
||||||
silent: bool?
|
silent: bool?
|
||||||
ssl: bool
|
ssl: bool
|
||||||
wireguard_config: str?
|
wireguard_config: match(^\w+\.conf$)?
|
||||||
wireguard_enabled: bool?
|
wireguard_enabled: bool?
|
||||||
whitelist: str?
|
whitelist: str?
|
||||||
slug: qbittorrent
|
slug: qbittorrent
|
||||||
udev: true
|
udev: true
|
||||||
url: https://github.com/alexbelgium/hassio-addons
|
url: https://github.com/alexbelgium/hassio-addons
|
||||||
version: "5.1.4-6"
|
version: "5.1.4-7"
|
||||||
|
|||||||
@@ -2,269 +2,112 @@
|
|||||||
# shellcheck shell=bash
|
# shellcheck shell=bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
declare openvpn_config
|
OPENVPN_STATE_DIR="/var/run/openvpn"
|
||||||
|
QBT_CONFIG_FILE="/config/qBittorrent/qBittorrent.conf"
|
||||||
|
declare openvpn_config=""
|
||||||
|
declare openvpn_runtime_config=""
|
||||||
|
declare interface_name=""
|
||||||
declare openvpn_username
|
declare openvpn_username
|
||||||
declare openvpn_password
|
declare openvpn_password
|
||||||
|
|
||||||
QBT_CONFIG_FILE="/config/qBittorrent/qBittorrent.conf"
|
if bashio::fs.directory_exists "${OPENVPN_STATE_DIR}"; then
|
||||||
|
bashio::log.warning "Previous OpenVPN state directory found, cleaning up."
|
||||||
if bashio::config.true 'openvpn_enabled'; then
|
rm -Rf "${OPENVPN_STATE_DIR}"
|
||||||
|
|
||||||
bashio::log.info "----------------------------"
|
|
||||||
bashio::log.info "Openvpn enabled, configuring"
|
|
||||||
bashio::log.info "----------------------------"
|
|
||||||
|
|
||||||
# Function to check for files path
|
|
||||||
function check_path() {
|
|
||||||
|
|
||||||
# Get variable
|
|
||||||
file="$1"
|
|
||||||
|
|
||||||
# Double check exists
|
|
||||||
if [ ! -f "$file" ]; then
|
|
||||||
bashio::warning "$file not found"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check each lines
|
|
||||||
cp "$file" /tmpfile
|
|
||||||
line_number=0
|
|
||||||
while read -r line; do
|
|
||||||
# Increment the line number
|
|
||||||
((line_number = line_number + 1))
|
|
||||||
|
|
||||||
# Check if lines starting with auth-user-pass have a valid argument
|
|
||||||
###################################################################
|
|
||||||
if [[ "$line" == "auth-user-pass"* ]]; then
|
|
||||||
# Extract the second argument
|
|
||||||
file_name="$(echo "$line" | awk -F' ' '{print $2}')"
|
|
||||||
# If second argument is null or -
|
|
||||||
if [ -z "$file_name" ] || [[ "$file_name" == -* ]]; then
|
|
||||||
# Insert to explain why a comment is made
|
|
||||||
sed -i "${line_number}i # The following line is commented out as does not contain a valid argument" "$file"
|
|
||||||
# Increment as new line added
|
|
||||||
((line_number = line_number + 1))
|
|
||||||
# Comment out the line
|
|
||||||
sed -i "${line_number}s/^/# /" "$file"
|
|
||||||
# Go to next line
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if the line contains a txt file
|
|
||||||
#######################################
|
|
||||||
if [[ ! $line =~ ^"#" ]] && [[ ! $line =~ ^";" ]] && [[ ! $line =~ ^"remote" ]] && [[ "$line" == *" "*"."* ]] || [[ "$line" == "auth-user-pass"* ]]; then
|
|
||||||
# Extract the txt file name from the line
|
|
||||||
file_name="$(echo "$line" | awk -F' ' '{print $2}')"
|
|
||||||
# if contains only numbers and dots it is likely an ip, don't check it
|
|
||||||
if [[ "$file_name" =~ ^[0-9\.]+$ ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
# Check if the txt file exists
|
|
||||||
if [[ "$file_name" != *"/etc/openvpn/credentials"* ]] && [ ! -f "$file_name" ]; then
|
|
||||||
# Check if the txt file exists in the /config/openvpn/ directory
|
|
||||||
if [ -f "/config/openvpn/${file_name##*/}" ]; then
|
|
||||||
# Append /config/openvpn/ in front of the original txt file in the ovpn file
|
|
||||||
sed -i "${line_number}s|$file_name|/config/openvpn/${file_name##*/}|" "$file"
|
|
||||||
# Print a success message
|
|
||||||
bashio::log.warning "Appended /config/openvpn/ to ${file_name##*/} in $file"
|
|
||||||
else
|
|
||||||
# Print an error message
|
|
||||||
bashio::log.warning "$file_name is referenced in your ovpn file but does not exist, and can't be found either in the /config/openvpn/ directory"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done < /tmpfile
|
|
||||||
rm /tmpfile
|
|
||||||
|
|
||||||
# Standardize lf
|
|
||||||
dos2unix "$file"
|
|
||||||
|
|
||||||
# Remove custom up & down
|
|
||||||
sed -i '/^up /s/^/#/' "$file"
|
|
||||||
sed -i '/^down /s/^/#/' "$file"
|
|
||||||
|
|
||||||
# Remove blank lines
|
|
||||||
sed -i '/^[[:blank:]]*$/d' "$file"
|
|
||||||
|
|
||||||
# Ensure config ends with a line feed
|
|
||||||
sed -i "\$q" "$file"
|
|
||||||
|
|
||||||
# Correct paths
|
|
||||||
sed -i "s=/etc/openvpn=/config/openvpn=g" "$file"
|
|
||||||
sed -i "s=/config/openvpn/credentials=/etc/openvpn/credentials=g" "$file"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#####################
|
|
||||||
# CONFIGURE OPENVPN #
|
|
||||||
#####################
|
|
||||||
|
|
||||||
# If openvpn_config option used
|
|
||||||
if bashio::config.has_value "openvpn_config"; then
|
|
||||||
openvpn_config=$(bashio::config 'openvpn_config')
|
|
||||||
# If file found
|
|
||||||
if [ -f /config/openvpn/"$openvpn_config" ]; then
|
|
||||||
# If correct type
|
|
||||||
if [[ "$openvpn_config" == *".ovpn" ]] || [[ "$openvpn_config" == *".conf" ]]; then
|
|
||||||
echo "... configured ovpn file : using /addon_configs/$HOSTNAME/openvpn/$openvpn_config"
|
|
||||||
else
|
|
||||||
bashio::exit.nok "Configured ovpn file : $openvpn_config is set but does not end by .ovpn ; it can't be used!"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
bashio::exit.nok "Configured ovpn file : $openvpn_config not found! Are you sure you added it in /addon_configs/$HOSTNAME/openvpn using the Filebrowser addon ?"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If openvpn_config not set, but folder is not empty
|
|
||||||
elif ls /config/openvpn/*.ovpn > /dev/null 2>&1; then
|
|
||||||
# Look for openvpn files
|
|
||||||
# Wildcard search for openvpn config files and store results in array
|
|
||||||
mapfile -t VPN_CONFIGS < <(find /config/openvpn -maxdepth 1 -name "*.ovpn" -print)
|
|
||||||
# Choose random config
|
|
||||||
VPN_CONFIG="${VPN_CONFIGS[$RANDOM % ${#VPN_CONFIGS[@]}]}"
|
|
||||||
# Get the VPN_CONFIG name without the path and extension
|
|
||||||
openvpn_config="${VPN_CONFIG##*/}"
|
|
||||||
echo "... Openvpn enabled, but openvpn_config option empty. Selecting a random ovpn file : ${openvpn_config}. Other available files :"
|
|
||||||
printf '%s\n' "${VPN_CONFIGS[@]}"
|
|
||||||
# If openvpn_enabled set, config not set, and openvpn folder empty
|
|
||||||
else
|
|
||||||
bashio::exit.nok "openvpn_enabled is set, however, your openvpn folder is empty ! Are you sure you added it in /addon_configs/$HOSTNAME/openvpn using the Filebrowser addon ?"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Send to openvpn script
|
|
||||||
sed -i "s|/config/openvpn/config.ovpn|/config/openvpn/$openvpn_config|g" /etc/s6-overlay/s6-rc.d/svc-qbittorrent/run
|
|
||||||
|
|
||||||
# Check path
|
|
||||||
check_path /config/openvpn/"${openvpn_config}"
|
|
||||||
|
|
||||||
# Set credentials
|
|
||||||
if bashio::config.has_value "openvpn_username"; then
|
|
||||||
openvpn_username=$(bashio::config 'openvpn_username')
|
|
||||||
echo "${openvpn_username}" > /etc/openvpn/credentials
|
|
||||||
else
|
|
||||||
bashio::exit.nok "Openvpn is enabled, but openvpn_username option is empty! Exiting"
|
|
||||||
fi
|
|
||||||
if bashio::config.has_value "openvpn_password"; then
|
|
||||||
openvpn_password=$(bashio::config 'openvpn_password')
|
|
||||||
echo "${openvpn_password}" >> /etc/openvpn/credentials
|
|
||||||
else
|
|
||||||
bashio::exit.nok "Openvpn is enabled, but openvpn_password option is empty! Exiting"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add credentials file
|
|
||||||
if grep -q ^auth-user-pass /config/openvpn/"$openvpn_config"; then
|
|
||||||
# Credentials specified are they custom ?
|
|
||||||
file_name="$(sed -n "/^auth-user-pass/p" /config/openvpn/"$openvpn_config" | awk -F' ' '{print $2}')"
|
|
||||||
file_name="${file_name:-null}"
|
|
||||||
if [[ "$file_name" != *"/etc/openvpn/credentials"* ]] && [[ "$file_name" != "null" ]]; then
|
|
||||||
if [ -f "$file_name" ]; then
|
|
||||||
# If credential specified, exists, and is not the addon default
|
|
||||||
bashio::log.warning "auth-user-pass specified in the ovpn file, addon username and passwords won't be used !"
|
|
||||||
else
|
|
||||||
# Credential referenced but doesn't exist
|
|
||||||
bashio::log.warning "auth-user-pass $file_name is referenced in your ovpn file but does not exist, and can't be found either in the /config/openvpn/ directory. The addon will attempt to use it's own username and password instead."
|
|
||||||
# Comment previous lines
|
|
||||||
sed -i '/^auth-user-pass/i # specified auth-user-pass file not found, disabling' /config/openvpn/"$openvpn_config"
|
|
||||||
sed -i '/^auth-user-pass/s/^/#/' /config/openvpn/"$openvpn_config"
|
|
||||||
# No credentials specified, using addons username and password
|
|
||||||
echo "# Please do not remove the line below, it allows using the addon username and password" >> /config/openvpn/"$openvpn_config"
|
|
||||||
echo "auth-user-pass /etc/openvpn/credentials" >> /etc/openvpn/"$openvpn_config"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Standardize just to be sure
|
|
||||||
sed -i "/\/etc\/openvpn\/credentials/c auth-user-pass \/etc\/openvpn\/credentials" /config/openvpn/"$openvpn_config"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# No credentials specified, using addons username and password
|
|
||||||
echo "# Please do not remove the line below, it allows using the addon username and password" >> /config/openvpn/"$openvpn_config"
|
|
||||||
echo "auth-user-pass /etc/openvpn/credentials" >> /config/openvpn/"$openvpn_config"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Permissions
|
|
||||||
chmod 755 /config/openvpn/*
|
|
||||||
chmod 755 /etc/openvpn/*
|
|
||||||
chmod 600 /etc/openvpn/credentials
|
|
||||||
chmod 755 /etc/openvpn/up.sh
|
|
||||||
chmod 755 /etc/openvpn/down.sh
|
|
||||||
chmod 755 /etc/openvpn/up-qbittorrent.sh
|
|
||||||
chmod +x /etc/openvpn/up.sh
|
|
||||||
chmod +x /etc/openvpn/down.sh
|
|
||||||
chmod +x /etc/openvpn/up-qbittorrent.sh
|
|
||||||
|
|
||||||
echo "... openvpn correctly set, qbittorrent will run tunnelled through openvpn"
|
|
||||||
|
|
||||||
#########################
|
|
||||||
# CONFIGURE QBITTORRENT #
|
|
||||||
#########################
|
|
||||||
|
|
||||||
# WITH CONTAINER BINDING
|
|
||||||
#########################
|
|
||||||
# If alternative mode enabled, bind container
|
|
||||||
if bashio::config.true 'openvpn_alt_mode'; then
|
|
||||||
echo "Using container binding"
|
|
||||||
|
|
||||||
# Remove interface
|
|
||||||
echo "... deleting previous interface settings"
|
|
||||||
sed -i '/Interface/d' "$QBT_CONFIG_FILE"
|
|
||||||
|
|
||||||
# Modify ovpn config
|
|
||||||
if grep -q route-nopull /config/openvpn/"$openvpn_config"; then
|
|
||||||
echo "... removing route-nopull from your config.ovpn"
|
|
||||||
sed -i '/route-nopull/d' /config/openvpn/"$openvpn_config"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Exit
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# WITH INTERFACE BINDING
|
|
||||||
#########################
|
|
||||||
# Connection with interface binding
|
|
||||||
echo "Using interface binding in the qBittorrent app"
|
|
||||||
|
|
||||||
# Define preferences line
|
|
||||||
cd /config/qBittorrent/ || exit 1
|
|
||||||
|
|
||||||
# If qBittorrent.conf exists
|
|
||||||
if [ -f "$QBT_CONFIG_FILE" ]; then
|
|
||||||
# Remove previous line and bind tun0
|
|
||||||
echo "... deleting previous interface settings"
|
|
||||||
sed -i '/Interface/d' "$QBT_CONFIG_FILE"
|
|
||||||
|
|
||||||
# Bind tun0
|
|
||||||
echo "... binding tun0 interface in qBittorrent configuration"
|
|
||||||
sed -i "/\[Preferences\]/ i\Connection\\\Interface=tun0" "$QBT_CONFIG_FILE"
|
|
||||||
sed -i "/\[Preferences\]/ i\Connection\\\InterfaceName=tun0" "$QBT_CONFIG_FILE"
|
|
||||||
|
|
||||||
# Add to ongoing session
|
|
||||||
sed -i "/\[BitTorrent\]/a \Session\\\Interface=tun0" "$QBT_CONFIG_FILE"
|
|
||||||
sed -i "/\[BitTorrent\]/a \Session\\\InterfaceName=tun0" "$QBT_CONFIG_FILE"
|
|
||||||
|
|
||||||
else
|
|
||||||
bashio::log.error "qBittorrent config file doesn't exist, openvpn must be added manually to qbittorrent options "
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Modify ovpn config
|
|
||||||
if ! grep -q route-nopull /config/openvpn/"$openvpn_config"; then
|
|
||||||
echo "... adding route-nopull to your config.ovpn"
|
|
||||||
sed -i "1a route-nopull" /config/openvpn/"$openvpn_config"
|
|
||||||
fi
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
##################
|
|
||||||
# REMOVE OPENVPN #
|
|
||||||
##################
|
|
||||||
|
|
||||||
if ! bashio::config.true 'wireguard_enabled'; then
|
|
||||||
# Ensure no redirection by removing the direction tag when no VPN is used
|
|
||||||
if [ -f "$QBT_CONFIG_FILE" ]; then
|
|
||||||
sed -i '/Interface/d' "$QBT_CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
bashio::log.info "Direct connection without VPN enabled"
|
|
||||||
else
|
|
||||||
bashio::log.info "OpenVPN disabled. WireGuard handling network binding."
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! bashio::config.true 'openvpn_enabled'; then
|
||||||
|
bashio::exit.ok 'OpenVPN is disabled.'
|
||||||
|
elif bashio::config.true 'wireguard_enabled'; then
|
||||||
|
bashio::exit.nok 'OpenVPN and WireGuard cannot be enabled simultaneously. Disable one of them.'
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${OPENVPN_STATE_DIR}"
|
||||||
|
|
||||||
|
bashio::log.info "----------------------------"
|
||||||
|
bashio::log.info "Openvpn enabled, configuring"
|
||||||
|
bashio::log.info "----------------------------"
|
||||||
|
|
||||||
|
# Set credentials
|
||||||
|
if bashio::config.has_value "openvpn_username"; then
|
||||||
|
openvpn_username=$(bashio::config 'openvpn_username')
|
||||||
|
else
|
||||||
|
bashio::exit.nok "Openvpn is enabled, but openvpn_username option is empty! Exiting"
|
||||||
|
fi
|
||||||
|
if bashio::config.has_value "openvpn_password"; then
|
||||||
|
openvpn_password=$(bashio::config 'openvpn_password')
|
||||||
|
else
|
||||||
|
bashio::exit.nok "Openvpn is enabled, but openvpn_password option is empty! Exiting"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${openvpn_username}\n${openvpn_password}" > "${OPENVPN_STATE_DIR}/credentials.conf"
|
||||||
|
chmod 600 "${OPENVPN_STATE_DIR}/credentials.conf"
|
||||||
|
|
||||||
|
if bashio::config.has_value "openvpn_config"; then
|
||||||
|
openvpn_config="$(bashio::config 'openvpn_config')"
|
||||||
|
openvpn_config="${openvpn_config##*/}"
|
||||||
|
fi
|
||||||
|
if [[ -z "${openvpn_config}" ]]; then
|
||||||
|
bashio::log.info 'openvpn_config option left empty. Attempting automatic selection.'
|
||||||
|
mapfile -t configs < <(find /config/openvpn -maxdepth 1 \( -type f -name '*.conf' -o -name '*.ovpn' \) -print)
|
||||||
|
if [ "${#configs[@]}" -eq 0 ]; then
|
||||||
|
bashio::exit.nok 'OpenVPN is enabled but no .conf or .ovpn file was found in /config/openvpn.'
|
||||||
|
elif [ "${#configs[@]}" -eq 1 ]; then
|
||||||
|
openvpn_config="${configs[0]}"
|
||||||
|
bashio::log.info "OpenVPN configuration not specified. Using ${openvpn_config##*/}."
|
||||||
|
elif bashio::fs.file_exists '/config/openvpn/config.conf'; then
|
||||||
|
openvpn_config='/config/openvpn/config.conf'
|
||||||
|
bashio::log.info 'Using default OpenVPN configuration config.conf.'
|
||||||
|
else
|
||||||
|
bashio::exit.nok "Multiple OpenVPN configuration files detected. Please set the 'openvpn_config' option."
|
||||||
|
fi
|
||||||
|
elif bashio::fs.file_exists "/config/openvpn/${openvpn_config}"; then
|
||||||
|
openvpn_config="/config/openvpn/${openvpn_config}"
|
||||||
|
else
|
||||||
|
bashio::exit.nok "OpenVPN configuration '/config/openvpn/${openvpn_config}' not found."
|
||||||
|
fi
|
||||||
|
|
||||||
|
interface_name="$(sed -n "/^dev tun/p" "${openvpn_config}" | awk -F' ' '{print $2}')"
|
||||||
|
if [[ -z "${interface_name}" ]]; then
|
||||||
|
bashio::exit.nok "OpenVPN configuration '${openvpn_config}' misses device directive."
|
||||||
|
elif [[ ${interface_name} = "tun" ]]; then
|
||||||
|
interface_name='tun0'
|
||||||
|
elif [[ ${interface_name} = "tap" ]]; then
|
||||||
|
interface_name='tap0'
|
||||||
|
fi
|
||||||
|
|
||||||
|
openvpn_runtime_config="${OPENVPN_STATE_DIR}/${interface_name}.conf"
|
||||||
|
|
||||||
|
cp "${openvpn_config}" "${openvpn_runtime_config}"
|
||||||
|
chmod 600 "${openvpn_runtime_config}"
|
||||||
|
|
||||||
|
dos2unix "${openvpn_runtime_config}" >/dev/null 2>&1 || true
|
||||||
|
sed -i '/^[[:space:]]*[;#]/d' "${openvpn_runtime_config}"
|
||||||
|
sed -i 's/#.*//' "${openvpn_runtime_config}"
|
||||||
|
sed -i '/^[[:space:]]*$/d' "${openvpn_runtime_config}"
|
||||||
|
sed -i '/^[[:blank:]]*$/d' "${openvpn_runtime_config}"
|
||||||
|
sed -i '/^up/d' "${openvpn_runtime_config}"
|
||||||
|
sed -i '/^down/d' "${openvpn_runtime_config}"
|
||||||
|
sed -i '/^route/d' "${openvpn_runtime_config}"
|
||||||
|
sed -i '/^auth-user-pass /d' "${openvpn_runtime_config}"
|
||||||
|
sed -i '/^cd /d' "${openvpn_runtime_config}"
|
||||||
|
sed -i '/^chroot /d' "${openvpn_runtime_config}"
|
||||||
|
sed -i '$q' "${openvpn_runtime_config}"
|
||||||
|
|
||||||
|
bashio::log.info 'Prepared OpenVPN runtime configuration for initial connection attempt.'
|
||||||
|
|
||||||
|
echo "${openvpn_runtime_config}" > "${OPENVPN_STATE_DIR}/config"
|
||||||
|
echo "${interface_name}" > "${OPENVPN_STATE_DIR}/interface"
|
||||||
|
|
||||||
|
bashio::log.info "Using interface binding in the qBittorrent app"
|
||||||
|
|
||||||
|
if bashio::fs.file_exists "${QBT_CONFIG_FILE}"; then
|
||||||
|
sed -i '/Interface/d' "${QBT_CONFIG_FILE}"
|
||||||
|
sed -i "/\\[Preferences\\]/ i\\Connection\\\\Interface=${interface_name}" "${QBT_CONFIG_FILE}"
|
||||||
|
sed -i "/\\[Preferences\\]/ i\\Connection\\\\InterfaceName=${interface_name}" "${QBT_CONFIG_FILE}"
|
||||||
|
sed -i "/\\[BitTorrent\\]/a \\Session\\\\Interface=${interface_name}" "${QBT_CONFIG_FILE}"
|
||||||
|
sed -i "/\\[BitTorrent\\]/a \\Session\\\\InterfaceName=${interface_name}" "${QBT_CONFIG_FILE}"
|
||||||
|
else
|
||||||
|
bashio::log.warning "qBittorrent config file not found. Bind the client manually to interface ${interface_name}."
|
||||||
|
fi
|
||||||
|
|
||||||
|
bashio::log.info "OpenVPN prepared with interface ${interface_name} using configuration ${openvpn_config##*/}."
|
||||||
|
|||||||
@@ -6,37 +6,32 @@ WIREGUARD_STATE_DIR="/var/run/wireguard"
|
|||||||
QBT_CONFIG_FILE="/config/qBittorrent/qBittorrent.conf"
|
QBT_CONFIG_FILE="/config/qBittorrent/qBittorrent.conf"
|
||||||
declare wireguard_config=""
|
declare wireguard_config=""
|
||||||
declare wireguard_runtime_config=""
|
declare wireguard_runtime_config=""
|
||||||
declare configured_name
|
declare interface_name=""
|
||||||
|
|
||||||
mkdir -p "${WIREGUARD_STATE_DIR}"
|
if bashio::fs.directory_exists "${WIREGUARD_STATE_DIR}"; then
|
||||||
|
bashio::log.warning "Previous WireGuard state directory found, cleaning up."
|
||||||
if ! bashio::config.true 'wireguard_enabled'; then
|
rm -Rf "${WIREGUARD_STATE_DIR}"
|
||||||
rm -f "${WIREGUARD_STATE_DIR}/config" "${WIREGUARD_STATE_DIR}/interface"
|
|
||||||
exit 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if bashio::config.true 'openvpn_enabled'; then
|
if ! bashio::config.true 'wireguard_enabled'; then
|
||||||
|
bashio::exit.ok 'WireGuard is disabled.'
|
||||||
|
elif bashio::config.true 'openvpn_enabled'; then
|
||||||
bashio::exit.nok 'OpenVPN and WireGuard cannot be enabled simultaneously. Disable one of them.'
|
bashio::exit.nok 'OpenVPN and WireGuard cannot be enabled simultaneously. Disable one of them.'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if bashio::config.true 'openvpn_alt_mode'; then
|
mkdir -p "${WIREGUARD_STATE_DIR}"
|
||||||
bashio::log.warning 'The openvpn_alt_mode option is ignored when WireGuard is enabled.'
|
|
||||||
fi
|
|
||||||
|
|
||||||
if bashio::config.has_value 'wireguard_config'; then
|
bashio::log.info "------------------------------"
|
||||||
configured_name="$(bashio::config 'wireguard_config')"
|
bashio::log.info "Wireguard enabled, configuring"
|
||||||
configured_name="${configured_name##*/}"
|
bashio::log.info "------------------------------"
|
||||||
if [[ -z "${configured_name}" ]]; then
|
|
||||||
bashio::log.info 'wireguard_config option left empty. Attempting automatic selection.'
|
|
||||||
elif bashio::fs.file_exists "/config/wireguard/${configured_name}"; then
|
|
||||||
wireguard_config="/config/wireguard/${configured_name}"
|
|
||||||
else
|
|
||||||
bashio::exit.nok "WireGuard configuration '/config/wireguard/${configured_name}' not found."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${wireguard_config:-}" ]; then
|
if bashio::config.has_value "wireguard_config"; then
|
||||||
mapfile -t configs < <(find /config/wireguard -maxdepth 1 -type f -name '*.conf' -print)
|
wireguard_config="$(bashio::config 'wireguard_config')"
|
||||||
|
wireguard_config="${wireguard_config##*/}"
|
||||||
|
fi
|
||||||
|
if [[ -z "${wireguard_config}" ]]; then
|
||||||
|
bashio::log.info 'wireguard_config option left empty. Attempting automatic selection.'
|
||||||
|
mapfile -t configs < <(find /config/wireguard -maxdepth 1 -type f -name '*.conf' -print)
|
||||||
if [ "${#configs[@]}" -eq 0 ]; then
|
if [ "${#configs[@]}" -eq 0 ]; then
|
||||||
bashio::exit.nok 'WireGuard is enabled but no .conf file was found in /config/wireguard.'
|
bashio::exit.nok 'WireGuard is enabled but no .conf file was found in /config/wireguard.'
|
||||||
elif [ "${#configs[@]}" -eq 1 ]; then
|
elif [ "${#configs[@]}" -eq 1 ]; then
|
||||||
@@ -48,10 +43,12 @@ if [ -z "${wireguard_config:-}" ]; then
|
|||||||
else
|
else
|
||||||
bashio::exit.nok "Multiple WireGuard configuration files detected. Please set the 'wireguard_config' option."
|
bashio::exit.nok "Multiple WireGuard configuration files detected. Please set the 'wireguard_config' option."
|
||||||
fi
|
fi
|
||||||
|
elif bashio::fs.file_exists "/config/wireguard/${wireguard_config}"; then
|
||||||
|
wireguard_config="/config/wireguard/${wireguard_config}"
|
||||||
|
else
|
||||||
|
bashio::exit.nok "WireGuard configuration '/config/wireguard/${wireguard_config}' not found."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dos2unix "${wireguard_config}" >/dev/null 2>&1 || true
|
|
||||||
|
|
||||||
interface_name="$(basename "${wireguard_config}" .conf)"
|
interface_name="$(basename "${wireguard_config}" .conf)"
|
||||||
if [[ -z "${interface_name}" ]]; then
|
if [[ -z "${interface_name}" ]]; then
|
||||||
interface_name='wg0'
|
interface_name='wg0'
|
||||||
@@ -60,12 +57,26 @@ fi
|
|||||||
wireguard_runtime_config="${WIREGUARD_STATE_DIR}/${interface_name}.conf"
|
wireguard_runtime_config="${WIREGUARD_STATE_DIR}/${interface_name}.conf"
|
||||||
|
|
||||||
cp "${wireguard_config}" "${wireguard_runtime_config}"
|
cp "${wireguard_config}" "${wireguard_runtime_config}"
|
||||||
chmod 600 "${wireguard_runtime_config}" 2>/dev/null || true
|
chmod 600 "${wireguard_runtime_config}"
|
||||||
|
|
||||||
|
dos2unix "${wireguard_runtime_config}" >/dev/null 2>&1 || true
|
||||||
|
sed -i '/^[[:space:]]*[;#]/d' "${wireguard_runtime_config}"
|
||||||
|
sed -i 's/#.*//' "${wireguard_runtime_config}"
|
||||||
|
sed -i '/^[[:space:]]*$/d' "${wireguard_runtime_config}"
|
||||||
|
sed -i '/^[[:blank:]]*$/d' "${wireguard_runtime_config}"
|
||||||
|
sed -i '/DNS/d' "${wireguard_runtime_config}"
|
||||||
|
sed -i '/PostUp/d' "${wireguard_runtime_config}"
|
||||||
|
sed -i '/PostDown/d' "${wireguard_runtime_config}"
|
||||||
|
sed -i '/SaveConfig/d' "${wireguard_runtime_config}"
|
||||||
|
sed -i "\$q" "${wireguard_runtime_config}"
|
||||||
|
|
||||||
bashio::log.info 'Prepared WireGuard runtime configuration for initial connection attempt.'
|
bashio::log.info 'Prepared WireGuard runtime configuration for initial connection attempt.'
|
||||||
|
|
||||||
echo "${wireguard_runtime_config}" > "${WIREGUARD_STATE_DIR}/config"
|
echo "${wireguard_runtime_config}" > "${WIREGUARD_STATE_DIR}/config"
|
||||||
echo "${interface_name}" > "${WIREGUARD_STATE_DIR}/interface"
|
echo "${interface_name}" > "${WIREGUARD_STATE_DIR}/interface"
|
||||||
|
|
||||||
|
bashio::log.info "Using interface binding in the qBittorrent app"
|
||||||
|
|
||||||
if bashio::fs.file_exists "${QBT_CONFIG_FILE}"; then
|
if bashio::fs.file_exists "${QBT_CONFIG_FILE}"; then
|
||||||
sed -i '/Interface/d' "${QBT_CONFIG_FILE}"
|
sed -i '/Interface/d' "${QBT_CONFIG_FILE}"
|
||||||
sed -i "/\\[Preferences\\]/ i\\Connection\\\\Interface=${interface_name}" "${QBT_CONFIG_FILE}"
|
sed -i "/\\[Preferences\\]/ i\\Connection\\\\Interface=${interface_name}" "${QBT_CONFIG_FILE}"
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# shellcheck disable=SC2154,SC2004,SC2059,SC2086
|
|
||||||
# Copyright (c) 2006-2007 Gentoo Foundation
|
|
||||||
# Distributed under the terms of the GNU General Public License v2
|
|
||||||
# Contributed by Roy Marples (uberlord@gentoo.org)
|
|
||||||
|
|
||||||
# If we have a service specific script, run this now
|
|
||||||
if [ -x /etc/openvpn/"${RC_SVCNAME}"-down.sh ]; then
|
|
||||||
/etc/openvpn/"${RC_SVCNAME}"-down.sh "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Restore resolv.conf to how it was
|
|
||||||
if [ "${PEER_DNS}" != "no" ]; then
|
|
||||||
if [ -x /sbin/resolvconf ]; then
|
|
||||||
/sbin/resolvconf -d "${dev}"
|
|
||||||
elif [ -e /etc/resolv.conf-"${dev}".sv ]; then
|
|
||||||
# Important that we cat instead of move incase resolv.conf is
|
|
||||||
# a symlink and not an actual file
|
|
||||||
cat /etc/resolv.conf-"${dev}".sv > /etc/resolv.conf
|
|
||||||
rm -f /etc/resolv.conf-"${dev}".sv
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "${RC_SVCNAME}" ]; then
|
|
||||||
# Re-enter the init script to start any dependant services
|
|
||||||
if /etc/init.d/"${RC_SVCNAME}" --quiet status; then
|
|
||||||
export IN_BACKGROUND=true
|
|
||||||
if [ -d /var/run/s6/container_environment ]; then printf "%s" "true" > /var/run/s6/container_environment/IN_BACKGROUND; fi
|
|
||||||
printf "%s\n" "IN_BACKGROUND=\"true\"" >> ~/.bashrc
|
|
||||||
/etc/init.d/"${RC_SVCNAME}" --quiet stop
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
|
|
||||||
# vim: ts=4 :
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/with-contenv bashio
|
|
||||||
# shellcheck shell=bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
WEBUI_PORT=${WEBUI_PORT:-8080}
|
|
||||||
|
|
||||||
exec \
|
|
||||||
s6-notifyoncheck -d -n 300 -w 1000 -c "nc -z localhost ${WEBUI_PORT}" \
|
|
||||||
s6-setuidgid abc /usr/bin/qbittorrent-nox --webui-port="${WEBUI_PORT}"
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# shellcheck disable=SC2154,SC2004,SC2059,SC2086
|
|
||||||
|
|
||||||
# launch qbittorrent
|
|
||||||
/etc/openvpn/up-qbittorrent.sh "${4}" &
|
|
||||||
|
|
||||||
# Copyright (c) 2006-2007 Gentoo Foundation
|
|
||||||
# Distributed under the terms of the GNU General Public License v2
|
|
||||||
# Contributed by Roy Marples (uberlord@gentoo.org)
|
|
||||||
|
|
||||||
# Setup our resolv.conf
|
|
||||||
# Vitally important that we use the domain entry in resolv.conf so we
|
|
||||||
# can setup the nameservers are for the domain ONLY in resolvconf if
|
|
||||||
# we're using a decent dns cache/forwarder like dnsmasq and NOT nscd/libc.
|
|
||||||
# nscd/libc users will get the VPN nameservers before their other ones
|
|
||||||
# and will use the first one that responds - maybe the LAN ones?
|
|
||||||
# non resolvconf users just the the VPN resolv.conf
|
|
||||||
|
|
||||||
# FIXME:- if we have >1 domain, then we have to use search :/
|
|
||||||
# We need to add a flag to resolvconf to say
|
|
||||||
# "these nameservers should only be used for the listed search domains
|
|
||||||
# if other global nameservers are present on other interfaces"
|
|
||||||
# This however, will break compatibility with Debians resolvconf
|
|
||||||
# A possible workaround would be to just list multiple domain lines
|
|
||||||
# and try and let resolvconf handle it
|
|
||||||
|
|
||||||
if [ "${PEER_DNS}" != "no" ]; then
|
|
||||||
NS=
|
|
||||||
DOMAIN=
|
|
||||||
SEARCH=
|
|
||||||
i=1
|
|
||||||
while true; do
|
|
||||||
eval opt=\$foreign_option_${i}
|
|
||||||
[ -z "${opt}" ] && break
|
|
||||||
if [ "${opt}" != "${opt#dhcp-option DOMAIN *}" ]; then
|
|
||||||
if [ -z "${DOMAIN}" ]; then
|
|
||||||
DOMAIN="${opt#dhcp-option DOMAIN *}"
|
|
||||||
else
|
|
||||||
SEARCH="${SEARCH}${SEARCH:+ }${opt#dhcp-option DOMAIN *}"
|
|
||||||
fi
|
|
||||||
elif [ "${opt}" != "${opt#dhcp-option DNS *}" ]; then
|
|
||||||
NS="${NS}nameserver ${opt#dhcp-option DNS *}\n"
|
|
||||||
fi
|
|
||||||
i=$((${i} + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -n "${NS}" ]; then
|
|
||||||
DNS="# Generated by openvpn for interface ${dev}\n"
|
|
||||||
if [ -n "${SEARCH}" ]; then
|
|
||||||
DNS="${DNS}search ${DOMAIN} ${SEARCH}\n"
|
|
||||||
elif [ -n "${DOMAIN}" ]; then
|
|
||||||
DNS="${DNS}domain ${DOMAIN}\n"
|
|
||||||
fi
|
|
||||||
DNS="${DNS}${NS}"
|
|
||||||
if [ -x /sbin/resolvconf ]; then
|
|
||||||
printf "${DNS}" | /sbin/resolvconf -a "${dev}"
|
|
||||||
else
|
|
||||||
# Preserve the existing resolv.conf
|
|
||||||
if [ -e /etc/resolv.conf ]; then
|
|
||||||
cp /etc/resolv.conf /etc/resolv.conf-"${dev}".sv
|
|
||||||
fi
|
|
||||||
printf "${DNS}" > /etc/resolv.conf
|
|
||||||
chmod 644 /etc/resolv.conf
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Below section is Gentoo specific
|
|
||||||
# Quick summary - our init scripts are re-entrant and set the RC_SVCNAME env var
|
|
||||||
# as we could have >1 openvpn service
|
|
||||||
|
|
||||||
if [ -n "${RC_SVCNAME}" ]; then
|
|
||||||
# If we have a service specific script, run this now
|
|
||||||
if [ -x /etc/openvpn/"${RC_SVCNAME}"-up.sh ]; then
|
|
||||||
/etc/openvpn/"${RC_SVCNAME}"-up.sh "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Re-enter the init script to start any dependant services
|
|
||||||
if ! /etc/init.d/"${RC_SVCNAME}" --quiet status; then
|
|
||||||
export IN_BACKGROUND=true
|
|
||||||
if [ -d /var/run/s6/container_environment ]; then printf "%s" "true" > /var/run/s6/container_environment/IN_BACKGROUND; fi
|
|
||||||
printf "%s\n" "IN_BACKGROUND=\"true\"" >> ~/.bashrc
|
|
||||||
/etc/init.d/${RC_SVCNAME} --quiet start
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
###############
|
|
||||||
# ALLOW WEBUI #
|
|
||||||
###############
|
|
||||||
|
|
||||||
ip route add 10.0.0.0/8 via 172.30.32.1
|
|
||||||
ip route add 192.168.0.0/16 via 172.30.32.1
|
|
||||||
ip route add 172.16.0.0/12 via 172.30.32.1
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
|
|
||||||
# vim: ts=4 :
|
|
||||||
@@ -10,125 +10,6 @@ if bashio::config.true 'silent'; then
|
|||||||
sed -i 's|/proc/1/fd/1 hassio;|off;|g' /etc/nginx/nginx.conf
|
sed -i 's|/proc/1/fd/1 hassio;|off;|g' /etc/nginx/nginx.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- WireGuard Specific Logic ---
|
|
||||||
|
|
||||||
_setup_wireguard() {
|
|
||||||
local WIREGUARD_STATE_DIR="/var/run/wireguard"
|
|
||||||
local output=""
|
|
||||||
local status=0
|
|
||||||
|
|
||||||
if ! bashio::fs.file_exists "${WIREGUARD_STATE_DIR}/config"; then
|
|
||||||
bashio::exit.nok 'WireGuard runtime configuration not prepared. Please restart the add-on.'
|
|
||||||
fi
|
|
||||||
|
|
||||||
local wireguard_config
|
|
||||||
wireguard_config="$(cat "${WIREGUARD_STATE_DIR}/config")"
|
|
||||||
local wireguard_interface
|
|
||||||
wireguard_interface="$(cat "${WIREGUARD_STATE_DIR}/interface" 2>/dev/null || echo 'wg0')"
|
|
||||||
|
|
||||||
if ip link show "${wireguard_interface}" >/dev/null 2>&1; then
|
|
||||||
bashio::log.warning "WireGuard interface ${wireguard_interface} already exists. Resetting."
|
|
||||||
wg-quick down "${wireguard_config}" >/dev/null 2>&1 || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
bashio::log.info "Starting WireGuard interface ${wireguard_interface}..."
|
|
||||||
|
|
||||||
# Internal helper: fallback for iptables-legacy
|
|
||||||
_wg_prepare_legacy() {
|
|
||||||
local legacy_bin_dir="${WIREGUARD_STATE_DIR}/iptables-legacy-bin"
|
|
||||||
mkdir -p "${legacy_bin_dir}"
|
|
||||||
local cmd
|
|
||||||
for cmd in iptables iptables-save iptables-restore ip6tables ip6tables-save ip6tables-restore; do
|
|
||||||
if command -v "${cmd}-legacy" >/dev/null 2>&1; then
|
|
||||||
ln -sf "$(command -v "${cmd}-legacy")" "${legacy_bin_dir}/${cmd}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
chmod 700 "${legacy_bin_dir}" 2>/dev/null || true
|
|
||||||
export PATH="${legacy_bin_dir}:${PATH}"
|
|
||||||
bashio::log.warning 'Retrying WireGuard using iptables-legacy wrappers.'
|
|
||||||
}
|
|
||||||
|
|
||||||
# Internal helper: Attempt connection
|
|
||||||
_wg_up_attempt() {
|
|
||||||
local config_path="$1"
|
|
||||||
output="$(wg-quick up "${config_path}" 2>&1)" || status=$?
|
|
||||||
|
|
||||||
if [ "${status}" -eq 0 ]; then return 0; fi
|
|
||||||
|
|
||||||
# Allow sysctl failures on read-only hosts while keeping the interface up
|
|
||||||
if echo "${output}" | grep -qi 'net\.ipv4\.conf\.all\.src_valid_mark=1'; then
|
|
||||||
if echo "${output}" | grep -qiE 'read-only file system|operation not permitted'; then
|
|
||||||
if ip link show "${wireguard_interface}" >/dev/null 2>&1; then
|
|
||||||
bashio::log.warning 'WireGuard applied but sysctl net.ipv4.conf.all.src_valid_mark=1 could not be set (read-only). Continuing.'
|
|
||||||
status=0
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check for iptables errors and try legacy fallback
|
|
||||||
if echo "${output}" | grep -qiE 'iptables-restore|ip6tables-restore|xtables'; then
|
|
||||||
if command -v iptables-legacy >/dev/null 2>&1; then
|
|
||||||
wg-quick down "${config_path}" >/dev/null 2>&1 || true
|
|
||||||
_wg_prepare_legacy
|
|
||||||
output="$(wg-quick up "${config_path}" 2>&1)" || status=$?
|
|
||||||
else
|
|
||||||
bashio::log.warning 'iptables errors detected but iptables-legacy missing.'
|
|
||||||
status=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return "${status}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 1. First Attempt
|
|
||||||
if ! _wg_up_attempt "${wireguard_config}"; then
|
|
||||||
bashio::log.warning 'Initial WireGuard connection failed. Trying IPv4-only endpoints.'
|
|
||||||
bashio::log.debug "Output: ${output}"
|
|
||||||
|
|
||||||
# 2. IPv4 Fallback Preparation
|
|
||||||
local ipv4_config="${WIREGUARD_STATE_DIR}/${wireguard_interface}-ipv4.conf"
|
|
||||||
: > "${ipv4_config}"
|
|
||||||
chmod 600 "${ipv4_config}" 2>/dev/null || true
|
|
||||||
|
|
||||||
local line endpoint endpoint_host endpoint_port
|
|
||||||
while IFS= read -r line || [ -n "$line" ]; do
|
|
||||||
if [[ "${line}" =~ ^Endpoint ]]; then
|
|
||||||
endpoint="${line#Endpoint = }"
|
|
||||||
endpoint_host="${endpoint%:*}"
|
|
||||||
endpoint_port="${endpoint##*:}"
|
|
||||||
|
|
||||||
# Resolve hostname to IPv4
|
|
||||||
mapfile -t ipv4_candidates < <(getent ahostsv4 "${endpoint_host}" | awk '{print $1}' | uniq)
|
|
||||||
|
|
||||||
if [ ${#ipv4_candidates[@]} -gt 0 ]; then
|
|
||||||
bashio::log.debug "Resolved ${endpoint_host} to ${ipv4_candidates[0]}"
|
|
||||||
echo "Endpoint = ${ipv4_candidates[0]}:${endpoint_port}" >> "${ipv4_config}"
|
|
||||||
else
|
|
||||||
echo "${line}" >> "${ipv4_config}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "${line}" >> "${ipv4_config}"
|
|
||||||
fi
|
|
||||||
done < "${wireguard_config}"
|
|
||||||
|
|
||||||
wg-quick down "${wireguard_config}" >/dev/null 2>&1 || true
|
|
||||||
|
|
||||||
# 3. Second Attempt (IPv4 only)
|
|
||||||
if ! _wg_up_attempt "${ipv4_config}"; then
|
|
||||||
bashio::log.error 'WireGuard failed to establish connection.'
|
|
||||||
bashio::log.error "${output}"
|
|
||||||
bashio::exit.nok 'WireGuard start failed.'
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
bashio::log.info "WireGuard interface ${wireguard_interface} is up."
|
|
||||||
|
|
||||||
# DNS Refresh
|
|
||||||
if command -v resolvconf >/dev/null 2>&1; then
|
|
||||||
resolvconf -u >/dev/null 2>&1 || bashio::log.warning 'resolvconf -u failed.'
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Main Execution ---
|
# --- Main Execution ---
|
||||||
|
|
||||||
openvpn_enabled=false
|
openvpn_enabled=false
|
||||||
@@ -148,24 +29,9 @@ if [[ "${openvpn_enabled}" == true && "${wireguard_enabled}" == true ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${openvpn_enabled}" == true ]]; then
|
if [[ "${openvpn_enabled}" == true ]]; then
|
||||||
|
/usr/local/sbin/vpn openvpn up
|
||||||
exec /usr/sbin/openvpn \
|
|
||||||
--config /config/openvpn/config.ovpn \
|
|
||||||
--script-security 2 \
|
|
||||||
--up /etc/openvpn/up.sh \
|
|
||||||
--down /etc/openvpn/down.sh \
|
|
||||||
--pull-filter ignore "route-ipv6" \
|
|
||||||
--pull-filter ignore "ifconfig-ipv6" \
|
|
||||||
--pull-filter ignore "tun-ipv6" \
|
|
||||||
--pull-filter ignore "redirect-gateway ipv6" \
|
|
||||||
--pull-filter ignore "dhcp-option DNS6" \
|
|
||||||
&
|
|
||||||
|
|
||||||
elif [[ "${wireguard_enabled}" == true ]]; then
|
elif [[ "${wireguard_enabled}" == true ]]; then
|
||||||
|
/usr/local/sbin/vpn wireguard up
|
||||||
# Run modularized WireGuard setup
|
|
||||||
_setup_wireguard
|
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Launch qBittorrent ---
|
# --- Launch qBittorrent ---
|
||||||
|
|||||||
@@ -129,13 +129,6 @@ if bashio::config.true 'openvpn_enabled'; then
|
|||||||
vpn_openvpn=true
|
vpn_openvpn=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${vpn_openvpn}" == true ]] && ! bashio::config.true 'openvpn_alt_mode'; then
|
|
||||||
VPN_INTERFACE="tun0"
|
|
||||||
bashio::log.info "VPN monitor set to query external IP through interface ${VPN_INTERFACE} (interface binding)."
|
|
||||||
else
|
|
||||||
VPN_INTERFACE=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
if bashio::config.true 'wireguard_enabled'; then
|
if bashio::config.true 'wireguard_enabled'; then
|
||||||
vpn_wireguard=true
|
vpn_wireguard=true
|
||||||
fi
|
fi
|
||||||
@@ -151,6 +144,19 @@ if [[ "${vpn_openvpn}" == true && "${vpn_wireguard}" == true ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "${vpn_openvpn}" == true ]]; then
|
||||||
|
VPN_INTERFACE=$(cat "/var/run/openvpn/interface")
|
||||||
|
bashio::log.info "VPN monitor set to query external IP through interface ${VPN_INTERFACE} (interface binding)."
|
||||||
|
elif [[ "${vpn_wireguard}" == true ]]; then
|
||||||
|
VPN_INTERFACE=$(cat "/var/run/wireguard/interface")
|
||||||
|
bashio::log.info "VPN monitor set to query external IP through interface ${VPN_INTERFACE} (interface binding)."
|
||||||
|
fi
|
||||||
|
if [[ -z "${VPN_INTERFACE}" ]] || ! ip link show "${VPN_INTERFACE}" > /dev/null 2>&1 ; then
|
||||||
|
bashio::log.error "VPN interface not found."
|
||||||
|
bashio::addon.stop
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
REAL_IP="$(read_real_ip)"
|
REAL_IP="$(read_real_ip)"
|
||||||
|
|
||||||
if [[ -n "${REAL_IP}" ]]; then
|
if [[ -n "${REAL_IP}" ]]; then
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
STATE_DIR="/var/run/wireguard/resolvconf"
|
|
||||||
BACKUP_FILE="${STATE_DIR}/resolv.conf.backup"
|
|
||||||
|
|
||||||
mkdir -p "${STATE_DIR}"
|
|
||||||
|
|
||||||
if [ "$#" -eq 0 ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
command="$1"
|
|
||||||
shift || true
|
|
||||||
|
|
||||||
restore_backup() {
|
|
||||||
if [ -f "${BACKUP_FILE}" ]; then
|
|
||||||
cat "${BACKUP_FILE}" > /etc/resolv.conf
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
apply_dns() {
|
|
||||||
iface="$1"
|
|
||||||
shift || true
|
|
||||||
|
|
||||||
# Skip optional arguments such as -m <metric> or -x
|
|
||||||
while [ "$#" -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
-m|-p|-w)
|
|
||||||
shift 2 || true
|
|
||||||
;;
|
|
||||||
-x|-y|-Z)
|
|
||||||
shift 1 || true
|
|
||||||
;;
|
|
||||||
--)
|
|
||||||
shift
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
tmp_file="${STATE_DIR}/${iface}.conf"
|
|
||||||
cat > "${tmp_file}"
|
|
||||||
|
|
||||||
if [ ! -f "${BACKUP_FILE}" ]; then
|
|
||||||
cp /etc/resolv.conf "${BACKUP_FILE}" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
{
|
|
||||||
echo "# Generated by WireGuard add-on resolvconf shim"
|
|
||||||
cat "${tmp_file}"
|
|
||||||
} > /etc/resolv.conf
|
|
||||||
}
|
|
||||||
|
|
||||||
case "${command}" in
|
|
||||||
-a)
|
|
||||||
if [ "$#" -eq 0 ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
apply_dns "$@"
|
|
||||||
;;
|
|
||||||
-d)
|
|
||||||
if [ "$#" -gt 0 ]; then
|
|
||||||
rm -f "${STATE_DIR}/$1.conf"
|
|
||||||
fi
|
|
||||||
restore_backup
|
|
||||||
;;
|
|
||||||
-u)
|
|
||||||
latest_conf="$(find "${STATE_DIR}" -maxdepth 1 -type f -name '*.conf' -print | head -n 1 || true)"
|
|
||||||
if [ -n "${latest_conf}" ] && [ -f "${latest_conf}" ]; then
|
|
||||||
{
|
|
||||||
echo "# Generated by WireGuard add-on resolvconf shim"
|
|
||||||
cat "${latest_conf}"
|
|
||||||
} > /etc/resolv.conf
|
|
||||||
else
|
|
||||||
restore_backup
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# Treat other commands as successful no-ops to remain compatible with wg-quick.
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
REAL_IP6TABLES_RESTORE="/sbin/ip6tables-restore"
|
|
||||||
if [[ ! -x "${REAL_IP6TABLES_RESTORE}" ]]; then
|
|
||||||
REAL_IP6TABLES_RESTORE="/usr/sbin/ip6tables-restore"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
local exit_code=$?
|
|
||||||
[[ -n "${RULES_FILE:-}" && -f "${RULES_FILE}" ]] && rm -f "${RULES_FILE}"
|
|
||||||
[[ -n "${SANITIZED_FILE:-}" && -f "${SANITIZED_FILE}" ]] && rm -f "${SANITIZED_FILE}"
|
|
||||||
return $exit_code
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
RULES_FILE="$(mktemp)"
|
|
||||||
cat > "${RULES_FILE}"
|
|
||||||
|
|
||||||
ipv6_unavailable() {
|
|
||||||
local message="$1"
|
|
||||||
[[ $message =~ [Tt]able[[:space:]]does[[:space:]]not[[:space:]]exist ]] && return 0
|
|
||||||
[[ $message =~ address[[:space:]]family[[:space:]]not[[:space:]]supported ]] && return 0
|
|
||||||
[[ $message =~ can[[:punct:]]t[[:space:]]initialize[[:space:]]ip6tables[[:space:]]table ]] && return 0
|
|
||||||
[[ $message =~ IPv6[[:space:]]support[[:space:]]not[[:space:]]available ]] && return 0
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# First attempt with the original ruleset
|
|
||||||
output=""
|
|
||||||
if output="$(${REAL_IP6TABLES_RESTORE} "$@" < "${RULES_FILE}" 2>&1)"; then
|
|
||||||
[[ -n "${output}" ]] && printf '%s\n' "${output}" >&2
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
status=$?
|
|
||||||
|
|
||||||
# Retry without comment matches if the kernel is missing the comment module
|
|
||||||
SANITIZED_FILE="$(mktemp)"
|
|
||||||
sed -E 's/-m[[:space:]]+comment[[:space:]]+--comment[[:space:]]+"[^"]*"//g' "${RULES_FILE}" > "${SANITIZED_FILE}"
|
|
||||||
|
|
||||||
retry_output=""
|
|
||||||
if retry_output="$(${REAL_IP6TABLES_RESTORE} "$@" < "${SANITIZED_FILE}" 2>&1)"; then
|
|
||||||
printf '%s\n' "ip6tables-restore failed with comment matches; reapplied without comments." >&2
|
|
||||||
printf '%s\n' "Original error: ${output}" >&2
|
|
||||||
[[ -n "${retry_output}" ]] && printf '%s\n' "${retry_output}" >&2
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
retry_status=$?
|
|
||||||
|
|
||||||
# Final fallback: try legacy backend if available
|
|
||||||
legacy_output=""
|
|
||||||
for legacy in /sbin/ip6tables-restore-legacy /usr/sbin/ip6tables-restore-legacy; do
|
|
||||||
if [[ -x "${legacy}" ]]; then
|
|
||||||
if legacy_output="$(${legacy} "$@" < "${RULES_FILE}" 2>&1)"; then
|
|
||||||
printf '%s\n' "ip6tables-restore failed; succeeded using legacy backend." >&2
|
|
||||||
printf '%s\n' "Original error: ${output}" >&2
|
|
||||||
[[ -n "${legacy_output}" ]] && printf '%s\n' "${legacy_output}" >&2
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
if ipv6_unavailable "${output}" || ipv6_unavailable "${retry_output}" || ipv6_unavailable "${legacy_output}"; then
|
|
||||||
printf '%s\n' "IPv6 firewall support not detected; skipping IPv6 ruleset restore and continuing." >&2
|
|
||||||
printf '%s\n' "Original error: ${output}" >&2
|
|
||||||
[[ -n "${retry_output}" ]] && printf '%s\n' "Sanitized retry error: ${retry_output}" >&2
|
|
||||||
[[ -n "${legacy_output}" ]] && printf '%s\n' "Legacy backend error: ${legacy_output}" >&2
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf '%s\n' "ip6tables-restore failed and fallbacks were unsuccessful." >&2
|
|
||||||
printf '%s\n' "Original error: ${output}" >&2
|
|
||||||
printf '%s\n' "Sanitized retry error: ${retry_output}" >&2
|
|
||||||
exit ${retry_status}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
REAL_IPTABLES_RESTORE="/sbin/iptables-restore"
|
|
||||||
if [[ ! -x "${REAL_IPTABLES_RESTORE}" ]]; then
|
|
||||||
REAL_IPTABLES_RESTORE="/usr/sbin/iptables-restore"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
local exit_code=$?
|
|
||||||
[[ -n "${RULES_FILE:-}" && -f "${RULES_FILE}" ]] && rm -f "${RULES_FILE}"
|
|
||||||
[[ -n "${SANITIZED_FILE:-}" && -f "${SANITIZED_FILE}" ]] && rm -f "${SANITIZED_FILE}"
|
|
||||||
return $exit_code
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
RULES_FILE="$(mktemp)"
|
|
||||||
cat > "${RULES_FILE}"
|
|
||||||
|
|
||||||
# First attempt with the original ruleset
|
|
||||||
if output="$(${REAL_IPTABLES_RESTORE} "$@" < "${RULES_FILE}" 2>&1)"; then
|
|
||||||
[[ -n "${output}" ]] && printf '%s\n' "${output}" >&2
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
status=$?
|
|
||||||
|
|
||||||
# Retry without comment matches if the kernel is missing the comment module
|
|
||||||
SANITIZED_FILE="$(mktemp)"
|
|
||||||
sed -E 's/-m[[:space:]]+comment[[:space:]]+--comment[[:space:]]+"[^"]*"//g' "${RULES_FILE}" > "${SANITIZED_FILE}"
|
|
||||||
|
|
||||||
if retry_output="$(${REAL_IPTABLES_RESTORE} "$@" < "${SANITIZED_FILE}" 2>&1)"; then
|
|
||||||
printf '%s\n' "iptables-restore failed with comment matches; reapplied without comments." >&2
|
|
||||||
printf '%s\n' "Original error: ${output}" >&2
|
|
||||||
[[ -n "${retry_output}" ]] && printf '%s\n' "${retry_output}" >&2
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
retry_status=$?
|
|
||||||
|
|
||||||
# Final fallback: try legacy backend if available
|
|
||||||
for legacy in /sbin/iptables-restore-legacy /usr/sbin/iptables-restore-legacy; do
|
|
||||||
if [[ -x "${legacy}" ]]; then
|
|
||||||
if legacy_output="$(${legacy} "$@" < "${RULES_FILE}" 2>&1)"; then
|
|
||||||
printf '%s\n' "iptables-restore failed; succeeded using legacy backend." >&2
|
|
||||||
printf '%s\n' "Original error: ${output}" >&2
|
|
||||||
[[ -n "${legacy_output}" ]] && printf '%s\n' "${legacy_output}" >&2
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
printf '%s\n' "iptables-restore failed and fallbacks were unsuccessful." >&2
|
|
||||||
printf '%s\n' "Original error: ${output}" >&2
|
|
||||||
printf '%s\n' "Sanitized retry error: ${retry_output}" >&2
|
|
||||||
exit ${retry_status}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
REAL_SYSCTL="/sbin/sysctl"
|
|
||||||
if [[ ! -x "${REAL_SYSCTL}" ]]; then
|
|
||||||
REAL_SYSCTL="/usr/sbin/sysctl"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$#" -ge 2 && "$1" == "-q" && "$2" == "net.ipv4.conf.all.src_valid_mark=1" ]]; then
|
|
||||||
if "${REAL_SYSCTL}" "$@" >/dev/null 2>&1; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
# Suppress failure for this specific key to keep wg-quick from aborting in unprivileged environments.
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "${REAL_SYSCTL}" "$@"
|
|
||||||
453
qbittorrent/rootfs/usr/local/sbin/vpn
Executable file
453
qbittorrent/rootfs/usr/local/sbin/vpn
Executable file
@@ -0,0 +1,453 @@
|
|||||||
|
#!/usr/bin/with-contenv bashio
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
# --- Common Functions ---
|
||||||
|
|
||||||
|
declare -A config
|
||||||
|
config["MySelf"]="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
|
||||||
|
|
||||||
|
declare -a dns_servers_ipv4=()
|
||||||
|
declare -a dns_servers_ipv6=()
|
||||||
|
|
||||||
|
_parse_config() {
|
||||||
|
local -n config_ref="$1"
|
||||||
|
local config_file="$2"
|
||||||
|
local line
|
||||||
|
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
# Skip comments and empty lines
|
||||||
|
[[ "$line" =~ ^[#!] ]] && continue
|
||||||
|
# Extract key and value using regex (trim spaces)
|
||||||
|
#if [[ "$line" =~ ^[[:space:]]*([^ =]+)[[:space:]]*=[[:space:]]*(.*)[[:space:]]* ]]; then
|
||||||
|
if [[ "$line" =~ ^[[:space:]]*([^=[:space:]]+)[=[:space:]]+(.*)[[:space:]]* ]]; then
|
||||||
|
local key="${BASH_REMATCH[1]}"
|
||||||
|
local value="${BASH_REMATCH[2]}"
|
||||||
|
config_ref["$key"]="$value"
|
||||||
|
fi
|
||||||
|
done < "$config_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse_dns() {
|
||||||
|
local -a dns_conf=()
|
||||||
|
local -a dns_backup_ipv4=("8.8.8.8" "1.1.1.1")
|
||||||
|
local -a dns_backup_ipv6=("2001:4860:4860::8888" "2606:4700:4700::1111")
|
||||||
|
local dns_servers=$(bashio::config 'DNS_server')
|
||||||
|
|
||||||
|
mapfile -d ',' -t dns_conf < <(echo "${dns_servers}" | tr -d ' ' | tr -d '\n')
|
||||||
|
if [ ${config["IPv4Enabled"]} = "true" ]; then
|
||||||
|
for dns_ip in "${dns_conf[@]}"; do
|
||||||
|
local result=0
|
||||||
|
_check_host "${dns_ip}" || result=$?
|
||||||
|
if [ "${result}" -eq 1 ]; then
|
||||||
|
dns_servers_ipv4+=("${dns_ip}")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ ${#dns_servers_ipv4[@]} -eq 0 ]; then
|
||||||
|
bashio::log.warning "No valid IPv4 DNS servers configured. Using addon defaults ${dns_backup_ipv4[@]}"
|
||||||
|
dns_servers_ipv4=("${dns_backup_ipv4[@]}")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ ${config["IPv6Enabled"]} = "true" ]; then
|
||||||
|
for dns_ip in "${dns_conf[@]}"; do
|
||||||
|
local result=0
|
||||||
|
_check_host "${dns_ip}" || result=$?
|
||||||
|
if [ "${result}" -eq 2 ]; then
|
||||||
|
dns_servers_ipv6+=("${dns_ip}")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ ${#dns_servers_ipv6[@]} -eq 0 ]; then
|
||||||
|
bashio::log.warning "No valid IPv6 DNS servers configured. Using addon defaults ${dns_backup_ipv6[@]}"
|
||||||
|
dns_servers_ipv6=("${dns_backup_ipv6[@]}")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_cmd() {
|
||||||
|
cmd="$1"
|
||||||
|
bashio::log.debug "Executing command: ${cmd}"
|
||||||
|
eval "${cmd}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_check_host() {
|
||||||
|
if ipcalc -c -4 "$1" >/dev/null 2>&1; then
|
||||||
|
return 1 # IPv4
|
||||||
|
elif ipcalc -c -6 "$1" >/dev/null 2>&1; then
|
||||||
|
return 2 # IPv6
|
||||||
|
elif getent ahosts "$1" >/dev/null 2>&1; then
|
||||||
|
return 3 # resolvable hostnamee
|
||||||
|
else
|
||||||
|
return 0 # neither IP nor resolvable hostname
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_resolvconf() {
|
||||||
|
local mode=$1
|
||||||
|
local resolv_conf="/etc/resolv.conf"
|
||||||
|
local resolv_backup="/etc/resolv.conf.bak"
|
||||||
|
|
||||||
|
if [ "${mode}" = "reset" ]; then
|
||||||
|
bashio::log.info "Resetting ${resolv_conf} to default DNS servers."
|
||||||
|
if bashio::fs.file_exists "${resolv_backup}"; then
|
||||||
|
cp "${resolv_backup}" "${resolv_conf}"
|
||||||
|
else
|
||||||
|
bashio::log.warning "No original resolv.conf backup found. Leaving as is."
|
||||||
|
fi
|
||||||
|
elif [ "${mode}" = "update" ]; then
|
||||||
|
bashio::log.info "Updating ${resolv_conf} with VPN DNS servers."
|
||||||
|
if ! bashio::fs.file_exists "${resolv_backup}"; then
|
||||||
|
bashio::log.debug "Creating backup of original resolv.conf at ${resolv_backup}"
|
||||||
|
cp "${resolv_conf}" "${resolv_backup}" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
bashio::log.debug "Updating ${resolv_conf} with DNS servers: ${dns_servers_ipv4[*]} ${dns_servers_ipv6[*]}"
|
||||||
|
{
|
||||||
|
echo "# Generated by vpn script"
|
||||||
|
local dns_ip
|
||||||
|
for dns_ip in ${dns_servers_ipv4[@]} ${dns_servers_ipv6[@]}; do
|
||||||
|
echo "nameserver ${dns_ip}"
|
||||||
|
done
|
||||||
|
} > "${resolv_conf}"
|
||||||
|
else
|
||||||
|
bashio::exit.nok "Invalid resolvconf mode specified. Use 'update' or 'reset'."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_resolve_hostname() {
|
||||||
|
local hostname=$1
|
||||||
|
local -a ips=""
|
||||||
|
local -a ipv4_candidates=()
|
||||||
|
local -a ipv6_candidates=()
|
||||||
|
|
||||||
|
# Resolve hostname to IPv6
|
||||||
|
mapfile -t ipv6_candidates < <(getent ahostsv6 "${hostname}" | awk '{print $1}' | uniq)
|
||||||
|
|
||||||
|
# Resolve hostname to IPv4
|
||||||
|
mapfile -t ipv4_candidates < <(getent ahostsv4 "${hostname}" | awk '{print $1}' | uniq)
|
||||||
|
|
||||||
|
if [ ${#ipv6_candidates[@]} -gt 0 ]; then
|
||||||
|
bashio::log.debug "Resolved ${hostname} to ${ipv6_candidates[@]}"
|
||||||
|
ips+=("${ipv6_candidates[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#ipv4_candidates[@]} -gt 0 ]; then
|
||||||
|
bashio::log.debug "Resolved ${hostname} to ${ipv4_candidates[@]}"
|
||||||
|
ips+=("${ipv4_candidates[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${ips[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_routing_add() {
|
||||||
|
bashio::log.info "Adding routing rules for VPN interface ${config["Interface"]}..."
|
||||||
|
|
||||||
|
local local_ipv4=$(ip addr show ${config["Interface"]} | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)
|
||||||
|
local local_ipv6=$(ip addr show ${config["Interface"]} | grep 'inet6 ' | awk '{print $2}' | cut -d'/' -f1)
|
||||||
|
local ipv4
|
||||||
|
local ipv6
|
||||||
|
|
||||||
|
# add routing rules for local IPs
|
||||||
|
for ipv4 in ${local_ipv4}; do
|
||||||
|
config["IPv4Enabled"]="true"
|
||||||
|
_cmd "ip -4 route add default dev ${config["Interface"]} table ${config["Table"]}" || return 1
|
||||||
|
_cmd "ip -4 rule add priority 1 from ${ipv4} table ${config["Table"]}" || return 1
|
||||||
|
done
|
||||||
|
for ipv6 in ${local_ipv6}; do
|
||||||
|
config["IPv6Enabled"]="true"
|
||||||
|
_cmd "ip -6 route add default dev ${config["Interface"]} table ${config["Table"]}" || return 1
|
||||||
|
_cmd "ip -6 rule add priority 1 from ${ipv6} table ${config["Table"]}" || return 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# get valid DNS servers
|
||||||
|
_parse_dns
|
||||||
|
|
||||||
|
# add routing rules for DNS servers
|
||||||
|
for dns_ip in "${dns_servers_ipv4[@]}"; do
|
||||||
|
#_cmd "ip -4 route add ${dns_ip} dev ${config["Interface"]}" || return 1
|
||||||
|
_cmd "ip -4 rule add priority 1 to ${dns_ip} table ${config["Table"]}" || return 1
|
||||||
|
done
|
||||||
|
for dns_ip in "${dns_servers_ipv6[@]}"; do
|
||||||
|
#_cmd "ip -6 route add ${dns_ip} dev ${config["Interface"]}" || return 1
|
||||||
|
_cmd "ip -6 rule add priority 1 to ${dns_ip} table ${config["Table"]}" || return 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Update resolv.conf with VPN DNS servers
|
||||||
|
_resolvconf "update"
|
||||||
|
}
|
||||||
|
|
||||||
|
_routing_del() {
|
||||||
|
bashio::log.info "Removing routing rules for VPN interface ${config["Interface"]}..."
|
||||||
|
|
||||||
|
_resolvconf "reset"
|
||||||
|
while _cmd "ip -4 rule del priority 1 from all table ${config["Table"]} 2>/dev/null"; do :; done
|
||||||
|
while _cmd "ip -4 rule del priority 1 to all table ${config["Table"]} 2>/dev/null"; do :; done
|
||||||
|
while _cmd "ip -4 route del default dev ${config["Interface"]} table ${config["Table"]} 2>/dev/null"; do :; done
|
||||||
|
while _cmd "ip -6 rule del priority 1 from all table ${config["Table"]} 2>/dev/null"; do :; done
|
||||||
|
while _cmd "ip -6 rule del priority 1 to all table ${config["Table"]} 2>/dev/null"; do :; done
|
||||||
|
while _cmd "ip -6 route del default dev ${config["Interface"]} table ${config["Table"]} 2>/dev/null"; do :; done
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- WireGuard Specific Logic ---
|
||||||
|
|
||||||
|
_wireguard_up() {
|
||||||
|
bashio::log.warning "This script force Wireguard to ignore any routes and DNS settings."
|
||||||
|
bashio::log.warning "Default route will be inserted into custom routing table: ${config["Table"]}"
|
||||||
|
bashio::log.warning "This routing table will be used for traffic from the VPN interface and to the configured DNS servers."
|
||||||
|
bashio::log.warning "Qbittorrent bittorrent client shall be set to use the VPN interface ${config["Interface"]} only."
|
||||||
|
|
||||||
|
for key in "Interface" "ListenPort" "PrivateKey" "PublicKey" "EndpointIP" "EndpointPort" ; do
|
||||||
|
if [ ! -v config[$key] ] || [ -z "${config[$key]}" ]; then
|
||||||
|
bashio::log.error "Missing required WireGuard configuration parameter: ${key}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
_cmd "ip link add ${config["Interface"]} type wireguard" || return 1
|
||||||
|
local allowed_ips=""
|
||||||
|
local -a local_ips=()
|
||||||
|
mapfile -d ',' -t local_ips < <(echo "${config["Address"]}" | tr -d ' ')
|
||||||
|
for local_ip in ${local_ips[@]}; do
|
||||||
|
local result=0
|
||||||
|
_check_host "${local_ip}" || result=$?
|
||||||
|
if [ "${result}" -eq 1 ]; then
|
||||||
|
allowed_ips="${allowed_ips},0.0.0.0/0"
|
||||||
|
_cmd "ip addr add ${local_ip} dev ${config["Interface"]}" || return 1
|
||||||
|
elif [ "${result}" -eq 2 ]; then
|
||||||
|
allowed_ips="${allowed_ips},::/0"
|
||||||
|
_cmd "ip addr add ${local_ip} dev ${config["Interface"]}" || return 1
|
||||||
|
else
|
||||||
|
bashio::log.warning "Ignoring invalid local IP address: ${local_ip}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
allowed_ips="${allowed_ips#,}"
|
||||||
|
if [ -z "${allowed_ips}" ]; then
|
||||||
|
bashio::log.error "No valid local IP addresses configured."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_cmd "wg set ${config["Interface"]} listen-port ${config["ListenPort"]} private-key ${config["PrivateKey"]}" || return 1
|
||||||
|
if [ -v config["PersistentKeepalive"] ] && [ -n "${config["PersistentKeepalive"]}" ]; then
|
||||||
|
_cmd "wg set ${config["Interface"]} peer ${config["PublicKey"]} endpoint ${config["EndpointIP"]}:${config["EndpointPort"]} allowed-ips ${allowed_ips} persistent-keepalive ${config["PersistentKeepalive"]}" || return 1
|
||||||
|
else
|
||||||
|
_cmd "wg set ${config["Interface"]} peer ${config["PublicKey"]} endpoint ${config["EndpointIP"]}:${config["EndpointPort"]} allowed-ips ${allowed_ips}" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -v config["MTU"] ] && [ -n "${config["MTU"]}" ]; then
|
||||||
|
_cmd "ip link set ${config["Interface"]} mtu ${config["MTU"]}" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_cmd "ip link set ${config["Interface"]} up" || return 1
|
||||||
|
_routing_add
|
||||||
|
}
|
||||||
|
|
||||||
|
_wireguard_down() {
|
||||||
|
_routing_del
|
||||||
|
_cmd "ip link set ${config["Interface"]} down" 2>/dev/null || true
|
||||||
|
_cmd "ip link del ${config["Interface"]}" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
wireguard() {
|
||||||
|
local mode=$1
|
||||||
|
local interface
|
||||||
|
local config_file
|
||||||
|
local WIREGUARD_STATE_DIR="/var/run/wireguard"
|
||||||
|
|
||||||
|
if ! bashio::fs.file_exists "${WIREGUARD_STATE_DIR}/interface"; then
|
||||||
|
bashio::exit.nok 'WireGuard runtime configuration not prepared. Please restart the add-on.'
|
||||||
|
fi
|
||||||
|
interface=$(cat "${WIREGUARD_STATE_DIR}/interface")
|
||||||
|
if [ -z "${interface}" ]; then
|
||||||
|
bashio::exit.nok 'WireGuard runtime configuration not prepared. Please restart the add-on.'
|
||||||
|
fi
|
||||||
|
if ! bashio::fs.file_exists "${WIREGUARD_STATE_DIR}/config"; then
|
||||||
|
bashio::exit.nok 'WireGuard runtime configuration not prepared. Please restart the add-on.'
|
||||||
|
fi
|
||||||
|
config_file=$(cat "${WIREGUARD_STATE_DIR}/config")
|
||||||
|
if [ -z "${config_file}" ]; then
|
||||||
|
bashio::exit.nok 'WireGuard runtime configuration not prepared. Please restart the add-on.'
|
||||||
|
fi
|
||||||
|
|
||||||
|
bashio::log.info "Using Wireguard configuration file: ${config_file}"
|
||||||
|
|
||||||
|
_parse_config config "${config_file}"
|
||||||
|
config["Interface"]="${interface}"
|
||||||
|
config["ConfigFile"]="${config_file}"
|
||||||
|
config["Table"]="${config["Table"]:-1000}"
|
||||||
|
config["ListenPort"]="${config["ListenPort"]:-51820}"
|
||||||
|
config["EndpointHost"]="${config["Endpoint"]%:*}"
|
||||||
|
config["EndpointPort"]="${config["Endpoint"]##*:}"
|
||||||
|
config["IPv4Enabled"]="false"
|
||||||
|
config["IPv6Enabled"]="false"
|
||||||
|
for key in "${!config[@]}"; do
|
||||||
|
bashio::log.debug "${key}: ${config[$key]}"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ${config["PrivateKey"]} > ${WIREGUARD_STATE_DIR}/privatekey
|
||||||
|
config["PrivateKey"]="${WIREGUARD_STATE_DIR}/privatekey"
|
||||||
|
|
||||||
|
if [ "${mode}" = "up" ]; then
|
||||||
|
bashio::log.info "Starting WireGuard on interface ${config["Interface"]}..."
|
||||||
|
local result=0
|
||||||
|
_check_host ${config["EndpointHost"]} || result=$?
|
||||||
|
if [ "${result}" -eq 0 ]; then
|
||||||
|
bashio::log.error "WireGuard endpoint ${config["EndpointHost"]} is neither a valid IP address nor a resolvable hostname."
|
||||||
|
bashio::exit.nok 'WireGuard start failed.'
|
||||||
|
elif [ "${result}" -eq 3 ]; then
|
||||||
|
local -a endpoint_ips=()
|
||||||
|
mapfile -d ' ' -t endpoint_ips < <(_resolve_hostname ${config["EndpointHost"]})
|
||||||
|
if [ ${#endpoint_ips[@]} -eq 0 ]; then
|
||||||
|
bashio::log.error "Failed to resolve WireGuard endpoint hostname: ${config["EndpointHost"]}"
|
||||||
|
bashio::exit.nok 'WireGuard start failed.'
|
||||||
|
fi
|
||||||
|
for endpoint_ip in "${endpoint_ips[@]}"; do
|
||||||
|
bashio::log.info "Resolved WireGuard endpoint hostname ${config["EndpointHost"]} to IP: ${endpoint_ip}"
|
||||||
|
config["EndpointIP"]="${endpoint_ip}"
|
||||||
|
if _wireguard_up; then
|
||||||
|
bashio::log.info "WireGuard interface ${config["Interface"]} is up."
|
||||||
|
bashio::exit.ok 'WireGuard started.'
|
||||||
|
fi
|
||||||
|
bashio::log.error 'WireGuard failed to establish connection.'
|
||||||
|
_wireguard_down
|
||||||
|
done
|
||||||
|
else
|
||||||
|
bashio::log.debug "WireGuard endpoint ${config["EndpointHost"]} is a valid IP address. Using as is."
|
||||||
|
config["EndpointIP"]="${config["EndpointHost"]}"
|
||||||
|
if _wireguard_up; then
|
||||||
|
bashio::log.info "WireGuard interface ${config["Interface"]} is up."
|
||||||
|
bashio::exit.ok 'WireGuard started.'
|
||||||
|
fi
|
||||||
|
bashio::log.error 'WireGuard failed to establish connection.'
|
||||||
|
_wireguard_down
|
||||||
|
fi
|
||||||
|
elif [ "${mode}" = "down" ]; then
|
||||||
|
bashio::log.info "Stopping WireGuard on interface ${config["Interface"]}..."
|
||||||
|
_wireguard_down
|
||||||
|
bashio::log.info "WireGuard on interface ${config["Interface"]} is down."
|
||||||
|
bashio::exit.ok 'WireGuard stopped.'
|
||||||
|
else
|
||||||
|
bashio::log.error "Invalid WireGuard mode specified. Use 'up' or 'down'."
|
||||||
|
bashio::exit.nok 'WireGuard start failed.'
|
||||||
|
fi
|
||||||
|
|
||||||
|
bashio::exit.nok 'WireGuard start failed.'
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- OpenVPN Specific Logic ---
|
||||||
|
|
||||||
|
_openvpn_up() {
|
||||||
|
bashio::log.warning "This script force OpenvPN to ignore any routes and DNS settings pushed by the server."
|
||||||
|
bashio::log.warning "Default route will be inserted into custom routing table: ${config["Table"]}"
|
||||||
|
bashio::log.warning "This routing table will be used for traffic from the VPN interface and to the configured DNS servers."
|
||||||
|
bashio::log.warning "Qbittorrent bittorrent client shall be set to use the VPN interface ${config["Interface"]} only."
|
||||||
|
|
||||||
|
# Register this script as OpenVPN up/down handlers to manage routing
|
||||||
|
echo '#!/bin/bash' > ${config["PostUpScript"]}
|
||||||
|
echo "${config["MySelf"]} openvpn postup" >> ${config["PostUpScript"]}
|
||||||
|
chmod 755 ${config["PostUpScript"]}
|
||||||
|
echo '#!/bin/bash' > ${config["PostDownScript"]}
|
||||||
|
echo "${config["MySelf"]} openvpn postdown" >> ${config["PostDownScript"]}
|
||||||
|
chmod 755 ${config["PostDownScript"]}
|
||||||
|
|
||||||
|
# Start OpenVPN in the background
|
||||||
|
_cmd "/usr/sbin/openvpn \
|
||||||
|
--config "${config["ConfigFile"]}" \
|
||||||
|
--client \
|
||||||
|
--daemon \
|
||||||
|
--log /dev/null \
|
||||||
|
--script-security 2 \
|
||||||
|
--auth-user-pass "${OPENVPN_STATE_DIR}/credentials.conf" \
|
||||||
|
--auth-retry none \
|
||||||
|
--up ${config["PostUpScript"]} \
|
||||||
|
--down ${config["PostDownScript"]} \
|
||||||
|
--up-delay \
|
||||||
|
--up-restart \
|
||||||
|
--route-nopull \
|
||||||
|
--route-noexec" || return 1
|
||||||
|
|
||||||
|
#wait for slow OpenVPN interface to come up
|
||||||
|
for i in {1..10}; do
|
||||||
|
if ip link show "${config["Interface"]}" > /dev/null 2>&1 ; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
bashio::log.error "OpenVPN interface ${config["Interface"]} failed to come up."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_openvpn_down() {
|
||||||
|
# Terminate OpenVPN process
|
||||||
|
pkill -f "openvpn --config ${config["ConfigFile"]}" || true
|
||||||
|
_routing_del
|
||||||
|
}
|
||||||
|
|
||||||
|
openvpn() {
|
||||||
|
local mode=$1
|
||||||
|
local interface
|
||||||
|
local config_file
|
||||||
|
local OPENVPN_STATE_DIR="/var/run/openvpn"
|
||||||
|
|
||||||
|
if ! bashio::fs.file_exists "${OPENVPN_STATE_DIR}/interface"; then
|
||||||
|
bashio::exit.nok 'OpenVPN runtime configuration not prepared. Please restart the add-on.'
|
||||||
|
fi
|
||||||
|
interface=$(cat "${OPENVPN_STATE_DIR}/interface")
|
||||||
|
if [ -z "${interface}" ]; then
|
||||||
|
bashio::exit.nok 'OpenVPN runtime configuration not prepared. Please restart the add-on.'
|
||||||
|
fi
|
||||||
|
if ! bashio::fs.file_exists "${OPENVPN_STATE_DIR}/config"; then
|
||||||
|
bashio::exit.nok 'OpenVPN runtime configuration not prepared. Please restart the add-on.'
|
||||||
|
fi
|
||||||
|
config_file=$(cat "${OPENVPN_STATE_DIR}/config")
|
||||||
|
if [ -z "${config_file}" ]; then
|
||||||
|
bashio::exit.nok 'OpenVPN runtime configuration not prepared. Please restart the add-on.'
|
||||||
|
fi
|
||||||
|
|
||||||
|
bashio::log.warning "Using OpenVPN configuration file: ${config_file}"
|
||||||
|
|
||||||
|
_parse_config config "${config_file}"
|
||||||
|
config["Interface"]="${interface}"
|
||||||
|
config["ConfigFile"]="${config_file}"
|
||||||
|
config["Table"]="${config["Table"]:-1000}"
|
||||||
|
config["PostUpScript"]="${OPENVPN_STATE_DIR}/up.sh"
|
||||||
|
config["PostDownScript"]="${OPENVPN_STATE_DIR}/down.sh"
|
||||||
|
|
||||||
|
if [ "${mode}" = "up" ]; then
|
||||||
|
# register up and down scripts
|
||||||
|
bashio::log.info "Starting OpenVPN on interface ${config["Interface"]}..."
|
||||||
|
if _openvpn_up; then
|
||||||
|
bashio::log.info "OpenVPN interface ${config["Interface"]} is up."
|
||||||
|
bashio::exit.ok 'OpenVPN started.'
|
||||||
|
fi
|
||||||
|
bashio::log.error 'OpenVPN failed to establish connection.'
|
||||||
|
_openvpn_down
|
||||||
|
elif [ "${mode}" = "down" ]; then
|
||||||
|
bashio::log.info "Stopping OpenVPN on interface ${config["Interface"]}..."
|
||||||
|
_openvpn_down
|
||||||
|
bashio::log.info "OpenVPN on interface ${config["Interface"]} is down."
|
||||||
|
bashio::exit.ok 'OpenVPN stopped.'
|
||||||
|
elif [ "${mode}" = "postup" ]; then
|
||||||
|
_routing_add
|
||||||
|
bashio::exit.ok 'OpenVPN routes added.'
|
||||||
|
elif [ "${mode}" = "postdown" ]; then
|
||||||
|
_routing_del
|
||||||
|
bashio::exit.ok 'OpenVPN routes deleted.'
|
||||||
|
else
|
||||||
|
bashio::log.error "Invalid OpenVPN mode specified. Use 'up', 'down', 'postup', or 'postdown'."
|
||||||
|
bashio::exit.nok 'OpenVPN start failed.'
|
||||||
|
fi
|
||||||
|
|
||||||
|
bashio::exit.nok 'OpenVPN start failed.'
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Entry Point ---
|
||||||
|
|
||||||
|
if [ $# -ne 2 ]; then
|
||||||
|
bashio::log.error "Invalid number of arguments. Usage: vpn.sh <wireguard|openvpn> <up|down>"
|
||||||
|
bashio::exit.nok 'VPN start failed.'
|
||||||
|
fi
|
||||||
|
if [[ "$1" == "wireguard" ]]; then
|
||||||
|
wireguard "$2"
|
||||||
|
elif [[ "$1" == "openvpn" ]]; then
|
||||||
|
openvpn "$2"
|
||||||
|
else
|
||||||
|
bashio::log.error "Invalid VPN type specified. Use 'wireguard' or 'openvpn'."
|
||||||
|
bashio::exit.nok 'VPN start failed.'
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user