mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-01-10 09:51:02 +01:00
Handle IPv6-less hosts in ip6tables shim
This commit is contained in:
@@ -1,5 +1,29 @@
|
||||
## 5.1.2-17 (20-11-2025)
|
||||
- FEAT: restore dual-stack WireGuard runtime configs so IPv6 peers work alongside IPv4.
|
||||
- FIX: add ip6tables-restore shim with comment-stripping and legacy fallbacks to match the IPv4 handling.
|
||||
|
||||
## 5.1.2-16 (19-11-2025)
|
||||
- FIX: add an iptables-restore shim that retries without comment matches and falls back to legacy backends when the host kernel lacks the comment module.
|
||||
|
||||
## 5.1.2-15 (19-11-2025)
|
||||
- FIX: strip IPv6 configuration from the WireGuard runtime file to avoid host environments without IPv6 firewall or sysctl support.
|
||||
- FIX: add a sysctl shim to suppress `net.ipv4.conf.all.src_valid_mark` permission failures from wg-quick.
|
||||
|
||||
## 5.1.2-14 (19-11-2025)
|
||||
- FIX: detect missing IPv6 nat/comment modules and fall back to IPv4-only WireGuard configs to avoid ip6tables-restore failures.
|
||||
|
||||
## 5.1.2-13 (18-11-2025)
|
||||
- FIX: fall back to an IPv4-only WireGuard runtime config when the host is missing IPv6 firewall support to prevent ip6tables errors.
|
||||
- FIX: tighten WireGuard config file permissions to silence the "world accessible" warning from wg-quick.
|
||||
|
||||
## 5.1.2-12 (17-11-2025)
|
||||
- FIX: make the WireGuard resolvconf shim executable so WireGuard uses it instead of the upstream tool that fails with signature errors.
|
||||
- Added support for configuring extra environment variables via the `env_vars` add-on option alongside config.yaml. See https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2 for details.
|
||||
|
||||
## 5.1.2-8 (19-08-2025)
|
||||
- FEAT: add first-class WireGuard support with runtime validation and troubleshooting logs
|
||||
- FIX: allow WireGuard connections on arbitrary remote ports by removing the mandatory 51820/udp mapping check
|
||||
|
||||
## 5.1.2-7 (17-08-2025)
|
||||
- Minor bugs fixed
|
||||
## 5.1.2-6 (31-07-2025)
|
||||
|
||||
@@ -111,7 +111,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
|
||||
|
||||
# Manual apps
|
||||
ARG PACKAGES="wireguard-tools"
|
||||
ARG PACKAGES="wireguard-tools iptables ip6tables"
|
||||
|
||||
# Automatic apps & bashio
|
||||
ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_autoapps.sh" "/ha_autoapps.sh"
|
||||
|
||||
@@ -33,7 +33,7 @@ This addons has several configurable options :
|
||||
- [alternative webUI](https://github.com/qbittorrent/qBittorrent/wiki/List-of-known-alternate-WebUIs)
|
||||
- usage of ssl
|
||||
- ingress
|
||||
- optional openvpn support
|
||||
- optional OpenVPN or WireGuard support
|
||||
- allow setting specific DNS servers
|
||||
|
||||
## Configuration
|
||||
@@ -70,10 +70,16 @@ Network disk is mounted to `/mnt/<share_name>`. You need to map the exposed port
|
||||
| `openvpn_username` | str | | OpenVPN username |
|
||||
| `openvpn_password` | str | | OpenVPN password |
|
||||
| `openvpn_alt_mode` | bool | `false` | Bind at container level instead of app level |
|
||||
| `wireguard_enabled` | bool | `false` | Enable WireGuard tunnel |
|
||||
| `wireguard_config` | str | _(empty)_ | WireGuard config file name (in `/config/wireguard/`) |
|
||||
| `qbit_manage` | bool | `false` | Enable qBit Manage integration |
|
||||
| `run_duration` | str | | Run duration (e.g., `12h`, `5d`) |
|
||||
| `silent` | bool | `false` | Suppress debug messages |
|
||||
|
||||
### WireGuard Setup
|
||||
|
||||
WireGuard configuration files must be stored in `/config/wireguard`. If several `.conf` files are present, set `wireguard_config` to the file name you want to use (for example `wg0.conf`). Expose UDP port `51820` in the add-on options and forward it from your router only when your tunnel expects inbound peers (for example, site-to-site setups). Outbound-only commercial VPN providers usually do not require a mapped port. The runtime configuration now preserves both IPv4 and IPv6 entries, so you can use dual-stack WireGuard peers when your endpoint supports them.
|
||||
|
||||
### Example Configuration
|
||||
|
||||
```yaml
|
||||
@@ -93,6 +99,7 @@ networkdisks: "//192.168.1.100/downloads"
|
||||
cifsusername: "username"
|
||||
cifspassword: "password"
|
||||
openvpn_enabled: false
|
||||
wireguard_enabled: false
|
||||
```
|
||||
|
||||
### Mounting Drives
|
||||
@@ -167,6 +174,18 @@ Delete your nova3 folder in /config and restart qbittorrent
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>### WireGuard connection fails</summary>
|
||||
|
||||
- If your deployment expects inbound peers, verify that the UDP port exposed in the add-on options maps 51820/udp and is forwarded by your router. Skip this step for outbound-only commercial VPN providers.
|
||||
- Confirm that the selected configuration file in `/config/wireguard` matches the `wireguard_config` option (or that only one `.conf` file is present).
|
||||
- Check the add-on logs for the detailed `wg-quick` error message printed by the startup routine.
|
||||
- Hosts missing the iptables `comment` kernel module are automatically retried without comment matches and, when available, using the legacy iptables backend. Inspect the log for messages about these fallbacks if you see iptables-restore errors.
|
||||
- Dual-stack WireGuard peers are supported. If you see ip6tables-restore errors, confirm that your host provides IPv6 firewall support or adjust your configuration to match your environment.
|
||||
- The startup scripts suppress the `net.ipv4.conf.all.src_valid_mark` sysctl failure emitted by `wg-quick` on some hosts, so persistent errors in the logs typically point to configuration or connectivity issues.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>### Monitored folders (@FaliseDotCom)</summary>
|
||||
|
||||
|
||||
@@ -91,6 +91,8 @@ options:
|
||||
keyfile: privkey.pem
|
||||
qbit_manage: false
|
||||
ssl: false
|
||||
wireguard_enabled: false
|
||||
wireguard_config: ""
|
||||
whitelist: localhost,127.0.0.1,172.30.0.0/16,192.168.0.0/16
|
||||
panel_admin: false
|
||||
panel_icon: mdi:progress-download
|
||||
@@ -137,8 +139,10 @@ schema:
|
||||
run_duration: str?
|
||||
silent: bool?
|
||||
ssl: bool
|
||||
wireguard_config: str?
|
||||
wireguard_enabled: bool?
|
||||
whitelist: str?
|
||||
slug: qbittorrent
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons
|
||||
version: 5.1.2-7
|
||||
version: 5.1.2-18
|
||||
|
||||
@@ -260,10 +260,14 @@ else
|
||||
# REMOVE OPENVPN #
|
||||
##################
|
||||
|
||||
# Ensure no redirection by removing the direction tag
|
||||
if [ -f "$QBT_CONFIG_FILE" ]; then
|
||||
sed -i '/Interface/d' "$QBT_CONFIG_FILE"
|
||||
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
|
||||
bashio::log.info "Direct connection without VPN enabled"
|
||||
|
||||
fi
|
||||
|
||||
86
qbittorrent/rootfs/etc/cont-init.d/94-wireguard.sh
Executable file
86
qbittorrent/rootfs/etc/cont-init.d/94-wireguard.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
WIREGUARD_STATE_DIR="/var/run/wireguard"
|
||||
QBT_CONFIG_FILE="/config/qBittorrent/qBittorrent.conf"
|
||||
declare wireguard_config=""
|
||||
declare wireguard_runtime_config=""
|
||||
declare configured_name
|
||||
|
||||
mkdir -p "${WIREGUARD_STATE_DIR}"
|
||||
|
||||
if ! bashio::config.true 'wireguard_enabled'; then
|
||||
rm -f "${WIREGUARD_STATE_DIR}/config" "${WIREGUARD_STATE_DIR}/interface"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if bashio::config.true 'openvpn_enabled'; then
|
||||
bashio::exit.nok 'OpenVPN and WireGuard cannot be enabled simultaneously. Disable one of them.'
|
||||
fi
|
||||
|
||||
if bashio::config.true 'openvpn_alt_mode'; then
|
||||
bashio::log.warning 'The openvpn_alt_mode option is ignored when WireGuard is enabled.'
|
||||
fi
|
||||
|
||||
port="$(bashio::addon.port '51820/udp' || true)"
|
||||
if bashio::var.has_value "${port}"; then
|
||||
bashio::log.info "WireGuard host port ${port}/udp mapped to container port 51820."
|
||||
else
|
||||
bashio::log.info 'WireGuard port 51820/udp is not exposed in the add-on options. Continuing with outbound-only connectivity.'
|
||||
fi
|
||||
|
||||
if bashio::config.has_value 'wireguard_config'; then
|
||||
configured_name="$(bashio::config 'wireguard_config')"
|
||||
configured_name="${configured_name##*/}"
|
||||
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
|
||||
mapfile -t configs < <(find /config/wireguard -maxdepth 1 -type f -name '*.conf' -print)
|
||||
if [ "${#configs[@]}" -eq 0 ]; then
|
||||
bashio::exit.nok 'WireGuard is enabled but no .conf file was found in /config/wireguard.'
|
||||
elif [ "${#configs[@]}" -eq 1 ]; then
|
||||
wireguard_config="${configs[0]}"
|
||||
bashio::log.info "WireGuard configuration not specified. Using ${wireguard_config##*/}."
|
||||
elif bashio::fs.file_exists '/config/wireguard/config.conf'; then
|
||||
wireguard_config='/config/wireguard/config.conf'
|
||||
bashio::log.info 'Using default WireGuard configuration config.conf.'
|
||||
else
|
||||
bashio::exit.nok "Multiple WireGuard configuration files detected. Please set the 'wireguard_config' option."
|
||||
fi
|
||||
fi
|
||||
|
||||
dos2unix "${wireguard_config}" >/dev/null 2>&1 || true
|
||||
|
||||
interface_name="$(basename "${wireguard_config}" .conf)"
|
||||
if [[ -z "${interface_name}" ]]; then
|
||||
interface_name='wg0'
|
||||
fi
|
||||
|
||||
wireguard_runtime_config="${WIREGUARD_STATE_DIR}/${interface_name}.conf"
|
||||
|
||||
cp "${wireguard_config}" "${wireguard_runtime_config}"
|
||||
chmod 600 "${wireguard_runtime_config}" 2>/dev/null || true
|
||||
bashio::log.info 'Prepared WireGuard runtime configuration with both IPv4 and IPv6 entries.'
|
||||
|
||||
echo "${wireguard_runtime_config}" > "${WIREGUARD_STATE_DIR}/config"
|
||||
echo "${interface_name}" > "${WIREGUARD_STATE_DIR}/interface"
|
||||
|
||||
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 "WireGuard prepared with interface ${interface_name} using configuration ${wireguard_config##*/}."
|
||||
@@ -3,20 +3,67 @@
|
||||
|
||||
WEBUI_PORT=${WEBUI_PORT:-8080}
|
||||
|
||||
export PATH="/usr/local/sbin:/usr/local/bin:${PATH}"
|
||||
|
||||
if bashio::config.true 'silent'; then
|
||||
sed -i 's|/proc/1/fd/1 hassio;|off;|g' /etc/nginx/nginx.conf
|
||||
fi
|
||||
|
||||
if bashio::config.true 'openvpn_enabled'; then
|
||||
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"
|
||||
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"
|
||||
else
|
||||
########################################################
|
||||
# DRAFT : Start wireguard if needed
|
||||
if bashio::config.true 'wireguard_enabled'; then
|
||||
wg-quick up /config/wireguard/config.conf &
|
||||
true
|
||||
WIREGUARD_STATE_DIR="/var/run/wireguard"
|
||||
|
||||
if ! bashio::fs.file_exists "${WIREGUARD_STATE_DIR}/config"; then
|
||||
bashio::exit.nok 'WireGuard runtime configuration not prepared. Please restart the add-on.'
|
||||
fi
|
||||
|
||||
wireguard_config="$(cat "${WIREGUARD_STATE_DIR}/config")"
|
||||
wireguard_interface="$(cat "${WIREGUARD_STATE_DIR}/interface" 2>/dev/null || echo 'wg0')"
|
||||
|
||||
if ip link show "${wireguard_interface}" &> /dev/null; then
|
||||
bashio::log.warning "WireGuard interface ${wireguard_interface} already exists. Attempting to reset it."
|
||||
wg-quick down "${wireguard_config}" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
bashio::log.info "Starting WireGuard interface ${wireguard_interface} using ${wireguard_config##*/}."
|
||||
|
||||
if ! output=$(wg-quick up "${wireguard_config}" 2>&1); then
|
||||
bashio::log.error 'WireGuard failed to establish a connection.'
|
||||
bashio::log.error "wg-quick output:"
|
||||
bashio::log.error "${output}"
|
||||
bashio::log.error 'Troubleshooting steps:'
|
||||
bashio::log.error " 1. Confirm that the WireGuard configuration file '${wireguard_config}' exists inside the container and contains valid private/public keys, endpoint and AllowedIPs."
|
||||
bashio::log.error ' 2. Ensure UDP port 51820 (or the port defined in your config) is forwarded on your router to this host and not blocked by your firewall or ISP.'
|
||||
bashio::log.error ' 3. Verify that the configured endpoint (IP/hostname and port) is reachable from this container (e.g. ping or nc from a debug shell).'
|
||||
bashio::log.error ' 4. Check that the system time is correct (NTP); large time drift can break key handshakes.'
|
||||
bashio::log.error ' 5. Confirm that WireGuard kernel support / module is available in the host system.'
|
||||
bashio::log.error ' 6. If DNS names are used for the endpoint, verify DNS resolution from inside the container (e.g. nslookup or dig).'
|
||||
bashio::exit.nok 'WireGuard start failed. See the log above for details.'
|
||||
fi
|
||||
|
||||
bashio::log.info "WireGuard interface ${wireguard_interface} is up."
|
||||
|
||||
# Refresh DNS resolver configuration if resolvconf is present
|
||||
if command -v resolvconf >/dev/null 2>&1; then
|
||||
bashio::log.info 'Refreshing DNS resolver configuration via resolvconf -u.'
|
||||
if ! resolvconf -u >/dev/null 2>&1; then
|
||||
bashio::log.warning 'resolvconf -u failed. DNS configuration may not have been updated.'
|
||||
fi
|
||||
else
|
||||
bashio::log.debug 'resolvconf not found in PATH; skipping DNS refresh.'
|
||||
fi
|
||||
fi
|
||||
########################################################
|
||||
|
||||
if bashio::config.true 'silent'; then
|
||||
exec \
|
||||
|
||||
@@ -13,7 +13,10 @@ if [ -f /currentip ]; then
|
||||
nginx || nginx -s reload &
|
||||
while true; do
|
||||
# Get vpn ip
|
||||
if ! bashio::config.true 'wireguard_enabled' && bashio::config.true 'openvpn_alt_mode'; then
|
||||
if bashio::config.true 'wireguard_enabled'; then
|
||||
wireguard_interface="$(cat /var/run/wireguard/interface 2>/dev/null || echo 'wg0')"
|
||||
curl -s ipecho.net/plain --interface "${wireguard_interface}" > /vpnip
|
||||
elif bashio::config.true 'openvpn_alt_mode'; then
|
||||
curl -s ipecho.net/plain > /vpnip
|
||||
else
|
||||
curl -s ipecho.net/plain --interface tun0 > /vpnip
|
||||
|
||||
86
qbittorrent/rootfs/usr/local/bin/resolvconf
Executable file
86
qbittorrent/rootfs/usr/local/bin/resolvconf
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/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
|
||||
73
qbittorrent/rootfs/usr/local/sbin/ip6tables-restore
Executable file
73
qbittorrent/rootfs/usr/local/sbin/ip6tables-restore
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/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() {
|
||||
[[ -n "${RULES_FILE:-}" && -f "${RULES_FILE}" ]] && rm -f "${RULES_FILE}"
|
||||
[[ -n "${SANITIZED_FILE:-}" && -f "${SANITIZED_FILE}" ]] && rm -f "${SANITIZED_FILE}"
|
||||
}
|
||||
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'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}
|
||||
52
qbittorrent/rootfs/usr/local/sbin/iptables-restore
Executable file
52
qbittorrent/rootfs/usr/local/sbin/iptables-restore
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/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() {
|
||||
[[ -n "${RULES_FILE:-}" && -f "${RULES_FILE}" ]] && rm -f "${RULES_FILE}"
|
||||
[[ -n "${SANITIZED_FILE:-}" && -f "${SANITIZED_FILE}" ]] && rm -f "${SANITIZED_FILE}"
|
||||
}
|
||||
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}
|
||||
17
qbittorrent/rootfs/usr/local/sbin/sysctl
Executable file
17
qbittorrent/rootfs/usr/local/sbin/sysctl
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/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}" "$@"
|
||||
Reference in New Issue
Block a user