From b064eba78c1d1d69dfc789fac84ee4ec85217d26 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 3 Nov 2026 22:44:23 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=81=20Sync=202026-11-03=2022:44:23?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cups/Makefile | 4 +- filebrowser-q/Makefile | 4 +- honk/Makefile | 39 ++--- honk/build_honk_core.sh | 164 ++++++++++++++++++ honk/honk_toolchain.sh | 73 ++++++++ .../htdocs/luci-static/resources/fchomo.js | 17 +- .../luci-static/resources/view/fchomo/node.js | 18 +- .../resources/view/firewall/zones.js | 10 ++ luci-app-firewall/po/zh_Hans/firewall.po | 9 + luci-app-ssr-plus/Makefile | 3 +- .../model/cbi/shadowsocksr/client-config.lua | 94 +++++++++- .../usr/share/shadowsocksr/gen_config.lua | 46 ++++- ooniprobe/Makefile | 4 +- 13 files changed, 428 insertions(+), 57 deletions(-) create mode 100755 honk/build_honk_core.sh create mode 100755 honk/honk_toolchain.sh diff --git a/cups/Makefile b/cups/Makefile index aad42c5b2..d4fa93c63 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -9,8 +9,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=cups -PKG_VERSION:=2.3.3op2 -PKG_RELEASE:=6 +PKG_VERSION:=2.4.20 +PKG_RELEASE:=7 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-source.tar.gz PKG_SOURCE_URL:=https://github.com/OpenPrinting/cups/releases/download/v$(PKG_VERSION) PKG_MD5SUM:=skip diff --git a/filebrowser-q/Makefile b/filebrowser-q/Makefile index fcb9039ab..0406ef6fe 100644 --- a/filebrowser-q/Makefile +++ b/filebrowser-q/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=filebrowser-q -PKG_VERSION:=1.5.6-stable -PKG_RELEASE:=12 +PKG_VERSION:=2.0.2-stable +PKG_RELEASE:=13 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/gtsteffaniak/filebrowser/tar.gz/v$(PKG_VERSION)? diff --git a/honk/Makefile b/honk/Makefile index 76669cfa6..9f6b1ae92 100644 --- a/honk/Makefile +++ b/honk/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=honk PKG_VERSION:=2026.11.03~77176ff -PKG_RELEASE:=27 +PKG_RELEASE:=28 HONK_SRC_URL:=https://github.com/daeuniverse/honk.git HONK_SRC_VERSION:=77176ff8e8cc2b75385a7030dc376536c382574a @@ -55,36 +55,31 @@ define Package/honk/conffiles endef define Build/Prepare - mkdir -p $(PKG_BUILD_DIR) + mkdir -p "$(PKG_BUILD_DIR)" endef define Build/Compile - @if [ -f $(CURDIR)/files/honk-core.bin ]; then \ - $(INSTALL_DIR) $(PKG_INSTALL_DIR)/bin; \ - $(INSTALL_BIN) $(CURDIR)/files/honk-core.bin $(PKG_INSTALL_DIR)/bin/honk-core; \ - else \ - echo "ERROR: $(CURDIR)/files/honk-core.bin missing!" >&2; \ - echo "Compile it first via: ./scripts/build_honk_core.sh " >&2; \ - exit 1; \ - fi + "$(CURDIR)/build_honk_core.sh" --if-needed "$(ARCH)" "$(CURDIR)/files/honk-core.bin" + $(INSTALL_DIR) "$(PKG_INSTALL_DIR)/bin" + $(INSTALL_BIN) "$(CURDIR)/files/honk-core.bin" "$(PKG_INSTALL_DIR)/bin/honk-core" endef define Package/honk/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/bin/honk-core $(1)/usr/bin/honk-core + $(INSTALL_DIR) "$(1)/usr/bin" + $(INSTALL_BIN) "$(PKG_INSTALL_DIR)/bin/honk-core" "$(1)/usr/bin/honk-core" - $(INSTALL_DIR) $(1)/etc/honk/config.d - $(INSTALL_CONF) $(CURDIR)/files/config.dae $(1)/etc/honk/config.dae - $(INSTALL_CONF) $(CURDIR)/files/config.d/node.dae $(1)/etc/honk/config.d/node.dae - $(INSTALL_CONF) $(CURDIR)/files/config.d/route.dae $(1)/etc/honk/config.d/route.dae - $(INSTALL_CONF) $(CURDIR)/files/config.d/dns.dae $(1)/etc/honk/config.d/dns.dae - $(INSTALL_CONF) $(CURDIR)/files/config.d/api.dae $(1)/etc/honk/config.d/api.dae + $(INSTALL_DIR) "$(1)/etc/honk/config.d" + $(INSTALL_CONF) "$(CURDIR)/files/config.dae" "$(1)/etc/honk/config.dae" + $(INSTALL_CONF) "$(CURDIR)/files/config.d/node.dae" "$(1)/etc/honk/config.d/node.dae" + $(INSTALL_CONF) "$(CURDIR)/files/config.d/route.dae" "$(1)/etc/honk/config.d/route.dae" + $(INSTALL_CONF) "$(CURDIR)/files/config.d/dns.dae" "$(1)/etc/honk/config.d/dns.dae" + $(INSTALL_CONF) "$(CURDIR)/files/config.d/api.dae" "$(1)/etc/honk/config.d/api.dae" - $(INSTALL_DIR) $(1)/etc/config - $(INSTALL_CONF) $(CURDIR)/files/honk.config $(1)/etc/config/honk + $(INSTALL_DIR) "$(1)/etc/config" + $(INSTALL_CONF) "$(CURDIR)/files/honk.config" "$(1)/etc/config/honk" - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_BIN) $(CURDIR)/files/honk.init $(1)/etc/init.d/honk + $(INSTALL_DIR) "$(1)/etc/init.d" + $(INSTALL_BIN) "$(CURDIR)/files/honk.init" "$(1)/etc/init.d/honk" endef $(eval $(call BuildPackage,honk)) diff --git a/honk/build_honk_core.sh b/honk/build_honk_core.sh new file mode 100755 index 000000000..8a3ef4c0e --- /dev/null +++ b/honk/build_honk_core.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash +# Build honk-core for an OpenWrt arch/target triple. +# +# ./honk/build_honk_core.sh [--if-needed] [output_file] [source_dir] +# +# --if-needed: skip when the output exists and its .stamp matches the target +# (or has no stamp, i.e. a prebuilt artifact); rebuild on a target mismatch. +set -euo pipefail + +IF_NEEDED=0 +while [ $# -gt 0 ]; do + case "$1" in + --if-needed) IF_NEEDED=1; shift ;; + *) break ;; + esac +done + +TARGET_IN="${1:?usage: $0 [--if-needed] [output_file] [source_dir]}" +OUT_FILE="${2:-}" +SRC_DIR="${3:-}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [ -f "${HOME:-}/.cargo/env" ]; then + . "${HOME:-}/.cargo/env" +fi +export PATH="${HOME:-}/.cargo/bin:/usr/local/bin:/usr/bin:/bin:${PATH:-}" + +case "$TARGET_IN" in + x86_64|x86_64-unknown-linux-musl) + RUST_TARGET=x86_64-unknown-linux-musl + ZIG_TARGET=x86_64-linux-musl + ;; + aarch64|aarch64_generic|aarch64-unknown-linux-musl) + RUST_TARGET=aarch64-unknown-linux-musl + ZIG_TARGET=aarch64-linux-musl + ;; + *) + echo "ERROR: unsupported arch: $TARGET_IN" >&2 + exit 1 + ;; +esac + +OUT_FILE="${OUT_FILE:-$SCRIPT_DIR/files/honk-core.bin}" +case "$OUT_FILE" in + /*) ;; + *) OUT_FILE="$PWD/$OUT_FILE" ;; +esac + +if [ "$IF_NEEDED" = 1 ] && [ -f "$OUT_FILE" ]; then + if [ ! -f "$OUT_FILE.stamp" ]; then + echo "==> using prebuilt honk-core (no stamp): $OUT_FILE" + exit 0 + fi + if [ "$(cat "$OUT_FILE.stamp")" = "$RUST_TARGET" ]; then + echo "==> honk-core is up to date: $OUT_FILE" + exit 0 + fi + echo "==> honk-core target changed, rebuilding: $OUT_FILE" +fi + +# Building: drop the old artifact so a failed build cannot be reused. +rm -f "$OUT_FILE" "$OUT_FILE.stamp" + +MAKEFILE="${HONK_MAKEFILE:-$SCRIPT_DIR/Makefile}" +if [ -n "$SRC_DIR" ]; then + eval "$("$SCRIPT_DIR/honk_toolchain.sh" --src "$SRC_DIR" "$MAKEFILE")" +else + eval "$("$SCRIPT_DIR/honk_toolchain.sh" "$MAKEFILE")" + SRC_DIR="$SCRIPT_DIR/honk-src" + CACHED_REV=$(git -C "$SRC_DIR" rev-parse HEAD 2>/dev/null || true) + if [ -d "$SRC_DIR/crates/honk-core" ] && [ "$CACHED_REV" = "$HONK_SRC_VERSION" ]; then + echo "==> Reusing $SRC_DIR at ${HONK_SRC_VERSION}" + else + if [ -n "$CACHED_REV" ]; then + echo "==> honk-src is at ${CACHED_REV}, expected ${HONK_SRC_VERSION}; refetching..." + fi + rm -rf "$SRC_DIR" + echo "==> Fetching honk source (${HONK_SRC_URL} @ ${HONK_SRC_VERSION})..." + git init -q "$SRC_DIR" + git -C "$SRC_DIR" remote add origin "$HONK_SRC_URL" + git -C "$SRC_DIR" fetch --depth 1 origin "$HONK_SRC_VERSION" + git -C "$SRC_DIR" checkout -q --detach FETCH_HEAD + fi +fi + +SRC_DIR="$(cd "$SRC_DIR" && pwd)" +echo "==> Source: $SRC_DIR" +echo "==> Target: $RUST_TARGET (zig: $ZIG_TARGET)" + +command -v zig >/dev/null 2>&1 || { echo "ERROR: zig not found in PATH" >&2; exit 1; } +command -v bpf-linker >/dev/null 2>&1 || { echo "ERROR: bpf-linker not found in PATH" >&2; exit 1; } +command -v cargo >/dev/null 2>&1 || { echo "ERROR: cargo not found in PATH" >&2; exit 1; } + +ZIG_ACTUAL="$(zig version)" +if [ "$ZIG_ACTUAL" != "$ZIG_VERSION" ]; then + echo "ERROR: zig ${ZIG_ACTUAL} does not match the honk pin ${ZIG_VERSION}" >&2 + exit 1 +fi +echo "==> zig ${ZIG_ACTUAL}" + +# bpf-linker 0.11.0 reports 0.0.0; its tarball is checked by sha256 at install time. +echo "==> $(bpf-linker --version 2>/dev/null | head -n 1)" + +cd "$SRC_DIR" +EBPF_CHANNEL=$(sed -n 's/^channel[[:space:]]*=[[:space:]]*"\(.*\)"/\1/p' crates/honk-ebpf/rust-toolchain.toml 2>/dev/null | head -n 1) +EBPF_CHANNEL="${EBPF_CHANNEL:-nightly}" + +if command -v rustup >/dev/null 2>&1; then + rustup target add "$RUST_TARGET" + rustup toolchain install "$EBPF_CHANNEL" --component rust-src,llvm-tools +fi + +echo "==> Building honk-ebpf object..." +( + cd crates/honk-ebpf + cargo "+${EBPF_CHANNEL}" build --release -Zbuild-std=core --target bpfel-unknown-none +) + +EBPF_OBJ="crates/honk-ebpf/target/bpfel-unknown-none/release/honk-ebpf" +[ -f "$EBPF_OBJ" ] || { echo "ERROR: eBPF object not found at $EBPF_OBJ" >&2; exit 1; } +if command -v readelf >/dev/null 2>&1; then + readelf -S "$EBPF_OBJ" | grep -q '\.BTF' || { echo "ERROR: $EBPF_OBJ has no .BTF section" >&2; exit 1; } +fi + +export ZIGCC_TARGET="$ZIG_TARGET" +L=$(printf '%s' "$RUST_TARGET" | tr '-' '_') +U=$(printf '%s' "$RUST_TARGET" | tr 'a-z-' 'A-Z_') +export "CC_${L}=$SRC_DIR/ci/zigcc" +export "CXX_${L}=$SRC_DIR/ci/zigcxx" +export "CARGO_TARGET_${U}_LINKER=$SRC_DIR/ci/zigcc" +if [[ "$RUST_TARGET" == *-musl ]]; then + export "CARGO_TARGET_${U}_RUSTFLAGS=-C link-self-contained=no" +fi +export BINDGEN_EXTRA_CLANG_ARGS="$("$SRC_DIR/ci/zig-bindgen-env" "$ZIGCC_TARGET")" + +echo "==> Building honk-core for $RUST_TARGET..." +cargo build --release --locked \ + -p honk-core \ + --no-default-features \ + --features ebpf,rprx,clash-api,native-api,mimalloc \ + --target "$RUST_TARGET" + +BUILT_BIN="$SRC_DIR/target/$RUST_TARGET/release/honk-core" +[ -f "$BUILT_BIN" ] || { echo "ERROR: expected output not found at $BUILT_BIN" >&2; exit 1; } + +FILE_DESC=$(file -b "$BUILT_BIN") +case "$FILE_DESC" in + ELF*) ;; + *) echo "ERROR: output is not an ELF binary: $FILE_DESC" >&2; exit 1 ;; +esac +if [[ "$RUST_TARGET" == *-musl ]] && [[ "$FILE_DESC" != *"statically linked"* ]]; then + echo "ERROR: $RUST_TARGET binary is not statically linked: $FILE_DESC" >&2 + exit 1 +fi + +mkdir -p "$(dirname "$OUT_FILE")" +cp -f "$BUILT_BIN" "$OUT_FILE" +chmod +x "$OUT_FILE" +printf '%s\n' "$RUST_TARGET" > "$OUT_FILE.stamp" + +echo "==> Build succeeded: $OUT_FILE" +echo "==> $FILE_DESC" +ls -lh "$OUT_FILE" diff --git a/honk/honk_toolchain.sh b/honk/honk_toolchain.sh new file mode 100755 index 000000000..fd3fa1d2d --- /dev/null +++ b/honk/honk_toolchain.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# Resolve the toolchain pins for the honk commit pinned by the package Makefile. +# +# ./honk/honk_toolchain.sh [--src DIR] [Makefile] +# +# Prints HONK_SRC_URL / HONK_SRC_VERSION plus BPF_LINKER_VERSION / SHA256 and +# ZIG_VERSION, read from that commit's .github/ci/pins.env and release.yml (or +# from --src when the source is already checked out). +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +SRC_DIR="" +MAKEFILE="" +while [ $# -gt 0 ]; do + case "$1" in + --src) SRC_DIR="${2:?--src needs a directory}"; shift 2 ;; + *) MAKEFILE="$1"; shift ;; + esac +done +MAKEFILE="${MAKEFILE:-${HONK_MAKEFILE:-$SCRIPT_DIR/Makefile}}" + +[ -f "$MAKEFILE" ] || { echo "ERROR: Makefile not found: $MAKEFILE" >&2; exit 1; } + +URL=$(sed -n 's/^[[:space:]]*HONK_SRC_URL:=//p' "$MAKEFILE" | head -n 1) +REV=$(sed -n 's/^[[:space:]]*HONK_SRC_VERSION:=//p' "$MAKEFILE" | head -n 1) +[ -n "$URL" ] && [ -n "$REV" ] || { + echo "ERROR: HONK_SRC_URL / HONK_SRC_VERSION missing in $MAKEFILE" >&2 + exit 1 +} + +if [ -n "$SRC_DIR" ]; then + SRC_DIR="$(cd "$SRC_DIR" && pwd)" + PINS_FILE="$SRC_DIR/.github/ci/pins.env" + RELEASE_FILE="$SRC_DIR/.github/workflows/release.yml" + [ -f "$PINS_FILE" ] && [ -f "$RELEASE_FILE" ] || { + echo "ERROR: $SRC_DIR is not a honk checkout with .github metadata" >&2 + exit 1 + } +else + REPO_PATH="${URL#https://github.com/}" + REPO_PATH="${REPO_PATH%.git}" + RAW="https://raw.githubusercontent.com/${REPO_PATH}/${REV}" + fetch() { + curl -fsSL --retry 3 "$1" || { echo "ERROR: failed to fetch $1" >&2; exit 1; } + } + PINS_FILE="$(mktemp)" + RELEASE_FILE="$(mktemp)" + trap 'rm -f "$PINS_FILE" "$RELEASE_FILE"' EXIT + fetch "${RAW}/.github/ci/pins.env" > "$PINS_FILE" + fetch "${RAW}/.github/workflows/release.yml" > "$RELEASE_FILE" +fi + +BPF_LINKER_VERSION=$(sed -n 's/^BPF_LINKER_VERSION=//p' "$PINS_FILE" | head -n 1) +BPF_LINKER_SHA256=$(sed -n 's/^BPF_LINKER_SHA256=//p' "$PINS_FILE" | head -n 1) +[ -n "$BPF_LINKER_VERSION" ] && [ -n "$BPF_LINKER_SHA256" ] || { + echo "ERROR: BPF_LINKER_VERSION / BPF_LINKER_SHA256 missing in $PINS_FILE" >&2 + exit 1 +} + +ZIG_VERSION=$(awk ' + /setup-zig/ { seen = 1; next } + seen && /^[[:space:]]*version:[[:space:]]*/ { + sub(/^[[:space:]]*version:[[:space:]]*/, "") + gsub(/[[:space:]"]/, "") + print + exit + } +' "$RELEASE_FILE") +[ -n "$ZIG_VERSION" ] || { echo "ERROR: no setup-zig version in $RELEASE_FILE" >&2; exit 1; } + +printf 'HONK_SRC_URL=%s\nHONK_SRC_VERSION=%s\nBPF_LINKER_VERSION=%s\nBPF_LINKER_SHA256=%s\nZIG_VERSION=%s\n' \ + "$URL" "$REV" "$BPF_LINKER_VERSION" "$BPF_LINKER_SHA256" "$ZIG_VERSION" diff --git a/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js b/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js index b5df3718b..1a98789f0 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js @@ -710,8 +710,8 @@ const CBITextValue = form.TextValue.extend({ const CBIGenValue = form.Value.extend({ __name__: 'CBI.GenValue', - renderWidget(/* ... */) { - let node = form.Value.prototype.renderWidget.apply(this, arguments); + renderWidget(section_id, option_index, cfgvalue) { + let node = form.Value.prototype.renderWidget.call(this, section_id, option_index, cfgvalue); if (!this.password) node.classList.add('control-group'); @@ -719,7 +719,7 @@ const CBIGenValue = form.Value.extend({ (node.querySelector('.control-group') || node).appendChild(E('button', { class: 'cbi-button cbi-button-add', title: _('Generate'), - click: ui.createHandlerFn(this, handleGenKey, this.hm_options || this.option) + click: ui.createHandlerFn(this, handleGenKey, section_id, this.hm_options || this.option) }, [ _('Generate') ])); return node; @@ -729,13 +729,13 @@ const CBIGenValue = form.Value.extend({ const CBIGenText = CBITextValue.extend({ __name__: 'CBI.GenText', - renderWidget(/* ... */) { - let node = CBITextValue.prototype.renderWidget.apply(this, arguments); + renderWidget(section_id, option_index, cfgvalue) { + let node = CBITextValue.prototype.renderWidget.call(this, section_id, option_index, cfgvalue); node.appendChild(E('button', { class: 'cbi-button cbi-button-add', title: _('Generate'), - click: ui.createHandlerFn(this, handleGenKey, this.hm_options || this.option) + click: ui.createHandlerFn(this, handleGenKey, section_id, this.hm_options || this.option) }, [ _('Generate') ])); return node; @@ -912,7 +912,7 @@ const CBIHandleImport = baseclass.extend(/** @lends hm.HandleImport.prototype */ return uci.save() .then(L.bind(this.map.load, this.map)) .then(L.bind(this.map.reset, this.map)) - .then(L.ui.hideModal) + .then(ui.hideModal) .catch(() => {}); }, @@ -1548,8 +1548,7 @@ function renderResLink(section_id) { return El; } -function handleGenKey(option) { - const section_id = this.section.section; +function handleGenKey(section_id, option) { const type = this.section.getOption('type')?.formvalue(section_id); const widget = L.bind(function(option) { return this.map.findElement('id', 'widget.' + this.cbid(section_id).replace(/\.[^\.]+$/, '.') + option); diff --git a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js index 8f3833ee0..a95ac116a 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js @@ -1653,7 +1653,7 @@ return view.extend({ const zerotier_listen_port = { load(section_id) { - const listen_port = this.map.data.get(this.section.config, section_id, 'zerotier_listen_port') || ''; + const listen_port = uci.get(this.section.config, section_id, 'zerotier_listen_port') || ''; const value = [ this.map.data.get(this.section.config, section_id, 'zerotier_primary_port'), this.map.data.get(this.section.config, section_id, 'zerotier_secondary_port') @@ -1661,13 +1661,12 @@ return view.extend({ if (listen_port != value) { uci.set(this.section.config, section_id, 'zerotier_listen_port', value); - return uci.save() - .then(L.bind(this.map.load, this.map)) + uci.save() .then(L.bind(this.map.reset, this.map)) .catch(() => {}); } - return form.Value.prototype.load.apply(this, arguments); + return this.super('load', section_id); }, write(section_id, formvalue) { @@ -1678,7 +1677,7 @@ return view.extend({ uci.set(this.section.config, section_id, 'zerotier_listen_port', value); - return form.Value.prototype[formvalue ? 'write' : 'remove'].apply(this, arguments); + return this.super(formvalue ? 'write' : 'remove', ...arguments); } }; @@ -1705,19 +1704,18 @@ return view.extend({ const easytier_listen_port = { load(section_id) { - const listen_port = this.map.data.get(this.section.config, section_id, 'easytier_listen_port') || ''; + const listen_port = uci.get(this.section.config, section_id, 'easytier_listen_port') || ''; const value = [...new Set(this.map.data.get(this.section.config, section_id, 'endpoint_listeners')?.map(uri => new URL(uri).port) || [])] .filter(Boolean).join(','); if (listen_port != value) { uci.set(this.section.config, section_id, 'easytier_listen_port', value); - return uci.save() - .then(L.bind(this.map.load, this.map)) + uci.save() .then(L.bind(this.map.reset, this.map)) .catch(() => {}); } - return form.Value.prototype.load.apply(this, arguments); + return this.super('load', section_id); }, write(section_id, formvalue) { @@ -1726,7 +1724,7 @@ return view.extend({ uci.set(this.section.config, section_id, 'easytier_listen_port', value); - return form.Value.prototype[formvalue ? 'write' : 'remove'].apply(this, arguments); + return this.super(formvalue ? 'write' : 'remove', ...arguments); } }; diff --git a/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js index fe4688bc6..780f817ac 100644 --- a/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js +++ b/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -162,6 +162,16 @@ return view.extend({ uci.set('firewall', section_id, 'flow_offloading_hw', (value === '2' && L.hasSystemFeature('offloading_hw')) ? '1' : null); }; + + if (fw4 && L.hasSystemFeature('offloading_hw')) { + o = s.option(form.ListValue, 'flow_offloading_hw_ipv6', _('Hardware offloading protocols')); + o.value('1', _('IPv4+v6 acceleration')); + o.value('0', _('IPv4 acceleration')); + o.default = '1'; + o.rmempty = false; + o.retain = true; + o.depends('offloading_type', '2'); + } } diff --git a/luci-app-firewall/po/zh_Hans/firewall.po b/luci-app-firewall/po/zh_Hans/firewall.po index d0a496d4c..00c2cd10d 100644 --- a/luci-app-firewall/po/zh_Hans/firewall.po +++ b/luci-app-firewall/po/zh_Hans/firewall.po @@ -557,6 +557,15 @@ msgstr "基于硬件的流量卸载,可能支持 NAT。" msgid "Hardware flow offloading" msgstr "硬件流量卸载" +msgid "Hardware offloading protocols" +msgstr "硬件加速协议" + +msgid "IPv4+v6 acceleration" +msgstr "IPv4+v6加速" + +msgid "IPv4 acceleration" +msgstr "IPv4加速" + #: applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/ipsets.js:145 msgid "IP (range)" msgstr "IP(范围)" diff --git a/luci-app-ssr-plus/Makefile b/luci-app-ssr-plus/Makefile index 9548463fc..421fe9218 100644 --- a/luci-app-ssr-plus/Makefile +++ b/luci-app-ssr-plus/Makefile @@ -4,7 +4,7 @@ LUCI_TITLE:=luci-app-ssr-plus LUCI_PKGARCH:=all PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=198 -PKG_RELEASE:=98 +PKG_RELEASE:=99 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ @@ -20,6 +20,7 @@ PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Client \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_NONE_Server \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Simple_Obfs \ diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index 263064b30..919644f22 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -479,6 +479,9 @@ end if is_finded("xray") then o:value("hysteria2", translate("Hysteria2")) end +if is_finded("xray") then + o:value("masque", translate("MASQUE")) +end if is_finded("xray") or is_finded("mihomo") then o:value("snell", translate("Snell")) end @@ -495,6 +498,7 @@ o:depends("type", "ss-rust") o:depends("type", "trojan") o:depends("type", "naiveproxy") o:depends("type", "hysteria2") +o:depends("type", "masque") o:depends("type", "tuic") o:depends("type", "shadowtls") o:depends("type", "socks5") @@ -520,6 +524,7 @@ o:depends("type", "ss-rust") o:depends("type", "trojan") o:depends("type", "naiveproxy") o:depends("type", "hysteria2") +o:depends("type", "masque") o:depends("type", "tuic") o:depends("type", "shadowtls") o:depends("type", "socks5") @@ -542,6 +547,7 @@ o.default = "0" o:depends("type", "socks5") o:depends({type = "v2ray", v2ray_protocol = "http"}) o:depends({type = "v2ray", v2ray_protocol = "socks"}) +o:depends({type = "v2ray", v2ray_protocol = "masque"}) o = s:option(Value, "username", translate("Username")) o.rmempty = true @@ -550,6 +556,7 @@ o:depends({type = "v2ray", v2ray_protocol = "naive"}) o:depends({type = "socks5", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "http", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "socks", auth_enable = true}) +o:depends({type = "v2ray", v2ray_protocol = "masque", auth_enable = true}) o = s:option(Value, "password", translate("Password")) o.password = true @@ -563,6 +570,7 @@ o:depends("type", "shadowtls") o:depends({type = "socks5", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "http", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "socks", socks_ver = "5", auth_enable = true}) +o:depends({type = "v2ray", v2ray_protocol = "masque", auth_enable = true}) o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"}) o:depends({type = "v2ray", v2ray_protocol = "trojan"}) o:depends({type = "v2ray", v2ray_protocol = "anytls"}) @@ -581,6 +589,56 @@ for _, field in ipairs({ o:depends({type = "v2ray", v2ray_protocol = "anytls"}) end +-- [[ MASQUE ]] -- +o = s:option(Flag, "masque_warp", "WARP") +o.default = "0" +o:depends({type = "v2ray", v2ray_protocol = "masque"}) + +for _, field in ipairs({ + { "masque_warp_private_key", translate("WARP Device Private Key") }, + { "masque_warp_public_key", translate("WARP Endpoint Public Key") } +}) do + o = s:option(TextValue, field[1], field[2]) + o.rows = 3 + o.wrap = "off" + o:depends({type = "v2ray", v2ray_protocol = "masque", masque_warp = "1"}) + o.cfgvalue = function(self, section) + return (m:get(section, self.option) or ""):gsub("\\n", "\n") + end + o.validate = function(self, value) + return trim(value):gsub("\r\n?", "\n"):gsub("\n", "\\n") + end +end + +o = s:option(DynamicList, "masque_warp_address", "WARP " .. translate("Local Address")) +o:depends({type = "v2ray", v2ray_protocol = "masque", masque_warp = "1"}) + +o = s:option(Value, "masque_path", translate("MASQUE Path")) +o:depends({type = "v2ray", v2ray_protocol = "masque"}) + +o = s:option(TextValue, "masque_headers", translate("Custom HTTP Headers")) +o.rows = 5 +o.wrap = "off" +o:depends({type = "v2ray", v2ray_protocol = "masque"}) +o.cfgvalue = function(self, section) + return (m:get(section, "masque_headers") or ""):gsub("\\n", "\n") +end +o.validate = function(self, value) + value = trim(value):gsub("\r\n", "\n"):gsub("\r", "\n") + local headers = {} + for line in value:gmatch("[^\n]+") do + if trim(line) ~= "" then + local key = line:match("^%s*([^:]+):") + key = key and trim(key):lower() + if not key or not key:match("^[!#$%%&'*+%.%^_`|~%w%-]+$") or headers[key] or key == "host" or key == "capsule-protocol" then + return nil, translate("Not true format, please re-enter!") .. " (" .. line .. ")" + end + headers[key] = true + end + end + return value:gsub("\n", "\\n") +end + o = s:option(Value, "snell_psk", translate("Snell PSK")) o.password = true o.rmempty = true @@ -1501,6 +1559,7 @@ o:depends("transport", "ws") o:depends("transport", "httpupgrade") o:depends("transport", "xhttp") o:depends("transport", "grpc") +o:depends("v2ray_protocol", "masque") --[[ FinalMask部分 ]]-- o = s:option(Flag, "enable_finalmask", translate("FinalMask")) @@ -1591,6 +1650,7 @@ o:depends({type = "v2ray", v2ray_protocol = "vmess", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "trojan", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "shadowsocks", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "hysteria2", reality = false}) +o:depends({type = "v2ray", v2ray_protocol = "masque", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "anytls", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "socks", socks_ver = "5", reality = false}) o:depends({type = "v2ray", v2ray_protocol = "http", reality = false}) @@ -1649,8 +1709,17 @@ if is_finded("xray") then o:value("randomized", translate("randomized")) o:value("unsafe", translate("unsafe")) o:value("", translate("disable")) - o:depends({type = "v2ray", tls = true}) - o:depends({type = "v2ray", reality = true}) + local protocols = s.fields["v2ray_protocol"].keylist + if protocols and type(protocols) == "table" and #protocols > 0 then + for _, proto in ipairs(protocols) do + if not proto:find("^_") then + if proto ~= "masque" then + o:depends({type = "v2ray", v2ray_protocol = proto, tls = true}) + o:depends({type = "v2ray", v2ray_protocol = proto, reality = true}) + end + end + end + end o = s:option(Flag, "enable_ech", translate("Enable ECH(optional)")) o.rmempty = true @@ -1730,6 +1799,8 @@ o:value("h3,h2") o:value("http/1.1") o:value("h2,http/1.1") o:value("h3,h2,http/1.1") +o:depends("type", "trojan") +o:depends("type", "hysteria2") o:depends("tls", true) -- TUIC ALPN @@ -1782,6 +1853,23 @@ if xray_version_val >= 260131 then string.format("%s", "→ " .. translate("Fetch Manually")) end +o = s:option(Flag, "masque_certificate", translate("TLS Certificate (PEM)")) +o.default = "0" +o:depends({type = "v2ray", v2ray_protocol = "masque", tls = true}) + +o = s:option(TextValue, "masque_certificate_pem", " ", translate("Full certificate (chain), PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends("masque_certificate", 1) +o.cfgvalue = function(self, section) + return (m:get(section, "masque_certificate_pem") or ""):gsub("\\n", "\n") +end +o.validate = function(self, value) + value = trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value:gsub("\n", "\\n") +end + -- [[ Hysteria2 TLS pinSHA256 ]] -- o = s:option(Value, "pinsha256", translate("Certificate fingerprint")) o:depends("type", "hysteria2") @@ -1861,6 +1949,7 @@ o:depends({type = "v2ray", v2ray_protocol = "trojan"}) o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"}) o:depends({type = "v2ray", v2ray_protocol = "socks"}) o:depends({type = "v2ray", v2ray_protocol = "http"}) +o:depends({type = "v2ray", v2ray_protocol = "masque"}) -- [[ TESTPRE ]]-- o = s:option(Value, "preconns", translate("Pre-connections"), translate("Number of early established connections to reduce latency.")) @@ -1956,6 +2045,7 @@ o:depends("type", "ss-rust") o:depends("type", "trojan") o:depends("type", "hysteria2") o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "xhttp"}) +o:depends({type = "v2ray", v2ray_protocol = "masque"}) o:depends({type = "v2ray", v2ray_protocol = "hysteria2"}) o = s:option(Flag, "switch_enable", translate("Enable Auto Switch")) diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua index e4d127fe7..e549f947f 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua @@ -584,10 +584,20 @@ Xray.outbounds = { return server.insecure == "1" end)(), serverName = server.tls_host, - certificates = server.certificate and { - usage = "verify", - certificateFile = server.certpath - } or nil, + certificates = (function() + if server.masque_certificate == "1" and server.masque_certificate_pem and server.masque_certificate_pem ~= "" then + return { + certificate = split(server.masque_certificate_pem:gsub("\\n", "\n"), "\n"), + usage = "verify" + } + elseif server.certificate == "1" and server.certpath and server.certpath ~= "" then + return { + usage = "verify", + certificateFile = server.certpath + } + end + return nil + end)(), pinnedPeerCertSha256 = (function() if xray_version_val < 260131 then return nil end if not server.tls_CertSha then return "" end @@ -712,6 +722,28 @@ Xray.outbounds = { initial_windows_size = server.initial_windows_size and tonumber(server.initial_windows_size) or nil, user_agent = server.user_agent } or nil, + masqueSettings = (server.v2ray_protocol == "masque") and { + path = (server.masque_path and server.masque_path ~= "") and server.masque_path or nil, + warp = (server.masque_warp == "1") and { + privateKey = (server.masque_warp_private_key or ""):gsub("\\n", "\n"), + publicKey = (server.masque_warp_public_key or ""):gsub("\\n", "\n"), + address = server.masque_warp_address + } or nil, + headers = (function() + local headers = {} + if server.auth_enable == "1" and server.masque_warp ~= "1" and ((server.username and server.username ~= "") or (server.password and server.password ~= "")) then + headers["authorization"] = "Basic " .. base64Encode((server.username or "") .. ":" .. (server.password or "")) + end + if server.user_agent and server.user_agent ~= "" then + headers["user-agent"] = server.user_agent + end + for line in (server.masque_headers or ""):gsub("\\n", "\n"):gmatch("[^\r\n]+") do + local key, value = line:match("^%s*([^:]+):%s*(.-)%s*$") + if key then headers[trim(key):lower()] = value end + end + return next(headers) and headers or nil + end)() + } or nil, hysteriaSettings = (server.v2ray_protocol == "hysteria2") and { -- hysteria2 version = 2, @@ -922,7 +954,7 @@ Xray.outbounds = { tcpFastOpen = (function() if server.transport == "xhttp" then return (server.fast_open == "1") and true or false - elseif server.v2ray_protocol == "hysteria2" then + elseif server.v2ray_protocol == "hysteria2" or server.v2ray_protocol == "masque" then return (server.fast_open == "1") and true or nil else return nil @@ -936,7 +968,7 @@ Xray.outbounds = { ((remarks and remarks ~= "") and (node_id .. "." .. remarks) or ("direct" .. "." .. node_id)) or nil } } or nil, - mux = (server.v2ray_protocol ~= "hysteria2" and server.v2ray_protocol ~= "wireguard" and server.v2ray_protocol ~= "anytls") and { + mux = (server.v2ray_protocol ~= "hysteria2" and server.v2ray_protocol ~= "wireguard" and server.v2ray_protocol ~= "anytls" and server.v2ray_protocol ~= "masque") and { -- mux enabled = (server.mux == "1"), -- Mux concurrency = (server.mux == "1" and (tonumber(server.concurrency) or -1)) or nil, -- TCP 最大并发连接数 @@ -1027,7 +1059,7 @@ if xray_fragment.fragment ~= "0" or (xray_fragment.noise ~= "0" and xray_noise.e tcpFastOpen = (function() if server.transport == "xhttp" then return (server.fast_open == "1") and true or false - elseif server.v2ray_protocol == "hysteria2" then + elseif server.v2ray_protocol == "hysteria2" or server.v2ray_protocol == "masque" then return (server.fast_open == "1") and true or nil else return nil diff --git a/ooniprobe/Makefile b/ooniprobe/Makefile index 58a3352a5..c4033758b 100644 --- a/ooniprobe/Makefile +++ b/ooniprobe/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ooniprobe -PKG_VERSION:=3.30.0 -PKG_RELEASE:=11 +PKG_VERSION:=3.31.1 +PKG_RELEASE:=12 PKG_SOURCE:=probe-cli-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/ooni/probe-cli/tar.gz/v$(PKG_VERSION)?