🎈 Sync 2026-08-24 18:23:48

This commit is contained in:
github-actions[bot] committed 2026-08-24 18:23:48 +08:00
1 parent 91bee6a90e
commit 6b8877f5e1
119 files changed
+2501 -2677

No files matched your search

+2 -2
View File
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=hysteria
PKG_VERSION:=2.12.1
PKG_RELEASE:=15
PKG_VERSION:=2.12.2
PKG_RELEASE:=16
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/apernet/hysteria/tar.gz/app/v$(PKG_VERSION)?
+3 -2
View File
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=librespeed-common
PKG_VERSION:=1.0.0
PKG_RELEASE:=2
PKG_RELEASE:=3
PKG_MAINTAINER:=Josef Schlehofer <pepe.schlehofer@gmail.com>
PKG_LICENSE:=GPL-2.0-only
@@ -21,7 +21,8 @@ define Package/librespeed-common
SECTION:=utils
CATEGORY:=Utilities
TITLE:=LibreSpeed measurement orchestration
DEPENDS:=+librespeed-cli +rpcd-mod-ucode +jsonfilter
DEPENDS:=+librespeed-cli +rpcd-mod-ucode +jsonfilter +ucode +ucode-mod-fs \
+ucode-mod-uci +jshn
PKGARCH:=all
endef
+20 -7
View File
@@ -12,7 +12,7 @@
'use strict';
import { open, readfile, writefile, rename, mkdir, error } from 'fs';
import { open, readfile, rename, mkdir, unlink, error } from 'fs';
// Packaging checks probe every executable for these.
if (length(ARGV) > 0) {
@@ -176,12 +176,25 @@ const dir = replace(archive_path, /\/[^\/]+$/, '');
if (dir != '' && dir != archive_path)
mkdir(dir, 0o755);
// Atomic: a reader never sees a half-written archive. A failed write goes to
// syslog: this runs from cron, where stderr has nowhere to go. The reason
// comes along, since a missing mount, a read-only filesystem and a full disk
// each want something different from whoever reads that log.
if (writefile(tmp, out) != null)
// Atomic: a reader never sees a half-written archive. Written by hand
// rather than writefile(), which drops fclose()'s status and would let a
// full disk truncate the archive in silence -- flush() is where a short
// write surfaces. A failed write goes to syslog: this runs from cron,
// where stderr has nowhere to go. The reason comes along, since a missing
// mount, a read-only filesystem and a full disk each want something
// different from whoever reads that log.
const af = open(tmp, 'w');
let wrote = af != null && af.write(out) == length(out);
if (af) {
wrote = af.flush() != null && wrote;
af.close();
}
if (wrote)
rename(tmp, archive_path);
else
else {
system(['logger', '-t', 'librespeed',
`aggregate: cannot write ${tmp}: ${error()}`]);
unlink(tmp);
}
+29 -11
View File
@@ -78,9 +78,16 @@ sampler() {
else printf "- -"
}')
prx=$rx; ptx=$tx
# The runner may die without reaching its kill (SIGKILL, a trap that
# never ran); without this check the sampler would rewrite state.json
# forever and mask every later run's result.
kill -0 $$ 2>/dev/null || return 0
# An idle second keeps the last phase: the frontend reads an empty
# phase as "not started yet" and would collapse mid-run.
if [ "$1" = "-" ]; then
write_state 1 $$ "$started" "" "" "" ""
write_state 1 $$ "$started" "" "" "$phase" ""
else
phase=$1
write_state 1 $$ "$started" "" "" "$1" "$2"
fi
done
@@ -184,7 +191,9 @@ write_state 1 $$ "$started"
# stop kills our whole process group, so librespeed-cli dies with us; ash runs
# this trap once the foreground child has exited, and it records that the run
# was stopped rather than pretending the measurement failed.
trap 'write_state 0 "" "" "$(date +%s)" "stopped"; exit 1' TERM
trap '[ -n "$sampler_pid" ] && kill "$sampler_pid" 2>/dev/null
write_state 0 "" "" "$(date +%s)" "stopped"; exit 1' TERM
sampler_pid=
if [ "$stream" = 1 ]; then
# The while runs in a subshell, so the reports cannot come back in a
@@ -213,18 +222,23 @@ if [ "$stream" = 1 ]; then
# stream delivered: a client that failed never emitted a result event.
out=$(cat "$STATE_DIR/reports.json" 2>/dev/null)
rm -f "$STATE_DIR/reports.json"
[ -n "$out" ] || \
fail "$(tail -n 1 "$STATE_DIR/stderr.log" 2>/dev/null || echo 'measurement failed')"
if [ -z "$out" ]; then
# tail succeeds on an empty file, so the substitution guards the
# value, not the command: an empty log still reports a failure.
err=$(tail -n 1 "$STATE_DIR/stderr.log" 2>/dev/null)
fail "${err:-measurement failed}"
fi
else
sampler_pid=""
if [ -n "$dev" ]; then
sampler "$dev" &
sampler_pid=$!
fi
out=$("$@" 2>"$STATE_DIR/stderr.log" < /dev/null); rc=$?
[ -n "$sampler_pid" ] && kill "$sampler_pid" 2>/dev/null
[ "$rc" = 0 ] || \
fail "$(tail -n 1 "$STATE_DIR/stderr.log" 2>/dev/null || echo 'measurement failed')"
if [ "$rc" != 0 ]; then
err=$(tail -n 1 "$STATE_DIR/stderr.log" 2>/dev/null)
fail "${err:-measurement failed (exit $rc)}"
fi
fi
finished=$(date +%s)
@@ -346,9 +360,12 @@ if [ "$hist_enabled" = "1" ]; then
# a gigabyte a year through the flash instead of a few megabytes. The
# file therefore holds somewhat more than the window, and is trimmed
# once enough has accumulated to be worth the write.
# jshn writes '"epoch": 175...' with a space, so the match is
# tolerant and the digits are extracted rather than offset-counted.
expired=$(awk -v c="$cutoff" '
match($0, /"epoch":[0-9]+/) {
if (substr($0, RSTART + 8, RLENGTH - 8) + 0 < c) n++
match($0, /"epoch":[[:space:]]*[0-9]+/) {
v = substr($0, RSTART, RLENGTH); gsub(/[^0-9]/, "", v)
if (v + 0 < c) n++
}
END { print n + 0 }
' "$hist_path")
@@ -357,8 +374,9 @@ if [ "$hist_enabled" = "1" ]; then
if [ "$expired" -ge 50 ] || [ "$expired" -ge $(( total / 2 )) ] && [ "$expired" -gt 0 ]; then
tmp="$hist_path.$$"
awk -v c="$cutoff" '
match($0, /"epoch":[0-9]+/) {
if (substr($0, RSTART + 8, RLENGTH - 8) + 0 < c) next
match($0, /"epoch":[[:space:]]*[0-9]+/) {
v = substr($0, RSTART, RLENGTH); gsub(/[^0-9]/, "", v)
if (v + 0 < c) next
}
{ print }
' "$hist_path" > "$tmp" && mv "$tmp" "$hist_path"
+29 -1
View File
@@ -15,6 +15,26 @@ AGG=/usr/libexec/librespeed-aggregate
# random time is drawn from, drawn here at sync time. That keeps the herd
# apart -- every router lands on its own minute -- without any process
# sleeping through the night, at the cost of re-drawing on every reload.
# Every comma-separated part must be a number or an ascending range within
# [0, max]; the caller already reduced the alphabet to digits, commas and
# dashes.
valid_field() {
local val="$1" max="$2" part a b oifs="$IFS"
IFS=','
for part in $val; do
IFS="$oifs"
a=${part%-*}; b=${part#*-}
# Each half on its own: concatenated, '5-' and '-5' hide their empty
# side and the arithmetic below would print a shell error where the
# caller promises a silent fallback.
case "$a" in ''|*[!0-9]*) return 1 ;; esac
case "$b" in ''|*[!0-9]*) return 1 ;; esac
[ "$a" -le "$max" ] && [ "$b" -le "$max" ] && [ "$a" -le "$b" ] || return 1
done
IFS="$oifs"
return 0
}
cron_expr() {
local interval="$1" days="$2" hours="$3"
local start end m h v
@@ -77,8 +97,16 @@ sync_cron() {
# These end up verbatim in root's crontab, so anything unexpected becomes
# the harmless default rather than a cron field it was not meant to be.
case "$days" in *[!0-9,-]*) days='*' ;; '') days='*' ;; esac
# Values are checked as well as characters: '99' is made of digits, but
# as an hour it would turn a daily schedule into an hourly one.
case "$days" in *[!0-9,-]*|'') days='*' ;; esac
if [ "$days" != '*' ] && ! valid_field "$days" 6; then
days='*'
fi
case "$hours" in *[!0-9-]*) hours='' ;; esac
if [ -n "$hours" ] && ! valid_field "$hours" 23; then
hours=''
fi
mkdir -p "${CRONTAB%/*}"
touch "$CRONTAB"
+43 -8
View File
@@ -78,6 +78,11 @@ function config_get(uci, section, option, fallback) {
// browser: the schedule fires in the router's timezone, and the browser may
// well sit in another one. Understands only the shapes librespeed.init
// emits: numbers, ranges, ranges with a step, star, and comma lists.
// Hoisted: ucode recompiles a regex literal on every evaluation, and these
// two dominate cron_next's cost inside rpcd, which must never stall.
const CRON_STEP = /^(.+)\/([0-9]+)$/;
const CRON_RANGE = /^([0-9]+)-([0-9]+)$/;
function cron_next(line, count) {
const f = split(trim(line ?? ''), /\s+/);
@@ -87,7 +92,7 @@ function cron_next(line, count) {
const match_field = function(pat, val) {
for (let part in split(pat, ',')) {
let step = 1;
let m = match(part, /^(.+)\/([0-9]+)$/);
let m = match(part, CRON_STEP);
if (m) {
part = m[1];
@@ -101,7 +106,7 @@ function cron_next(line, count) {
b = 59;
}
else {
m = match(part, /^([0-9]+)-([0-9]+)$/);
m = match(part, CRON_RANGE);
if (m) {
a = int(m[1]);
b = int(m[2]);
@@ -123,14 +128,36 @@ function cron_next(line, count) {
let t = time();
t -= t % 60;
for (let i = 0; i < 8 * 24 * 60 && length(out) < count; i++) {
// A miss skips the rest of the day or hour instead of walking its
// minutes; that keeps this cheap inside rpcd's event loop, and cheap
// enough for a five-week horizon, which a weekly schedule needs to
// fill three rows where eight days could not. The day jump aims at
// 23:00, not midnight: it is computed in local minutes but applied as
// real ones, and across a spring-forward that lands an hour long --
// from 23:00 the hour branch walks the last hour and cannot overshoot
// into minutes that were never examined.
for (let i = 0; i < 35 * 24 * 60 && length(out) < count; ) {
t += 60;
const lt = localtime(t);
let skip;
// % 7 folds both weekday conventions onto cron's 0-6 with Sunday 0.
if (match_field(f[0], lt.min) && match_field(f[1], lt.hour) &&
match_field(f[4], lt.wday % 7))
push(out, t);
if (!match_field(f[4], lt.wday % 7)) {
skip = (24 - lt.hour) * 60 - lt.min - 60;
if (skip <= 0)
skip = 60 - lt.min;
}
else if (!match_field(f[1], lt.hour))
skip = 60 - lt.min;
else {
if (match_field(f[0], lt.min))
push(out, t);
i++;
continue;
}
t += (skip - 1) * 60;
i += skip;
}
return out;
@@ -182,8 +209,12 @@ const methods = {
if (st.pid)
out.pid = int(st.pid);
if (st.started)
if (st.started) {
out.started = int(st.started);
// Elapsed is computed here, on the clock that stamped
// started: the browser's clock may sit anywhere.
out.elapsed = time() - int(st.started);
}
if (st.mbps != null)
out.mbps = st.mbps + 0.0;
if (st.progress != null)
@@ -297,7 +328,11 @@ const methods = {
scheme: config_get(uci, 'main', 'scheme', 'auto'),
server_list: config_get(uci, 'main', 'server_list', ''),
schedule: {
enabled: config_get(uci, 'schedule', 'enabled', '0') == '1',
// What the crontab holds, not what UCI intends: a
// hand-set 'true' satisfies the init script's bool but
// not a string compare, and the page would say No while
// cron fires. The line is the one source of truth.
enabled: cron != '',
interval: config_get(uci, 'schedule', 'interval', '1d'),
days: config_get(uci, 'schedule', 'days', '*'),
hours: config_get(uci, 'schedule', 'hours', ''),
+9
View File
@@ -23,4 +23,13 @@ sh -n /etc/init.d/librespeed || fail "init script does not parse"
ucode /usr/share/rpcd/ucode/librespeed.uc >/dev/null \
|| fail "rpcd plugin does not load"
# Retention must recognise epoch as jshn actually writes it -- with a space
# after the colon. The fixture comes from json_dump itself, so the check
# breaks if either side changes shape.
line=$(. /usr/share/libubox/jshn.sh; json_init; json_add_int epoch 1; json_dump) \
|| fail "jshn not usable"
echo "$line" | awk 'match($0, /"epoch":[[:space:]]*[0-9]+/) { ok = 1 }
{ print }
END { exit !ok }' || fail "retention regex does not match jshn output"
echo "librespeed-common: installed files OK"
+2 -2
View File
@@ -12,7 +12,7 @@ PKG_ARCH_LINKEASE:=$(ARCH)
PKG_NAME:=linkease-common-bin
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
PKG_SOURCE_DATE:=1.7.5
PKG_RELEASE:=13
PKG_RELEASE:=14
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
@@ -28,7 +28,7 @@ else ifeq ($(ARCH),mipsel)
ARCH_HEXCODE=1b0c
endif
PKG_SOURCE_VERSION:=70c21864a1e95ece2ae6e4b144ce2d7a68d0405f
PKG_SOURCE_VERSION:=2036fce819b5a44574d07cca9927eae73da43efc
PKG_SOURCE:=linkease-common-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/linkease-runtime-v$(PKG_SOURCE_DATE)/
PKG_BUILD_DIR:=$(BUILD_DIR)/linkease-common-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE)
+2 -2
View File
@@ -12,7 +12,7 @@ PKG_ARCH_LINKEASE:=$(ARCH)
PKG_NAME:=linkease
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
PKG_SOURCE_DATE:=1.7.5
PKG_RELEASE:=16
PKG_RELEASE:=17
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
@@ -28,7 +28,7 @@ else ifeq ($(ARCH),mipsel)
ARCH_HEXCODE=1b0c
endif
PKG_SOURCE_VERSION:=70c21864a1e95ece2ae6e4b144ce2d7a68d0405f
PKG_SOURCE_VERSION:=2036fce819b5a44574d07cca9927eae73da43efc
PKG_SOURCE:=linkease-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/linkease-runtime-v$(PKG_SOURCE_DATE)/
PKG_BUILD_DIR:=$(BUILD_DIR)/linkease-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE)
+2 -2
View File
@@ -11,7 +11,7 @@ PKG_ARCH_LINKEASE:=$(ARCH)
PKG_NAME:=linkeasefull
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
PKG_SOURCE_DATE:=3.0.12
PKG_RELEASE:=15
PKG_RELEASE:=16
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
@@ -24,7 +24,7 @@ LINKEASE_RUNTIME_ARCH:=arm64
PKG_HASH:=skip
endif
PKG_SOURCE_VERSION:=70c21864a1e95ece2ae6e4b144ce2d7a68d0405f
PKG_SOURCE_VERSION:=2036fce819b5a44574d07cca9927eae73da43efc
PKG_SOURCE:=linkease-runtime-$(PKG_SOURCE_DATE)-linux-$(LINKEASE_RUNTIME_ARCH).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/linkeasefull-runtime-v$(PKG_SOURCE_DATE)/
PKG_BUILD_DIR:=$(BUILD_DIR)/linkease-runtime-$(PKG_SOURCE_DATE)-linux-$(LINKEASE_RUNTIME_ARCH)
+2 -2
View File
@@ -2,8 +2,8 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.0.0-r20260804
PKG_RELEASE:=5
PKG_VERSION:=1.0.0-r20260824
PKG_RELEASE:=6
LUCI_TITLE:=LuCI support for arcadia
LUCI_PKGARCH:=all
@@ -8,10 +8,9 @@ local m, s, o
m = taskd.docker_map("arcadia", "arcadia", "/usr/libexec/istorec/arcadia.sh",
translate("Arcadia"),
translate("Arcadia one-stop code operation and maintenance platform.")
translate("Arcadia · One-Stop Code Automation & DevOps Platform.")
.. translate("Official website:") .. ' <a href=\"https://arcadia.cool\" target=\"_blank\">https://arcadia.cool</a>'
.. "<dl><dt>" .. translate("Arcadia is mainly aimed at scripting language programming and operation and maintenance, supports scheduled task scheduling, has a complete file system and underlying CLI command design, and is suitable for the development and operation and maintenance environment of small and medium-sized teams and individuals.") .. "</dt>"
.. "<dt>" .. translate("The project is based on TypeScript full-stack development and adopts many cutting-edge technologies. Vue + Vite is used on the front end, and Node.js + Express + Prisma ORM is used on the back end.") .. "</dt>"
.. "<dl><dt>" .. translate("Arcadia is designed for script-based programming and operations scenarios. It provides capabilities including scheduled task scheduling, multi-language code execution, a comprehensive file system, and well-designed underlying CLI commands. It is suitable for individual developers and small to medium-sized teams who seek to improve development and operations efficiency through automated scripting.") .. "</dt>"
.. "<dt>" .. translate("The initial username and password are 'useradmin' and 'passwd' respectively.") .. "</dt>"
.. "</dl>")
@@ -27,11 +26,11 @@ s.anonymous=true
o = s:option(Value, "image", translate("Docker Image"))
o.datatype = "string"
o:value("", translate("Default"))
o:value("supermanito/arcadia:beta", "supermanito/arcadia:beta")
o:value("registry.cn-hangzhou.aliyuncs.com/supermanito/arcadia:beta", "registry.cn-hangzhou.aliyuncs.com/supermanito/arcadia:beta")
o:value("docker.m.daocloud.io/supermanito/arcadia:beta", "docker.m.daocloud.io/supermanito/arcadia:beta")
o:value("docker.1ms.run/supermanito/arcadia:beta", "docker.1ms.run/supermanito/arcadia:beta")
o:value("docker.xuanyuan.me/supermanito/arcadia:beta", "docker.xuanyuan.me/supermanito/arcadia:beta")
o:value("supermanito/arcadia", "supermanito/arcadia")
o:value("registry.cn-hangzhou.aliyuncs.com/supermanito/arcadia", "registry.cn-hangzhou.aliyuncs.com/supermanito/arcadia")
o:value("docker.m.daocloud.io/supermanito/arcadia", "docker.m.daocloud.io/supermanito/arcadia")
o:value("docker.1ms.run/supermanito/arcadia", "docker.1ms.run/supermanito/arcadia")
o:value("docker.xuanyuan.me/supermanito/arcadia", "docker.xuanyuan.me/supermanito/arcadia")
o = s:option(Flag, "hostnet", translate("Host network"), translate("Arcadia running in host network, port is always 5678 if enabled"))
o.default = 0
+5 -8
View File
@@ -4,17 +4,14 @@ msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Official website:"
msgstr "官方网站:"
msgid "Arcadia one-stop code operation and maintenance platform."
msgstr "Arcadia 一站式代码运维平台。"
msgid "Arcadia · One-Stop Code Automation & DevOps Platform."
msgstr "Arcadia 一站式代码自动化运维平台。"
msgid "Arcadia is mainly aimed at scripting language programming and operation and maintenance, supports scheduled task scheduling, has a complete file system and underlying CLI command design, and is suitable for the development and operation and maintenance environment of small and medium-sized teams and individuals."
msgstr "Arcadia 主要面向于脚本语言编程与运维,支持定时任务调度,有着完善的文件系统和底层CLI命令设计,适用于中小型团队与个人的开发与运维环境。"
msgid "The project is based on TypeScript full-stack development and adopts many cutting-edge technologies. Vue + Vite is used on the front end, and Node.js + Express + Prisma ORM is used on the back end."
msgstr "项目基于 TypeScript 全栈开发,采用了众多前沿技术,前端使用 Vue + Vite,后端使用 Node.js + Express + Prisma ORM。"
msgid "Arcadia is designed for script-based programming and operations scenarios. It provides capabilities including scheduled task scheduling, multi-language code execution, a comprehensive file system, and well-designed underlying CLI commands. It is suitable for individual developers and small to medium-sized teams who seek to improve development and operations efficiency through automated scripting."
msgstr "Arcadia 平台面向脚本语言编程与运维场景,提供定时任务调度、多语言代码执行、完善的文件系统与底层 CLI 命令设计等能力,适用于希望借助自动化脚本提升开发运维效率的个人开发者与中小型团队。"
msgid "The initial username and password are 'useradmin' and 'passwd' respectively."
msgstr "初始的用户名和密码分别是'useradmin'和'passwd'。"
msgstr "初始的用户名和密码分别是 'useradmin' 和 'passwd'。"
msgid "Docker Image"
msgstr "镜像"
@@ -11,7 +11,7 @@ IMAGE_NAME='default'
get_image() {
IMAGE_NAME=`uci get arcadia.@arcadia[0].image 2>/dev/null`
if [ -z "$IMAGE_NAME" -o "$IMAGE_NAME" == "default" ]; then
IMAGE_NAME="supermanito/arcadia:beta"
IMAGE_NAME="supermanito/arcadia"
fi
}
@@ -37,7 +37,7 @@ do_install_detail() {
[ -z "$port" ] && port=5678
local cmd="docker run --restart=unless-stopped -d -v \"$config/config:/arcadia/config\" -v \"$config/log:/arcadia/log\" -v \"$config/scripts:/arcadia/scripts\" -v \"$config/repo:/arcadia/repo\" -v \"$config/raw:/arcadia/raw\" -v \"$config/tgbot:/arcadia/tgbot\" "
local cmd="docker run --restart=unless-stopped -d --cap-add SYS_PTRACE -v \"$config/config:/arcadia/config\" -v \"$config/log:/arcadia/log\" -v \"$config/scripts:/arcadia/scripts\" -v \"$config/repo:/arcadia/repo\" -v \"$config/raw:/arcadia/raw\" -v \"$config/tgbot:/arcadia/tgbot\" "
if [ "$hostnet" = 1 ]; then
cmd="$cmd\
--dns=127.0.0.1 \
@@ -46,10 +46,6 @@ function download(name, mime, text) {
window.URL.revokeObjectURL(url);
}
/* Bumped whenever librespeed.css changes, so a routine page load picks the
* new stylesheet up instead of pairing new views with a cached old one. */
const CSS_VERSION = '18';
function metricOf(key) {
return METRICS.find(m => m[0] == key);
}
@@ -142,46 +138,79 @@ return baseclass.extend({
GROUPS: GROUPS,
RANGES: RANGES,
/* The app stylesheet, cache-busted by its own version: LuCI's resource
* version only changes when luci-base does, which is not when we do. */
/* Linked plainly, the way the other applications do: uhttpd serves
* static resources with ETag revalidation, so an upgraded stylesheet
* reaches the browser without a cache-busting version to maintain. */
cssLink() {
return E('link', {
'rel': 'stylesheet',
'href': L.resource('librespeed/librespeed.css') + '?v=' + CSS_VERSION
'href': L.resource('librespeed/librespeed.css')
});
},
/* One token->label table for the schedule intervals: Settings builds
* its choices from it and the Test page looks the status label up, so
* the two cannot drift. The init script accepts more shapes than these
* six, so readers must fall back to the raw token. */
INTERVALS: {
'15m': _('Every 15 minutes'),
'30m': _('Every 30 minutes'),
'1h': _('Hourly'),
'6h': _('Every 6 hours'),
'12h': _('Every 12 hours'),
'1d': _('Daily')
},
/* Exported alongside the chart: every timestamp a page prints should
* come through here, or the date-only guard gets lost in a copy. */
chartStampFull: chartStampFull,
/* Plain figures of one series: what is normal, how much it wobbles, and
* where it stands now. The story sentences are built from these. */
seriesStats(entries, metric) {
* where it stands now. The story sentences are built from these. On
* daily aggregates the extremes come from the _min/_max columns the
* chart also draws -- min/max of the daily means would understate the
* spread and contradict the band directly above the sentence. */
seriesStats(entries, metric, resolution) {
const vals = (entries || []).map(e => e[metric]).filter(v => typeof v == 'number');
if (!vals.length)
return null;
const avg = vals.reduce((a, b) => a + b, 0) / vals.length;
const lows = (resolution == '1d')
? (entries || []).map(e => typeof e[metric + '_min'] == 'number'
? e[metric + '_min'] : e[metric]).filter(v => typeof v == 'number')
: vals;
const highs = (resolution == '1d')
? (entries || []).map(e => typeof e[metric + '_max'] == 'number'
? e[metric + '_max'] : e[metric]).filter(v => typeof v == 'number')
: vals;
return {
count: vals.length,
avg: avg,
min: Math.min.apply(null, vals),
max: Math.max.apply(null, vals),
min: Math.min.apply(null, lows),
max: Math.max.apply(null, highs),
current: vals[vals.length - 1]
};
},
/* A row of toggle buttons; the active one is highlighted. */
switcher(view, items, current, onpick) {
return E('div', {}, items.map(it =>
E('button', {
'class': it[0] == current ? 'cbi-button cbi-button-action' : 'cbi-button',
'style': 'margin-right:.3em',
'click': ui.createHandlerFn(view, function() {
return onpick.call(view, it[0]);
})
/* Callers hand in display-ready labels: a runtime _() here
* would both miss the extractor and translate twice. */
}, [ it[1] != null ? it[1] : it[0] ])));
/* A row of toggle buttons; the active one is highlighted. The state is
* also spoken: colour alone says nothing to a screen reader, so each
* button carries aria-pressed and the group a name for what it picks. */
switcher(view, items, current, onpick, label) {
return E('div', { 'role': 'group', 'aria-label': label || null },
items.map(it =>
E('button', {
'class': it[0] == current ? 'cbi-button cbi-button-action' : 'cbi-button',
'style': 'margin-right:.3em',
'aria-pressed': it[0] == current ? 'true' : 'false',
'click': ui.createHandlerFn(view, function() {
return onpick.call(view, it[0]);
})
/* Callers hand in display-ready labels: a runtime _() here
* would both miss the extractor and translate twice. */
}, [ it[1] != null ? it[1] : it[0] ])));
},
/* The one chart component: hand-built SVG, the way the realtime status
@@ -254,8 +283,9 @@ return baseclass.extend({
const avg = valid.reduce((a, p) => a + p[2], 0) / valid.length;
body += '<line class="librespeed-avgline librespeed-stroke-%d" x1="%d" y1="%f" x2="%d" y2="%f"/>'
.format(ci, L, sc.ys(avg), W - R, sc.ys(avg));
body += '<text x="%d" y="%f" font-size="9" fill="currentColor" fill-opacity=".55" text-anchor="end">avg %s</text>'
.format(W - R, sc.ys(avg) - 4, avg.toFixed(avg >= 100 ? 0 : 1));
body += '<text x="%d" y="%f" font-size="9" fill="currentColor" fill-opacity=".55" text-anchor="end">%h %s</text>'
.format(W - R, sc.ys(avg) - 4, _('avg'),
avg.toFixed(avg >= 100 ? 0 : 1));
body += (valid.length > 1)
? '<polyline class="librespeed-line librespeed-stroke-%d" points="%s"/>'.format(ci, pts)
@@ -314,7 +344,7 @@ return baseclass.extend({
opts.legend.all.forEach(k => {
const m = metricOf(k);
const st = this.seriesStats(entries, k);
const st = this.seriesStats(entries, k, opts.resolution);
const cb = E('input', { 'type': 'checkbox' });
cb.checked = opts.series.indexOf(k) >= 0;
@@ -426,7 +456,8 @@ return baseclass.extend({
if (typeof e[k] != 'number')
return;
let txt = fmtVal(e[k], m[2]);
if (typeof e[k + '_min'] == 'number')
if (typeof e[k + '_min'] == 'number' &&
typeof e[k + '_max'] == 'number')
txt += ' (%s – %s)'.format(
e[k + '_min'].toFixed(m[2] == 'Mbps' ? 0 : 1),
e[k + '_max'].toFixed(m[2] == 'Mbps' ? 0 : 1));
@@ -1,3 +1,19 @@
/* The theme's accent where the theme publishes one: --primary-color-medium
* exists only in luci-theme-bootstrap. Every other in-tree theme sees the
* fallback, which must clear 3:1 against a light page -- the arc and the
* history line are the only graphical encoding of the data. */
:root {
--librespeed-accent: var(--primary-color-medium, #3c8dbc);
}
/* Dark is an attribute in LuCI, not a media preference: bootstrap stamps
* data-darkmode on the root and pins it for its light/dark variants, while
* the themes that actually reach the fallback have no dark mode at all --
* an OS-level preference must not darken their light pages. */
:root[data-darkmode="true"] {
--librespeed-accent: var(--primary-color-medium, #6ab0de);
}
/* The one piece of CSS this application owns: layout and type scale. Colors,
* borders, buttons and spacing inside sections stay with the theme. */
@@ -55,31 +71,31 @@
max-width: 20em;
display: inline-block;
vertical-align: middle;
accent-color: var(--primary-color-medium, #5bc0de);
accent-color: var(--librespeed-accent);
}
/* The chart takes its color from the theme where one is exposed, and falls
* back to a neutral accent where none is. */
.librespeed-chart-line {
stroke: var(--primary-color-medium, #5bc0de);
stroke: var(--librespeed-accent);
fill: none;
stroke-width: 1.5;
}
.librespeed-chart-fill {
fill: var(--primary-color-medium, #5bc0de);
fill: var(--librespeed-accent);
fill-opacity: .1;
stroke: none;
}
.librespeed-chart-band {
fill: var(--primary-color-medium, #5bc0de);
fill: var(--librespeed-accent);
fill-opacity: .18;
stroke: none;
}
.librespeed-chart-dot {
fill: var(--primary-color-medium, #5bc0de);
fill: var(--librespeed-accent);
}
.librespeed-toolbar {
@@ -138,7 +154,7 @@
.librespeed-gauge-fill {
fill: none;
stroke: var(--primary-color-medium, #5bc0de);
stroke: var(--librespeed-accent);
stroke-width: 12;
stroke-linecap: round;
}
@@ -219,17 +235,17 @@
/* One theme color for every series: the second one differs by pattern, not
* by a hardcoded hue -- a dashed line and a striped swatch survive any theme
* and read for color-blind users too. */
.librespeed-stroke-0 { stroke: var(--primary-color-medium, #5bc0de); }
.librespeed-stroke-1 { stroke: var(--primary-color-medium, #5bc0de); }
.librespeed-stroke-0 { stroke: var(--librespeed-accent); }
.librespeed-stroke-1 { stroke: var(--librespeed-accent); }
polyline.librespeed-stroke-1 { stroke-dasharray: 6 3; }
.librespeed-avgline.librespeed-stroke-1 { stroke-dasharray: 2 4; }
.librespeed-fill-0 { fill: var(--primary-color-medium, #5bc0de); }
.librespeed-fill-1 { fill: var(--primary-color-medium, #5bc0de); }
.librespeed-fill-0 { fill: var(--librespeed-accent); }
.librespeed-fill-1 { fill: var(--librespeed-accent); }
circle.librespeed-fill-1 { fill-opacity: .55; }
.librespeed-bg-0 { background: var(--primary-color-medium, #5bc0de); }
.librespeed-bg-0 { background: var(--librespeed-accent); }
.librespeed-bg-1 {
background: repeating-linear-gradient(90deg,
var(--primary-color-medium, #5bc0de) 0 4px, transparent 4px 7px);
var(--librespeed-accent) 0 4px, transparent 4px 7px);
}
.librespeed-legend {
@@ -266,8 +282,8 @@ circle.librespeed-fill-1 { fill-opacity: .55; }
margin: 0 auto;
}
.librespeed-fg-0 { color: var(--primary-color-medium, #5bc0de); }
.librespeed-fg-1 { color: var(--primary-color-medium, #5bc0de); }
.librespeed-fg-0 { color: var(--librespeed-accent); }
.librespeed-fg-1 { color: var(--librespeed-accent); }
.librespeed-cards {
display: flex;
@@ -283,15 +299,17 @@ circle.librespeed-fill-1 { fill-opacity: .55; }
padding: .45em .9em;
min-width: 11em;
cursor: pointer;
opacity: .5;
/* Dim, still legible: .5 with the muted name inside multiplied down to
* an unreadable third. */
opacity: .78;
user-select: none;
}
.librespeed-metric-card-on { opacity: 1; }
.librespeed-metric-card:hover { border-color: rgba(128, 128, 128, .45); }
.librespeed-accent-0 { border-top-color: var(--primary-color-medium, #5bc0de); }
.librespeed-accent-1 { border-top-color: var(--primary-color-medium, #5bc0de); border-top-style: dashed; }
.librespeed-accent-0 { border-top-color: var(--librespeed-accent); }
.librespeed-accent-1 { border-top-color: var(--librespeed-accent); border-top-style: dashed; }
.librespeed-card-value {
font-size: 1.3em;
@@ -313,3 +331,14 @@ circle.librespeed-fill-1 { fill-opacity: .55; }
text-align: left;
font-size: .95em;
}
/* Off-screen but reachable: the live region announcing the running phase,
* and the gauge figures repeated as plain text for browse mode. */
.librespeed-visually-hidden {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
@@ -14,6 +14,12 @@
* second fetch, since the entries are in memory anyway. */
const pageSize = 50;
const callConfig = rpc.declare({
object: 'librespeed',
method: 'config',
expect: { '': {} }
});
const callHistory = rpc.declare({
object: 'librespeed',
method: 'history',
@@ -61,7 +67,13 @@ return view.extend({
speed: lscommon.GROUPS.speed.slice(),
latency: lscommon.GROUPS.latency.slice()
};
return this.fetch();
/* The config rides along for one purpose: with history keeping off,
* the empty state must not send the user to run a test that will
* never produce an entry. */
return Promise.all([
this.fetch(),
callConfig().then(c => { this.config = c; }, () => {})
]);
},
/* The server/interface filters narrow the fetched range on the client;
@@ -107,8 +119,8 @@ return view.extend({
lscommon.GROUPS[this.group].forEach(L.bind(function(k, ki) {
const m = lscommon.METRICS.find(x => x[0] == k),
st = lscommon.seriesStats(entries, k),
ps = lscommon.seriesStats(prev, k),
st = lscommon.seriesStats(entries, k, this.resolution),
ps = lscommon.seriesStats(prev, k, this.prevResolution),
on = act.indexOf(k) >= 0;
let diff = ' ';
@@ -146,7 +158,9 @@ return view.extend({
(on ? ' librespeed-metric-card-on' : ''),
'title': on ? _('Hide this series') : _('Show this series')
}, [
E('div', { 'class': 'librespeed-muted librespeed-caps' },
/* Not muted: the card's own off-state opacity already dims
* it, and two factors multiply into illegibility. */
E('div', { 'class': 'librespeed-caps' },
[ cb, ' ', m[1] ]),
E('div', { 'class': 'librespeed-card-value' }, [
st ? '%.1f'.format(st.avg) + ' ' + m[2] : '–',
@@ -189,10 +203,24 @@ return view.extend({
const noneAtAll = !this.entries.length;
if (!entries.length) {
this.emptyText.textContent = noneAtAll
? _('Run a speed test to start building your connection history.')
: _('No measurements match the current filters.');
/* Strict, matching test.js: the backend emits a real boolean
* (derived from UCI, never its raw '0'/'1'), and an absent or
* failed config must read as "history on", not off. */
const histOff = noneAtAll && this.config &&
this.config.history && this.config.history.enabled === false;
/* With history keeping off, a test would never write an entry:
* the way out is Settings, not the Start button. */
this.emptyText.textContent = histOff
? _('History keeping is switched off, so measurements are not recorded.')
: (noneAtAll
? _('Run a speed test to start building your connection history.')
: _('No measurements match the current filters.'));
this.emptyStart.style.display = noneAtAll ? '' : 'none';
this.emptyStart.href = histOff
? L.url('admin', 'network', 'librespeed', 'settings')
: L.url('admin', 'network', 'librespeed', 'test');
this.emptyStart.textContent = histOff ? _('Open settings') : _('Start test');
this.emptyNode.style.display = '';
this.dataNode.style.display = 'none';
return;
@@ -220,17 +248,12 @@ return view.extend({
this.chartNode.appendChild(E('p', { 'class': 'librespeed-muted' },
[ _('Daily minimum, average and maximum.') ]));
const num = v => (typeof v == 'number') ? v : -1;
/* The sort key carries the same decimal count as the display half:
* ui.Table stringifies the whole cell and compares digit runs one by
* one, so ragged fractions would put 94.4 above 94.35. */
const num = (v, d) => (typeof v == 'number') ? v.toFixed(d) : '';
const fmtNum = (v, d) => (typeof v == 'number') ? v.toFixed(d) : '–';
const when = e => {
if (!e.timestamp)
return '?';
if (this.resolution == '1d' || e.timestamp.indexOf('T') < 0)
return e.timestamp;
const d = new Date(e.timestamp);
/* A garbled timestamp shows as itself, never as "Invalid Date". */
return isNaN(d.getTime()) ? e.timestamp : d.toLocaleString();
};
const when = e => lscommon.chartStampFull(e, this.resolution);
/* One column carries both what the packets were (IPv4/IPv6) and how
* they travelled (HTTPS/HTTP); either half may be unknown. */
@@ -244,15 +267,19 @@ return view.extend({
* cell, and ui.Table only ever orders the rows it was handed, so
* paging first would turn the headers into a per-page sort while the
* count below still speaks for every measurement. */
/* Every display half is a node: ui.Table writes bare strings into
* innerHTML, and the server name comes from a downloaded list --
* text must stay text. The sort key stays the first element. */
const cell = t => E('span', {}, [ t ]);
let rows = entries.slice().reverse().map(e => [
[ e.epoch ?? 0, when(e) ],
(e.server && e.server.name) || '–',
e.interface || '–',
protoCell(e),
[ num(e.download_mbps), fmtNum(e.download_mbps, 2) ],
[ num(e.upload_mbps), fmtNum(e.upload_mbps, 2) ],
[ num(e.ping_ms), fmtNum(e.ping_ms, 1) ],
[ num(e.jitter_ms), fmtNum(e.jitter_ms, 1) ]
[ e.epoch ?? 0, cell(when(e)) ],
cell((e.server && e.server.name) || '–'),
cell(e.interface || '–'),
cell(protoCell(e)),
[ num(e.download_mbps, 2), cell(fmtNum(e.download_mbps, 2)) ],
[ num(e.upload_mbps, 2), cell(fmtNum(e.upload_mbps, 2)) ],
[ num(e.ping_ms, 1), cell(fmtNum(e.ping_ms, 1)) ],
[ num(e.jitter_ms, 1), cell(fmtNum(e.jitter_ms, 1)) ]
]);
const sorting = this.table.getActiveSortState();
@@ -274,7 +301,6 @@ return view.extend({
this.renderPager(rows.length, pages);
this.table.update(rows.slice(this.page * pageSize, (this.page + 1) * pageSize));
},
/* Shown only when there is more than one page; the count is always
@@ -286,7 +312,7 @@ return view.extend({
}, this);
const nav = [ E('span', { 'class': 'librespeed-muted' },
[ _('%d measurements').format(total) ]) ];
[ N_(total, '%d measurement', '%d measurements').format(total) ]) ];
if (pages > 1) {
nav.push(E('button', {
@@ -341,7 +367,7 @@ return view.extend({
const renderControls = L.bind(function() {
const groups = lscommon.switcher(this,
[ [ 'speed', _('Speed') ], [ 'latency', _('Latency') ] ], this.group,
function(v) { this.group = v; renderControls(); this.redraw(); });
function(v) { this.group = v; renderControls(); this.redraw(); }, _('Series'));
const ranges = lscommon.switcher(this,
lscommon.RANGES.map(r => [ String(r[1]), r[0] ]), String(this.range),
function(v) {
@@ -352,7 +378,7 @@ return view.extend({
renderControls();
this.redraw();
}, this));
});
}, _('Range'));
ranges.classList.add('librespeed-push');
@@ -367,6 +393,17 @@ return view.extend({
ifaces.push(e.interface);
});
/* The freshly fetched window may no longer contain the chosen
* server or interface -- daily aggregates carry neither field at
* all. The widget would then quietly repaint as "All" while the
* model kept filtering everything out, with no control on screen
* able to clear it; reconcile the model here, where the choice
* lists are built. */
if (this.server && servers.indexOf(this.server) < 0)
this.server = '';
if (this.iface && ifaces.indexOf(this.iface) < 0)
this.iface = '';
const filters = E('div', { 'class': 'librespeed-toolbar' }, [
this.filterSelect(_('Server'), servers.sort(), this.server,
function(v) { this.server = v; this.page = 0; this.redraw(); }),
@@ -3,6 +3,7 @@
'require form';
'require rpc';
'require tools.widgets as widgets';
'require librespeed.common as lscommon';
const callConfig = rpc.declare({
object: 'librespeed',
@@ -59,12 +60,10 @@ return view.extend({
_('Runs a measurement from cron at the chosen interval. Note that a measurement saturates the connection while it runs.'));
o = s.option(form.ListValue, 'interval', _('Interval'));
o.value('15m', _('Every 15 minutes'));
o.value('30m', _('Every 30 minutes'));
o.value('1h', _('Hourly'));
o.value('6h', _('Every 6 hours'));
o.value('12h', _('Every 12 hours'));
o.value('1d', _('Daily'));
/* From the shared table, so the Test page's status label and these
* choices cannot drift apart. */
Object.keys(lscommon.INTERVALS).forEach(k =>
o.value(k, lscommon.INTERVALS[k]));
o.default = '1d';
o.depends('enabled', '1');
@@ -163,8 +162,11 @@ return view.extend({
]));
}
node.appendChild(box);
return node;
/* A sibling of the form, not a child: Map.render() replaces its
* own root on every Save and Reset, and would take the schedule
* preview with it. The preview reads the applied crontab, so it
* is correct to keep it as it is until Apply. */
return E([], [ node, box ]);
});
}
});
@@ -220,7 +220,8 @@ return view.extend({
this.recentNode.innerHTML = '';
this.recentCount.textContent = entries.length
? _('%d measurements').format(entries.length) : '';
? N_(entries.length, '%d measurement', '%d measurements')
.format(entries.length) : '';
/* The active button names the metric, so the subtitle only carries
* the window. */
@@ -232,12 +233,12 @@ return view.extend({
function(v) {
this.recentMetric = v;
this.renderRecent(this.recentData);
}).childNodes);
}, _('Metric')).childNodes);
/* The stability story of the last day, told in one sentence and four
* figures: what is normal, how much it wobbles, where it is now. */
const metric = this.recentMetric || 'download_mbps';
const st = lscommon.seriesStats(entries, metric);
const st = lscommon.seriesStats(entries, metric, data && data.resolution);
if (st && st.count > 1) {
const varPct = (st.max - st.min) / st.avg * 100,
@@ -297,20 +298,26 @@ return view.extend({
}
const fmtNum = (v, d) => (typeof v == 'number') ? v.toFixed(d) : '–';
const when = e => {
const d = new Date(e.timestamp);
return isNaN(d.getTime()) ? String(e.timestamp || '?') : d.toLocaleString();
};
/* The shared formatter carries the date-only guard: a daily
* aggregate's bare date fed to new Date() is read as UTC midnight
* and shifts a calendar day in negative offsets. */
const when = e => lscommon.chartStampFull(e, data && data.resolution);
const num = v => (typeof v == 'number') ? v : -1;
/* The sort key carries the same decimal count as the display half:
* ui.Table stringifies the whole cell and compares digit runs one by
* one, so ragged fractions would put 94.4 above 94.35. */
const num = (v, d) => (typeof v == 'number') ? v.toFixed(d) : '';
/* Nodes, not strings: ui.Table writes bare strings into innerHTML
* and the server name comes from a downloaded list. */
const cell = t => E('span', {}, [ t ]);
this.recentTable.update(entries.slice(-recentRows).reverse().map(e => [
[ e.epoch ?? 0, when(e) ],
(e.server && e.server.name) || '–',
[ num(e.download_mbps), fmtNum(e.download_mbps, 2) ],
[ num(e.upload_mbps), fmtNum(e.upload_mbps, 2) ],
[ num(e.ping_ms), fmtNum(e.ping_ms, 1) ],
[ num(e.jitter_ms), fmtNum(e.jitter_ms, 1) ]
[ e.epoch ?? 0, cell(when(e)) ],
cell((e.server && e.server.name) || '–'),
[ num(e.download_mbps, 2), cell(fmtNum(e.download_mbps, 2)) ],
[ num(e.upload_mbps, 2), cell(fmtNum(e.upload_mbps, 2)) ],
[ num(e.ping_ms, 1), cell(fmtNum(e.ping_ms, 1)) ],
[ num(e.jitter_ms, 1), cell(fmtNum(e.jitter_ms, 1)) ]
]));
this.recentNode.appendChild(this.recentTableNode);
@@ -374,6 +381,17 @@ return view.extend({
this.resultHeading.textContent = (!status.running && status.last_error)
? _('Last successful measurement') : '';
/* One quiet live region, outside the tree that is rebuilt every
* poll: announcing the rebuilt gauge SVG would read the whole dial
* out several times a run. Set only on change, so it speaks once
* per phase step. */
const announce = status.running
? (PHASES.find(p => p[0] == status.phase) || [])[3] || _('Connecting to the test server…')
: '';
if (this.liveNode.textContent != announce)
this.liveNode.textContent = announce;
if (status.running) {
const rows = [];
@@ -385,7 +403,10 @@ return view.extend({
PHASES.map((p, i) => E('span', {
'class': 'librespeed-step' +
(i == phaseIdx ? ' librespeed-step-active' :
(phaseIdx >= 0 && i < phaseIdx ? ' librespeed-step-done' : ''))
(phaseIdx >= 0 && i < phaseIdx ? ' librespeed-step-done' : '')),
/* Spoken as well as dimmed: opacity is invisible to a
* screen reader. */
'aria-current': i == phaseIdx ? 'step' : null
}, [ p[3] ]))));
/* The dial range is frozen at the start of the run -- a familiar
@@ -404,13 +425,20 @@ return view.extend({
rows.push(E('p', { 'class': 'spinning', 'style': 'margin-top:.75em' },
[ _('Connecting to the test server…') ]));
else {
const holder = E('div', {});
/* The dial is hidden from assistive tech -- its ten tick
* labels are noise there -- so the one figure it carries,
* the running rate, is repeated as plain hidden text that
* browse mode can still reach. */
const holder = E('div', { 'aria-hidden': 'true' });
holder.innerHTML = gauge(
(typeof status.mbps == 'number' && status.mbps > 0)
? status.mbps : null,
this.runTop,
status.phase == 'upload' ? 1 : 0);
rows.push(holder);
if (typeof status.mbps == 'number' && status.mbps > 0)
rows.push(E('span', { 'class': 'librespeed-visually-hidden' },
[ '%.2f Mbps'.format(status.mbps) ]));
}
/* Completion is a different number than the rate on the arc, so
@@ -422,8 +450,13 @@ return view.extend({
rows.push(E('div', { 'class': 'librespeed-muted' },
[ overall + ' %' ]));
const elapsed = status.started
? fmtElapsed(Date.now() / 1000 - status.started) : '';
/* The backend counts on the clock that stamped the start; the
* difference of two unrelated clocks can be negative. The old
* subtraction stays as a fallback for an updating router. */
const elapsed = typeof status.elapsed == 'number'
? fmtElapsed(status.elapsed)
: (status.started
? fmtElapsed(Date.now() / 1000 - status.started) : '');
if (elapsed)
rows.push(E('div', { 'class': 'librespeed-muted' },
@@ -439,7 +472,15 @@ return view.extend({
else
this.wasRunning = false;
if (!status.running && status.last_error) {
if (!status.running && status.last_error == 'stopped') {
/* Stopping is something the user did, not something that went
* wrong; a red banner would turn their own click into an error. */
this.alertNode.appendChild(E('p', { 'class': 'librespeed-muted' }, [
_('The last measurement was stopped.'),
status.last_finished ? ' · ' + fmtTime(status.last_finished) : ''
]));
}
else if (!status.running && status.last_error) {
/* Compact, and above the figures: the failure is news, the last
* good result is still the substance of the page. */
this.alertNode.appendChild(E('div', {
@@ -553,6 +594,11 @@ return view.extend({
this.resultHeading = E('div', { 'class': 'librespeed-muted', 'style': 'margin-top:.35em' });
this.resultNode = E('div', {});
this.recentNode = E('div', {});
this.liveNode = E('div', {
'role': 'status',
'aria-live': 'polite',
'class': 'librespeed-visually-hidden'
});
this.recentCount = E('span', { 'class': 'librespeed-muted' });
this.recentSubtitle = E('div', { 'class': 'librespeed-muted' },
[ _('last 24 hours') ]);
@@ -624,10 +670,15 @@ return view.extend({
* well sit in another one, so it only formats the epoch. */
const sched = config.schedule || {};
const next = sched.next_runs || [];
const schedRows = [ [ _('Enabled'), sched.enabled ? _('Yes') : _('No') ] ];
/* Strict, matching history.js: the backend derives this from the
* crontab and emits a real boolean, never UCI's '0'/'1'. */
const schedRows = [ [ _('Enabled'), sched.enabled === true ? _('Yes') : _('No') ] ];
if (sched.enabled) {
schedRows.push([ _('Interval'), sched.interval || '1d' ]);
if (sched.enabled === true) {
/* The shared table translates the six tokens the UI offers; the
* init script accepts more, so the raw token is the fallback. */
schedRows.push([ _('Interval'),
lscommon.INTERVALS[sched.interval || '1d'] || sched.interval ]);
if (next.length)
schedRows.push([ _('Next run'), new Date(next[0] * 1000).toLocaleString() ]);
}
@@ -660,6 +711,7 @@ return view.extend({
const main = E('div', { 'class': 'cbi-section librespeed-center', 'style': 'margin:0' }, [
this.alertNode,
this.liveNode,
this.statusNode,
this.resultHeading,
this.resultNode,
+181 -152
View File
@@ -1,17 +1,19 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:288
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:315
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:223
msgid "%d measurements"
msgstr ""
msgid "%d measurement"
msgid_plural "%d measurements"
msgstr[0] ""
msgstr[1] ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:430
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:463
msgid "%s elapsed"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:124
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:136
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:123
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:135
msgid "1 year"
msgstr ""
@@ -19,7 +21,7 @@ msgstr ""
msgid "1y"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:137
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:136
msgid "2 years"
msgstr ""
@@ -27,7 +29,7 @@ msgstr ""
msgid "24h"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:122
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:121
msgid "30 days"
msgstr ""
@@ -35,7 +37,7 @@ msgstr ""
msgid "30d"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:121
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:120
msgid "7 days"
msgstr ""
@@ -43,23 +45,23 @@ msgstr ""
msgid "7d"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:123
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:135
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:122
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:134
msgid "90 days"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:157
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:156
msgid ""
"A daily measurement runs at a time drawn when the schedule is applied; "
"saving draws it anew."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:31
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:82
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:94
msgid "All"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:95
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:94
msgid ""
"An hour window on the 24-hour clock, such as 2-5 for 02:00–05:59. A daily "
"measurement runs at a random time inside it, drawn when the schedule is "
@@ -67,99 +69,100 @@ msgid ""
"window across midnight is not supported."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:128
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:127
msgid "Archive path"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:134
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:133
msgid "Archive retention"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:521
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:562
msgid "Completed"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:129
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:128
msgid ""
"Completed days are reduced to daily minimum, average and maximum and "
"appended here once a day, so measurements since the last flush may be lost "
"after an unexpected power loss. Leave empty to keep no persistent history."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:405
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:389
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:426
msgid "Connecting to the test server…"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:327
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:334
msgid "Could not start the measurement: %s"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:67
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:161
msgid "Daily"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:221
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:249
msgid "Daily minimum, average and maximum."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:71
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:70
msgid "Days"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:251
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:252
msgid "Declining — the last measurement is %d%% below the 24-hour average."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:11
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:92
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:491
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:532
msgid "Download"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:328
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:563
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:355
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:609
msgid "Download [Mbps]"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:58
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:59
msgid "Enable"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:627
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:675
msgid "Enabled"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:651
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:702
msgid ""
"Encrypted transfers, which on hardware without AES acceleration may bound "
"the result."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:66
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:160
msgid "Every 12 hours"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:62
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:156
msgid "Every 15 minutes"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:63
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:157
msgid "Every 30 minutes"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:65
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:159
msgid "Every 6 hours"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:405
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:443
msgid "Export CSV"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:408
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:446
msgid "Export JSON"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:77
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:76
msgid "Friday"
msgstr ""
@@ -167,243 +170,263 @@ msgstr ""
msgid "Grant access to LibreSpeed measurements"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:646
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:697
msgid "HTTP (forced)"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:645
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:696
msgid "HTTPS (forced)"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:147
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:159
msgid "Hide this series"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:110
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:109
#: applications/luci-app-librespeed/root/usr/share/luci/menu.d/luci-app-librespeed.json:25
msgid "History"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:116
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:215
msgid "History keeping is switched off, so measurements are not recorded."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:115
msgid "History stored in /tmp is lost when the router reboots."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:64
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:158
msgid "Hourly"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:94
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:93
msgid "Hours"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:327
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:372
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:25
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:509
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:641
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:354
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:410
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:26
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:550
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:692
msgid "Interface"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:61
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:630
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:62
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:680
msgid "Interval"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:14
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:499
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:540
msgid "Jitter"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:328
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:563
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:355
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:609
msgid "Jitter [ms]"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:112
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:111
msgid "Keep history"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:449
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:490
msgid "Last measurement failed"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:375
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:382
msgid "Last successful measurement"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:342
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:369
msgid "Latency"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:72
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:71
msgid "Leave empty to run every day."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:686
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:738
#: applications/luci-app-librespeed/root/usr/share/luci/menu.d/luci-app-librespeed.json:3
msgid "LibreSpeed"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:417
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:455
msgid "LibreSpeed – History"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:21
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:22
msgid "LibreSpeed – Settings"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:26
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:27
msgid "Logical interface the measurement is bound to."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:23
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:24
msgid "Measurement"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:400
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:438
msgid "Measurements"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:689
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:741
msgid "Measures the internet connection from this router."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:73
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:236
msgid "Metric"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:72
msgid "Monday"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:36
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:37
msgid "Must be a server id or 'auto'"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:46
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:47
msgid "Must be an http(s) URL"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:302
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:329
msgid "Next"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:632
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:683
msgid "Next run"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:627
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:675
msgid "No"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:218
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:246
msgid "No data for the selected metric."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:278
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:279
msgid "No data in the last 24 hours."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:466
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:507
msgid "No measurement yet."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:194
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:218
msgid "No measurements match the current filters."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:392
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:430
msgid "No measurements yet"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:162
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:161
msgid ""
"No schedule is active. Enable it above and apply to draw the measurement "
"time."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:31
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:32
msgid ""
"Numeric server id from the LibreSpeed server list, or 'auto' to pick the "
"closest."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:50
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:51
msgid ""
"On routers without AES acceleration, TLS itself can bound the result — "
"forcing plain HTTP then measures the line rather than the cipher."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:297
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:223
msgid "Open settings"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:324
msgid "Page %d of %d"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:115
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:114
msgid "Path"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:13
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:91
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:498
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:539
msgid "Ping"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:328
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:563
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:355
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:609
msgid "Ping [ms]"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:295
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:322
msgid "Previous"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:327
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:49
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:518
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:644
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:354
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:50
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:559
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:695
msgid "Protocol"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:674
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:381
msgid "Range"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:726
msgid "Recent history"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:120
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:119
msgid "Retention"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:687
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:739
msgid "Router speed test"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:193
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:217
msgid "Run a speed test to start building your connection history."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:59
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:60
msgid ""
"Runs a measurement from cron at the chosen interval. Note that a measurement "
"saturates the connection while it runs."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:78
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:77
msgid "Saturday"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:656
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:707
msgid "Schedule status"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:56
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:57
msgid "Scheduled measurements"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:327
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:370
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:30
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:507
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:562
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:642
msgid "Series"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:354
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:408
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:31
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:548
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:608
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:693
msgid "Server"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:39
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:40
msgid "Server list URL"
msgstr ""
@@ -411,33 +434,34 @@ msgstr ""
msgid "Settings"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:147
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:159
msgid "Show this series"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:342
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:369
msgid "Speed"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:175
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:189
msgid "Stable over the selected period."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:257
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:258
msgid "Stable — averaged %d Mbps, ranging from %d to %d Mbps."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:386
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:349
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:573
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:223
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:424
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:356
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:619
msgid "Start test"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:349
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:356
msgid "Stop test"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:79
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:78
msgid "Sunday"
msgstr ""
@@ -445,28 +469,32 @@ msgstr ""
msgid "Test"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:639
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:690
msgid "Test configuration"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:106
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:479
msgid "The last measurement was stopped."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:105
msgid "The window must not cross midnight"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:76
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:75
msgid "Thursday"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:327
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:562
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:354
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:608
msgid "Time"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:74
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:73
msgid "Tuesday"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:40
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:41
msgid ""
"URL of a LibreSpeed server list in JSON, from a self-hosted deployment: "
"either a static file such as https://example.org/servers.json or a generator "
@@ -474,120 +502,121 @@ msgid ""
"official list."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:649
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:700
msgid "Unencrypted transfers, so the line is measured rather than the cipher."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:150
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:149
msgid "Upcoming measurements"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:12
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:93
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:492
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:533
msgid "Upload"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:328
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:563
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:355
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:609
msgid "Upload [Mbps]"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:104
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:103
msgid "Use an hour (0-23) or a range like 2-5"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:254
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:255
msgid "Variable — ranged from %d to %d Mbps."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:319
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:326
msgid "View full history »"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:540
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:581
msgid "View result"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:75
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:74
msgid "Wednesday"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:652
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:703
msgid "Whichever scheme the server list provides."
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:627
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:675
msgid "Yes"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:643
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:694
msgid "automatic (nearest)"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:293
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:294
msgid "average"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:328
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:154
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:287
#: applications/luci-app-librespeed/htdocs/luci-static/resources/librespeed/common.js:358
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:168
msgid "avg"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:294
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:295
msgid "best"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:292
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:293
msgid "current"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:165
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:179
msgid "declining"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:516
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:557
msgid "encrypted (HTTPS)"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:53
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:54
msgid "force HTTP"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:52
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:53
msgid "force HTTPS"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:165
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:179
msgid "highly variable"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:558
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:604
msgid "last 24 hours"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:516
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:557
msgid "plain HTTP"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:360
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:367
msgid "server %s"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:51
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:647
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/settings.js:52
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:698
msgid "server default"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:165
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:172
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:179
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:186
msgid "stable"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:122
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/history.js:134
msgid "vs previous period"
msgstr ""
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:295
#: applications/luci-app-librespeed/htdocs/luci-static/resources/view/librespeed/test.js:296
msgid "worst"
msgstr ""
@@ -3,15 +3,40 @@
"description": "Grant access to LibreSpeed measurements",
"read": {
"ubus": {
"librespeed": [ "status", "result", "history", "config" ]
"librespeed": [
"status",
"result",
"history",
"config"
],
"network.interface": [
"dump"
],
"network": [
"get_proto_handlers"
],
"luci-rpc": [
"getBoardJSON",
"getNetworkDevices",
"getWirelessDevices"
]
},
"uci": [ "librespeed" ]
"uci": [
"librespeed",
"network",
"wireless"
]
},
"write": {
"ubus": {
"librespeed": [ "start", "stop" ]
"librespeed": [
"start",
"stop"
]
},
"uci": [ "librespeed" ]
"uci": [
"librespeed"
]
}
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-mosdns
PKG_VERSION:=1.7.7
PKG_RELEASE:=14
PKG_VERSION:=1.7.8
PKG_RELEASE:=15
LUCI_TITLE:=LuCI Support for mosdns
LUCI_PKGARCH:=all
+7 -7
View File
@@ -152,7 +152,7 @@ msgstr "自动保存缓存"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:323
msgid "Cache Prefetching"
msgstr "缓存预读"
msgstr "缓存预取"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/update.js:150
msgid "Check And Update"
@@ -577,7 +577,7 @@ msgstr "覆盖最小 TTL 值(默认 0)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:336
msgid ""
"Minimum cache hits required since the last refresh to trigger a prefetch."
msgstr "触发预读所需的最小缓存命中次数(自上次刷新起)"
msgstr "触发预取所需的最小缓存命中次数(自上次刷新起)"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:366
msgid ""
@@ -630,19 +630,19 @@ msgstr "请稍候,这可能需要一点时间..."
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:329
msgid "Prefetch Before Expire"
msgstr "预读触发阈值"
msgstr "预取触发阈值"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:335
msgid "Prefetch Min Hits"
msgstr "预读最小命中次数"
msgstr "预取最小命中次数"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:341
msgid "Prefetch Scan Interval"
msgstr "预读扫描周期"
msgstr "预取扫描周期"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:330
msgid "Prefetch when the remaining TTL is less than this value (in seconds)."
msgstr "当剩余 TTL 小于此值(秒)时触发预读"
msgstr "当剩余 TTL 小于此值(秒)时触发预取"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:301
msgid "Prevent DNS Leaks"
@@ -651,7 +651,7 @@ msgstr "防止 DNS 泄漏"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:324
msgid ""
"Proactively refresh hot cache entries in the background before they expire."
msgstr "在缓存到期前,后台主动预读并刷新高频访问的 DNS 记录"
msgstr "在缓存到期前,后台主动预取并刷新高频访问的 DNS 记录"
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:227
#: luci-app-mosdns/htdocs/luci-static/resources/view/mosdns/basic.js:244
+1 -1
View File
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.8.19
PKG_RELEASE:=238
PKG_RELEASE:=239
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
@@ -149,7 +149,8 @@ end
o = s:taboption("Main", Value, "node_socks_port", translate("Node") .. " Socks " .. translate("Listen Port"))
o.default = 1070
o.datatype = "port"
o.datatype = "range(1,65535)"
o.rmempty = false
o:depends({ node = "", ["!reverse"] = true })
--[[
if has_singbox or has_xray then
@@ -687,7 +688,16 @@ s2.addremove = true
s2.extedit = api.url("socks_config", "%s")
function s2.create(e, t)
local uid = "socks_" .. api.gen_random_char(5)
local n = 1
m:foreach("socks", function(s)
if s[".name"] == section then
return false
end
n = n + 1
end)
TypedSection.create(e, uid)
m:set(uid, "port", 1080 + n)
m:set(uid, "http_port", 0)
luci.http.redirect(e.extedit:format(uid))
end
function s2.remove(e, t)
@@ -730,12 +740,6 @@ function s2.remove(e, t)
TypedSection.remove(e, t)
end
o = s2:option(DummyValue, "status", translate("Status"))
o.rawhtml = true
o.cfgvalue = function(t, n)
return string.format('<div class="_status" socks_id="%s"></div>', n)
end
---- Enable
o = s2:option(Flag, "enabled", translate("Enable"))
o.default = 1
@@ -757,26 +761,19 @@ o.cfgvalue = function(_, n)
end
end
local n = 1
m:foreach("socks", function(s)
if s[".name"] == section then
return false
end
n = n + 1
end)
o = s2:option(Value, "port", "Socks " .. translate("Listen Port"))
o.default = n + 1080
o.datatype = "port"
o.rmempty = false
--[[
if has_singbox or has_xray then
o = s2:option(Value, "http_port", "HTTP " .. translate("Listen Port"))
o.default = 0
o.datatype = "port"
o = s2:option(DummyValue, "port_status", translate("Port Status"))
o.rawhtml = true
o.cfgvalue = function(t, n)
local socks = m:get(n, "port") or "0"
local http = m:get(n, "http_port") or "0"
return string.format([[
<div class="_socks_status" socks_id="%s">
<span class="_socks"></span> SOCKS: %s
<br>
<span class="_http"></span> HTTP: %s
</div>
]], n, socks, http)
end
]]--
local o_node = s.fields["node"]
local o_socks = s2.fields["node"]
@@ -46,8 +46,9 @@ o:depends("console_auth", true)
---- Console Port
o = s:option(Value, "console_port", translate("Console Port"), translate("In the browser input routing IP plus port access, such as:192.168.1.1:1188"))
o.datatype = "port"
o.default = 1188
o.datatype = "range(1,65535)"
o.rmempty = false
o:depends("balancing_enable", true)
o = s:option(Flag, "bind_local", translate("Haproxy Port") .. " " .. translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
@@ -151,8 +152,8 @@ end
---- Haproxy Port
o = s:option(Value, "haproxy_port", translate("Haproxy Port"))
o.datatype = "port"
o.default = 1181
o.datatype = "range(1,65535)"
o.rmempty = false
---- Node Weight
@@ -63,7 +63,7 @@ end)
o = s:option(Value, "port", "Socks " .. translate("Listen Port"))
o.default = n + 1080
o.datatype = "port"
o.datatype = "range(1,65535)"
o.rmempty = false
if has_singbox or has_xray then
@@ -30,6 +30,16 @@ for i, v in ipairs(user_list) do
end
o:depends({ auth = true })
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ firewall_allow = true })
o = s:option(Flag, "log", translate("Log"))
o.default = "1"
@@ -456,9 +456,16 @@ if singbox_tags:find("with_wireguard") then
o:depends({ protocol = "wireguard" })
end
o = s:option(Flag, "bind_local", translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o:depends({ custom = false, is_endpoint = "" })
o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "accept_lan", translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
o.default = "0"
@@ -468,10 +468,17 @@ o = s:option(DummyValue, "gen_wireguard_key")
o.template = m:template_path("/server/gen_wireguard_key")
o:depends({ protocol = "wireguard" })
o = s:option(Flag, "bind_local", translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "accept_lan", translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
o.default = "0"
o:depends({ custom = false })
@@ -72,6 +72,17 @@ o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
@@ -103,6 +103,17 @@ o = s:option(Flag, "udp_forward", translate("UDP Forward"))
o.default = "1"
o.rmempty = false
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
@@ -147,6 +147,17 @@ o.validate = function(self, value, t)
end
o:depends({ custom = false })
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
@@ -8,16 +8,10 @@ local jsonc = api.jsonc
local CONFIG = api.s_config
local CONFIG_PATH = api.S_TMP_PATH
local NFT_INCLUDE_FILE = CONFIG_PATH .. "/" .. CONFIG .. ".nft"
local LOG_APP_FILE = "/tmp/log/" .. CONFIG .. ".log"
local TMP_BIN_PATH = CONFIG_PATH .. "/bin"
local require_dir = "luci.passwall."
local ipt_bin = sys.exec("echo -n $(/usr/share/passwall/iptables.sh get_ipt_bin)")
local ip6t_bin = sys.exec("echo -n $(/usr/share/passwall/iptables.sh get_ip6t_bin)")
local nft_flag = api.is_finded("fw4") and "1" or "0"
local function log(...)
local f, err = io.open(LOG_APP_FILE, "a")
if f and err == nil then
@@ -31,18 +25,6 @@ local function cmd(cmd)
sys.call(cmd)
end
local function ipt(arg)
if ipt_bin and #ipt_bin > 0 then
cmd(ipt_bin .. " -w " .. arg)
end
end
local function ip6t(arg)
if ip6t_bin and #ip6t_bin > 0 then
cmd(ip6t_bin .. " -w " .. arg)
end
end
local function ln_run(s, d, command, output)
if not output then
output = "/dev/null"
@@ -52,37 +34,6 @@ local function ln_run(s, d, command, output)
return string.format("%s >%s 2>&1 &", d .. " " .. command, output)
end
local function gen_include()
cmd(string.format("echo '#!/bin/sh' > %s.include", CONFIG_PATH))
local function extract_rules(n, a)
local _ipt = ipt_bin
if n == "6" then
_ipt = ip6t_bin
end
local result = "*" .. a
result = result .. "\n" .. sys.exec(_ipt .. '-save -t ' .. a .. ' | grep "PSW-SERVER" | sed -e "s/^-A \\(INPUT\\)/-I \\1 1/"')
result = result .. "COMMIT"
return result
end
local f, err = io.open(CONFIG_PATH .. ".include", "a")
if f and err == nil then
if nft_flag == "0" then
f:write(ipt_bin .. '-save -c | grep -v "PSW-SERVER" | ' .. ipt_bin .. '-restore -c' .. "\n")
f:write(ipt_bin .. '-restore -n <<-EOT' .. "\n")
f:write(extract_rules("4", "filter") .. "\n")
f:write("EOT" .. "\n")
f:write(ip6t_bin .. '-save -c | grep -v "PSW-SERVER" | ' .. ip6t_bin .. '-restore -c' .. "\n")
f:write(ip6t_bin .. '-restore -n <<-EOT' .. "\n")
f:write(extract_rules("6", "filter") .. "\n")
f:write("EOT" .. "\n")
f:close()
else
f:write("nft -f " .. NFT_INCLUDE_FILE .. "\n")
f:close()
end
end
end
local function start()
local enabled = tonumber(api.uci_get_s("@global[0]", "enable") or 0)
if enabled == nil or enabled == 0 then
@@ -90,18 +41,7 @@ local function start()
end
cmd(string.format("mkdir -p %s %s", CONFIG_PATH, TMP_BIN_PATH))
cmd(string.format("touch %s", LOG_APP_FILE))
if nft_flag == "0" then
ipt("-N PSW-SERVER")
ipt("-I INPUT -j PSW-SERVER")
ip6t("-N PSW-SERVER")
ip6t("-I INPUT -j PSW-SERVER")
else
nft_file, err = io.open(NFT_INCLUDE_FILE, "w")
nft_file:write('#!/usr/sbin/nft -f\n')
nft_file:write('add chain inet fw4 PSW-SERVER\n')
nft_file:write('flush chain inet fw4 PSW-SERVER\n')
nft_file:write('insert rule inet fw4 input position 0 jump PSW-SERVER comment "PSW-SERVER"\n')
end
local firewall_num = 0
api.uci_foreach_s("server", function(server)
local id = server[".name"]
local enable = server.enable
@@ -207,48 +147,38 @@ local function start()
cmd(bin)
end
local bind_local = server.bind_local or 0
if bind_local and tonumber(bind_local) ~= 1 and port then
if nft_flag == "0" then
ipt(string.format('-A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
ip6t(string.format('-A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
if udp_forward == 1 then
ipt(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
ip6t(string.format('-A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
end
else
nft_file:write(string.format('add rule inet fw4 PSW-SERVER meta l4proto tcp tcp dport {%s} counter accept comment "%s"\n', port, remarks))
if udp_forward == 1 then
nft_file:write(string.format('add rule inet fw4 PSW-SERVER meta l4proto udp udp dport {%s} counter accept comment "%s"\n', port, remarks))
end
end
local firewall_allow = server.firewall_allow
if firewall_allow == "1" then
firewall_num = firewall_num + 1
local uid = CONFIG .. "_" .. id
uci:section("firewall", "rule", uid)
uci:set("firewall", uid, "name", uid)
uci:set("firewall", uid, "src", server.firewall_allow_src or "wan")
uci:set("firewall", uid, "dest_port", port)
uci:set("firewall", uid, "target", "ACCEPT")
end
end
end)
if nft_flag == "1" then
nft_file:write("add rule inet fw4 PSW-SERVER return\n")
nft_file:close()
cmd("nft -f " .. NFT_INCLUDE_FILE)
if firewall_num > 0 then
api.uci_save(uci, "firewall", true, true)
end
gen_include()
end
local function stop()
cmd(string.format("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/' | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1", CONFIG_PATH))
if nft_flag == "0" then
ipt("-D INPUT -j PSW-SERVER 2>/dev/null")
ipt("-F PSW-SERVER 2>/dev/null")
ipt("-X PSW-SERVER 2>/dev/null")
ip6t("-D INPUT -j PSW-SERVER 2>/dev/null")
ip6t("-F PSW-SERVER 2>/dev/null")
ip6t("-X PSW-SERVER 2>/dev/null")
else
local nft_cmd = "handles=$(nft -a list chain inet fw4 input | grep -E \"PSW-SERVER\" | awk -F '# handle ' '{print$2}')\n for handle in $handles; do\n nft delete rule inet fw4 input handle ${handle} 2>/dev/null\n done"
cmd(nft_cmd)
cmd("nft flush chain inet fw4 PSW-SERVER 2>/dev/null")
cmd("nft delete chain inet fw4 PSW-SERVER 2>/dev/null")
if true then
local num = 0
uci:foreach("firewall", "rule", function(rule)
if rule[".name"]:find(CONFIG) == 1 then
num = num + 1
uci:delete("firewall", rule[".name"])
end
end)
if num > 0 then
api.uci_save(uci, "firewall", true, true)
end
end
cmd(string.format("rm -rf %s %s %s", CONFIG_PATH, LOG_APP_FILE, CONFIG_PATH .. ".include"))
cmd(string.format("rm -rf %s %s", CONFIG_PATH, LOG_APP_FILE))
end
if action then
@@ -762,7 +762,7 @@ function gen_config_server(node)
local inbound = {
type = node.protocol,
tag = "inbound",
listen = (node.bind_local == "1") and "127.0.0.1" or "::",
listen = "::",
listen_port = tonumber(node.port),
}
@@ -669,7 +669,7 @@ function gen_config_server(node)
-- 传入连接
inbounds = {
{
listen = (node.bind_local == "1") and "127.0.0.1" or nil,
listen = "::",
port = tonumber(node.port),
protocol = node.protocol,
settings = settings,
@@ -24,16 +24,6 @@ local sid = "@global[0]"
display: none !important;
}
}
@media screen and (min-width: 1152px) {
#cbi-<%=appname%>-socks input[id*=".<%=appname%>."][id$=".port"],
#cbi-<%=appname%>-socks input[id*=".<%=appname%>."][id$=".http_port"] {
width: 100px !important;
min-width: unset !important;
max-width: unset !important;
text-align: center !important;
}
}
</style>
<script type="text/javascript">
//<![CDATA[
@@ -68,7 +58,7 @@ local sid = "@global[0]"
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function go() {
const _status = document.getElementsByClassName('_status');
const _status = document.getElementsByClassName('_socks_status');
for (let i = 0; i < _status.length; i++) {
const id = _status[i].getAttribute("socks_id");
XHR.get('<%=api.url("socks_status")%>', {
@@ -76,24 +66,22 @@ local sid = "@global[0]"
id: id
},
function(x, result) {
const index = result.index;
let div = '';
const div1 = '<font style="font-weight:bold;" color="green">✓</font>&nbsp';
const div2 = '<font style="font-weight:bold;" color="red">X</font>&nbsp';
if (result.socks_status) {
div += div1;
} else {
div += div2;
const socks = _status[i].querySelector('._socks');
const http = _status[i].querySelector('._http');
if (socks) {
socks.textContent = result.socks_status ? "✓" : "X";
socks.style.fontWeight = "bold";
socks.style.color = result.socks_status ? "green" : "red";
}
if (result.use_http) {
if (result.http_status) {
div += div1;
if (http) {
if (result.use_http) {
http.textContent = result.http_status ? "✓" : "X";
http.style.fontWeight = "bold";
http.style.color = result.http_status ? "green" : "red";
} else {
div += div2;
http.textContent = "";
}
}
_status[index].innerHTML = div;
}
);
}
@@ -497,7 +497,8 @@ table td, .table .td {
ajax.abortAll();
switch (action) {
case "add":
const dom = document.getElementsByClassName("cbi-tab")[0];
const master = document.getElementById("node_list");
const dom = master.getElementsByClassName("cbi-tab")[0];
const current_group = dom ? (dom.getAttribute("group_name") || "default") : "default";
window.location.href='<%=api.url("add_node")%>?redirect=1&group=' + current_group;
break;
@@ -1215,11 +1216,15 @@ table td, .table .td {
const set_node_div = {
section: '',
open(cbi_id) {
open(cbi_id, protocol) {
this.section = cbi_id;
document.getElementById("set_node_div").style.display="block";
const node_name = document.getElementById("cbid.<%=appname%>." + cbi_id + ".remarks").value;
document.getElementById("set_node_name").textContent = node_name;
const shunt_div = document.getElementById("set_node_shunt_div");
if (shunt_div) {
shunt_div.style.display = protocol === "_shunt" ? "none" : "";
}
},
close() {
document.getElementById("set_node_div").style.display="none";
@@ -1286,7 +1291,7 @@ table td, .table .td {
<td class="td cbi-section-table-cell nowrap cbi-section-actions pw-actions">
<div class="node-wrapper">
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:To Top%>" onclick="node_action('row_top', null, {btn:this, group:'{{group}}'})" title="<%:To Top%>"/>
<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Use%>" id="apply_{{id}}" onclick="set_node_div.open('{{id}}')"/>
<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Use%>" id="apply_{{id}}" onclick="set_node_div.open('{{id}}','{{protocol}}')"/>
<input class="btn cbi-button cbi-button-add" type="button" value="<%:Copy%>" onclick="node_action('copy', '{{id}}')"/>
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:Edit%>" onclick="node_action('edit', '{{id}}')" alt="<%:Edit%>" title="<%:Edit%>">
<input class="btn cbi-button cbi-button-remove" type="button" value="<%:Delete%>" onclick="node_action('del', '{{id}}')" alt="<%:Delete%>" title="<%:Delete%>">
@@ -1432,6 +1437,7 @@ table td, .table .td {
innerHTML = innerHTML.split("{{remarks_val}}").join(o["remarks"]);
innerHTML = innerHTML.split("{{address_val}}").join(o["address"] || "");
innerHTML = innerHTML.split("{{port_val}}").join(o["port"] || "");
innerHTML = innerHTML.split("{{protocol}}").join(o["protocol"] || "");
node_tr_html += innerHTML
}
@@ -1620,20 +1626,27 @@ table td, .table .td {
<div style="display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; -webkit-justify-content: center; justify-content: center;">
<div id="set_node_div">
<div class="cbi-value" style="display: flex; justify-content: center; align-items: center; margin: 1em 0; height: 2em;">
<div class="cbi-value" style="display: flex; justify-content: center; align-items: center; margin: 0.2em 0; height: 2em;">
<font color=#666><%:You choose node is:%></font><a style="color: red" id="set_node_name"></a>
<div style="position:absolute; right:0.5em; top: 0.5em;"><input class="btn cbi-button" type="button" onclick="set_node_div.close()" value="X" /></div>
</div>
<div class="cbi-value" style="justify-content: center; gap: 8px; margin: 1em 0;">
<%- if default_node_type == "_shunt" then
for i, v in ipairs(shunt_rule_list) do
-%>
<input class="btn cbi-button" type="button" onclick="set_node_div.set('<%=node%>', '<%=v[".name"]%>')" value="<%=v.remarks%>" />
<%-
end
-%>
<% else %>
<input class="btn cbi-button" type="button" onclick="set_node_div.set('@global[0]', 'node')" value="<%:Node%>" />
<div class="cbi-value" style="justify-content: center; gap: 8px; margin: 0.2em 0;">
<div style="margin: 0.5em 0; padding: 0.5em; background: #f7f7f7; border-radius: 4px;">
<div class="cbi-section-descr" style="text-align: left;"><a style="color:#FF8C00"><%:Set as the main proxy node:%></a></div>
<div>
<input class="btn cbi-button" type="button" onclick="set_node_div.set('@global[0]', 'node')" value="<%:OK%>" />
</div>
</div>
<% if default_node_type == "_shunt" then %>
<div id="set_node_shunt_div" style="margin: 0.5em 0; padding: 0.5em; background: #f7f7f7; border-radius: 4px;">
<div class="cbi-section-descr" style="text-align: left;"><a style="color:#FF8C00"><%:Set as the routing rule node:%></a></div>
<div>
<% for i, v in ipairs(shunt_rule_list) do %>
<input class="btn cbi-button" type="button" onclick="set_node_div.set('<%=node%>', '<%=v[".name"]%>')" value="<%=v.remarks%>" />
<% end %>
<input class="btn cbi-button" type="button" onclick="set_node_div.set('<%=node%>', 'default_node')" value="<%:Default%>" />
</div>
</div>
<% end %>
</div>
</div>
@@ -148,7 +148,8 @@ table td, .table .td {
//<![CDATA[
function toPage(action, cbi_id) {
if (action == "add") {
const dom = document.getElementsByClassName("cbi-tab")[0];
const master = document.getElementById("shunt_rule_list");
const dom = master.getElementsByClassName("cbi-tab")[0];
const current_group = dom ? (dom.getAttribute("group_name") || "default") : "default";
const add_name_val = document.getElementById("add_name_" + current_group).value;
if (add_name_val.length > 1) {
@@ -333,15 +334,19 @@ table td, .table .td {
var shunt_rule_list = result
var group_shunt_rules = {}
for (let i = 0; i < shunt_rule_list.length; i++) {
let _shunt_rule = shunt_rule_list[i]
if (!_shunt_rule.group || _shunt_rule.group === "") {
_shunt_rule.group = "default"
if (shunt_rule_list.length > 0) {
for (let i = 0; i < shunt_rule_list.length; i++) {
let _shunt_rule = shunt_rule_list[i]
if (!_shunt_rule.group || _shunt_rule.group === "") {
_shunt_rule.group = "default"
}
if (!group_shunt_rules[_shunt_rule.group]) {
group_shunt_rules[_shunt_rule.group] = []
}
group_shunt_rules[_shunt_rule.group].push(_shunt_rule)
}
if (!group_shunt_rules[_shunt_rule.group]) {
group_shunt_rules[_shunt_rule.group] = []
}
group_shunt_rules[_shunt_rule.group].push(_shunt_rule)
} else {
group_shunt_rules["default"] = [];
}
var tab_ul_li_html = '';
+15 -3
View File
@@ -154,12 +154,12 @@ msgstr "当前节点"
msgid "Listen Port"
msgstr "监听端口"
msgid "Port Status"
msgstr "端口状态"
msgid "0 is not use"
msgstr "0 为不使用"
msgid "Same as the tcp node"
msgstr "与 TCP 节点相同"
msgid "Current node: %s"
msgstr "当前节点:%s"
@@ -469,6 +469,12 @@ msgstr "你确定要删除选择的节点吗?"
msgid "You no select nodes !"
msgstr "你没有选择任何节点!"
msgid "Set as the main proxy node:"
msgstr "应用为主代理节点:"
msgid "Set as the routing rule node:"
msgstr "应用为分流规则节点:"
msgid "Are you sure set this node?"
msgstr "你确定要设置这个节点吗?"
@@ -1607,6 +1613,12 @@ msgstr "本机监听"
msgid "When selected, it can only be accessed localhost."
msgstr "当勾选时,只能本机访问。"
msgid "Firewall Allow"
msgstr "允许通过防火墙"
msgid "Source zone"
msgstr "源区域"
msgid "Accept LAN Access"
msgstr "接受局域网访问"
@@ -17,21 +17,6 @@ if [ -e "/etc/config/ucitrack" ]; then
EOF
fi
uci -q batch <<-EOF
delete firewall.passwall_server
set firewall.passwall_server=include
set firewall.passwall_server.type='script'
set firewall.passwall_server.path='/var/etc/passwall_server.include'
EOF
if [ -x "/sbin/fw3" ]; then
uci -q set firewall.passwall_server.reload='1'
else
uci -q delete firewall.passwall_server.reload
uci -q delete firewall.passwall_server.fw4_compatible
fi
uci commit firewall
# Migrate server sections from the old `user` section type. New user entries
# also use `user`, so only sections with a server `type` option are renamed.
for sid in $(uci -q show passwall_server | sed -n 's/^passwall_server\.\([^.=]*\)=user$/\1/p'); do
@@ -15,11 +15,11 @@ UTIL_SS=$LUA_UTIL_PATH/util_shadowsocks.lua
UTIL_XRAY=$LUA_UTIL_PATH/util_xray.lua
UTIL_NAIVE=$LUA_UTIL_PATH/util_naiveproxy.lua
UTIL_HYSTERIA2=$LUA_UTIL_PATH/util_hysteria2.lua
SINGBOX_BIN=$(first_type $(config_t_get global_app sing_box_file) sing-box)
XRAY_BIN=$(first_type $(config_t_get global_app xray_file) xray)
SINGBOX_BIN=$(first_type $(config_n_get @global_app[0] sing_box_file) sing-box)
XRAY_BIN=$(first_type $(config_n_get @global_app[0] xray_file) xray)
check_run_environment() {
local prefer_nft=$(config_t_get global_forwarding prefer_nft 1)
local prefer_nft=$(config_n_get @global_forwarding[0] prefer_nft 1)
local dnsmasq_info=$(dnsmasq -v 2>/dev/null)
local dnsmasq_ver=$(echo "$dnsmasq_info" | sed -n '1s/.*version \([0-9.]*\).*/\1/p')
# local dnsmasq_opts=$(echo "$dnsmasq_info" | grep -i "Compile time options")
@@ -102,7 +102,7 @@ run_singbox() {
json_add_string "log" "1"
json_add_string "logfile" "${log_file}"
fi
[ -z "$loglevel" ] && local loglevel=$(config_t_get global loglevel "warn")
[ -z "$loglevel" ] && local loglevel=$(config_n_get @global[0] loglevel "warn")
json_add_string "loglevel" "$loglevel"
[ -n "$flag" ] && json_add_string "flag" "$flag"
@@ -196,7 +196,7 @@ run_xray() {
[ -z "$type" ] && return 1
json_init
[ -n "$log_file" ] || local log_file="/dev/null"
[ -z "$loglevel" ] && local loglevel=$(config_t_get global loglevel "warning")
[ -z "$loglevel" ] && local loglevel=$(config_n_get @global[0] loglevel "warning")
[ -n "$flag" ] && json_add_string "flag" "$flag"
[ -n "$node" ] && json_add_string "node" "$node"
[ -n "$use_proxy_list" ] && json_add_string "use_proxy_list" "$use_proxy_list"
@@ -481,7 +481,7 @@ run_socks() {
json_add_string "local_socks_address" "$bind"
json_add_string "local_socks_port" "$socks_port"
lua $UTIL_HYSTERIA2 gen_config "$(json_dump)" > $config_file
[ -n "$no_run" ] || ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client
[ -n "$no_run" ] || ln_run "$(first_type $(config_n_get @global_app[0] hysteria_file))" "hysteria" $log_file -c "$config_file" client
;;
esac
@@ -519,8 +519,8 @@ run_socks() {
start_global() {
[ -z "$NODE" ] && return 1
local type=$(echo $(config_n_get $NODE type) | tr 'A-Z' 'a-z')
[ -z "$type" ] && return 1
local config_file=${GLOBAL_ACL_PATH}/global.json
local log_file=${GLOBAL_ACL_PATH}/global.log
@@ -545,7 +545,7 @@ start_global() {
port=$node2socks_port
remarks="Socks 配置($port 端口)"
fi
local enable_log=$(config_t_get global log_node 1)
local enable_log=$(config_n_get @global[0] log_node 1)
[ "$enable_log" != "1" ] && log_file="/dev/null"
[ -n "$server_host" ] && [ -n "$port" ] && {
check_host $server_host
@@ -556,15 +556,15 @@ start_global() {
}
echolog "全局节点:[$remarks],监听端口:$REDIR_PORT"
local on_node_socks=1
local node_socks_bind_local=$(config_t_get global node_socks_bind_local 1)
local node_socks_bind_local=$(config_n_get @global[0] node_socks_bind_local 1)
local node_socks_bind="127.0.0.1"
[ "${node_socks_bind_local}" != "1" ] && node_socks_bind="0.0.0.0"
local global_socks_port=$(config_t_get global node_socks_port 1070)
local global_socks_port=$(config_n_get @global[0] node_socks_port 1070)
GLOBAL_SOCKS_port=$(get_new_port $global_socks_port)
if [ "$GLOBAL_SOCKS_port" != "$global_socks_port" ]; then
echolog "注意:全局节点 Socks 端口冲突,原端口 ${global_socks_port} 已自动更改为 ${GLOBAL_SOCKS_port}!"
fi
GLOBAL_HTTP_port=$(config_t_get global node_http_port 0)
GLOBAL_HTTP_port=$(config_n_get @global[0] node_http_port 0)
[ "$GLOBAL_HTTP_port" != "0" ] && local on_node_http=1
if [ $PROXY_IPV6 = "1" ]; then
echolog "开启实验性IPv6透明代理(TProxy),请确认您的节点及类型支持IPv6!"
@@ -616,7 +616,7 @@ start_global() {
}
local protocol=$(config_n_get $NODE protocol)
local v2ray_dns_mode=$(config_t_get global v2ray_dns_mode tcp)
local v2ray_dns_mode=$(config_n_get @global[0] v2ray_dns_mode tcp)
[ "${DNS_MODE}" != "sing-box" ] && [ "$protocol" = "_shunt" ] && {
DNS_MODE="sing-box"
[ "$v2ray_dns_mode" = "tcp+doh" ] && v2ray_dns_mode="tcp"
@@ -638,18 +638,18 @@ start_global() {
NO_PLUGIN_DNS=1
_args="${_args} remote_dns_query_strategy=${REMOTE_DNS_QUERY_STRATEGY}"
DNSMASQ_FILTER_PROXY_IPV6=0
local _remote_dns_client_ip=$(config_t_get global remote_dns_client_ip)
local _remote_dns_client_ip=$(config_n_get @global[0] remote_dns_client_ip)
[ -n "${_remote_dns_client_ip}" ] && _args="${_args} remote_dns_client_ip=${_remote_dns_client_ip}"
[ "${DNS_CACHE}" = "0" ] && _args="${_args} dns_cache=0"
resolve_dns_port=${NEXT_DNS_LISTEN_PORT}
_args="${_args} dns_listen_port=${resolve_dns_port}"
case "$(config_t_get global direct_dns_mode "auto")" in
case "$(config_n_get @global[0] direct_dns_mode "auto")" in
udp)
_args="${_args} direct_dns_udp_server=$(normalize_dns "$(config_t_get global direct_dns 223.5.5.5:53)")"
_args="${_args} direct_dns_udp_server=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")"
;;
tcp)
_args="${_args} direct_dns_tcp_server=$(normalize_dns "$(config_t_get global direct_dns 223.5.5.5:53)")"
_args="${_args} direct_dns_tcp_server=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")"
;;
esac
@@ -661,19 +661,19 @@ start_global() {
resolve_dns_log="Sing-Box DNS(127.0.0.1#${resolve_dns_port}) -> ${_proto}://${REMOTE_DNS}"
;;
doh|http3)
local remote_dns_doh=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query")
local remote_dns_doh=$(config_n_get @global[0] remote_dns_doh "https://1.1.1.1/dns-query")
_args="${_args} remote_dns_doh=${remote_dns_doh}"
resolve_dns_log="Sing-Box DNS(127.0.0.1#${resolve_dns_port}) -> ${remote_dns_doh}"
;;
esac
local remote_fakedns=$(config_t_get global remote_fakedns 0)
local remote_fakedns=$(config_n_get @global[0] remote_fakedns 0)
[ "${remote_fakedns}" = "1" ] && {
REMOTE_FAKEDNS=1
_args="${_args} remote_fakedns=1"
resolve_dns_log="${resolve_dns_log} + FakeDNS"
USE_FAKEDNS=1
}
_args="${_args} remote_rewrite_ttl=$(config_t_get global remote_rewrite_ttl)"
_args="${_args} remote_rewrite_ttl=$(config_n_get @global[0] remote_rewrite_ttl)"
NEXT_DNS_LISTEN_PORT=$(expr $NEXT_DNS_LISTEN_PORT + 1)
}
_args="${_args} use_proxy_list=$USE_PROXY_LIST use_gfw_list=$USE_GFW_LIST chn_list=$CHN_LIST"
@@ -692,7 +692,7 @@ start_global() {
}
local protocol=$(config_n_get $NODE protocol)
local v2ray_dns_mode=$(config_t_get global v2ray_dns_mode tcp)
local v2ray_dns_mode=$(config_n_get @global[0] v2ray_dns_mode tcp)
[ "${DNS_MODE}" != "xray" ] && [ "$protocol" = "_shunt" ] && {
DNS_MODE="xray"
[ "$v2ray_dns_mode" = "http3" ] && v2ray_dns_mode="tcp"
@@ -714,18 +714,18 @@ start_global() {
NO_PLUGIN_DNS=1
_args="${_args} remote_dns_query_strategy=${REMOTE_DNS_QUERY_STRATEGY}"
DNSMASQ_FILTER_PROXY_IPV6=0
local _remote_dns_client_ip=$(config_t_get global remote_dns_client_ip)
local _remote_dns_client_ip=$(config_n_get @global[0] remote_dns_client_ip)
[ -n "${_remote_dns_client_ip}" ] && _args="${_args} remote_dns_client_ip=${_remote_dns_client_ip}"
[ "${DNS_CACHE}" = "0" ] && _args="${_args} dns_cache=0"
resolve_dns_port=${NEXT_DNS_LISTEN_PORT}
_args="${_args} dns_listen_port=${resolve_dns_port}"
case "$(config_t_get global direct_dns_mode "auto")" in
case "$(config_n_get @global[0] direct_dns_mode "auto")" in
udp)
_args="${_args} direct_dns_udp_server=$(normalize_dns "$(config_t_get global direct_dns 223.5.5.5:53)")"
_args="${_args} direct_dns_udp_server=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")"
;;
tcp)
_args="${_args} direct_dns_tcp_server=$(normalize_dns "$(config_t_get global direct_dns 223.5.5.5:53)")"
_args="${_args} direct_dns_tcp_server=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")"
;;
esac
@@ -737,12 +737,12 @@ start_global() {
resolve_dns_log="Xray DNS(127.0.0.1#${resolve_dns_port}) -> ${_proto}://${REMOTE_DNS}"
;;
doh)
local remote_dns_doh=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query")
local remote_dns_doh=$(config_n_get @global[0] remote_dns_doh "https://1.1.1.1/dns-query")
_args="${_args} remote_dns_doh=${remote_dns_doh}"
resolve_dns_log="Xray DNS(127.0.0.1#${resolve_dns_port}) -> ${remote_dns_doh}"
;;
esac
local remote_fakedns=$(config_t_get global remote_fakedns 0)
local remote_fakedns=$(config_n_get @global[0] remote_fakedns 0)
[ "${remote_fakedns}" = "1" ] && {
REMOTE_FAKEDNS=1
_args="${_args} remote_fakedns=1"
@@ -800,7 +800,7 @@ start_global() {
}
json_add_string "tcp_proxy_way" "${TCP_PROXY_WAY}"
lua $UTIL_HYSTERIA2 gen_config "$(json_dump)" > $config_file
ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client
ln_run "$(first_type $(config_n_get @global_app[0] hysteria_file))" "hysteria" $log_file -c "$config_file" client
;;
esac
if [ -n "${_socks_flag}" ]; then
@@ -918,7 +918,7 @@ start_crontab() {
local update_loop
if [ "$ENABLED_DEFAULT_ACL" = "1" ] || [ "$ENABLED_ACLS" = "1" ]; then
local start_daemon=$(config_t_get global_delay start_daemon 0)
local start_daemon=$(config_n_get @global_delay[0] start_daemon 0)
[ "$start_daemon" = "1" ] && { $APP_PATH/monitor.sh > /dev/null 2>&1 & }
fi
@@ -969,15 +969,15 @@ start_crontab() {
}
# ===== stop/start/restart =====
add_service_cron "$(config_t_get global_delay stop_week_mode)" "$(config_t_get global_delay stop_time_mode)" "stop" "配置定时任务:自动关闭服务。"
add_service_cron "$(config_n_get @global_delay[0] stop_week_mode)" "$(config_n_get @global_delay[0] stop_time_mode)" "stop" "配置定时任务:自动关闭服务。"
add_service_cron "$(config_t_get global_delay start_week_mode)" "$(config_t_get global_delay start_time_mode)" "start" "配置定时任务:自动开启服务。"
add_service_cron "$(config_n_get @global_delay[0] start_week_mode)" "$(config_n_get @global_delay[0] start_time_mode)" "start" "配置定时任务:自动开启服务。"
add_service_cron "$(config_t_get global_delay restart_week_mode)" "$(config_t_get global_delay restart_time_mode)" "restart" "配置定时任务:自动重启服务。"
add_service_cron "$(config_n_get @global_delay[0] restart_week_mode)" "$(config_n_get @global_delay[0] restart_time_mode)" "restart" "配置定时任务:自动重启服务。"
# ===== rule update =====
local rules_update_week_mode=$(config_t_get global_rules update_week_mode)
local rules_update_time_mode=$(config_t_get global_rules update_time_mode)
local rules_update_week_mode=$(config_n_get @global_rules[0] update_week_mode)
local rules_update_time_mode=$(config_n_get @global_rules[0] update_time_mode)
if [ -n "$rules_update_week_mode" ]; then
local rule_t=$(build_time "$rules_update_week_mode" "$rules_update_time_mode")
if [ "$rules_update_week_mode" = "8" ]; then
@@ -1037,12 +1037,20 @@ stop_crontab() {
#echolog "清除定时执行命令。"
}
start_adblock() {
[ "$(config_t_get global adblock 0)" != "1" ] && {
[ -s $RULES_PATH/my_block_host ] && ln -sf $RULES_PATH/my_block_host $RULES_PATH/block_host || > $RULES_PATH/block_host
return
}
"$APP_PATH/adblock.sh" > /dev/null 2>&1 &
}
start_dns() {
echolog "DNS域名解析:"
local china_ng_local_dns=$(IFS=','; set -- $LOCAL_DNS; [ "${1%%[#:]*}" = "127.0.0.1" ] && echo "$1" || ([ -n "$2" ] && echo "$*" || echo "$1"))
local sing_box_local_dns=
local direct_dns_mode=$(config_t_get global direct_dns_mode "auto")
local direct_dns_mode=$(config_n_get @global[0] direct_dns_mode "auto")
#获取访问控制节点所使用的DNS分流模式
local ACL_RULE_DNSMASQ=0
@@ -1056,12 +1064,12 @@ start_dns() {
case "$direct_dns_mode" in
udp)
LOCAL_DNS=$(normalize_dns "$(config_t_get global direct_dns 223.5.5.5:53)")
LOCAL_DNS=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")
china_ng_local_dns=${LOCAL_DNS}
sing_box_local_dns="direct_dns_udp_server=${LOCAL_DNS}"
;;
tcp)
local DIRECT_DNS=$(normalize_dns "$(config_t_get global direct_dns 223.5.5.5:53)")
local DIRECT_DNS=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")
china_ng_local_dns="tcp://${DIRECT_DNS}"
sing_box_local_dns="direct_dns_tcp_server=${DIRECT_DNS}"
@@ -1082,7 +1090,7 @@ start_dns() {
esac
# 追加直连DNS到iptables/nftables
[ "$(config_t_get global_haproxy balancing_enable 0)" != "1" ] && IPT_APPEND_DNS=
[ "$(config_n_get @global_haproxy[0] balancing_enable 0)" != "1" ] && IPT_APPEND_DNS=
add_default_port() {
[ -z "$1" ] && echo "" || echo "$1" | awk -F',' '{for(i=1;i<=NF;i++){if($i !~ /#/) $i=$i"#53";} print $0;}' OFS=','
}
@@ -1101,7 +1109,7 @@ start_dns() {
case "$DNS_MODE" in
dns2socks)
local dns2socks_socks_server=$(echo $(config_t_get global socks_server 127.0.0.1:1080) | sed "s/#/:/g")
local dns2socks_socks_server=$(echo $(config_n_get @global[0] socks_server 127.0.0.1:1080) | sed "s/#/:/g")
local dns2socks_forward=$(get_first_dns REMOTE_DNS 53 | sed 's/#/:/g')
run_dns2socks socks=$dns2socks_socks_server listen_address=127.0.0.1 listen_port=${NEXT_DNS_LISTEN_PORT} dns=$dns2socks_forward cache=$DNS_CACHE
echolog " - dns2socks(${TUN_DNS}),${dns2socks_socks_server} -> tcp://${dns2socks_forward}"
@@ -1116,17 +1124,17 @@ start_dns() {
_args="${_args} direct_dns_query_strategy=${DIRECT_DNS_QUERY_STRATEGY}"
_args="${_args} remote_dns_query_strategy=${REMOTE_DNS_QUERY_STRATEGY}"
DNSMASQ_FILTER_PROXY_IPV6=0
local remote_fakedns=$(config_t_get global remote_fakedns 0)
local remote_fakedns=$(config_n_get @global[0] remote_fakedns 0)
[ "${remote_fakedns}" = "1" ] && {
REMOTE_FAKEDNS=1
_args="${_args} remote_fakedns=1"
USE_FAKEDNS=1
}
_args="${_args} remote_rewrite_ttl=$(config_t_get global remote_rewrite_ttl)"
local _remote_dns_client_ip=$(config_t_get global remote_dns_client_ip)
_args="${_args} remote_rewrite_ttl=$(config_n_get @global[0] remote_rewrite_ttl)"
local _remote_dns_client_ip=$(config_n_get @global[0] remote_dns_client_ip)
[ -n "${_remote_dns_client_ip}" ] && _args="${_args} remote_dns_client_ip=${_remote_dns_client_ip}"
TCP_PROXY_DNS=1
local v2ray_dns_mode=$(config_t_get global v2ray_dns_mode tcp)
local v2ray_dns_mode=$(config_n_get @global[0] v2ray_dns_mode tcp)
_args="${_args} dns_listen_port=${NEXT_DNS_LISTEN_PORT}"
_args="${_args} remote_dns_protocol=${v2ray_dns_mode}"
case "$v2ray_dns_mode" in
@@ -1136,7 +1144,7 @@ start_dns() {
echolog " - Sing-Box DNS(${TUN_DNS}) -> ${_proto}://${REMOTE_DNS}"
;;
doh|http3)
local remote_dns_doh=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query")
local remote_dns_doh=$(config_n_get @global[0] remote_dns_doh "https://1.1.1.1/dns-query")
_args="${_args} remote_dns_doh=${remote_dns_doh}"
echolog " - Sing-Box DNS(${TUN_DNS}) -> ${remote_dns_doh}"
;;
@@ -1156,16 +1164,16 @@ start_dns() {
_args="${_args} direct_dns_query_strategy=${DIRECT_DNS_QUERY_STRATEGY}"
_args="${_args} remote_dns_query_strategy=${REMOTE_DNS_QUERY_STRATEGY}"
DNSMASQ_FILTER_PROXY_IPV6=0
local remote_fakedns=$(config_t_get global remote_fakedns 0)
local remote_fakedns=$(config_n_get @global[0] remote_fakedns 0)
[ "${remote_fakedns}" = "1" ] && {
REMOTE_FAKEDNS=1
_args="${_args} remote_fakedns=1"
USE_FAKEDNS=1
}
local _remote_dns_client_ip=$(config_t_get global remote_dns_client_ip)
local _remote_dns_client_ip=$(config_n_get @global[0] remote_dns_client_ip)
[ -n "${_remote_dns_client_ip}" ] && _args="${_args} remote_dns_client_ip=${_remote_dns_client_ip}"
TCP_PROXY_DNS=1
local v2ray_dns_mode=$(config_t_get global v2ray_dns_mode tcp)
local v2ray_dns_mode=$(config_n_get @global[0] v2ray_dns_mode tcp)
_args="${_args} dns_listen_port=${NEXT_DNS_LISTEN_PORT}"
_args="${_args} remote_dns_protocol=${v2ray_dns_mode}"
case "$v2ray_dns_mode" in
@@ -1175,7 +1183,7 @@ start_dns() {
echolog " - Xray DNS(${TUN_DNS}) -> ${_proto}://${REMOTE_DNS}"
;;
doh)
local remote_dns_doh=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query")
local remote_dns_doh=$(config_n_get @global[0] remote_dns_doh "https://1.1.1.1/dns-query")
_args="${_args} remote_dns_doh=${remote_dns_doh}"
echolog " - Xray DNS(${TUN_DNS}) -> ${remote_dns_doh}"
;;
@@ -1219,8 +1227,8 @@ start_dns() {
[ "${DNS_SHUNT}" = "smartdns" ] && {
if command -v smartdns > /dev/null 2>&1; then
rm -rf $TMP_PATH2/dnsmasq_default*
local group_domestic=$(config_t_get global group_domestic)
local smartdns_remote_dns=$(config_t_get global smartdns_remote_dns)
local group_domestic=$(config_n_get @global[0] group_domestic)
local smartdns_remote_dns=$(config_n_get @global[0] smartdns_remote_dns)
if [ -n "${smartdns_remote_dns}" ] && [ "${smartdns_remote_dns}" != "nil" ]; then
smartdns_remote_dns=$(echo ${smartdns_remote_dns} | tr -s ' ' '|')
else
@@ -1232,7 +1240,7 @@ start_dns() {
echolog " - SmartDNS(127.0.0.1#${SMARTDNS_LOCAL_PORT}) -> 国内分组(${group_domestic:-null}),SmartDNS(${china_ng_listen}) -> Dnsmasq"
china_ng_listen="${china_ng_listen},::1#${SMARTDNS_LISTEN_PORT}"
local subnet_ip=$(config_t_get global remote_dns_client_ip)
local subnet_ip=$(config_n_get @global[0] remote_dns_client_ip)
lua $APP_PATH/helper_smartdns_add.lua -FLAG "default" -SMARTDNS_CONF "/tmp/etc/smartdns/$CONFIG.conf" \
-LISTEN_PORT ${SMARTDNS_LISTEN_PORT} -LOCAL_PORT ${SMARTDNS_LOCAL_PORT} \
-LOCAL_GROUP ${group_domestic:-null} -REMOTE_GROUP "passwall_proxy" -REMOTE_PROXY_SERVER ${GLOBAL_SOCKS_server} -USE_DEFAULT_DNS "${USE_DEFAULT_DNS:-direct}" \
@@ -1277,11 +1285,11 @@ start_dns() {
_gfwlist=${USE_GFW_LIST} \
_chnlist=${CHN_LIST} \
_default_mode=${TCP_PROXY_MODE} \
_default_tag=$(config_t_get global chinadns_ng_default_tag smart) \
_default_tag=$(config_n_get @global[0] chinadns_ng_default_tag smart) \
_no_logic_log=0 \
_node=${NODE} \
_filter_https=$(config_t_get global force_https_soa 0) \
_log=$(config_t_get global log_chinadns_ng 0)
_filter_https=$(config_n_get @global[0] force_https_soa 0) \
_log=$(config_n_get @global[0] log_chinadns_ng 0)
USE_DEFAULT_DNS="chinadns_ng"
}
@@ -1338,16 +1346,8 @@ start_dns() {
fi
}
start_adblock() {
[ "$(config_t_get global adblock 0)" != "1" ] && {
[ -s $RULES_PATH/my_block_host ] && ln -sf $RULES_PATH/my_block_host $RULES_PATH/block_host || > $RULES_PATH/block_host
return
}
"$APP_PATH/adblock.sh" > /dev/null 2>&1 &
}
start_haproxy() {
[ "$(config_t_get global_haproxy balancing_enable 0)" != "1" ] && return
[ "$(config_n_get @global_haproxy[0] balancing_enable 0)" != "1" ] && return
local haproxy_ver=$($(first_type haproxy) -v 2>/dev/null | awk 'NR==1 {print $3}' | cut -d'-' -f1)
if [ "$(check_ver "$haproxy_ver" "3.0.0")" = "1" ]; then
echolog "* 注意:haproxy($haproxy_ver) 程序版本低,HAPROXY 负载均衡启动失败,请更新到 3.0 以上版本。"
@@ -1514,13 +1514,13 @@ acl_app() {
_china_ng_listen="127.0.0.1#${chinadns_port},::1#${chinadns_port}"
_chinadns_local_dns=$(IFS=','; set -- $LOCAL_DNS; [ "${1%%[#:]*}" = "127.0.0.1" ] && echo "$1" || ([ -n "$2" ] && echo "$1,$2" || echo "$1"))
_direct_dns_mode=$(config_t_get global direct_dns_mode "auto")
_direct_dns_mode=$(config_n_get @global[0] direct_dns_mode "auto")
case "${_direct_dns_mode}" in
udp)
_chinadns_local_dns=$(normalize_dns "$(config_t_get global direct_dns 223.5.5.5:53)")
_chinadns_local_dns=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")
;;
tcp)
_chinadns_local_dns="tcp://$(normalize_dns "$(config_t_get global direct_dns 223.5.5.5:53)")"
_chinadns_local_dns="tcp://$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")"
;;
esac
@@ -1638,7 +1638,7 @@ start() {
}
mkdir -p /tmp/etc /tmp/log $TMP_PATH $TMP_BIN_PATH $TMP_SCRIPT_FUNC_PATH $TMP_ROUTE_PATH $TMP_ACL_PATH $TMP_PATH2
get_config
export V2RAY_LOCATION_ASSET=$(config_t_get global_rules v2ray_location_asset "/usr/share/v2ray/")
export V2RAY_LOCATION_ASSET=$(config_n_get @global_rules[0] v2ray_location_asset "/usr/share/v2ray/")
export XRAY_LOCATION_ASSET=$V2RAY_LOCATION_ASSET
export ENABLE_DEPRECATED_GEOSITE=true
export ENABLE_DEPRECATED_GEOIP=true
@@ -1720,7 +1720,7 @@ stop() {
rm -rf $GLOBAL_DNSMASQ_CONF_PATH
[ "1" = "1" ] && {
#restore logic
bak_dnsmasq_dns_redirect=$(config_t_get global dnsmasq_dns_redirect)
bak_dnsmasq_dns_redirect=$(config_n_get @global[0] dnsmasq_dns_redirect)
[ -n "${bak_dnsmasq_dns_redirect}" ] && {
uci -q set dhcp.@dnsmasq[0].dns_redirect="${bak_dnsmasq_dns_redirect}"
uci -q commit dhcp
@@ -1746,50 +1746,50 @@ stop() {
get_config() {
ENABLED_DEFAULT_ACL=0
REDIR_PORT=$(echo $(get_new_port 1041 tcp,udp))
ENABLED=$(config_t_get global enabled 0)
SOCKS_ENABLED=$(config_t_get global socks_enabled 0)
NODE=$(config_t_get global node)
ENABLED=$(config_n_get @global[0] enabled 0)
SOCKS_ENABLED=$(config_n_get @global[0] socks_enabled 0)
NODE=$(config_n_get @global[0] node)
[ "$ENABLED" = 1 ] && {
if [ -n "$NODE" ] && ([ "$(config_get_type $NODE)" = "nodes" ] || [ "$(config_get_type $NODE)" = "socks" ]); then
ENABLED_DEFAULT_ACL=1
fi
}
ENABLED_ACLS=$(config_t_get global acl_enable 0)
ENABLED_ACLS=$(config_n_get @global[0] acl_enable 0)
set_cache_var ENABLED_DEFAULT_ACL $ENABLED_DEFAULT_ACL
set_cache_var ENABLED_ACLS $ENABLED_ACLS
TCP_PROXY_WAY=$(config_t_get global_forwarding tcp_proxy_way redirect)
PROXY_IPV6=$(config_t_get global_forwarding ipv6_tproxy 0)
TCP_REDIR_PORTS=$(config_t_get global_forwarding tcp_redir_ports '80,443')
UDP_REDIR_PORTS=$(config_t_get global_forwarding udp_redir_ports '1:65535')
TCP_NO_REDIR_PORTS=$(config_t_get global_forwarding tcp_no_redir_ports 'disable')
UDP_NO_REDIR_PORTS=$(config_t_get global_forwarding udp_no_redir_ports 'disable')
TCP_PROXY_DROP_PORTS=$(config_t_get global_forwarding tcp_proxy_drop_ports 'disable')
UDP_PROXY_DROP_PORTS=$(config_t_get global_forwarding udp_proxy_drop_ports '80,443')
USE_DIRECT_LIST=$(config_t_get global use_direct_list 1)
USE_PROXY_LIST=$(config_t_get global use_proxy_list 1)
USE_BLOCK_LIST=$(config_t_get global use_block_list 1)
USE_GFW_LIST=$(config_t_get global use_gfw_list 1)
CHN_LIST=$(config_t_get global chn_list direct)
TCP_PROXY_MODE=$(config_t_get global tcp_proxy_mode proxy)
UDP_PROXY_MODE=$(config_t_get global udp_proxy_mode proxy)
TCP_PROXY_WAY=$(config_n_get @global_forwarding[0] tcp_proxy_way redirect)
PROXY_IPV6=$(config_n_get @global_forwarding[0] ipv6_tproxy 0)
TCP_REDIR_PORTS=$(config_n_get @global_forwarding[0] tcp_redir_ports '80,443')
UDP_REDIR_PORTS=$(config_n_get @global_forwarding[0] udp_redir_ports '1:65535')
TCP_NO_REDIR_PORTS=$(config_n_get @global_forwarding[0] tcp_no_redir_ports 'disable')
UDP_NO_REDIR_PORTS=$(config_n_get @global_forwarding[0] udp_no_redir_ports 'disable')
TCP_PROXY_DROP_PORTS=$(config_n_get @global_forwarding[0] tcp_proxy_drop_ports 'disable')
UDP_PROXY_DROP_PORTS=$(config_n_get @global_forwarding[0] udp_proxy_drop_ports '80,443')
USE_DIRECT_LIST=$(config_n_get @global[0] use_direct_list 1)
USE_PROXY_LIST=$(config_n_get @global[0] use_proxy_list 1)
USE_BLOCK_LIST=$(config_n_get @global[0] use_block_list 1)
USE_GFW_LIST=$(config_n_get @global[0] use_gfw_list 1)
CHN_LIST=$(config_n_get @global[0] chn_list direct)
TCP_PROXY_MODE=$(config_n_get @global[0] tcp_proxy_mode proxy)
UDP_PROXY_MODE=$(config_n_get @global[0] udp_proxy_mode proxy)
[ "${TCP_PROXY_MODE}" != "disable" ] && TCP_PROXY_MODE="proxy"
[ "${UDP_PROXY_MODE}" != "disable" ] && UDP_PROXY_MODE="proxy"
LOCALHOST_PROXY=$(config_t_get global localhost_proxy 1)
LOCALHOST_PROXY=$(config_n_get @global[0] localhost_proxy 1)
[ "${LOCALHOST_PROXY}" = 1 ] && {
LOCALHOST_TCP_PROXY_MODE=$TCP_PROXY_MODE
LOCALHOST_UDP_PROXY_MODE=$UDP_PROXY_MODE
}
CLIENT_PROXY=$(config_t_get global client_proxy 1)
DNS_SHUNT=$(config_t_get global dns_shunt dnsmasq)
CLIENT_PROXY=$(config_n_get @global[0] client_proxy 1)
DNS_SHUNT=$(config_n_get @global[0] dns_shunt dnsmasq)
[ -z "$(first_type $DNS_SHUNT)" ] && DNS_SHUNT="dnsmasq"
DNS_MODE=$(config_t_get global dns_mode tcp)
[ "$DNS_SHUNT" = "smartdns" ] && DNS_MODE=$(config_t_get global smartdns_dns_mode socks)
REMOTE_DNS=$(normalize_dns "$(config_t_get global remote_dns 1.1.1.1:53)")
USE_DEFAULT_DNS=$(config_t_get global use_default_dns direct)
FILTER_PROXY_IPV6=$(config_t_get global filter_proxy_ipv6 0)
DNS_REDIRECT=$(config_t_get global dns_redirect 1)
DNS_MODE=$(config_n_get @global[0] dns_mode tcp)
[ "$DNS_SHUNT" = "smartdns" ] && DNS_MODE=$(config_n_get @global[0] smartdns_dns_mode socks)
REMOTE_DNS=$(normalize_dns "$(config_n_get @global[0] remote_dns 1.1.1.1:53)")
USE_DEFAULT_DNS=$(config_n_get @global[0] use_default_dns direct)
FILTER_PROXY_IPV6=$(config_n_get @global[0] filter_proxy_ipv6 0)
DNS_REDIRECT=$(config_n_get @global[0] dns_redirect 1)
REDIRECT_LIST="socks ss-rust ssr sing-box xray naiveproxy hysteria2"
TPROXY_LIST="socks ss-rust ssr sing-box xray hysteria2"
@@ -353,7 +353,7 @@ load_acl() {
}
local dns_redirect
[ $(config_t_get global dns_redirect "1") = "1" ] && dns_redirect=53
[ $(config_n_get @global[0] dns_redirect "1") = "1" ] && dns_redirect=53
if ([ -n "$tcp_port" ] && [ -n "${tcp_proxy_mode}" ]) || ([ -n "$udp_port" ] && [ -n "${udp_proxy_mode}" ]); then
[ "${use_proxy_list}" = "1" ] && {
[ "${use_global_config}" = "0" ] && {
@@ -583,7 +583,7 @@ load_acl() {
}
local DNS_REDIRECT
[ $(config_t_get global dns_redirect "1") = "1" ] && DNS_REDIRECT=53
[ $(config_n_get @global[0] dns_redirect "1") = "1" ] && DNS_REDIRECT=53
if [ -n "$NODE" ] && ([ -n "${TCP_PROXY_MODE}" ] || [ -n "${UDP_PROXY_MODE}" ]); then
[ -n "${DNS_REDIRECT_PORT}" ] && DNS_REDIRECT=${DNS_REDIRECT_PORT}
else
@@ -769,7 +769,7 @@ filter_server_port() {
local port=$(echo "$2" | tr '-' ':' | tr -d ' ')
local stream=$(echo "$3" | tr 'A-Z' 'a-z')
local ipt_tmp="$ipt_n" _is_tproxy _ipt_cmd _ver multi_ports p ports
[ "$(config_t_get global_forwarding tcp_proxy_way redirect)" = "tproxy" ] && _is_tproxy="TPROXY"
[ "$(config_n_get @global_forwarding[0] tcp_proxy_way redirect)" = "tproxy" ] && _is_tproxy="TPROXY"
[ "$stream" = "udp" ] && _is_tproxy="TPROXY"
[ -n "$_is_tproxy" ] && ipt_tmp="$ipt_m"
for _ver in 4 6; do
@@ -892,8 +892,8 @@ add_firewall_rule() {
local USE_DIRECT_LIST_ALL=${USE_DIRECT_LIST}
local USE_BLOCK_LIST_ALL=${USE_BLOCK_LIST}
USE_SHUNT_NODE=0
USE_GEOVIEW=$(config_t_get global_rules enable_geoview)
[ -z "$(first_type $(config_t_get global_app geoview_file) geoview)" ] && USE_GEOVIEW=0
USE_GEOVIEW=$(config_n_get @global_rules[0] enable_geoview)
[ -z "$(first_type $(config_n_get @global_app[0] geoview_file) geoview)" ] && USE_GEOVIEW=0
[ -n "$NODE" ] && [ "$(config_n_get $NODE protocol)" = "_shunt" ] && USE_SHUNT_NODE=1
@@ -1022,8 +1022,8 @@ add_firewall_rule() {
filter_vpsip > /dev/null 2>&1 &
# filter_haproxy > /dev/null 2>&1 &
accept_icmp=$(config_t_get global_forwarding accept_icmp 0)
accept_icmpv6=$(config_t_get global_forwarding accept_icmpv6 0)
accept_icmp=$(config_n_get @global_forwarding[0] accept_icmp 0)
accept_icmpv6=$(config_n_get @global_forwarding[0] accept_icmpv6 0)
if [ "${TCP_PROXY_WAY}" = "redirect" ]; then
unset is_tproxy
@@ -1050,7 +1050,7 @@ add_firewall_rule() {
$ipt_n -A PSW_OUTPUT -m mark --mark 255 -j RETURN
$ipt_n -N PSW_DNS
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
if [ $(config_n_get @global[0] dns_redirect "1") = "0" ]; then
#Only hijack when dest address is local IP
$ipt_n -I PREROUTING -m set --match-set $IPSET_LAN src $(dst $IPSET_LOCAL) -j PSW_DNS
else
@@ -1121,7 +1121,7 @@ add_firewall_rule() {
}
$ip6t_n -N PSW_DNS
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
if [ $(config_n_get @global[0] dns_redirect "1") = "0" ]; then
#Only hijack when dest address is local IP
$ip6t_n -I PREROUTING -m set --match-set $IPSET_LAN6 src $(dst $IPSET_LOCAL6) -j PSW_DNS
else
@@ -1532,7 +1532,7 @@ start() {
stop() {
[ -z "$(command -v echolog)" ] && . "$UTILS_PATH"
del_firewall_rule
[ $(config_t_get global flush_set_on_reboot "0") = "1" ] || [ $(config_t_get global flush_set "0") = "1" ] && {
[ $(config_n_get @global[0] flush_set_on_reboot "0") = "1" ] || [ $(config_n_get @global[0] flush_set "0") = "1" ] && {
uci -q delete ${CONFIG}.@global[0].flush_set
uci -q commit ${CONFIG}
flush_ipset
@@ -8,9 +8,13 @@ MAX_RESTART_COUNT=10
RESTART_STATS_DIR="${TMP_PATH}/script_rstats"
mkdir -p "$RESTART_STATS_DIR"
ENABLED=$(config_n_get @global[0] enabled 0)
[ "$ENABLED" != 1 ] && return 1
ENABLED=$(config_n_get @global_delay[0] start_daemon 0)
[ "$ENABLED" != 1 ] && return 1
sleep 58s
last_cleanup_date=$(date +%Y%m%d)
while [ 1 -eq 1 ]; do
while [ "$ENABLED" -eq 1 ]; do
[ -f "$LOCK_FILE" ] && {
sleep 6s
continue
@@ -406,7 +406,7 @@ load_acl() {
}
local dns_redirect
[ $(config_t_get global dns_redirect "1") = "1" ] && dns_redirect=53
[ $(config_n_get @global[0] dns_redirect "1") = "1" ] && dns_redirect=53
if ([ -n "$tcp_port" ] && [ -n "${tcp_proxy_mode}" ]) || ([ -n "$udp_port" ] && [ -n "${udp_proxy_mode}" ]); then
[ "${use_proxy_list}" = "1" ] && {
[ "${use_global_config}" = "0" ] && {
@@ -643,7 +643,7 @@ load_acl() {
}
local DNS_REDIRECT
[ $(config_t_get global dns_redirect "1") = "1" ] && DNS_REDIRECT=53
[ $(config_n_get @global[0] dns_redirect "1") = "1" ] && DNS_REDIRECT=53
if [ -n "$NODE" ] && ([ -n "${TCP_PROXY_MODE}" ] || [ -n "${UDP_PROXY_MODE}" ]); then
[ -n "${DNS_REDIRECT_PORT}" ] && DNS_REDIRECT=${DNS_REDIRECT_PORT}
else
@@ -842,7 +842,7 @@ filter_server_port() {
local stream=$(echo "$3" | tr 'A-Z' 'a-z')
local _ip_type _port_expr _ver _is_tproxy
local _nft_output_chain="PSW_OUTPUT_NAT"
[ "$(config_t_get global_forwarding tcp_proxy_way redirect)" = "tproxy" ] && _is_tproxy="TPROXY"
[ "$(config_n_get @global_forwarding[0] tcp_proxy_way redirect)" = "tproxy" ] && _is_tproxy="TPROXY"
[ "$stream" = "udp" ] && _is_tproxy="TPROXY"
[ -n "$_is_tproxy" ] && _nft_output_chain="PSW_OUTPUT_MANGLE"
case "$port" in
@@ -996,8 +996,8 @@ add_firewall_rule() {
local USE_DIRECT_LIST_ALL=${USE_DIRECT_LIST}
local USE_BLOCK_LIST_ALL=${USE_BLOCK_LIST}
USE_SHUNT_NODE=0
USE_GEOVIEW=$(config_t_get global_rules enable_geoview)
[ -z "$(first_type $(config_t_get global_app geoview_file) geoview)" ] && USE_GEOVIEW=0
USE_GEOVIEW=$(config_n_get @global_rules[0] enable_geoview)
[ -z "$(first_type $(config_n_get @global_app[0] geoview_file) geoview)" ] && USE_GEOVIEW=0
[ -n "$NODE" ] && [ "$(config_n_get $NODE protocol)" = "_shunt" ] && USE_SHUNT_NODE=1
@@ -1114,8 +1114,8 @@ add_firewall_rule() {
# Prevent some conditions
filter_vps_addr $(config_n_get $NODE address) $(config_n_get $NODE download_address) > /dev/null 2>&1 &
accept_icmp=$(config_t_get global_forwarding accept_icmp 0)
accept_icmpv6=$(config_t_get global_forwarding accept_icmpv6 0)
accept_icmp=$(config_n_get @global_forwarding[0] accept_icmp 0)
accept_icmpv6=$(config_n_get @global_forwarding[0] accept_icmpv6 0)
if [ "${TCP_PROXY_WAY}" = "redirect" ]; then
unset is_tproxy
@@ -1134,7 +1134,7 @@ add_firewall_rule() {
nft "add chain $NFTABLE_NAME PSW_DNS"
nft "flush chain $NFTABLE_NAME PSW_DNS"
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
if [ $(config_n_get @global[0] dns_redirect "1") = "0" ]; then
#Only hijack when dest address is local IP
nft "insert rule $NFTABLE_NAME dstnat ip saddr @${NFTSET_LAN} ip daddr @${NFTSET_LOCAL} jump PSW_DNS"
nft "insert rule $NFTABLE_NAME dstnat ip6 saddr @${NFTSET_LAN6} ip6 daddr @${NFTSET_LOCAL6} jump PSW_DNS"
@@ -1570,7 +1570,7 @@ start() {
stop() {
[ -z "$(command -v echolog)" ] && . "$UTILS_PATH"
del_firewall_rule
[ $(config_t_get global flush_set_on_reboot "0") = "1" ] || [ $(config_t_get global flush_set "0") = "1" ] && {
[ $(config_n_get @global[0] flush_set_on_reboot "0") = "1" ] || [ $(config_n_get @global[0] flush_set "0") = "1" ] && {
uci -q delete ${CONFIG}.@global[0].flush_set
uci -q commit ${CONFIG}
#flush_table
@@ -18,8 +18,8 @@ do
if [ "$CFG_UPDATE_INT" -ne 0 ]; then
restart_week_mode=$(config_t_get global_delay restart_week_mode)
restart_interval_mode=$(config_t_get global_delay restart_interval_mode)
restart_week_mode=$(config_n_get @global_delay[0] restart_week_mode)
restart_interval_mode=$(config_n_get @global_delay[0] restart_interval_mode)
restart_interval_mode=$(expr "$restart_interval_mode" \* 60)
if [ -n "$restart_week_mode" ]; then
[ "$restart_week_mode" = "8" ] && {
@@ -27,8 +27,8 @@ do
}
fi
rules_update_week_mode=$(config_t_get global_rules update_week_mode)
rules_update_interval_mode=$(config_t_get global_rules update_interval_mode)
rules_update_week_mode=$(config_n_get @global_rules[0] update_week_mode)
rules_update_interval_mode=$(config_n_get @global_rules[0] update_interval_mode)
rules_update_interval_mode=$(expr "$rules_update_interval_mode" \* 60)
if [ -n "$rules_update_week_mode" ]; then
[ "$rules_update_week_mode" = "8" ] && {
@@ -61,7 +61,7 @@ url_test_node() {
local curlx="socks5h://127.0.0.1:${_tmp_port}"
fi
sleep 2s
local probeUrl=$(config_t_get global_other url_test_url https://www.google.com/generate_204)
local probeUrl=$(config_n_get @global_other[0] url_test_url https://www.google.com/generate_204)
result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_pretransfer}" -x ${curlx} "${probeUrl}")
# 结束 SS 插件进程
local pid_file="${TMP_PATH}/url_test_${node_id}_plugin.pid"
@@ -40,12 +40,6 @@ config_n_get() {
echo "${ret:=$3}"
}
config_t_get() {
local index=${4:-0}
local ret=$(uci -q get "${CONFIG}.@${1}[${index}].${2}" 2>/dev/null)
echo "${ret:=${3}}"
}
config_t_set() {
local index=${4:-0}
local ret=$(uci -q set "${CONFIG}.@${1}[${index}].${2}=${3}" 2>/dev/null)
@@ -70,9 +64,9 @@ get_geoip() {
local geoip_type_flag=""
local output_path="${geo_output_path}/geoip-${geoip_code}-$2"
[ ! -s "${output_path}" ] && {
local geoip_path="$(config_t_get global_rules v2ray_location_asset)"
local geoip_path="$(config_n_get @global_rules[0] v2ray_location_asset)"
geoip_path="${geoip_path%*/}/geoip.dat"
local bin="$(first_type $(config_t_get global_app geoview_file) geoview)"
local bin="$(first_type $(config_n_get @global_app[0] geoview_file) geoview)"
[ -n "$bin" ] && [ -s "$geoip_path" ] || { echo ""; return; }
case "$2" in
"ipv4") geoip_type_flag="-ipv6=false" ;;
@@ -480,8 +474,8 @@ ln_run() {
return 1
}
[ "${output}" != "/dev/null" ] && [ -n "$(echo "${output}" | grep -E "default|socks_")" ] && [ "${ln_name}" != "chinadns-ng" ] && {
local persist_log_path=$(config_t_get global persist_log_path)
local sys_log=$(config_t_get global sys_log "0")
local persist_log_path=$(config_n_get @global[0] persist_log_path)
local sys_log=$(config_n_get @global[0] sys_log "0")
}
if [ -z "$persist_log_path" ] && [ "$sys_log" != "1" ]; then
${file_func:-echolog " - ${ln_name}"} "$@" >${output} 2>&1 &
+1 -7
View File
@@ -7,14 +7,13 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.8.20
PKG_RELEASE:=98
PKG_RELEASE:=99
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \
CONFIG_PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client \
@@ -104,11 +103,6 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy
select PACKAGE_haproxy
default y if aarch64||arm||i386||x86_64
config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria
bool "Include Hysteria"
select PACKAGE_hysteria
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client
bool "Include Shadowsocks Rust Client"
depends on !i386
@@ -72,7 +72,6 @@ function index()
entry({"admin", "services", appname, "get_now_use_node"}, call("get_now_use_node")).leaf = true
entry({"admin", "services", appname, "get_redir_log"}, call("get_redir_log")).leaf = true
entry({"admin", "services", appname, "get_socks_log"}, call("get_socks_log")).leaf = true
entry({"admin", "services", appname, "get_acl_log"}, call("get_acl_log")).leaf = true
entry({"admin", "services", appname, "get_log"}, call("get_log")).leaf = true
entry({"admin", "services", appname, "clear_log"}, call("clear_log")).leaf = true
entry({"admin", "services", appname, "index_status"}, call("index_status")).leaf = true
@@ -304,10 +303,9 @@ end
function get_redir_log()
local id = http.formvalue("id")
local name = http.formvalue("name")
local file_path = api.TMP_PATH .. "/acl/" .. id .. "/" .. name .. ".log"
local file_path = api.TMP_PATH .. "/acl/" .. id .. ".log"
if nixio.fs.access(file_path) then
local content = luci.sys.exec("tail -n 19999 '" .. file_path .. "'")
local content = luci.sys.exec("tail -n 5000 '" .. file_path .. "'")
content = content:gsub("\n", "<br />")
http.write(content)
else
@@ -327,18 +325,6 @@ function get_socks_log()
end
end
function get_acl_log()
local id = http.formvalue("id")
local path = api.TMP_PATH .. "/acl/" .. id .. "/node.log"
if nixio.fs.access(path) then
local content = luci.sys.exec("tail -n 5000 '" .. path .. "'")
content = content:gsub("\n", "<br />")
http.write(content)
else
http.write(string.format("<script>alert('%s');window.close();</script>", i18n.translate("Not enabled log")))
end
end
function get_log()
-- luci.sys.exec("[ -f /tmp/log/passwall2.log ] && sed '1!G;h;$!d' /tmp/log/passwall2.log > /tmp/log/passwall2_show.log")
http.write(luci.sys.exec("[ -f '/tmp/log/passwall2.log' ] && cat /tmp/log/passwall2.log"))
@@ -350,7 +336,7 @@ end
function index_status()
local e = {}
e["global_status"] = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/bin/' | grep 'default' | grep 'global' >/dev/null" % api.TMP_PATH) == 0
e["global_status"] = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/bin/' | grep '/acl/default' >/dev/null" % api.TMP_PATH) == 0
http_write_json(e)
end
@@ -50,20 +50,11 @@ end
o = s:option(DummyValue, "sources", translate("Source"))
o.rawhtml = true
o.cfgvalue = function(t, n)
local e = ''
local v = Value.cfgvalue(t, n) or '-'
string.gsub(v, '[^' .. " " .. ']+', function(w)
local a = w
if mac_t[w] then
a = a .. ' (' .. mac_t[w].ip .. ')'
end
if #e > 0 then
e = e .. "<br />"
end
e = e .. a
end)
return e
o.cfgvalue = function(self, section)
local v = self.map:get(section, self.option) or {}
if type(v) == "table" then
return table.concat(v, "<br/>")
end
end
i = s:option(DummyValue, "mode", translate("Mode"))
@@ -71,6 +62,8 @@ i.cfgvalue = function(t, n)
local v = Value.cfgvalue(t, n) or '0'
if v == "1" then
return translate("Proxy")
elseif v == "2" then
return translate("Proxy") .. " " .. translate("Use global config")
end
return translate("No Proxy")
end
@@ -98,25 +98,9 @@ sources.description = "<ul><li>" .. translate("Example:")
.. "</li><li>" .. translate("IP range") .. ": 192.168.1.100-192.168.1.200"
.. "</li><li>" .. translate("IPSet") .. ": ipset:lanlist"
.. "</li></ul>"
sources.cast = "string"
for _, key in pairs(mac_t) do
sources:value(key.mac, "%s (%s)" % {key.mac, key.ip})
end
sources.cfgvalue = function(self, section)
local value
if self.tag_error[section] then
value = self:formvalue(section)
else
value = self.map:get(section, self.option)
if type(value) == "string" then
local value2 = {}
string.gsub(value, '[^' .. " " .. ']+', function(w) table.insert(value2, w) end)
value = value2
end
end
return value
end
sources.validate = function(self, value, t)
local err = {}
for _, v in ipairs(value) do
@@ -155,47 +139,75 @@ sources.validate = function(self, value, t)
return value
end
local NODE = m:get("@global[0]", "node")
o = s:option(ListValue, "mode", translate("Mode"))
o:value("0", translate("No Proxy"))
o:value("1", translate("Proxy"))
o:value("2", translate("Proxy") .. " " .. translate("Use global config") .. "(" .. api.get_node_name(NODE) .. ")")
---- TCP No Redir Ports
local TCP_NO_REDIR_PORTS = m:get("@global_forwarding[0]", "tcp_no_redir_ports")
o = s:option(Value, "tcp_no_redir_ports", translate("TCP No Redir Ports"))
o:value("", translate("Use global config") .. "(" .. TCP_NO_REDIR_PORTS .. ")")
o:value("disable", translate("No patterns are used"))
o:value("", translate("No patterns are used"))
o:value("1:65535", translate("All"))
o:depends("mode", "1")
o:depends("mode", "2")
o.validate = port_validate
---- UDP No Redir Ports
local UDP_NO_REDIR_PORTS = m:get("@global_forwarding[0]", "udp_no_redir_ports")
o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"))
o:value("", translate("Use global config") .. "(" .. UDP_NO_REDIR_PORTS .. ")")
o:value("disable", translate("No patterns are used"))
o:value("", translate("No patterns are used"))
o:value("1:65535", translate("All"))
o:depends("mode", "1")
o:depends("mode", "2")
o.validate = port_validate
o = s:option(DummyValue, "_hide_node_option", "")
o = s:option(DummyValue, "_show_tcp_redir", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends({ tcp_no_redir_ports = "1:65535", ['!reverse'] = true })
o = s:option(DummyValue, "_show_udp_redir", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends({ udp_no_redir_ports = "1:65535", ['!reverse'] = true })
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
o:value("1:65535", translate("All"))
o:value("22,25,53,80,143,443,465,587,853,873,993,995,5222,8080,8443,9418", translate("Common Use"))
o:value("80,443", "80,443")
o.default = o.keylist[1]
o.validate = port_validate
o:depends({ _node = "1", _show_tcp_redir = "1" })
o:depends({ mode = "2", _show_tcp_redir = "1" })
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"))
o:value("1:65535", translate("All"))
o.default = o.keylist[1]
o.validate = port_validate
o:depends({ _node = "1", _show_udp_redir = "1" })
o:depends({ mode = "2", _show_udp_redir = "1" })
o = s:option(DummyValue, "tips", " ")
o.rawhtml = true
o.cfgvalue = function(t, n)
return string.format('<font color="red">%s</font>',
translate("The port settings support single ports and ranges.<br>Separate multiple ports with commas (,).<br>Example: 21,80,443,1000:2000."))
end
o:depends("mode", "1")
o:depends("mode", "2")
o = s:option(DummyValue, "_no_proxy", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends("mode", "0")
o:depends({ tcp_no_redir_ports = "1:65535", udp_no_redir_ports = "1:65535" })
if TCP_NO_REDIR_PORTS == "1:65535" and UDP_NO_REDIR_PORTS == "1:65535" then
o:depends({ tcp_no_redir_ports = "", udp_no_redir_ports = "" })
end
local GLOBAL_ENABLED = m:get("@global[0]", "enabled")
local NODE = m:get("@global[0]", "node")
o = s:option(DummyValue, "_show_node_option", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends({ mode = "1", _no_proxy = "" })
o = s:option(ListValue, "node", "<a style='color: red'>" .. translate("Node") .. "</a>")
if GLOBAL_ENABLED == "1" and NODE then
o:value("", translate("Use global config") .. "(" .. api.get_node_name(NODE) .. ")")
o.group = {""}
else
o.group = {}
end
o:depends({ _hide_node_option = "1", ['!reverse'] = true })
o.group = {}
o:depends("_show_node_option", "1")
o.template = m:template_path("/cbi/nodes_listvalue")
current_node_id = o:formvalue(arg[1])
@@ -204,9 +216,14 @@ if not current_node_id then
end
current_node = current_node_id and m:get(current_node_id) or {}
o = s:option(Flag, "log", translate("Enable Node Log"))
o = s:option(DummyValue, "_node", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends({ node = "", ['!reverse'] = true })
o = s:option(Flag, "log", translate("Enable Node Log"))
o:depends("_node", "1")
o = s:option(ListValue, "loglevel", translate("Log Level"))
o.default = "warn"
o:value("debug", "Debug")
@@ -218,8 +235,8 @@ o:depends("log", "1")
o = s:option(DummyValue, "_acl_log", translate("Log File"))
o.rawhtml = true
o.cfgvalue = function(t, n)
local log_path = api.TMP_PATH .. "/acl/" .. arg[1] .. "/node.log"
local log_url = api.url("get_acl_log") .. "?id=" .. arg[1]
local log_path = api.TMP_PATH .. "/acl/" .. arg[1] .. ".log"
local log_url = api.url("get_redir_log") .. "?id=" .. arg[1]
return string.format(
'<code>%s</code>&nbsp;&nbsp;<input class="btn cbi-button cbi-button-apply" type="button" value="%s" onclick="window.open(\'%s\', \'_blank\')" />',
log_path,
@@ -229,46 +246,17 @@ o.cfgvalue = function(t, n)
end
o:depends("log", "1")
---- TCP Redir Ports
local TCP_REDIR_PORTS = m:get("@global_forwarding[0]", "tcp_redir_ports")
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
o:value("", translate("Use global config") .. "(" .. TCP_REDIR_PORTS .. ")")
o:value("1:65535", translate("All"))
o:value("22,25,53,80,143,443,465,587,853,873,993,995,5222,8080,8443,9418", translate("Common Use"))
o:value("80,443", "80,443")
o.validate = port_validate
o:depends({ _hide_node_option = "1", ['!reverse'] = true })
---- UDP Redir Ports
local UDP_REDIR_PORTS = m:get("@global_forwarding[0]", "udp_redir_ports")
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"))
o:value("", translate("Use global config") .. "(" .. UDP_REDIR_PORTS .. ")")
o:value("1:65535", translate("All"))
o.validate = port_validate
o:depends({ _hide_node_option = "1", ['!reverse'] = true })
o = s:option(DummyValue, "tips", " ")
o.rawhtml = true
o.cfgvalue = function(t, n)
return string.format('<font color="red">%s</font>',
translate("The port settings support single ports and ranges.<br>Separate multiple ports with commas (,).<br>Example: 21,80,443,1000:2000."))
end
o:depends({ _hide_node_option = "1", ['!reverse'] = true })
o = s:option(DummyValue, "_hide_dns_option", "")
o = s:option(DummyValue, "_show_dns_option", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends({ node = "" })
if GLOBAL_ENABLED == "1" and NODE then
o:depends({ node = NODE })
end
o:depends("_hide", "1")
o = s:option(ListValue, "direct_dns_query_strategy", translate("Direct Query Strategy"))
o.default = "UseIP"
o:value("UseIP")
o:value("UseIPv4")
o:value("UseIPv6")
o:depends({ _hide_dns_option = "1", ['!reverse'] = true })
o:depends("_show_dns_option", "1")
o = s:option(ListValue, "remote_dns_protocol", translate("Remote DNS Protocol"))
o:value("tcp", "TCP")
@@ -279,7 +267,7 @@ if current_node.type == "sing-box" then
o:value("quic", "QUIC(DoQ)")
o:value("http3", "HTTP3(DoH3)")
end
o:depends({ _hide_dns_option = "1", ['!reverse'] = true })
o:depends("_show_dns_option", "1")
---- DNS over TCP or UDP or TLS (DoT) or QUIC (DoQ)
o = s:option(Value, "remote_dns", translate("Remote DNS"))
@@ -356,12 +344,13 @@ o:depends("remote_dns_protocol", "tls")
o = s:option(Value, "remote_rewrite_ttl", translate("Remote DNS") .. " TTL")
o.datatype = "min(1)"
o.default = "30"
o:depends("_hide", "1")
o = s:option(ListValue, "dns_hosts_mode", translate("Domain Override"))
o:value("default", translate("Use global config"))
o:value("disable", translate("No patterns are used"))
o:value("custom", translate("-- custom --"))
o:depends({ _hide_dns_option = "1", ['!reverse'] = true })
o:depends("_show_dns_option", "1")
o = s:option(TextValue, "dns_hosts", translate("Domain Override"))
o.rows = 5
@@ -385,6 +374,7 @@ for k, v in pairs(nodes_table) do
if v.type == "sing-box" then
s.fields["remote_rewrite_ttl"]:depends({ node = v.id })
end
s.fields["_show_dns_option"]:depends({ mode = "1", node = v.id })
if v.node_type == "normal" or v.protocol == "_balancing" or v.protocol == "_urltest" then
--Shunt node has its own separate options.
s.fields["remote_fakedns"]:depends({ node = v.id, remote_dns_protocol = "tcp" })
@@ -282,8 +282,8 @@ loglevel:value("error")
o = s:taboption("log", DummyValue, "_log", translate("Log File"))
o.rawhtml = true
o.cfgvalue = function(t, n)
local log_path = api.TMP_PATH .. "/acl/default/global.log"
local log_url = api.url("get_redir_log") .. "?id=default&name=global"
local log_path = api.TMP_PATH .. "/acl/default.log"
local log_url = api.url("get_redir_log") .. "?id=default"
return string.format(
'<code>%s</code>&nbsp;&nbsp;<input class="btn cbi-button cbi-button-apply" type="button" value="%s" onclick="window.open(\'%s\', \'_blank\')" />',
log_path,
@@ -4,7 +4,6 @@ api.set_default_cbi()
local has_ss_rust = api.is_finded("sslocal")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
local has_hysteria2 = api.finded_com("hysteria")
local ss_type = {}
local trojan_type = {}
local vmess_type = {}
@@ -33,10 +32,6 @@ if has_xray then
table.insert(hysteria2_type, s)
end
end
if has_hysteria2 then
local s = "hysteria2"
table.insert(hysteria2_type, s)
end
m = Map()
@@ -17,7 +17,6 @@ m:appendTemplate("/cbi/nodes_listvalue_com")
local has_ss_rust = api.is_finded("sslocal")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
local has_hysteria2 = api.finded_com("hysteria")
local ss_type = {}
local trojan_type = {}
local vmess_type = {}
@@ -46,10 +45,6 @@ if has_xray then
table.insert(hysteria2_type, s)
end
end
if has_hysteria2 then
local s = "hysteria2"
table.insert(hysteria2_type, s)
end
local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do
if e.node_type == "normal" then
@@ -72,8 +72,7 @@ s = m:section(NamedSection, "@global_forwarding[0]", "global_forwarding", transl
---- TCP No Redir Ports
o = s:option(Value, "tcp_no_redir_ports", translate("TCP No Redir Ports"))
o.default = "disable"
o:value("disable", translate("No patterns are used"))
o:value("", translate("No patterns are used"))
o:value("1:65535", translate("All"))
o.validate = port_validate
@@ -82,23 +81,22 @@ o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"),
"<font color='red'>" ..
translate("Fill in the ports you don't want to be forwarded by the agent, with the highest priority.") ..
"</font>")
o.default = "disable"
o:value("disable", translate("No patterns are used"))
o:value("", translate("No patterns are used"))
o:value("1:65535", translate("All"))
o.validate = port_validate
---- TCP Redir Ports
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
o.default = "22,25,53,80,143,443,465,587,853,873,993,995,5222,8080,8443,9418"
o:value("1:65535", translate("All"))
o:value("22,25,53,80,143,443,465,587,853,873,993,995,5222,8080,8443,9418", translate("Common Use"))
o:value("80,443", translate("Only Web"))
o.default = o.keylist[1]
o.validate = port_validate
---- UDP Redir Ports
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"))
o.default = "1:65535"
o:value("1:65535", translate("All"))
o.default = o.keylist[1]
o.validate = port_validate
o = s:option(DummyValue, "tips", " ")
@@ -1,106 +0,0 @@
if not api.finded_com("hysteria") then
return
end
-- [[ Hysteria2 ]]
local m, s1 = ...
local type_name = "Hysteria2"
s1.fields["type"]:value(type_name, "Hysteria2")
if s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
s.type_name = type_name
s.option_prefix = "hysteria2_"
o = s:option(Value, "address", translate("Address (Support Domain Name)"))
o:depends({ realms = false })
o = s:option(Value, "port", translate("Port"))
o.datatype = "port"
o:depends({ realms = false })
o = s:option(Value, "hop", translate("Port hopping range"))
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o:depends({ realms = false })
o = s:option(Value, "hop_interval", translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
o.datatype = "or(uinteger,portrange)"
o.placeholder = "30"
o.default = "30"
o:depends({ realms = false })
o = s:option(Flag, "realms", translate("Realms"))
o.default = "0"
o = s:option(Value, "realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
o:depends({ realms = "1" })
o.validate = function(self, value)
value = api.trim(value)
local realm = api.parse_realm_uri(value)
if realm then return value end
return nil, translate("Invalid Realm URL.")
end
o = s:option(DynamicList, "realm_stun", translate("Realm STUN"))
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
o:depends({ realms = "1" })
o = s:option(Value, "auth_password", translate("Auth Password"))
o.password = true
o = s:option(ListValue, "obfs_type", translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o = s:option(Value, "obfs_password", translate("Obfs Password"))
o:depends({ obfs_type = "salamander" })
o:depends({ obfs_type = "gecko" })
o = s:option(Value, "obfs_MinPacketSize", translate("Gecko Packet Size (min)"))
o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ obfs_type = "gecko" })
o = s:option(Value, "obfs_MaxPacketSize", translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ obfs_type = "gecko" })
o = s:option(Flag, "fast_open", translate("Fast Open"))
o.default = "0"
o = s:option(Value, "tls_serverName", translate("Domain"))
o = s:option(Flag, "tls_allowInsecure", translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
o.default = "0"
o = s:option(Value, "tls_pinSHA256", translate("PinSHA256"),translate("Certificate fingerprint"))
o = s:option(Value, "up_mbps", translate("Max upload Mbps"))
o = s:option(Value, "down_mbps", translate("Max download Mbps"))
o = s:option(Value, "recv_window", translate("QUIC stream receive window"))
o = s:option(Value, "recv_window_conn", translate("QUIC connection receive window"))
o = s:option(Value, "idle_timeout", translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)")
o.datatype = "range(4,120)"
o = s:option(Value, "keep_alive_period", translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)")
o.datatype = "range(2,60)"
o = s:option(Flag, "disable_mtu_discovery", translate("Disable MTU detection"))
o.default = "0"
o = s:option(Flag, "lazy_start", translate("Lazy Start"))
o.default = "0"
api.luci_types(s1, s)
@@ -455,9 +455,16 @@ if singbox_tags:find("with_wireguard") then
o:depends({ protocol = "wireguard" })
end
o = s:option(Flag, "bind_local", translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o:depends({ custom = false, is_endpoint = "" })
o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "accept_lan", translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
o.default = "0"
@@ -473,10 +473,17 @@ o = s:option(DummyValue, "gen_wireguard_key")
o.template = m:template_path("/server/gen_wireguard_key")
o:depends({ protocol = "wireguard" })
o = s:option(Flag, "bind_local", translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "accept_lan", translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
o.default = "0"
o:depends({ custom = false })
@@ -72,6 +72,17 @@ o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
@@ -103,6 +103,17 @@ o = s:option(Flag, "udp_forward", translate("UDP Forward"))
o.default = "1"
o.rmempty = false
o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true
o.allowany = true
o.default = "wan"
o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
@@ -1,143 +0,0 @@
if not api.finded_com("hysteria") then
return
end
-- [[ Hysteria2 ]]
local m, s1 = ...
local type_name = "Hysteria2"
s1.fields["type"]:value(type_name, "Hysteria2")
if not s1.val["type"] then
s1.val["type"] = type_name
end
if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
s.type_name = type_name
s.option_prefix = "hysteria2_"
o = s:option(Flag, "custom", translate("Use Custom Config"))
o = s:option(TextValue, "custom_config", translate("Custom Config"))
o.rows = 10
o.wrap = "off"
o:depends({ custom = true })
o.datatype = "json"
local o_validate = o.validate
o.validate = function(self, value)
local v = o_validate(self, value)
if v then return v end
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
o = s:option(Value, "port", translate("Listen Port"))
o.datatype = "port"
o:depends({ custom = false })
o = s:option(DynamicList, "users", translate("User"))
for i, v in ipairs(user_list) do
o:value(v[".name"], v.username)
end
o:depends({ custom = false })
o = s:option(Flag, "realms", translate("Realms"))
o.default = "0"
o:depends({ custom = false })
o = s:option(Value, "realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
o:depends({ realms = true })
o.validate = function(self, value)
value = api.trim(value)
local realm = api.parse_realm_uri(value)
if realm then return value end
return nil, translate("Invalid Realm URL.")
end
o = s:option(DynamicList, "realm_stun", translate("Realm STUN"))
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
o:depends({ realms = true })
o = s:option(ListValue, "obfs_type", translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o:depends({ custom = false })
o = s:option(Value, "obfs_password", translate("Obfs Password"))
o:depends({ obfs_type = "salamander" })
o:depends({ obfs_type = "gecko" })
o = s:option(Value, "obfs_MinPacketSize", translate("Gecko Packet Size (min)"))
o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ obfs_type = "gecko" })
o = s:option(Value, "obfs_MaxPacketSize", translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ obfs_type = "gecko" })
o = s:option(Flag, "udp", translate("UDP"))
o.default = "1"
o:depends({ custom = false })
o = s:option(Value, "up_mbps", translate("Max upload Mbps"))
o:depends({ custom = false })
o = s:option(Value, "down_mbps", translate("Max download Mbps"))
o:depends({ custom = false })
o = s:option(Flag, "ignoreClientBandwidth", translate("ignoreClientBandwidth"))
o.default = "0"
o:depends({ custom = false })
o = s:option(FileUpload, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o.validate = function(self, value, t)
if value and value ~= "" then
if not api.fs.access(value) then
return nil, translate("Can't find this file!")
else
return value
end
end
return nil
end
o:depends({ custom = false })
o = s:option(FileUpload, "tls_keyFile", translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o.validate = function(self, value, t)
if value and value ~= "" then
if not api.fs.access(value) then
return nil, translate("Can't find this file!")
else
return value
end
end
return nil
end
o:depends({ custom = false })
o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
api.luci_types(s1, s)
+6 -4
View File
@@ -26,6 +26,7 @@ TMP_PATH = "/tmp/etc/" .. c_config
CACHE_PATH = TMP_PATH .. "_tmp"
S_TMP_PATH = "/tmp/etc/" .. s_config
TMP_IFACE_PATH = TMP_PATH .. "/iface"
TMP_ACL_PATH = TMP_PATH .. "/acl"
local lang = uci:get("luci", "main", "lang") or "auto"
if lang == "auto" then
@@ -201,9 +202,10 @@ function get_cache_var(key)
return val
end
function get_new_port()
function get_new_port(p)
if not p then p = "auto" end
local cmd_format = ". /usr/share/passwall2/utils.sh ; echo -n $(get_new_port %s tcp,udp)"
return tonumber(sys.exec(string.format(cmd_format, "auto")))
return tonumber(sys.exec(string.format(cmd_format, p)))
end
function exec_call(cmd)
@@ -613,7 +615,7 @@ function get_valid_nodes()
end
end
local port = e.port or e.hysteria_hop or e.hysteria2_hop
local is_realm = (e.type == "Hysteria2" or e.protocol == 'hysteria2') and e.hysteria2_realms or nil
local is_realm = e.protocol == 'hysteria2' and e.hysteria2_realms or nil
if (port and e.address) or is_realm then
local address = e.address
if is_ip(address) or datatypes.hostname(address) or is_realm then
@@ -739,7 +741,7 @@ function get_node_remarks(n)
end
type_name = type_name .. " " .. protocol
end
if (n.type == "Hysteria2" or n.protocol == 'hysteria2') and n.hysteria2_realms then
if n.protocol == "hysteria2" and n.hysteria2_realms then
type_name = type_name .. " Realm"
end
remarks = trim("%s:[%s]" % {type_name, n.remarks})
@@ -10,21 +10,6 @@ local function gh_pre_release_url(self)
return "https://github.com/Openwrt-Passwall/openwrt-passwall-packages/releases/download/api-cache/" .. string.lower(self.name) .. "-pre-release-api.json"
end
_M.hysteria = {
name = "Hysteria",
repo = "HyNetwork/hysteria",
get_url = gh_release_url,
cmd_version = "version | awk '/^Version:/ {print $2}'",
remote_version_str_replace = "app/",
zipped = false,
default_path = "/usr/bin/hysteria",
match_fmt_str = "linux%%-%s$",
file_tree = {
armv6 = "arm",
armv7 = "arm"
}
}
_M["sing-box"] = {
name = "Sing-Box",
repo = "SagerNet/sing-box",
@@ -8,16 +8,10 @@ local jsonc = api.jsonc
local CONFIG = api.s_config
local CONFIG_PATH = api.S_TMP_PATH
local NFT_INCLUDE_FILE = CONFIG_PATH .. "/" .. CONFIG .. ".nft"
local LOG_APP_FILE = "/tmp/log/" .. CONFIG .. ".log"
local TMP_BIN_PATH = CONFIG_PATH .. "/bin"
local require_dir = "luci.passwall2."
local ipt_bin = sys.exec("echo -n $(/usr/share/passwall2/iptables.sh get_ipt_bin)")
local ip6t_bin = sys.exec("echo -n $(/usr/share/passwall2/iptables.sh get_ip6t_bin)")
local nft_flag = api.is_finded("fw4") and "1" or "0"
local function log(...)
local f, err = io.open(LOG_APP_FILE, "a")
if f and err == nil then
@@ -31,18 +25,6 @@ local function cmd(cmd)
sys.call(cmd)
end
local function ipt(arg)
if ipt_bin and #ipt_bin > 0 then
cmd(ipt_bin .. " -w " .. arg)
end
end
local function ip6t(arg)
if ip6t_bin and #ip6t_bin > 0 then
cmd(ip6t_bin .. " -w " .. arg)
end
end
local function ln_run(s, d, command, output)
if not output then
output = "/dev/null"
@@ -52,37 +34,6 @@ local function ln_run(s, d, command, output)
return string.format("%s >%s 2>&1 &", d .. " " ..command, output)
end
local function gen_include()
cmd(string.format("echo '#!/bin/sh' > %s.include", CONFIG_PATH))
local function extract_rules(n, a)
local _ipt = ipt_bin
if n == "6" then
_ipt = ip6t_bin
end
local result = "*" .. a
result = result .. "\n" .. sys.exec(_ipt .. '-save -t ' .. a .. ' | grep "PSW2-SERVER" | sed -e "s/^-A \\(INPUT\\)/-I \\1 1/"')
result = result .. "COMMIT"
return result
end
local f, err = io.open(CONFIG_PATH .. ".include", "a")
if f and err == nil then
if nft_flag == "0" then
f:write(ipt_bin .. '-save -c | grep -v "PSW2-SERVER" | ' .. ipt_bin .. '-restore -c' .. "\n")
f:write(ipt_bin .. '-restore -n <<-EOT' .. "\n")
f:write(extract_rules("4", "filter") .. "\n")
f:write("EOT" .. "\n")
f:write(ip6t_bin .. '-save -c | grep -v "PSW2-SERVER" | ' .. ip6t_bin .. '-restore -c' .. "\n")
f:write(ip6t_bin .. '-restore -n <<-EOT' .. "\n")
f:write(extract_rules("6", "filter") .. "\n")
f:write("EOT" .. "\n")
f:close()
else
f:write("nft -f " .. NFT_INCLUDE_FILE .. "\n")
f:close()
end
end
end
local function start()
local enabled = tonumber(api.uci_get_s("@global[0]", "enable") or 0)
if enabled == nil or enabled == 0 then
@@ -90,18 +41,7 @@ local function start()
end
cmd(string.format("mkdir -p %s %s", CONFIG_PATH, TMP_BIN_PATH))
cmd(string.format("touch %s", LOG_APP_FILE))
if nft_flag == "0" then
ipt("-N PSW2-SERVER")
ipt("-I INPUT -j PSW2-SERVER")
ip6t("-N PSW2-SERVER")
ip6t("-I INPUT -j PSW2-SERVER")
else
nft_file, err = io.open(NFT_INCLUDE_FILE, "w")
nft_file:write('#!/usr/sbin/nft -f\n')
nft_file:write('add chain inet fw4 PSW2-SERVER\n')
nft_file:write('flush chain inet fw4 PSW2-SERVER\n')
nft_file:write('insert rule inet fw4 input position 0 jump PSW2-SERVER comment "PSW2-SERVER"\n')
end
local firewall_num = 0
api.uci_foreach_s("server", function(server)
local id = server[".name"]
local enable = server.enable
@@ -169,13 +109,6 @@ local function start()
config = require(require_dir .. "util_sing-box").gen_config_server(server)
end
bin = ln_run(api.get_app_path("sing-box"), "sing-box", "run -c " .. config_file, log_path)
elseif type == "Hysteria2" then
if server.custom == "1" and server.config_str then
config = jsonc.parse(api.base64Decode(server.config_str))
else
config = require(require_dir .. "util_hysteria2").gen_config_server(server)
end
bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", log_path)
end
if next(config) then
@@ -191,48 +124,38 @@ local function start()
cmd(bin)
end
local bind_local = server.bind_local or 0
if bind_local and tonumber(bind_local) ~= 1 and port then
if nft_flag == "0" then
ipt(string.format('-A PSW2-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
ip6t(string.format('-A PSW2-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
if udp_forward == 1 then
ipt(string.format('-A PSW2-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
ip6t(string.format('-A PSW2-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
end
else
nft_file:write(string.format('add rule inet fw4 PSW2-SERVER meta l4proto tcp tcp dport {%s} counter accept comment "%s"\n', port, remarks))
if udp_forward == 1 then
nft_file:write(string.format('add rule inet fw4 PSW2-SERVER meta l4proto udp udp dport {%s} counter accept comment "%s"\n', port, remarks))
end
end
local firewall_allow = server.firewall_allow
if firewall_allow == "1" then
firewall_num = firewall_num + 1
local uid = CONFIG .. "_" .. id
uci:section("firewall", "rule", uid)
uci:set("firewall", uid, "name", uid)
uci:set("firewall", uid, "src", server.firewall_allow_src or "wan")
uci:set("firewall", uid, "dest_port", port)
uci:set("firewall", uid, "target", "ACCEPT")
end
end
end)
if nft_flag == "1" then
nft_file:write("add rule inet fw4 PSW2-SERVER return\n")
nft_file:close()
cmd("nft -f " .. NFT_INCLUDE_FILE)
if firewall_num > 0 then
api.uci_save(uci, "firewall", true, true)
end
gen_include()
end
local function stop()
cmd(string.format("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/' | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1", CONFIG_PATH))
if nft_flag == "0" then
ipt("-D INPUT -j PSW2-SERVER 2>/dev/null")
ipt("-F PSW2-SERVER 2>/dev/null")
ipt("-X PSW2-SERVER 2>/dev/null")
ip6t("-D INPUT -j PSW2-SERVER 2>/dev/null")
ip6t("-F PSW2-SERVER 2>/dev/null")
ip6t("-X PSW2-SERVER 2>/dev/null")
else
local nft_cmd = "handles=$(nft -a list chain inet fw4 input | grep -E \"PSW2-SERVER\" | awk -F '# handle ' '{print$2}')\n for handle in $handles; do\n nft delete rule inet fw4 input handle ${handle} 2>/dev/null\n done"
cmd(nft_cmd)
cmd("nft flush chain inet fw4 PSW2-SERVER 2>/dev/null")
cmd("nft delete chain inet fw4 PSW2-SERVER 2>/dev/null")
if true then
local num = 0
uci:foreach("firewall", "rule", function(rule)
if rule[".name"]:find(CONFIG) == 1 then
num = num + 1
uci:delete("firewall", rule[".name"])
end
end)
if num > 0 then
api.uci_save(uci, "firewall", true, true)
end
end
cmd(string.format("rm -rf %s %s %s", CONFIG_PATH, LOG_APP_FILE, CONFIG_PATH .. ".include"))
cmd(string.format("rm -rf %s %s", CONFIG_PATH, LOG_APP_FILE))
end
if action then
@@ -1,197 +0,0 @@
module("luci.passwall2.util_hysteria2", package.seeall)
local api = require "luci.passwall2.api"
local jsonc = api.jsonc
function gen_config_server(node)
local users = nil
if node.users and #node.users > 0 then
users = {}
for i, v in ipairs(node.users) do
local user = api.uci_get_s(v) or {}
if user[".type"] == "user" then
users[user.username] = user.password
end
end
if not next(users) then
users = nil
end
end
local config = {
listen = (function()
if node.realms and node.realm_url then
local url = node.realm_url:gsub("/+$", "")
if node.port then
url = url .. (url:find("?") and "&lport=" or "?lport=") .. node.port
end
return url
end
return ":" .. (node.port or "0")
end)(),
tls = {
cert = node.tls_certificateFile,
key = node.tls_keyFile,
},
obfs = (node.obfs_type and node.obfs_password) and {
type = node.obfs_type,
[node.obfs_type] = {
password = node.obfs_password
}
} or nil,
auth = users and {
type = "userpass",
userpass = users
} or nil,
bandwidth = (node.up_mbps or node.down_mbps) and {
up = node.up_mbps and node.up_mbps .. " mbps" or nil,
down = node.down_mbps and node.down_mbps .. " mbps" or nil
} or nil,
ignoreClientBandwidth = (node.ignoreClientBandwidth == "1") and true or false,
disableUDP = (node.udp == "0") and true or false,
realm = (node.realms and node.realm_stun) and {
stunServers = node.realm_stun
} or nil
}
if config.obfs and config.obfs.gecko then
local min = tonumber(node.obfs_MinPacketSize) or 512
local max = tonumber(node.obfs_MaxPacketSize) or 1200
if min <= 0 or min > max or max > 2048 then
min = 512
max = 1200
end
config.obfs.gecko.minPacketSize = min
config.obfs.gecko.maxPacketSize = max
end
return config
end
function gen_config(var)
local node_id = var["node"]
if not node_id then
print("node Cannot be empty!")
return
end
local node = api.uci_get_c(node_id)
local local_socks_address = var["local_socks_address"] or "0.0.0.0"
local local_socks_port = var["local_socks_port"]
local local_socks_username = var["local_socks_username"]
local local_socks_password = var["local_socks_password"]
local local_http_address = var["local_http_address"] or "0.0.0.0"
local local_http_port = var["local_http_port"]
local local_http_username = var["local_http_username"]
local local_http_password = var["local_http_password"]
local server_host = var["server_host"] or (node.address or ""):lower()
local server_port = var["server_port"] or node.port
if api.is_ipv6(server_host) then
server_host = api.get_ipv6_full(server_host)
end
local port_hop = ((server_port or "") .. "," .. (node.hysteria2_hop or "")):gsub("^[%s,]+", ""):gsub("[%s,]+$", ""):gsub(":", "-")
local server = server_host .. ":" .. (port_hop ~= "" and port_hop or "443")
local config = {
server = (function()
if node.hysteria2_realms and node.hysteria2_realm_url then
return node.hysteria2_realm_url:gsub("/+$", "")
end
return server
end)(),
realm = (node.hysteria2_realms and node.hysteria2_realm_stun) and {
stunServers = node.hysteria2_realm_stun
} or nil,
transport = {
type = "udp",
udp = node.hysteria2_hop and (function()
local udp = {}
local t = node.hysteria2_hop_interval
if not t then return nil end
if t:find("-", 1, true) then
local min, max = t:match("^(%d+)%-(%d+)$")
min = tonumber(min)
max = tonumber(max)
if min and max then
min = (min >= 5) and min or 5
max = (max >= min) and max or min
udp.minHopInterval = min .. "s"
udp.maxHopInterval = max .. "s"
return udp
end
end
t = tonumber((t or "30"):match("^%d+"))
t = (t and t >= 5) and t or 30
udp.hopInterval = t .. "s"
return udp
end)() or nil
},
obfs = (node.hysteria2_obfs_type and node.hysteria2_obfs_password) and {
type = node.hysteria2_obfs_type,
[node.hysteria2_obfs_type] = {
password = node.hysteria2_obfs_password
}
} or nil,
auth = node.hysteria2_auth_password,
tls = {
sni = node.tls_serverName,
insecure = (node.tls_allowInsecure == "1") and true or false,
pinSHA256 = (node.tls_pinSHA256) and node.tls_pinSHA256 or nil,
},
quic = {
initStreamReceiveWindow = (node.hysteria2_recv_window) and tonumber(node.hysteria2_recv_window) or nil,
initConnReceiveWindow = (node.hysteria2_recv_window_conn) and tonumber(node.hysteria2_recv_window_conn) or nil,
maxIdleTimeout = (function(t)
t = tonumber(tostring(t or "30"):match("^%d+"))
return (t and t >= 4 and t <= 120) and t .. "s" or "30s"
end)(node.hysteria2_idle_timeout),
keepAlivePeriod = (function(t)
t = tonumber(tostring(t or "0"):match("^%d+"))
return (t and t >= 2 and t <= 60) and t .. "s" or nil
end)(node.hysteria2_keep_alive_period),
disablePathMTUDiscovery = (node.hysteria2_disable_mtu_discovery) and true or false,
},
bandwidth = (node.hysteria2_up_mbps or node.hysteria2_down_mbps) and {
up = node.hysteria2_up_mbps and node.hysteria2_up_mbps .. " mbps" or nil,
down = node.hysteria2_down_mbps and node.hysteria2_down_mbps .. " mbps" or nil
} or nil,
fast_open = (node.fast_open == "1") and true or false,
lazy = (node.hysteria2_lazy_start == "1") and true or false,
socks5 = (local_socks_address and local_socks_port) and {
listen = local_socks_address .. ":" .. local_socks_port,
username = (local_socks_username and local_socks_password) and local_socks_username or nil,
password = (local_socks_username and local_socks_password) and local_socks_password or nil,
disableUDP = false,
} or nil,
http = (local_http_address and local_http_port) and {
listen = local_http_address .. ":" .. local_http_port,
username = (local_http_username and local_http_password) and local_http_username or nil,
password = (local_http_username and local_http_password) and local_http_password or nil,
} or nil
}
if config.obfs and config.obfs.gecko then
local min = tonumber(node.hysteria2_obfs_MinPacketSize) or 512
local max = tonumber(node.hysteria2_obfs_MaxPacketSize) or 1200
if min <= 0 or min > max or max > 2048 then
min = 512
max = 1200
end
config.obfs.gecko.minPacketSize = min
config.obfs.gecko.maxPacketSize = max
end
return jsonc.stringify(config, 1)
end
_G.gen_config = gen_config
if arg[1] then
local func =_G[arg[1]]
if func then
local var = nil
if arg[2] then
var = jsonc.parse(arg[2])
end
print(func(var))
end
end
@@ -784,7 +784,7 @@ function gen_config_server(node)
local inbound = {
type = node.protocol,
tag = "inbound",
listen = (node.bind_local == "1") and "127.0.0.1" or "::",
listen = "::",
listen_port = tonumber(node.port),
}
@@ -675,7 +675,7 @@ function gen_config_server(node)
},
inbounds = {
{
listen = (node.bind_local == "1") and "127.0.0.1" or nil,
listen = "::",
port = tonumber(node.port),
protocol = node.protocol,
settings = settings,
@@ -133,7 +133,7 @@ local sid = "@global[0]"
const m = cbid.match(/\.node$/);
if (m) {
html += '<a href="#" onclick="window.open(\'' + '<%=api.url("get_redir_log")%>?id=default&name=' + 'global' + '\', \'_blank\')"><%:Log%></a>';
html += '<a href="#" onclick="window.open(\'' + '<%=api.url("get_redir_log")%>?id=default' + '\', \'_blank\')"><%:Log%></a>';
}
html = '<div class="node-actions" style="display:inline-flex; align-items:center; gap:4px; flex-wrap:wrap; margin-left:4px;">' + html + '</div>'
@@ -7,13 +7,12 @@ local map = self.map
local has_ss_rust = api.is_finded("sslocal")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
local has_hysteria2 = api.finded_com("hysteria")
local ss_type = api.get_core("ss_type", {{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local trojan_type = api.get_core("trojan_type", {{has_singbox,"sing-box"},{has_xray,"xray"}})
local vmess_type = api.get_core("vmess_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local vless_type = api.get_core("vless_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local hysteria2_type = api.get_core("hysteria2_type", {{has_hysteria2,"hysteria2"},{has_singbox,"sing-box"}, {has_xray,"xray"}})
local hysteria2_type = api.get_core("hysteria2_type", {{has_singbox,"sing-box"}, {has_xray,"xray"}})
local current_node = map:get(section)
-%>
@@ -21,7 +20,6 @@ local current_node = map:get(section)
<script type="text/javascript">//<![CDATA[
let has_singbox = "<%=has_singbox%>"
let has_xray = "<%=has_xray%>"
let has_hysteria2 = "<%=has_hysteria2%>"
let ss_type = "<%=ss_type%>"
let trojan_type = "<%=trojan_type%>"
let vmess_type = "<%=vmess_type%>"
@@ -585,7 +583,7 @@ local current_node = map:get(section)
params = params.substring(1);
}
url += params;
} else if ((v_type === "Hysteria2") || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "hysteria2")) {
} else if (((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "hysteria2")) {
protocol = "hysteria2"
var v_port = opt.get(dom_prefix + "port");
var params = "";
@@ -595,36 +593,20 @@ local current_node = map:get(section)
params += opt.query("pcs", dom_prefix + "tls_pinSHA256");
params += opt.query("vcn", dom_prefix + "tls_CertByName");
var v_password = null;
if (v_type === "Hysteria2") {
v_password = opt.get("hysteria2_auth_password");
var dom_obfs_type = opt.get("hysteria2_obfs_type");
if (dom_obfs_type && dom_obfs_type.value != "") {
params += opt.query("obfs", "hysteria2_obfs_type");
params += opt.query("obfs-password", "hysteria2_obfs_password");
if (dom_obfs_type.value === "gecko") {
params += opt.query("minPacketSize", "hysteria2_obfs_MinPacketSize");
params += opt.query("maxPacketSize", "hysteria2_obfs_MaxPacketSize");
}
}
params += opt.query("mport", "hysteria2_hop");
} else {
v_password = opt.get(dom_prefix + "hysteria2_auth_password");
var dom_obfs_type = opt.get(dom_prefix + "hysteria2_obfs_type");
if (dom_obfs_type && dom_obfs_type.value != "") {
params += opt.query("obfs", dom_prefix + "hysteria2_obfs_type");
params += opt.query("obfs-password", dom_prefix + "hysteria2_obfs_password");
if (dom_obfs_type.value === "gecko") {
params += opt.query("minPacketSize", dom_prefix + "hysteria2_obfs_MinPacketSize");
params += opt.query("maxPacketSize", dom_prefix + "hysteria2_obfs_MaxPacketSize");
}
}
params += opt.query("mport", dom_prefix + "hysteria2_hop");
if (opt.get(dom_prefix + "use_finalmask")?.checked) {
params += opt.query("fm", dom_prefix + "finalmask");
var v_password = opt.get(dom_prefix + "hysteria2_auth_password");
var dom_obfs_type = opt.get(dom_prefix + "hysteria2_obfs_type");
if (dom_obfs_type && dom_obfs_type.value != "") {
params += opt.query("obfs", dom_prefix + "hysteria2_obfs_type");
params += opt.query("obfs-password", dom_prefix + "hysteria2_obfs_password");
if (dom_obfs_type.value === "gecko") {
params += opt.query("minPacketSize", dom_prefix + "hysteria2_obfs_MinPacketSize");
params += opt.query("maxPacketSize", dom_prefix + "hysteria2_obfs_MaxPacketSize");
}
}
params += opt.query("mport", dom_prefix + "hysteria2_hop");
if (opt.get(dom_prefix + "use_finalmask")?.checked) {
params += opt.query("fm", dom_prefix + "finalmask");
}
params = params.replace(/^&/, "");
url =
_address + ":" +
@@ -1640,19 +1622,6 @@ local current_node = map:get(section)
opt.set(dom_prefix + 'hysteria2_hop', queryParam.mport || "");
opt.set(dom_prefix + 'use_finalmask', !!queryParam.fm);
opt.set(dom_prefix + 'finalmask', queryParam.fm || "");
} else if (has_hysteria2) {
opt.set('type', "Hysteria2");
dom_prefix = "hysteria2_"
opt.set(dom_prefix + 'auth_password', decodeURIComponent(password));
if (queryParam["obfs-password"] || queryParam["obfs_password"]) {
opt.set(dom_prefix + 'obfs_type', queryParam.obfs || "salamander");
opt.set(dom_prefix + 'obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]);
}
if (queryParam.obfs === "gecko") {
opt.set(dom_prefix + 'obfs_MinPacketSize', queryParam.minPacketSize || "512");
opt.set(dom_prefix + 'obfs_MaxPacketSize', queryParam.maxPacketSize || "1200");
}
opt.set(dom_prefix + 'hop', queryParam.mport || "");
}
opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
@@ -495,7 +495,8 @@ table td, .table .td {
ajax.abortAll();
switch (action) {
case "add":
const dom = document.getElementsByClassName("cbi-tab")[0];
const master = document.getElementById("node_list");
const dom = master.getElementsByClassName("cbi-tab")[0];
const current_group = dom ? (dom.getAttribute("group_name") || "default") : "default";
window.location.href='<%=api.url("add_node")%>?redirect=1&group=' + current_group;
break;
@@ -144,7 +144,8 @@ table td, .table .td {
//<![CDATA[
function toPage(action, cbi_id) {
if (action == "add") {
const dom = document.getElementsByClassName("cbi-tab")[0];
const master = document.getElementById("shunt_rule_list");
const dom = master.getElementsByClassName("cbi-tab")[0];
const current_group = dom ? (dom.getAttribute("group_name") || "default") : "default";
const add_name_val = document.getElementById("add_name_" + current_group).value;
if (add_name_val.length > 1) {
@@ -329,15 +330,19 @@ table td, .table .td {
var shunt_rule_list = result
var group_shunt_rules = {}
for (let i = 0; i < shunt_rule_list.length; i++) {
let _shunt_rule = shunt_rule_list[i]
if (!_shunt_rule.group || _shunt_rule.group === "") {
_shunt_rule.group = "default"
if (shunt_rule_list.length > 0) {
for (let i = 0; i < shunt_rule_list.length; i++) {
let _shunt_rule = shunt_rule_list[i]
if (!_shunt_rule.group || _shunt_rule.group === "") {
_shunt_rule.group = "default"
}
if (!group_shunt_rules[_shunt_rule.group]) {
group_shunt_rules[_shunt_rule.group] = []
}
group_shunt_rules[_shunt_rule.group].push(_shunt_rule)
}
if (!group_shunt_rules[_shunt_rule.group]) {
group_shunt_rules[_shunt_rule.group] = []
}
group_shunt_rules[_shunt_rule.group].push(_shunt_rule)
} else {
group_shunt_rules["default"] = [];
}
var tab_ul_li_html = '';
+8 -2
View File
@@ -1426,6 +1426,12 @@ msgstr "اتصال محلی (Bind Local)"
msgid "When selected, it can only be accessed localhost."
msgstr "در صورت انتخاب، فقط از طریق localhost قابل دسترسی است."
msgid "Firewall Allow"
msgstr "فایروال مجاز است"
msgid "Source zone"
msgstr "منطقه منبع"
msgid "Accept LAN Access"
msgstr "پذیرش دسترسی شبکه داخلی (LAN)"
@@ -2147,8 +2153,8 @@ msgstr "پروکسی نکردن همه %s"
msgid "Use the %s node [%s]"
msgstr "استفاده از گره %s [%s]"
msgid "Using a node that is different from the global configuration, DNS has been forcibly redirected to a dedicated DNS server."
msgstr "استفاده از گره‌ای متفاوت از پیکربندی سراسری، DNS به اجبار به سرور DNS اختصاصی هدایت شده است."
msgid "DNS will redirected to the dedicated DNS server [%s]."
msgstr "DNS به سرور DNS اختصاصی [%s] هدایت خواهد شد."
msgid "Add direct DNS to %s: %s"
msgstr "افزودن DNS مستقیم به %s: %s"
+8 -2
View File
@@ -1427,6 +1427,12 @@ msgstr "Только для localhost"
msgid "When selected, it can only be accessed localhost."
msgstr "Если включено, доступ возможен только с самого роутера."
msgid "Firewall Allow"
msgstr "Брандмауэр разрешить"
msgid "Source zone"
msgstr "Зона источника"
msgid "Accept LAN Access"
msgstr "Разрешить доступ из LAN"
@@ -2148,8 +2154,8 @@ msgstr "не прокси все %s"
msgid "Use the %s node [%s]"
msgstr "Использовать %s сервер [%s]"
msgid "Using a node that is different from the global configuration, DNS has been forcibly redirected to a dedicated DNS server."
msgstr "Используется сервер, отличный от глобальной настройки: DNS принудительно перенаправлен на выделенный DNS-сервер."
msgid "DNS will redirected to the dedicated DNS server [%s]."
msgstr "DNS будет перенаправлен на выделенный DNS-сервер [%s]."
msgid "Add direct DNS to %s: %s"
msgstr "Добавление прямого DNS в %s: %s"
+8 -2
View File
@@ -1418,6 +1418,12 @@ msgstr "本机监听"
msgid "When selected, it can only be accessed localhost."
msgstr "当勾选时,只能本机访问。"
msgid "Firewall Allow"
msgstr "允许通过防火墙"
msgid "Source zone"
msgstr "源区域"
msgid "Accept LAN Access"
msgstr "接受局域网访问"
@@ -2133,8 +2139,8 @@ msgstr "不代理所有 %s"
msgid "Use the %s node [%s]"
msgstr "使用 %s 节点[%s]"
msgid "Using a node that is different from the global configuration, DNS has been forcibly redirected to a dedicated DNS server."
msgstr "使用与全局配置不相同节点,已将DNS强制重定向到专用 DNS 服务器。"
msgid "DNS will redirected to the dedicated DNS server [%s]."
msgstr "DNS 将重定向到专用 DNS 服务器 [%s]。"
msgid "Add direct DNS to %s: %s"
msgstr "追加直连 DNS 到 %s: %s"
+8 -2
View File
@@ -1418,6 +1418,12 @@ msgstr "本機監聽"
msgid "When selected, it can only be accessed localhost."
msgstr "當勾選時,只能本機訪問。"
msgid "Firewall Allow"
msgstr "允許通過防火墻"
msgid "Source zone"
msgstr "源區域"
msgid "Accept LAN Access"
msgstr "接受局域網訪問"
@@ -2139,8 +2145,8 @@ msgstr "不代理所有 %s"
msgid "Use the %s node [%s]"
msgstr "使用 %s 節點[%s]"
msgid "Using a node that is different from the global configuration, DNS has been forcibly redirected to a dedicated DNS server."
msgstr "使用与全局配置不相同節點,已將DNS強制重定向到專用 DNS 服務器。"
msgid "DNS will redirected to the dedicated DNS server [%s]."
msgstr "DNS 將重定向到專用 DNS 服務器 [%s]。"
msgid "Add direct DNS to %s: %s"
msgstr "追加直連 DNS 到 %s: %s"
@@ -38,45 +38,10 @@ else
fi
uci commit firewall
[ ! -s "/etc/config/passwall2" ] && cp -f /usr/share/passwall2/0_default_config /etc/config/passwall2
chmod +x /usr/share/passwall2/*.sh
[ "$(uci -q get passwall2.@global_xray[0].sniffing)" == "1" ] && [ "$(uci -q get passwall2.@global_xray[0].route_only)" != "1" ] && uci -q set passwall2.@global_xray[0].sniffing_override_dest=1
uci -q delete passwall2.@global_xray[0].sniffing
uci -q delete passwall2.@global_xray[0].route_only
frag_len=$(uci -q get passwall2.@global_xray[0].fragment_length)
[ -n "$frag_len" ] && uci -q set passwall2.@global_xray[0].fragment_lengths="$frag_len" && uci -q delete passwall2.@global_xray[0].fragment_length
frag_dly=$(uci -q get passwall2.@global_xray[0].fragment_delay)
[ -n "$frag_dly" ] && uci -q set passwall2.@global_xray[0].fragment_delays="$frag_dly" && uci -q delete passwall2.@global_xray[0].fragment_delay
for sid in $(uci show passwall2 | grep "=socks" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}'); do
if [ -z "$(echo ${sid} | grep '^socks_')" ]; then
new_id="socks_$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 5)"
old_ref="Socks_${sid}"
uci -q rename passwall2.${sid}="${new_id}"
for item in $(uci show passwall2 | grep "='${old_ref}'\$" | cut -d '=' -sf 1); do
uci -q set ${item}="${new_id}"
done
unset sid new_id old_ref item
fi
done
for sid in $(uci show passwall2 | grep "@acl_rule" | cut -d '.' -sf 2 | cut -d '=' -sf 1); do
new_id="acl_$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 5)"
uci -q rename passwall2.${sid}="${new_id}"
unset sid new_id
done
for sid in $(uci show passwall2 | grep "@subscribe_list" | cut -d '.' -sf 2 | cut -d '=' -sf 1); do
new_id="sub_$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 5)"
uci -q rename passwall2.${sid}="${new_id}"
unset sid new_id
done
uci -q commit passwall2
sed -i "s#add_from#group#g" /etc/config/passwall2 2>/dev/null
rm -f /tmp/luci-indexcache /tmp/luci-indexcache.*
rm -rf /tmp/luci-modulecache/
killall -HUP rpcd 2>/dev/null
@@ -17,21 +17,6 @@ if [ -e "/etc/config/ucitrack" ]; then
EOF
fi
uci -q batch <<-EOF
delete firewall.passwall2_server
set firewall.passwall2_server=include
set firewall.passwall2_server.type='script'
set firewall.passwall2_server.path='/var/etc/passwall2_server.include'
EOF
if [ -x "/sbin/fw3" ]; then
uci -q set firewall.passwall2_server.reload='1'
else
uci -q delete firewall.passwall2_server.reload
uci -q delete firewall.passwall2_server.fw4_compatible
fi
uci commit firewall
rm -f /tmp/luci-indexcache /tmp/luci-indexcache.*
rm -rf /tmp/luci-modulecache/
killall -HUP rpcd 2>/dev/null
@@ -25,8 +25,6 @@ config global_delay
option start_delay '60'
config global_forwarding
option tcp_no_redir_ports 'disable'
option udp_no_redir_ports 'disable'
option tcp_redir_ports '1:65535'
option udp_redir_ports '1:65535'
option accept_icmp '0'
@@ -45,13 +43,12 @@ config global_rules
option geosite_update '1'
option geoip_update '1'
option v2ray_location_asset '/usr/share/v2ray/'
option geoip_url 'https://github.com/Loyalsoldier/geoip/releases/latest/download/geoip.dat'
option geoip_url 'https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat'
option geosite_url 'https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat'
config global_app
option geoview_file '/usr/bin/geoview'
option xray_file '/usr/bin/xray'
option hysteria_file '/usr/bin/hysteria'
option sing_box_file '/usr/bin/sing-box'
config global_subscribe
+115 -375
View File
@@ -7,17 +7,15 @@
. /usr/share/libubox/jshn.sh
. /usr/share/passwall2/utils.sh
GLOBAL_ACL_PATH=${TMP_ACL_PATH}/default
LUA_UTIL_PATH=/usr/lib/lua/luci/passwall2
UTIL_SINGBOX=$LUA_UTIL_PATH/util_sing-box.lua
UTIL_SS=$LUA_UTIL_PATH/util_shadowsocks.lua
UTIL_XRAY=$LUA_UTIL_PATH/util_xray.lua
UTIL_HYSTERIA2=$LUA_UTIL_PATH/util_hysteria2.lua
SINGBOX_BIN=$(first_type $(config_t_get global_app sing_box_file) sing-box)
XRAY_BIN=$(first_type $(config_t_get global_app xray_file) xray)
SINGBOX_BIN=$(first_type $(config_n_get @global_app[0] sing_box_file) sing-box)
XRAY_BIN=$(first_type $(config_n_get @global_app[0] xray_file) xray)
check_run_environment() {
local prefer_nft=$(config_t_get global_forwarding prefer_nft 1)
local prefer_nft=$(config_n_get @global_forwarding[0] prefer_nft 1)
local dnsmasq_info=$(dnsmasq -v 2>/dev/null)
local dnsmasq_ver=$(echo "$dnsmasq_info" | sed -n '1s/.*version \([0-9.]*\).*/\1/p')
# local dnsmasq_opts=$(echo "$dnsmasq_info" | grep -i "Compile time options")
@@ -70,13 +68,13 @@ check_run_environment() {
}
run_xray() {
local flag node redir_port tcp_proxy_way socks_address socks_port socks_username socks_password http_address http_port http_username http_password
local flag node redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password
local dns_listen_port direct_dns_query_strategy remote_dns_protocol remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_dns_detour remote_fakedns remote_dns_query_strategy dns_cache
local loglevel log_file config_file
eval_set_val $@
node_protocol=$(config_n_get $node protocol)
[ -n "$log_file" ] || local log_file="/dev/null"
[ -z "$loglevel" ] && local loglevel=$(config_t_get global loglevel "warning")
[ -z "$loglevel" ] && local loglevel=$(config_n_get @global[0] loglevel "warning")
json_init
json_add_string "loglevel" "${loglevel}"
@@ -106,9 +104,8 @@ run_xray() {
[ -n "$dns_cache" ] && json_add_string "dns_cache" "${dns_cache}"
[ "${node_protocol}" = "_shunt" ] && local write_ipset_direct=$(config_n_get $node write_ipset_direct 0)
[ "${write_ipset_direct}" = "1" ] && {
direct_dnsmasq_listen_port=$(get_new_port $(expr $dns_listen_port + 1) udp)
local direct_ipset_conf=${GLOBAL_ACL_PATH}/dns_${flag}_direct.conf
[ -n "$(echo ${flag} | grep '^acl')" ] && direct_ipset_conf=${TMP_ACL_PATH}/${sid}/dns_${flag}_direct.conf
direct_dnsmasq_listen_port=$(get_new_port auto)
local direct_ipset_conf=${TMP_ACL_PATH}/dns_${flag}_direct.conf
if [ "${nftflag}" = "1" ]; then
local direct_nftset4="psw2_${node}_white"
local direct_nftset6="psw2_${node}_white6"
@@ -178,7 +175,7 @@ run_xray() {
[ -n "${redir_port}" ] && {
json_add_string "redir_port" "${redir_port}"
set_cache_var "node_${node}_redir_port" "${redir_port}"
[ -n "${tcp_proxy_way}" ] && json_add_string "tcp_proxy_way" "${tcp_proxy_way}"
json_add_string "tcp_proxy_way" "${TCP_PROXY_WAY}"
}
json_add_string "node" "${node}"
@@ -199,7 +196,7 @@ run_xray() {
}
run_singbox() {
local flag node redir_port tcp_proxy_way socks_address socks_port socks_username socks_password http_address http_port http_username http_password
local flag node redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password
local dns_listen_port direct_dns_query_strategy remote_dns_protocol remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_dns_detour remote_fakedns remote_dns_query_strategy remote_rewrite_ttl dns_cache
local loglevel log_file config_file
eval_set_val $@
@@ -207,7 +204,7 @@ run_singbox() {
[ -z "$type" ] && return 1
node_protocol=$(config_n_get $node protocol)
[ -n "$log_file" ] || local log_file="/dev/null"
[ -z "$loglevel" ] && local loglevel=$(config_t_get global loglevel "warn")
[ -z "$loglevel" ] && local loglevel=$(config_n_get @global[0] loglevel "warn")
local singbox_tag=$($SINGBOX_BIN version | grep 'Tags:' | awk '{print $2}')
json_init
@@ -244,9 +241,8 @@ run_singbox() {
[ -n "$dns_listen_port" ] && {
[ "${node_protocol}" = "_shunt" ] && local write_ipset_direct=$(config_n_get $node write_ipset_direct 0)
[ "${write_ipset_direct}" = "1" ] && {
direct_dnsmasq_listen_port=$(get_new_port $(expr $dns_listen_port + 1) udp)
local direct_ipset_conf=${GLOBAL_ACL_PATH}/dns_${flag}_direct.conf
[ -n "$(echo ${flag} | grep '^acl')" ] && direct_ipset_conf=${TMP_ACL_PATH}/${sid}/dns_${flag}_direct.conf
direct_dnsmasq_listen_port=$(get_new_port auto)
local direct_ipset_conf=${TMP_ACL_PATH}/dns_${flag}_direct.conf
if [ "${nftflag}" = "1" ]; then
local direct_nftset4="psw2_${node}_white"
local direct_nftset6="psw2_${node}_white6"
@@ -325,7 +321,7 @@ run_singbox() {
[ -n "${redir_port}" ] && {
json_add_string "redir_port" "${redir_port}"
set_cache_var "node_${node}_redir_port" "${redir_port}"
[ -n "${tcp_proxy_way}" ] && json_add_string "tcp_proxy_way" "${tcp_proxy_way}"
json_add_string "tcp_proxy_way" "${TCP_PROXY_WAY}"
}
json_add_string "node" "${node}"
@@ -411,7 +407,7 @@ run_socks() {
json_add_null "server_port"
}
[ "${log_file}" != "/dev/null" ] && {
local loglevel=$(config_t_get global loglevel "warn")
local loglevel=$(config_n_get @global[0] loglevel "warn")
json_add_string "log" "1"
json_add_string "loglevel" "${loglevel}"
json_add_string "logfile" "${log_file}"
@@ -439,7 +435,7 @@ run_socks() {
json_add_null "server_port"
}
[ "${log_file}" != "/dev/null" ] && {
local loglevel=$(config_t_get global loglevel "warn")
local loglevel=$(config_n_get @global[0] loglevel "warn")
json_add_string "log" "1"
json_add_string "loglevel" "${loglevel}"
}
@@ -478,19 +474,6 @@ run_socks() {
lua $UTIL_SS gen_config "${_json_arg}" > $config_file
[ -z "$no_run" ] && ln_run ${QUEUE_RUN} "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v
;;
hysteria2)
json_add_string "local_socks_address" "${bind}"
json_add_string "local_socks_port" "${socks_port}"
[ "$http_port" != "0" ] && {
http_flag=1
config_file="${config_file%%.*}+http${config_file#${config_file%%.*}}"
json_add_string "local_http_address" "${bind}"
json_add_string "local_http_port" "${http_port}"
}
local _json_arg="$(json_dump)"
lua $UTIL_HYSTERIA2 gen_config "${_json_arg}" > $config_file
[ -z "$no_run" ] && ln_run ${QUEUE_RUN} "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client
;;
esac
# http to socks
@@ -561,146 +544,6 @@ socks_node_switch() {
}
}
run_global() {
[ -z "$NODE" ] && return 1
TYPE=$(echo $(config_n_get $NODE type) | tr 'A-Z' 'a-z')
[ -z "$TYPE" ] && return 1
if [ $PROXY_IPV6 == "1" ]; then
log_i18n 0 "To enable experimental IPv6 transparent proxy (TProxy), please ensure your node and type support IPv6!"
fi
TUN_DNS_PORT=15353
TUN_DNS="127.0.0.1#${TUN_DNS_PORT}"
V2RAY_ARGS="flag=global node=$NODE redir_port=$REDIR_PORT tcp_proxy_way=${TCP_PROXY_WAY}"
V2RAY_ARGS="${V2RAY_ARGS} dns_listen_port=${TUN_DNS_PORT} direct_dns_query_strategy=${DIRECT_DNS_QUERY_STRATEGY} remote_dns_query_strategy=${REMOTE_DNS_QUERY_STRATEGY} dns_cache=${DNS_CACHE}"
local dns_msg="DNS: ${TUN_DNS} ($(i18n "Direct DNS: %s" "${AUTO_DNS}")"
[ -n "$REMOTE_DNS_PROTOCOL" ] && {
V2RAY_ARGS="${V2RAY_ARGS} remote_dns_protocol=${REMOTE_DNS_PROTOCOL} remote_dns_detour=${REMOTE_DNS_DETOUR}"
case "$REMOTE_DNS_PROTOCOL" in
udp|\
quic)
V2RAY_ARGS="${V2RAY_ARGS} remote_dns_udp_server=${REMOTE_DNS}"
dns_msg="${dns_msg} $(i18n "Remote DNS: %s" "${REMOTE_DNS}")"
;;
tcp|\
tls)
V2RAY_ARGS="${V2RAY_ARGS} remote_dns_tcp_server=${REMOTE_DNS}"
dns_msg="${dns_msg} $(i18n "Remote DNS: %s" "${REMOTE_DNS}")"
;;
doh|\
http3)
REMOTE_DNS_DOH=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query")
V2RAY_ARGS="${V2RAY_ARGS} remote_dns_doh=${REMOTE_DNS_DOH}"
dns_msg="${dns_msg} $(i18n "Remote DNS: %s" "${REMOTE_DNS_DOH}")"
;;
esac
[ "$REMOTE_FAKEDNS" = "1" ] && {
V2RAY_ARGS="${V2RAY_ARGS} remote_fakedns=1"
dns_msg="${dns_msg} + FakeDNS "
}
local _remote_dns_client_ip=$(config_t_get global remote_dns_client_ip)
[ -n "${_remote_dns_client_ip}" ] && V2RAY_ARGS="${V2RAY_ARGS} remote_dns_client_ip=${_remote_dns_client_ip}"
V2RAY_ARGS="${V2RAY_ARGS} remote_rewrite_ttl=$(config_t_get global remote_rewrite_ttl)"
}
dns_msg="${dns_msg})"
V2RAY_CONFIG=${GLOBAL_ACL_PATH}/global.json
V2RAY_LOG=${GLOBAL_ACL_PATH}/global.log
[ "$(config_t_get global log_node 1)" != "1" ] && V2RAY_LOG="/dev/null"
V2RAY_ARGS="${V2RAY_ARGS} log_file=${V2RAY_LOG} config_file=${V2RAY_CONFIG}"
node_socks_port=$(config_t_get global node_socks_port 1070)
node_socks_bind_local=$(config_t_get global node_socks_bind_local 1)
node_socks_bind="127.0.0.1"
[ "${node_socks_bind_local}" != "1" ] && node_socks_bind="0.0.0.0"
V2RAY_ARGS="${V2RAY_ARGS} socks_address=${node_socks_bind} socks_port=${node_socks_port}"
set_cache_var "GLOBAL_SOCKS_server" "127.0.0.1:$node_socks_port"
node_http_port=$(config_t_get global node_http_port 0)
[ "$node_http_port" != "0" ] && V2RAY_ARGS="${V2RAY_ARGS} http_port=${node_http_port}"
local run_func
[ -n "${XRAY_BIN}" ] && run_func="run_xray"
[ -n "${SINGBOX_BIN}" ] && run_func="run_singbox"
if [ "${TYPE}" = "xray" ] && [ -n "${XRAY_BIN}" ]; then
run_func="run_xray"
elif [ "${TYPE}" = "sing-box" ] && [ -n "${SINGBOX_BIN}" ]; then
run_func="run_singbox"
fi
${run_func} ${V2RAY_ARGS}; local status=$?
if [ "$status" == 0 ]; then
log 0 ${dns_msg}
else
log_i18n 0 "[%s] process %s error, skip this transparent proxy!" $(i18n "Global") "${V2RAY_CONFIG}"
cat ${_error_log_file} >> ${LOG_FILE}
unset _error_log_file
ENABLED_DEFAULT_ACL=0
return 1
fi
set_cache_var "ACL_GLOBAL_node" "$NODE"
set_cache_var "ACL_GLOBAL_redir_port" "$REDIR_PORT"
}
run_global_dnsmasq() {
[ -z "${ACL_GLOBAL_node}" ] && return
local RUN_NEW_DNSMASQ=1
RUN_NEW_DNSMASQ=${DNS_REDIRECT}
DNSMASQ_DEFAULT_DNS="${AUTO_DNS}"
DNSMASQ_LOCAL_DNS="${LOCAL_DNS:-${AUTO_DNS}}"
DNSMASQ_TUN_DNS="${TUN_DNS}"
if [ "${RUN_NEW_DNSMASQ}" == "0" ]; then
#The old logic will be removed in the future.
#Run a copy dnsmasq instance, DNS hijack that don't need a proxy devices.
[ "1" = "0" ] && {
DIRECT_DNSMASQ_PORT=$(get_new_port 11400)
DIRECT_DNSMASQ_CONF=${GLOBAL_ACL_PATH}/direct_dnsmasq.conf
DIRECT_DNSMASQ_CONF_PATH=${GLOBAL_ACL_PATH}/direct_dnsmasq.d
mkdir -p ${DIRECT_DNSMASQ_CONF_PATH}
json_init
json_add_string "LISTEN_PORT" "${DIRECT_DNSMASQ_PORT}"
json_add_string "DNSMASQ_CONF" "${DIRECT_DNSMASQ_CONF}"
json_add_string "TMP_DNSMASQ_PATH" "${DIRECT_DNSMASQ_CONF_PATH}"
lua $APP_PATH/helper_dnsmasq.lua copy_instance "$(json_dump)"
ln_run 0 "$(first_type dnsmasq)" "dnsmasq_direct" "/dev/null" -C ${DIRECT_DNSMASQ_CONF} -x ${GLOBAL_ACL_PATH}/direct_dnsmasq.pid
set_cache_var "DIRECT_DNSMASQ_PORT" "${DIRECT_DNSMASQ_PORT}"
}
#Rewrite the default DNS service configuration
#Modify the default dnsmasq service
lua $APP_PATH/helper_dnsmasq.lua stretch
json_init
json_add_string "FLAG" "default"
json_add_string "TMP_DNSMASQ_PATH" "${GLOBAL_DNSMASQ_CONF_PATH}"
json_add_string "DNSMASQ_CONF_FILE" "${GLOBAL_DNSMASQ_CONF}"
json_add_string "DEFAULT_DNS" "${DNSMASQ_DEFAULT_DNS}"
json_add_string "LOCAL_DNS" "${DNSMASQ_LOCAL_DNS}"
json_add_string "TUN_DNS" "${DNSMASQ_TUN_DNS}"
json_add_string "NFTFLAG" "${nftflag:-0}"
json_add_string "NO_LOGIC_LOG" "${NO_LOGIC_LOG:-0}"
lua $APP_PATH/helper_dnsmasq.lua add_rule "$(json_dump)"
uci -q add_list dhcp.@dnsmasq[0].addnmount=${GLOBAL_DNSMASQ_CONF_PATH}
uci -q commit dhcp
json_init
json_add_string "LOG" "1"
lua $APP_PATH/helper_dnsmasq.lua logic_restart "$(json_dump)"
else
#Run a copy dnsmasq instance, DNS hijack for that need proxy devices.
GLOBAL_DNSMASQ_PORT=$(get_new_port 11400)
run_copy_dnsmasq flag="default" listen_port=$GLOBAL_DNSMASQ_PORT local_dns="${DNSMASQ_LOCAL_DNS}" tun_dns="${DNSMASQ_TUN_DNS}" default_dns="${DNSMASQ_DEFAULT_DNS}"
DNS_REDIRECT_PORT=${GLOBAL_DNSMASQ_PORT}
#dhcp.leases to hosts
$APP_PATH/lease2hosts.sh > /dev/null 2>&1 &
fi
}
start_socks() {
[ "$SOCKS_ENABLED" = "1" ] && {
local ids=$(uci show $CONFIG | grep "=socks" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
@@ -746,7 +589,7 @@ clean_crontab() {
start_crontab() {
if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then
start_daemon=$(config_t_get global_delay start_daemon 0)
start_daemon=$(config_n_get @global_delay[0] start_daemon 0)
[ "$start_daemon" = "1" ] && { $APP_PATH/monitor.sh > /dev/null 2>&1 & }
fi
@@ -763,8 +606,8 @@ start_crontab() {
return
}
stop_week_mode=$(config_t_get global_delay stop_week_mode)
stop_time_mode=$(config_t_get global_delay stop_time_mode)
stop_week_mode=$(config_n_get @global_delay[0] stop_week_mode)
stop_time_mode=$(config_n_get @global_delay[0] stop_time_mode)
if [ -n "$stop_week_mode" ]; then
stop_time_hh=$(echo $stop_time_mode | awk -F ':' '{print $1}')
stop_time_mm=$(echo $stop_time_mode | awk -F ':' '{print $2}')
@@ -774,8 +617,8 @@ start_crontab() {
log_i18n 0 "Scheduled tasks: Auto stop service."
fi
start_week_mode=$(config_t_get global_delay start_week_mode)
start_time_mode=$(config_t_get global_delay start_time_mode)
start_week_mode=$(config_n_get @global_delay[0] start_week_mode)
start_time_mode=$(config_n_get @global_delay[0] start_time_mode)
if [ -n "$start_week_mode" ]; then
start_time_hh=$(echo $start_time_mode | awk -F ':' '{print $1}')
start_time_mm=$(echo $start_time_mode | awk -F ':' '{print $2}')
@@ -785,8 +628,8 @@ start_crontab() {
log_i18n 0 "Scheduled tasks: Auto start service."
fi
restart_week_mode=$(config_t_get global_delay restart_week_mode)
restart_time_mode=$(config_t_get global_delay restart_time_mode)
restart_week_mode=$(config_n_get @global_delay[0] restart_week_mode)
restart_time_mode=$(config_n_get @global_delay[0] restart_time_mode)
if [ -n "$restart_week_mode" ]; then
restart_time_hh=$(echo $restart_time_mode | awk -F ':' '{print $1}')
restart_time_mm=$(echo $restart_time_mode | awk -F ':' '{print $2}')
@@ -800,8 +643,8 @@ start_crontab() {
log_i18n 0 "Scheduled tasks: Auto restart service."
fi
rules_update_week_mode=$(config_t_get global_rules update_week_mode)
rules_update_time_mode=$(config_t_get global_rules update_time_mode)
rules_update_week_mode=$(config_n_get @global_rules[0] update_week_mode)
rules_update_time_mode=$(config_n_get @global_rules[0] update_time_mode)
if [ -n "$rules_update_week_mode" ]; then
rules_update_time_hh=$(echo $rules_update_time_mode | awk -F ':' '{print $1}')
rules_update_time_mm=$(echo $rules_update_time_mode | awk -F ':' '{print $2}')
@@ -865,7 +708,7 @@ stop_crontab() {
}
start_haproxy() {
[ "$(config_t_get global_haproxy balancing_enable 0)" != "1" ] && return
[ "$(config_n_get @global_haproxy[0] balancing_enable 0)" != "1" ] && return
haproxy_path=$TMP_PATH/haproxy
haproxy_conf="config.cfg"
lua $APP_PATH/haproxy.lua -path ${haproxy_path} -conf ${haproxy_conf}
@@ -875,8 +718,9 @@ start_haproxy() {
run_copy_dnsmasq() {
local flag listen_port local_dns tun_dns default_dns
eval_set_val $@
local dnsmasq_conf=$TMP_ACL_PATH/$flag/dnsmasq.conf
local dnsmasq_conf_path=$TMP_ACL_PATH/$flag/dnsmasq.d
local dnsmasq_conf="${TMP_ACL_PATH}/${flag}_dnsmasq.conf"
local dnsmasq_conf_path="${TMP_ACL_PATH}/${flag}_dnsmasq.d"
local dnsmasq_pid="${TMP_ACL_PATH}/${flag}_dnsmasq.pid"
mkdir -p $dnsmasq_conf_path
json_init
@@ -895,7 +739,7 @@ run_copy_dnsmasq() {
json_add_string "NO_LOGIC_LOG" "${NO_LOGIC_LOG:-0}"
lua $APP_PATH/helper_dnsmasq.lua add_rule "$(json_dump)"
ln_run 0 "$(first_type dnsmasq)" "dnsmasq_${flag}" "/dev/null" -C $dnsmasq_conf -x $TMP_ACL_PATH/$flag/dnsmasq.pid
ln_run 0 "$(first_type dnsmasq)" "dnsmasq_${flag}" "/dev/null" -C ${dnsmasq_conf} -x ${dnsmasq_pid}
set_cache_var "ACL_${flag}_dns_port" "${listen_port}"
}
@@ -958,156 +802,75 @@ run_ipset_dnsmasq() {
ln_run 0 "$(first_type dnsmasq)" "dnsmasq" "/dev/null" -C $config_file
}
acl_app() {
local items=$(uci show ${CONFIG} | grep "=acl_rule" | cut -d '.' -sf 2 | cut -d '=' -sf 1)
if [ -z "$items" ]; then
ENABLED_ACLS=0
return
else
local has_enabled
local index=0
local sid
local redir_port dns_port dnsmasq_port socks_port
local ipt_tmp msg msg2
redir_port=11200
socks_port=11600
dns_port=11300
dnsmasq_port=${GLOBAL_DNSMASQ_PORT:-11400}
for sid in $items; do
index=$(expr $index + 1)
local enabled sid remarks sources interface tcp_no_redir_ports udp_no_redir_ports node direct_dns_query_strategy remote_dns_protocol remote_dns remote_dns_doh remote_dns_client_ip remote_dns_detour remote_fakedns remote_dns_query_strategy remote_rewrite_ttl log loglevel log_file
local _ip _mac _iprange _ipset _ip_or_mac source_list config_file
[ "$(config_n_get $sid enabled)" = "1" ] || continue
has_enabled=1
eval $(uci -q show "${CONFIG}.${sid}" | cut -d'.' -sf 3-)
acl_node() {
local run_func
[ -n "${XRAY_BIN}" ] && run_func="run_xray"
[ -n "${SINGBOX_BIN}" ] && run_func="run_singbox"
local acl_node_num=0
for nid in $(jsonfilter -s "${acl_json}" -e '$.node_order[*]'); do
[ ! -f ${TMP_ACL_PATH}/acl_node_${nid} ] && continue
acl_node_num=$(expr $acl_node_num + 1)
local _var=$(cat ${TMP_ACL_PATH}/acl_node_${nid} 2>/dev/null)
eval local ${_var}
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
[ -n "${type}" ] || continue
if [ "${type}" = "xray" ] && [ -n "${XRAY_BIN}" ]; then
run_func="run_xray"
elif [ "${type}" = "sing-box" ] && [ -n "${SINGBOX_BIN}" ]; then
run_func="run_singbox"
fi
${run_func} ${_var}
local status=$?
if [ "$status" != 0 ]; then
log_i18n 2 "[%s] process %s error, skip this transparent proxy!" "${node}" "${config_file}"
cat ${_error_log_file} >> ${LOG_FILE}
unset _error_log_file
continue
fi
if [ "${flag}" = "default" ]; then
set_cache_var "GLOBAL_SOCKS_server" "127.0.0.1:$socks_port"
set_cache_var "ACL_GLOBAL_node" "$node"
local RUN_NEW_DNSMASQ=$(config_n_get @global[0] dns_redirect 1)
local DNSMASQ_DEFAULT_DNS="${AUTO_DNS}"
local DNSMASQ_LOCAL_DNS="${LOCAL_DNS:-${AUTO_DNS}}"
local DNSMASQ_TUN_DNS="127.0.0.1#${dns_listen_port}"
if [ "${RUN_NEW_DNSMASQ}" == "0" ]; then
#Rewrite the default DNS service configuration
#Modify the default dnsmasq service
lua $APP_PATH/helper_dnsmasq.lua stretch
json_init
json_add_string "FLAG" "default"
json_add_string "TMP_DNSMASQ_PATH" "${GLOBAL_DNSMASQ_CONF_PATH}"
json_add_string "DNSMASQ_CONF_FILE" "${GLOBAL_DNSMASQ_CONF}"
json_add_string "DEFAULT_DNS" "${DNSMASQ_DEFAULT_DNS}"
json_add_string "LOCAL_DNS" "${DNSMASQ_LOCAL_DNS}"
json_add_string "TUN_DNS" "${DNSMASQ_TUN_DNS}"
json_add_string "NFTFLAG" "${nftflag:-0}"
json_add_string "NO_LOGIC_LOG" "${NO_LOGIC_LOG:-0}"
lua $APP_PATH/helper_dnsmasq.lua add_rule "$(json_dump)"
uci -q add_list dhcp.@dnsmasq[0].addnmount=${GLOBAL_DNSMASQ_CONF_PATH}
uci -q commit dhcp
if [ -n "${sources}" ]; then
for s in $sources; do
local s2
is_iprange=$(lua_api "iprange(\"${s}\")")
if [ "${is_iprange}" = "true" ]; then
s2="iprange:${s}"
elif [ -n "$(echo ${s} | grep '^ipset:')" ]; then
s2="ipset:${s}"
else
_ip_or_mac=$(lua_api "ip_or_mac(\"${s}\")")
if [ "${_ip_or_mac}" = "ip" ]; then
s2="ip:${s}"
elif [ "${_ip_or_mac}" = "mac" ]; then
s2="mac:${s}"
fi
fi
[ -n "${s2}" ] && source_list="${source_list}\n${s2}"
unset s2
done
json_init
json_add_string "LOG" "1"
lua $APP_PATH/helper_dnsmasq.lua logic_restart "$(json_dump)"
else
source_list="any"
#Run a copy dnsmasq instance, DNS hijack for that need proxy devices.
dnsmasq_port=$(get_new_port auto)
run_copy_dnsmasq flag="default" listen_port=${dnsmasq_port} local_dns="${DNSMASQ_LOCAL_DNS}" tun_dns="${DNSMASQ_TUN_DNS}" default_dns="${DNSMASQ_DEFAULT_DNS}"
#dhcp.leases to hosts
$APP_PATH/lease2hosts.sh > /dev/null 2>&1 &
fi
local acl_path=${TMP_ACL_PATH}/$sid
mkdir -p ${acl_path}
[ -n "${source_list}" ] && echo -e "${source_list}" | sed '/^$/d' > ${acl_path}/source_list
log=${log:-0}
loglevel=${loglevel:-warn}
log_file="/dev/null"
[ "${log}" = "1" ] && log_file="${acl_path}/node.log"
node=${node:-default}
tcp_no_redir_ports=${tcp_no_redir_ports:-default}
udp_no_redir_ports=${udp_no_redir_ports:-default}
[ "$tcp_no_redir_ports" = "default" ] && tcp_no_redir_ports=$TCP_NO_REDIR_PORTS
[ "$udp_no_redir_ports" = "default" ] && udp_no_redir_ports=$UDP_NO_REDIR_PORTS
if has_1_65535 "$tcp_no_redir_ports" && has_1_65535 "$udp_no_redir_ports"; then
unset node
fi
[ -n "$node" ] && {
tcp_proxy_mode="global"
udp_proxy_mode="global"
direct_dns_query_strategy=${direct_dns_query_strategy:-UseIP}
remote_dns_protocol=${remote_dns_protocol:-tcp}
remote_dns=${remote_dns:-1.1.1.1}
case "$remote_dns_protocol" in
doh|\
http3)
remote_dns=${remote_dns_doh:-https://1.1.1.1/dns-query}
;;
esac
remote_dns_detour=${remote_dns_detour:-remote}
remote_fakedns=${remote_fakedns:-0}
remote_dns_query_strategy=${remote_dns_query_strategy:-UseIPv4}
local GLOBAL_node=$(get_cache_var "ACL_GLOBAL_node")
[ -n "${GLOBAL_node}" ] && GLOBAL_redir_port=$(get_cache_var "ACL_GLOBAL_redir_port")
if [ "$node" = "default" ]; then
if [ -n "${GLOBAL_node}" ]; then
set_cache_var "ACL_${sid}_node" "${GLOBAL_node}"
set_cache_var "ACL_${sid}_redir_port" "${GLOBAL_redir_port}"
set_cache_var "ACL_${sid}_dns_port" "${GLOBAL_DNSMASQ_PORT}"
set_cache_var "ACL_${sid}_default" "1"
else
log 1 "$(i18n "Global nodes are not enabled, skip [%s]." "${remarks}")"
fi
else
[ "$(config_get_type $node)" = "nodes" ] && {
if [ -n "${GLOBAL_node}" ] && [ "$node" = "${GLOBAL_node}" ]; then
set_cache_var "ACL_${sid}_node" "${GLOBAL_node}"
set_cache_var "ACL_${sid}_redir_port" "${GLOBAL_redir_port}"
set_cache_var "ACL_${sid}_dns_port" "${GLOBAL_DNSMASQ_PORT}"
set_cache_var "ACL_${sid}_default" "1"
else
redir_port=$(get_new_port $(expr $redir_port + 1))
socks_port=$(get_new_port $(expr $socks_port + 1))
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
if [ -n "${type}" ]; then
config_file=$TMP_ACL_PATH/${node}_TCP_UDP_DNS_${redir_port}.json
dns_port=$(get_new_port $(expr $dns_port + 1))
local acl_socks_port=$socks_port
local run_func
[ -n "${XRAY_BIN}" ] && run_func="run_xray"
[ -n "${SINGBOX_BIN}" ] && run_func="run_singbox"
if [ "${type}" = "xray" ] && [ -n "${XRAY_BIN}" ]; then
run_func="run_xray"
elif [ "${type}" = "sing-box" ] && [ -n "${SINGBOX_BIN}" ]; then
run_func="run_singbox"
fi
${run_func} flag=acl_$sid node=$node redir_port=$redir_port tcp_proxy_way=${TCP_PROXY_WAY} \
socks_address=127.0.0.1 socks_port=$acl_socks_port \
dns_listen_port=${dns_port} \
direct_dns_query_strategy=${direct_dns_query_strategy} \
remote_dns_protocol=${remote_dns_protocol} remote_dns_tcp_server=${remote_dns} remote_dns_udp_server=${remote_dns} remote_dns_doh="${remote_dns}" \
remote_dns_client_ip=${remote_dns_client_ip} remote_dns_detour=${remote_dns_detour} remote_dns_query_strategy=${remote_dns_query_strategy} \
remote_fakedns=${remote_fakedns} remote_rewrite_ttl=${remote_rewrite_ttl} \
config_file=${config_file} \
log_file="${log_file}" loglevel="${loglevel}"
local status=$?
if [ "$status" != 0 ]; then
log_i18n 2 "[%s] process %s error, skip this transparent proxy!" "${remarks}" "${config_file}"
cat ${_error_log_file} >> ${LOG_FILE}
unset _error_log_file
continue
fi
fi
dnsmasq_port=$(get_new_port $(expr $dnsmasq_port + 1))
run_copy_dnsmasq flag="$sid" listen_port=$dnsmasq_port local_dns="${LOCAL_DNS:-${AUTO_DNS}}" tun_dns="127.0.0.1#${dns_port}" default_dns="${AUTO_DNS}"
#dhcp.leases to hostsMore actions
$APP_PATH/lease2hosts.sh > /dev/null 2>&1 &
set_cache_var "ACL_${sid}_node" "$node"
set_cache_var "ACL_${sid}_redir_port" "$redir_port"
fi
}
fi
}
unset enabled sid remarks sources interface tcp_no_redir_ports udp_no_redir_ports node direct_dns_query_strategy remote_dns_protocol remote_dns remote_dns_doh remote_dns_client_ip remote_dns_detour remote_fakedns remote_dns_query_strategy remote_rewrite_ttl
unset _ip _mac _iprange _ipset _ip_or_mac source_list config_file
done
unset redir_port dns_port dnsmasq_port
[ -n "${has_enabled}" ] || ENABLED_ACLS=0
fi
else
dnsmasq_port=$(get_new_port auto)
run_copy_dnsmasq flag="${flag}" listen_port=${dnsmasq_port} local_dns="${LOCAL_DNS:-${AUTO_DNS}}" tun_dns="127.0.0.1#${dns_listen_port}" default_dns="${AUTO_DNS}"
#dhcp.leases to hostsMore actions
$APP_PATH/lease2hosts.sh > /dev/null 2>&1 &
fi
rm -f ${TMP_ACL_PATH}/acl_node_${nid}
done
[ ! -f ${TMP_ACL_PATH}/acl_node_default ] && ENABLED_DEFAULT_ACL=0
[ "${acl_node_num}" == 0 ] && ENABLED_ACLS=0 && ENABLED_DEFAULT_ACL=0
}
start() {
@@ -1118,7 +881,7 @@ start() {
}
mkdir -p /tmp/etc /tmp/log $TMP_PATH $TMP_BIN_PATH $TMP_SCRIPT_FUNC_PATH $TMP_ROUTE_PATH $TMP_ACL_PATH $TMP_PATH2
get_config
export V2RAY_LOCATION_ASSET=$(config_t_get global_rules v2ray_location_asset "/usr/share/v2ray/")
export V2RAY_LOCATION_ASSET=$(config_n_get @global_rules[0] v2ray_location_asset "/usr/share/v2ray/")
export XRAY_LOCATION_ASSET=$V2RAY_LOCATION_ASSET
export ENABLE_DEPRECATED_GEOSITE=true
export ENABLE_DEPRECATED_GEOIP=true
@@ -1129,21 +892,16 @@ start() {
nftflag=0
USE_TABLES=""
check_run_environment
if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then
[ "$(uci -q get dhcp.@dnsmasq[0].dns_redirect)" == "1" ] && {
uci -q set ${CONFIG}.@global[0].dnsmasq_dns_redirect='1'
uci -q commit ${CONFIG}
uci -q set dhcp.@dnsmasq[0].dns_redirect='0'
uci -q commit dhcp
[ "$(uci -q get dhcp.@dnsmasq[0].dns_redirect)" == "1" ] && {
uci -q set ${CONFIG}.@global[0].dnsmasq_dns_redirect='1'
uci -q commit ${CONFIG}
uci -q set dhcp.@dnsmasq[0].dns_redirect='0'
uci -q commit dhcp
json_init
json_add_string "LOG" "0"
lua $APP_PATH/helper_dnsmasq.lua restart "$(json_dump)"
}
fi
mkdir -p ${GLOBAL_ACL_PATH}
[ "$ENABLED_DEFAULT_ACL" == 1 ] && run_global
run_global_dnsmasq
json_init
json_add_string "LOG" "0"
lua $APP_PATH/helper_dnsmasq.lua restart "$(json_dump)"
}
[ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start
set_cache_var "USE_TABLES" "$USE_TABLES"
if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then
@@ -1200,7 +958,7 @@ stop() {
rm -rf $GLOBAL_DNSMASQ_CONF_PATH
[ "1" = "1" ] && {
#restore logic
bak_dnsmasq_dns_redirect=$(config_t_get global dnsmasq_dns_redirect)
bak_dnsmasq_dns_redirect=$(config_n_get @global[0] dnsmasq_dns_redirect)
[ -n "${bak_dnsmasq_dns_redirect}" ] && {
uci -q set dhcp.@dnsmasq[0].dns_redirect="${bak_dnsmasq_dns_redirect}"
uci -q commit dhcp
@@ -1247,32 +1005,14 @@ get_direct_dns() {
get_config() {
ENABLED_DEFAULT_ACL=0
ENABLED=$(config_t_get global enabled 0)
NODE=$(config_t_get global node)
[ "$ENABLED" == 1 ] && {
[ -n "$NODE" ] && [ "$(config_get_type $NODE)" == "nodes" ] && ENABLED_DEFAULT_ACL=1
}
ENABLED_ACLS=$(config_t_get global acl_enable 0)
SOCKS_ENABLED=$(config_t_get global socks_enabled 0)
REDIR_PORT=$(echo $(get_new_port 1041 tcp,udp))
TCP_PROXY_WAY=$(config_t_get global_forwarding tcp_proxy_way redirect)
TCP_NO_REDIR_PORTS=$(config_t_get global_forwarding tcp_no_redir_ports 'disable')
UDP_NO_REDIR_PORTS=$(config_t_get global_forwarding udp_no_redir_ports 'disable')
TCP_REDIR_PORTS=$(config_t_get global_forwarding tcp_redir_ports '22,25,53,143,465,587,853,993,995,80,443')
UDP_REDIR_PORTS=$(config_t_get global_forwarding udp_redir_ports '1:65535')
PROXY_IPV6=$(config_t_get global_forwarding ipv6_tproxy 0)
TCP_PROXY_MODE="global"
UDP_PROXY_MODE="global"
LOCALHOST_PROXY=$(config_t_get global localhost_proxy '1')
CLIENT_PROXY=$(config_t_get global client_proxy '1')
DIRECT_DNS_QUERY_STRATEGY=$(config_t_get global direct_dns_query_strategy UseIP)
REMOTE_DNS_PROTOCOL=$(config_t_get global remote_dns_protocol tcp)
REMOTE_DNS_DETOUR=$(config_t_get global remote_dns_detour remote)
REMOTE_DNS=$(config_t_get global remote_dns 1.1.1.1:53 | sed 's/#/:/g' | sed -E 's/\:([^:]+)$/#\1/g')
REMOTE_FAKEDNS=$(config_t_get global remote_fakedns '0')
REMOTE_DNS_QUERY_STRATEGY=$(config_t_get global remote_dns_query_strategy UseIPv4)
DNS_CACHE=$(config_t_get global dns_cache 1)
DNS_REDIRECT=$(config_t_get global dns_redirect 1)
ENABLED=$(config_n_get @global[0] enabled 0)
NODE=$(config_n_get @global[0] node)
[ "$ENABLED" == 1 ] && [ -n "$NODE" ] && [ "$(config_get_type $NODE)" == "nodes" ] && ENABLED_DEFAULT_ACL=1
ENABLED_ACLS=$(config_n_get @global[0] acl_enable 0)
SOCKS_ENABLED=$(config_n_get @global[0] socks_enabled 0)
TCP_PROXY_WAY=$(config_n_get @global_forwarding[0] tcp_proxy_way redirect)
PROXY_IPV6=$(config_n_get @global_forwarding[0] ipv6_tproxy 0)
DIRECT_DNS_QUERY_STRATEGY=$(config_n_get @global[0] direct_dns_query_strategy UseIP)
get_direct_dns
@@ -1288,7 +1028,7 @@ get_config() {
fi
fi
set_cache_var GLOBAL_DNSMASQ_CONF ${DNSMASQ_CONF_DIR}/dnsmasq-${CONFIG}.conf
set_cache_var GLOBAL_DNSMASQ_CONF_PATH ${GLOBAL_ACL_PATH}/dnsmasq.d
set_cache_var GLOBAL_DNSMASQ_CONF_PATH ${TMP_ACL_PATH}/default_dnsmasq.d
QUEUE_RUN=1
}
@@ -0,0 +1,227 @@
-- Copyright (C) 2026 xiaorouji
local api = require "luci.passwall2.api"
local jsonc = api.jsonc
local sys = api.sys
local fs = api.fs
local i18n = api.i18n
local log = api.log
local uci, uci_get, uci_set, uci_del, uci_foreach, uci_save = api.uci, api.uci_get_c, api.uci_set_c, api.uci_del_c, api.uci_foreach_c, api.uci_save_c
local VAR = {} -- Set VAR
local D = {} -- Default Global Access Control
local L = {
acl = {},
node = {},
node_order = {}
}
function add_args(t, k, v)
if not t or not k or not v then return end
table.insert(t, k .. "=" .. '"' .. v .. '"')
end
function init_acl()
if true then
-- Get Default AC
D.flag = "default"
D.remarks = api.i18n.translatef("Default")
D.tcp_no_redir_ports = uci_get("@global_forwarding[0]", "tcp_no_redir_ports")
D.udp_no_redir_ports = uci_get("@global_forwarding[0]", "udp_no_redir_ports")
D.tcp_redir_ports = uci_get("@global_forwarding[0]", "tcp_redir_ports")
D.udp_redir_ports = uci_get("@global_forwarding[0]", "udp_redir_ports")
D.node = uci_get("@global[0]", "node")
D.local_proxy = uci_get("@global[0]", "localhost_proxy")
D.client_proxy = uci_get("@global[0]", "client_proxy")
if D.node then
local node = uci_get(D.node)
if node and node[".type"] == "nodes" then
local n = {
config = node,
enabled = uci_get("@global[0]", "enabled") or "0",
log = uci_get("@global[0]", "log_node") or "0",
loglevel = uci_get("@global[0]", "loglevel") or "warn",
socks_listen = uci_get("@global[0]", "node_socks_bind_local") == "0" and "0.0.0.0" or "127.0.0.1",
socks_port = uci_get("@global[0]", "node_socks_port"),
redir_port = api.get_new_port(),
dns_port = api.get_new_port(),
direct_dns_query_strategy = uci_get("@global[0]", "direct_dns_query_strategy") or "UseIP",
remote_dns_protocol = uci_get("@global[0]", "remote_dns_protocol") or "tcp",
remote_dns_detour = uci_get("@global[0]", "remote_dns_detour") or "remote",
remote_dns = uci_get("@global[0]", "remote_dns") or "1.1.1.1:53",
remote_dns_doh = uci_get("@global[0]", "remote_dns_doh") or "https://1.1.1.1/dns-query",
remote_dns_client_ip = uci_get("@global[0]", "remote_dns_client_ip"),
remote_dns_query_strategy = uci_get("@global[0]", "remote_dns_query_strategy") or "UseIPv4",
remote_rewrite_ttl = uci_get("@global[0]", "remote_rewrite_ttl"),
remote_fakedns = uci_get("@global[0]", "remote_fakedns") or "0",
}
L.node[D.flag] = n
D.use = D.flag
if n.enabled == "1" then
L.node_order[#L.node_order + 1] = D.flag
end
end
end
end
local acl_num = 0
if uci_get("@global[0]", "acl_enable") == "1" then
uci_foreach("acl_rule", function(o)
if o.enabled == "1" then
acl_num = acl_num + 1
local a = {}
a.flag = o[".name"]
a.remarks = o.remarks
a.interface = o.interface
a.sources = o.sources
a.tcp_no_redir_ports = o.tcp_no_redir_ports
a.udp_no_redir_ports = o.udp_no_redir_ports
a.tcp_redir_ports = o.tcp_redir_ports
a.udp_redir_ports = o.udp_redir_ports
a.client_proxy = "1"
a.local_proxy = "0"
a.node = o.node
if o.mode == "0" then
a.tcp_no_redir_ports = "1:65535"
a.udp_no_redir_ports = "1:65535"
elseif o.mode == "2" then
local U = L.node[D.use]
if U.enabled == "0" then
U.enabled = "1"
D.local_proxy = "0"
D.client_proxy = "0"
end
a.use = D.use
end
if a.tcp_no_redir_ports == "1:65535" and a.udp_no_redir_ports == "1:65535" then
a.node = nil
end
if a.node then
local node = uci_get(a.node)
if node and node[".type"] == "nodes" then
local n = {
config = node,
enabled = "1",
log = o.log or "0",
loglevel = o.loglevel or "warn",
redir_port = api.get_new_port(),
dns_port = api.get_new_port(),
direct_dns_query_strategy = o.direct_dns_query_strategy,
remote_dns_protocol = o.remote_dns_protocol,
remote_dns_detour = o.remote_dns_detour,
remote_dns = o.remote_dns,
remote_dns_doh = o.remote_dns_doh,
remote_dns_client_ip = o.remote_dns_client_ip,
remote_dns_query_strategy = o.remote_dns_query_strategy,
remote_rewrite_ttl = o.remote_rewrite_ttl,
remote_fakedns = o.remote_fakedns,
}
L.node[a.flag] = n
a.use = a.flag
if n.enabled == "1" then
L.node_order[#L.node_order + 1] = a.flag
end
end
end
L.acl[#L.acl + 1] = a
end
end)
end
if next(D) then
L.acl[#L.acl + 1] = D
end
VAR["ENABLED_ACLS"] = acl_num > 0 and 1 or 0
return L
end
function acl_app(l)
if not l then l = L end
for i, v in ipairs(l.acl) do
local sid = v.flag
local acl_path = api.TMP_ACL_PATH .. "/" .. sid
sys.call("mkdir -p " .. acl_path)
local out = io.open(acl_path .. "/var", "a")
for k2, v2 in pairs(v) do
if type(v2) == "string" then
out:write(k2 .. "=" .. '"' .. v2 .. '"' .. "\n")
end
end
if v.use then
local node = l.node[v.use]
if node.config then
out:write("node" .. "=" .. '"' .. node.config[".name"] .. '"' .. "\n")
out:write("node_remarks" .. "=" .. '"' .. node.config.remarks .. '"' .. "\n")
end
out:write("redir_port" .. "=" .. '"' .. node.redir_port .. '"' .. "\n")
end
out:close()
local source_list = "any"
if v.sources and #v.sources > 0 then
local s1 = {}
for i, w in ipairs(v.sources) do
if api.iprange(w) then
s1[#s1 + 1] = "iprange:" .. w
elseif w:find("ipset:") == 1 then
s1[#s1 + 1] = "ipset:" .. w
else
local _ip_or_mac = api.ip_or_mac(w)
if _ip_or_mac == "ip" then
s1[#s1 + 1] = "ip:" .. w
elseif _ip_or_mac == "mac" then
s1[#s1 + 1] = "mac:" .. w
end
end
end
if #s1 > 0 then
source_list = table.concat(s1, "\n")
end
end
if #source_list > 0 then
local out = io.open(acl_path .. "/source_list", "a")
out:write(source_list)
out:close()
end
end
-- Gen shell param
for _, v1 in ipairs(l.node_order) do
local v = l.node[v1]
if v.enabled == "1" then
local flag = v1
local node = v.config
local run_args = {}
local config_path = api.TMP_ACL_PATH .. "/" .. flag
local config_file = config_path .. ".json"
local log_file = v.log == "0" and "/dev/null" or config_path .. ".log"
add_args(run_args, "flag", flag)
add_args(run_args, "node", node[".name"])
add_args(run_args, "redir_port", v.redir_port)
add_args(run_args, "socks_address", v.socks_listen)
add_args(run_args, "socks_port", v.socks_port)
add_args(run_args, "dns_listen_port", v.dns_port)
add_args(run_args, "direct_dns_query_strategy", v.direct_dns_query_strategy)
add_args(run_args, "remote_dns_protocol", v.remote_dns_protocol)
add_args(run_args, "remote_dns_tcp_server", v.remote_dns)
add_args(run_args, "remote_dns_udp_server", v.remote_dns)
add_args(run_args, "remote_dns_doh", v.remote_dns_doh)
add_args(run_args, "remote_dns_client_ip", v.remote_dns_client_ip)
add_args(run_args, "remote_dns_detour", v.remote_dns_detour)
add_args(run_args, "remote_dns_query_strategy", v.remote_dns_query_strategy)
add_args(run_args, "remote_fakedns", v.remote_fakedns)
add_args(run_args, "remote_rewrite_ttl", v.remote_rewrite_ttl)
add_args(run_args, "config_file", config_file)
add_args(run_args, "loglevel", v.loglevel)
add_args(run_args, "log_file", log_file)
local out = io.open(api.TMP_ACL_PATH .. "/acl_node_" .. flag , "a")
out:write(table.concat(run_args, " "))
out:close()
end
end
for k, v in pairs(VAR) do
api.set_cache_var(k, v)
end
end
local acls = init_acl()
acl_app()
print(jsonc.stringify(acls, 1))
@@ -211,7 +211,7 @@ gen_shunt_list() {
[ -n "$_geoip_code" ] && {
get_geoip $_geoip_code ipv4 | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | sed -e "s/^/add $ipset_v4 &/g" | awk '{print $0} END{print "COMMIT"}' | ipset -! -R
get_geoip $_geoip_code ipv6 | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | sed -e "s/^/add $ipset_v6 &/g" | awk '{print $0} END{print "COMMIT"}' | ipset -! -R
log 1 "$(i18n "parse the traffic splitting rules[%s]-[geoip:%s] add to %s to complete." "${shunt_id}" "${_geoip_code}" "IPSET")"
#log 3 "$(i18n "parse the traffic splitting rules[%s]-[geoip:%s] add to %s to complete." "${shunt_id}" "${_geoip_code}" "IPSET[${ipset_v4},${ipset_v6}]")"
}
}
}
@@ -230,6 +230,7 @@ gen_shunt_list() {
}
[ -n "${_SHUNT_LIST4}" ] && eval ${shunt_list4_var_name}=\"${_SHUNT_LIST4}\"
[ -n "${_SHUNT_LIST6}" ] && eval ${shunt_list6_var_name}=\"${_SHUNT_LIST6}\"
set_cache_var "${node}_gen_shunt_list" "1"
}
add_shunt_t_rule() {
@@ -255,45 +256,21 @@ add_shunt_t_rule() {
}
load_acl() {
acl_json=$(lua $APP_PATH/app_acl.lua)
acl_node
log_i18n 1 "Access Control:"
[ "$ENABLED_ACLS" == 1 ] && {
acl_app
for sid in $(ls -F ${TMP_ACL_PATH} | grep '/$' | awk -F '/' '{print $1}' | grep -v 'default'); do
eval $(uci -q show "${CONFIG}.${sid}" | cut -d'.' -sf 3-)
for sid in $(jsonfilter -s "${acl_json}" -e '$.acl[*].flag'); do
eval local $(cat "${TMP_ACL_PATH}/${sid}/var")
mode=${mode:-0}
tcp_no_redir_ports=${tcp_no_redir_ports:-default}
udp_no_redir_ports=${udp_no_redir_ports:-default}
tcp_proxy_mode="global"
udp_proxy_mode="global"
tcp_redir_ports=${tcp_redir_ports:-default}
udp_redir_ports=${udp_redir_ports:-default}
node=${node:-default}
[ "$mode" = "0" ] && {
tcp_no_redir_ports="1:65535"
udp_no_redir_ports="1:65535"
}
[ "$tcp_no_redir_ports" = "default" ] && tcp_no_redir_ports=$TCP_NO_REDIR_PORTS
[ "$udp_no_redir_ports" = "default" ] && udp_no_redir_ports=$UDP_NO_REDIR_PORTS
[ "$tcp_redir_ports" = "default" ] && tcp_redir_ports=$TCP_REDIR_PORTS
[ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS
[ -z "$(get_cache_var "${node}_gen_shunt_list")" ] && [ -n "${node}" ] && gen_shunt_list "${node}" shunt_list4 shunt_list6
[ -n "${use}" ] && local dns_redirect_port=$(get_cache_var "ACL_${use}_dns_port")
[ -n "$(get_cache_var "ACL_${sid}_node")" ] && node=$(get_cache_var "ACL_${sid}_node")
[ -n "$(get_cache_var "ACL_${sid}_redir_port")" ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port")
[ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port")
[ -n "$node" ] && node_remark=$(config_n_get $node remarks)
local ipt_tmp=$ipt_n
[ -n "${is_tproxy}" ] && ipt_tmp=$ipt_m
if [ -n "$(get_cache_var "ACL_${sid}_default")" ]; then
shunt_list4=${SHUNT_LIST4}
shunt_list6=${SHUNT_LIST6}
else
# Shunt rules IP list (import when use shunt node)
gen_shunt_list "${node}" shunt_list4 shunt_list6
fi
_acl_list=${TMP_ACL_PATH}/${sid}/source_list
for i in $(cat $_acl_list); do
[ "${client_proxy}" = "1" ] && {
msg1="$(i18n "[%s]," "${remarks}")"
for i in $(cat ${TMP_ACL_PATH}/${sid}/source_list); do
local _ipt_source _ipv4
local msg
if [ -n "${interface}" ]; then
@@ -344,41 +321,39 @@ load_acl() {
else
continue
fi
msg="$(i18n "[%s]," "${remarks}")${msg}"
ipt_tmp=$ipt_n
[ -n "${is_tproxy}" ] && ipt_tmp=$ipt_m
[ "$tcp_no_redir_ports" != "disable" ] && {
msg="${msg1}${msg}"
[ -n "$tcp_no_redir_ports" ] && {
if ! has_1_65535 "$tcp_no_redir_ports"; then
[ "$_ipv4" != "1" ] && add_port_rules "$ip6t_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p tcp" $tcp_no_redir_ports "-j RETURN" 2>/dev/null
add_port_rules "$ipt_tmp -A PSW2 $(comment "$remarks") ${_ipt_source} -p tcp" $tcp_no_redir_ports "-j RETURN"
log 2 "${msg}$(i18n "not proxy %s port [%s]" "TCP" "${tcp_no_redir_ports}")"
else
# It will return when it ends, so no extra rules are needed.
tcp_proxy_mode="disable"
no_tcp_proxy="1"
log 2 "${msg}$(i18n "not proxy all %s" "TCP")"
fi
}
[ "$udp_no_redir_ports" != "disable" ] && {
[ -n "$udp_no_redir_ports" ] && {
if ! has_1_65535 "$udp_no_redir_ports"; then
[ "$_ipv4" != "1" ] && add_port_rules "$ip6t_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p udp" $udp_no_redir_ports "-j RETURN" 2>/dev/null
add_port_rules "$ipt_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p udp" $udp_no_redir_ports "-j RETURN"
log 2 "${msg}$(i18n "not proxy %s port [%s]" "UDP" "${udp_no_redir_ports}")"
else
# It will return when it ends, so no extra rules are needed.
udp_proxy_mode="disable"
no_udp_proxy="1"
log 2 "${msg}$(i18n "not proxy all %s" "UDP")"
fi
}
if ([ "$tcp_proxy_mode" != "disable" ] || [ "$udp_proxy_mode" != "disable" ]) && [ -n "$dns_redirect_port" ]; then
if ([ -z "$no_tcp_proxy" ] || [ -z "$no_udp_proxy" ]) && [ -n "$dns_redirect_port" ]; then
$ipt_n -A PSW2_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port
$ip6t_n -A PSW2_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port 2>/dev/null
$ipt_n -A PSW2_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port
$ip6t_n -A PSW2_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port 2>/dev/null
[ -z "$(get_cache_var "ACL_${sid}_default")" ] && log 2 "${msg}$(i18n "Using a node that is different from the global configuration, DNS has been forcibly redirected to a dedicated DNS server.")"
log 2 "${msg}$(i18n "DNS will redirected to the dedicated DNS server [%s]." "${dns_redirect_port}")"
else
$ipt_n -A PSW2_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN
$ip6t_n -A PSW2_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null
@@ -386,8 +361,8 @@ load_acl() {
$ip6t_n -A PSW2_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null
fi
[ "$tcp_proxy_mode" != "disable" ] && [ -n "$redir_port" ] && {
msg2="${msg}$(i18n "Use the %s node [%s]" "TCP" "${node_remark}")"
[ -z "$no_tcp_proxy" ] && [ -n "$redir_port" ] && {
msg2="${msg}$(i18n "Use the %s node [%s]" "TCP" "${node_remarks}")"
if [ -n "${is_tproxy}" ]; then
msg2="${msg2}(TPROXY:${redir_port})"
ipt_j="-j PSW2_RULE"
@@ -424,8 +399,8 @@ load_acl() {
$ipt_tmp -A PSW2 $(comment "$remarks") ${_ipt_source} -p tcp -j RETURN
[ "$_ipv4" != "1" ] && $ip6t_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p tcp -j RETURN 2>/dev/null
[ "$udp_proxy_mode" != "disable" ] && [ -n "$redir_port" ] && {
msg2="${msg}$(i18n "Use the %s node [%s]" "UDP" "${node_remark}")(TPROXY:${redir_port})"
[ -z "$no_tcp_proxy" ] && [ -n "$redir_port" ] && {
msg2="${msg}$(i18n "Use the %s node [%s]" "UDP" "${node_remarks}")(TPROXY:${redir_port})"
$ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} -d $FAKE_IP -j PSW2_RULE
add_shunt_t_rule "${shunt_list4}" "$ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source}" "-j PSW2_RULE" $udp_redir_ports
@@ -442,105 +417,143 @@ load_acl() {
}
$ipt_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p udp -j RETURN
[ "$_ipv4" != "1" ] && $ip6t_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p udp -j RETURN 2>/dev/null
unset ipt_tmp ipt_j _ipt_source msg msg2 _ipv4
unset ipt_j _ipt_source msg msg2 _ipv4 no_tcp_proxy no_udp_proxy
done
unset enabled sid remarks sources tcp_no_redir_ports udp_no_redir_ports tcp_redir_ports udp_redir_ports node interface
unset node_remark _acl_list
done
}
[ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ] && {
local comment_d="$(i18n "Default")"
msg="$(i18n "[%s]," ${comment_d})"
local ipt_tmp=$ipt_n
[ -n "${is_tproxy}" ] && ipt_tmp=$ipt_m
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && {
add_port_rules "$ip6t_m -A PSW2 $(comment "${comment_d}") -p tcp" $TCP_NO_REDIR_PORTS "-j RETURN"
add_port_rules "$ipt_tmp -A PSW2 $(comment "${comment_d}") -p tcp" $TCP_NO_REDIR_PORTS "-j RETURN"
if ! has_1_65535 "$TCP_NO_REDIR_PORTS"; then
log 2 "${msg}$(i18n "not proxy %s port [%s]" "TCP" "${TCP_NO_REDIR_PORTS}")"
else
TCP_PROXY_MODE="disable"
log 2 "${msg}$(i18n "not proxy all %s" "TCP")"
fi
unset msg1
}
[ "$UDP_NO_REDIR_PORTS" != "disable" ] && {
add_port_rules "$ip6t_m -A PSW2 $(comment "${comment_d}") -p udp" $UDP_NO_REDIR_PORTS "-j RETURN"
add_port_rules "$ipt_tmp -A PSW2 $(comment "${comment_d}") -p udp" $UDP_NO_REDIR_PORTS "-j RETURN"
if ! has_1_65535 "$UDP_NO_REDIR_PORTS"; then
log 2 "${msg}$(i18n "not proxy %s port [%s]" "UDP" "${UDP_NO_REDIR_PORTS}")"
else
UDP_PROXY_MODE="disable"
log 2 "${msg}$(i18n "not proxy all %s" "UDP")"
fi
}
if ([ "$TCP_PROXY_MODE" != "disable" ] || [ "$UDP_PROXY_MODE" != "disable" ]) && [ -n "$NODE" ]; then
[ -n "$DNS_REDIRECT_PORT" ] && {
$ipt_n -A PSW2_DNS $(comment "${comment_d}") -p udp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
$ip6t_n -A PSW2_DNS $(comment "${comment_d}") -p udp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null
$ipt_n -A PSW2_DNS $(comment "${comment_d}") -p tcp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
$ip6t_n -A PSW2_DNS $(comment "${comment_d}") -p tcp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null
[ "${local_proxy}" = "1" ] && {
msg="$(i18n "[Local],")"
[ -n "$tcp_no_redir_ports" ] && {
add_port_rules "$ipt_tmp -A PSW2_OUTPUT -p tcp" $tcp_no_redir_ports "-j RETURN"
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p tcp" $tcp_no_redir_ports "-j RETURN"
if ! has_1_65535 "$tcp_no_redir_ports"; then
log 2 "${msg}$(i18n "not proxy %s port [%s]" "TCP" "${tcp_no_redir_ports}")"
else
no_tcp_local_proxy="1"
log 2 "${msg}$(i18n "not proxy all %s" "TCP")"
fi
}
fi
if [ "$TCP_PROXY_MODE" != "disable" ] && [ -n "$NODE" ]; then
msg2="${msg}$(i18n "Use the %s node [%s]" "TCP" "$(config_n_get $NODE remarks)")"
if [ -n "${is_tproxy}" ]; then
msg2="${msg2}(TPROXY:${REDIR_PORT})"
ipt_j="-j PSW2_RULE"
else
msg2="${msg2}(REDIRECT:${REDIR_PORT})"
ipt_j="$(REDIRECT $REDIR_PORT)"
fi
[ "$accept_icmp" = "1" ] && {
$ipt_n -A PSW2 $(comment "${comment_d}") -p icmp -d $FAKE_IP $(REDIRECT)
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_n -A PSW2 $(comment "${comment_d}") -p icmp" "$(REDIRECT)"
$ipt_n -A PSW2 $(comment "${comment_d}") -p icmp $(REDIRECT)
[ -n "$udp_no_redir_ports" ] && {
add_port_rules "$ipt_m -A PSW2_OUTPUT -p udp" $udp_no_redir_ports "-j RETURN"
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p udp" $udp_no_redir_ports "-j RETURN"
if ! has_1_65535 "$udp_no_redir_ports"; then
log 2 "${msg}$(i18n "not proxy %s port [%s]" "UDP" "${udp_no_redir_ports}")"
else
no_udp_local_proxy="1"
log 2 "${msg}$(i18n "not proxy all %s" "UDP")"
fi
}
[ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" == "1" ] && {
$ip6t_n -A PSW2 $(comment "${comment_d}") -p ipv6-icmp -d $FAKE_IP_6 $(REDIRECT)
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_n -A PSW2 $(comment "${comment_d}") -p ipv6-icmp" "$(REDIRECT)"
$ip6t_n -A PSW2 $(comment "${comment_d}") -p ipv6-icmp $(REDIRECT)
}
if [ -n "$node" ] && ([ -z "$no_tcp_local_proxy" ] || [ -z "$no_udp_local_proxy" ]); then
[ -n "$dns_redirect_port" ] && {
$ipt_n -A OUTPUT $(comment "PSW2_DNS") -p udp -o lo --dport 53 -j REDIRECT --to-ports $dns_redirect_port
$ip6t_n -A OUTPUT $(comment "PSW2_DNS") -p udp -o lo --dport 53 -j REDIRECT --to-ports $dns_redirect_port 2>/dev/null
$ipt_n -A OUTPUT $(comment "PSW2_DNS") -p tcp -o lo --dport 53 -j REDIRECT --to-ports $dns_redirect_port
$ip6t_n -A OUTPUT $(comment "PSW2_DNS") -p tcp -o lo --dport 53 -j REDIRECT --to-ports $dns_redirect_port 2>/dev/null
log 2 "${msg}$(i18n "DNS will redirected to the dedicated DNS server [%s]." "${dns_redirect_port}")"
}
fi
$ipt_tmp -A PSW2 $(comment "${comment_d}") -p tcp -d $FAKE_IP ${ipt_j}
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_tmp -A PSW2 $(comment "${comment_d}") -p tcp" "${ipt_j}" $TCP_REDIR_PORTS
add_port_rules "$ipt_tmp -A PSW2 $(comment "${comment_d}") -p tcp" $TCP_REDIR_PORTS "${ipt_j}"
[ -n "${is_tproxy}" ] && $ipt_m -A PSW2 $(comment "${comment_d}") -p tcp $(REDIRECT $REDIR_PORT TPROXY)
local comment_l="$(i18n "Local")"
[ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2 $(comment "${comment_d}") -p tcp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2 $(comment "${comment_d}") -p tcp" "-j PSW2_RULE" $TCP_REDIR_PORTS
add_port_rules "$ip6t_m -A PSW2 $(comment "${comment_d}") -p tcp" $TCP_REDIR_PORTS "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "${comment_d}") -p tcp $(REDIRECT $REDIR_PORT TPROXY)
}
# Loading local router proxy TCP
if [ -n "$node" ] && [ -z "$no_tcp_local_proxy" ]; then
[ "$accept_icmp" = "1" ] && {
$ipt_n -A OUTPUT $(dst $IPSET_DIRECT !) -p icmp -j PSW2_OUTPUT
$ipt_n -A PSW2_OUTPUT -p icmp -d $FAKE_IP $(REDIRECT)
add_shunt_t_rule "${shunt_list4}" "$ipt_n -A PSW2_OUTPUT -p icmp" "$(REDIRECT)"
$ipt_n -A PSW2_OUTPUT -p icmp $(REDIRECT)
}
log 2 "${msg2}"
fi
[ "$accept_icmpv6" = "1" ] && {
$ip6t_n -A OUTPUT $(dst $IPSET_DIRECT6 !) -p ipv6-icmp -j PSW2_OUTPUT
$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp -d $FAKE_IP_6 $(REDIRECT)
add_shunt_t_rule "${shunt_list6}" "$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp" "$(REDIRECT)"
$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp $(REDIRECT)
}
if [ "$UDP_PROXY_MODE" != "disable" ] && [ -n "$NODE" ]; then
msg2="${msg}$(i18n "Use the %s node [%s]" "UDP" "$(config_n_get $NODE remarks)")(TPROXY:${REDIR_PORT})"
msg2="${msg}$(i18n "Use the %s node [%s]" "TCP" "${node_remarks}")"
if [ -n "${is_tproxy}" ]; then
msg2="${msg2}(TPROXY:${redir_port})"
ipt_j="-j PSW2_RULE"
else
msg2="${msg2}(REDIRECT:${redir_port})"
ipt_j="$(REDIRECT $redir_port)"
fi
$ipt_m -A PSW2 $(comment "${comment_d}") -p udp -d $FAKE_IP -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_m -A PSW2 $(comment "${comment_d}") -p udp" "-j PSW2_RULE" $UDP_REDIR_PORTS
add_port_rules "$ipt_m -A PSW2 $(comment "${comment_d}") -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
$ipt_m -A PSW2 $(comment "${comment_d}") -p udp $(REDIRECT $REDIR_PORT TPROXY)
$ipt_tmp -A PSW2_OUTPUT -p tcp -d $FAKE_IP ${ipt_j}
add_shunt_t_rule "${shunt_list4}" "$ipt_tmp -A PSW2_OUTPUT -p tcp" "${ipt_j}" $tcp_redir_ports
add_port_rules "$ipt_tmp -A PSW2_OUTPUT -p tcp" $tcp_redir_ports "${ipt_j}"
[ -z "${is_tproxy}" ] && $ipt_n -A OUTPUT $(dst $IPSET_DIRECT !) -p tcp -j PSW2_OUTPUT
[ -n "${is_tproxy}" ] && {
$ipt_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo $(REDIRECT $redir_port TPROXY)
$ipt_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo -j RETURN
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT !) -p tcp -j PSW2_OUTPUT"
}
[ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2 $(comment "${comment_d}") -p udp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2 $(comment "${comment_d}") -p udp" "-j PSW2_RULE" $UDP_REDIR_PORTS
add_port_rules "$ip6t_m -A PSW2 $(comment "${comment_d}") -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "${comment_d}") -p udp $(REDIRECT $REDIR_PORT TPROXY)
}
[ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2_OUTPUT -p tcp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${shunt_list6}" "$ip6t_m -A PSW2_OUTPUT -p tcp" "-j PSW2_RULE" $tcp_redir_ports
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p tcp" $tcp_redir_ports "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo $(REDIRECT $redir_port TPROXY)
$ip6t_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo -j RETURN
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT6 !) -p tcp -j PSW2_OUTPUT"
}
log 2 "${msg2}"
fi
}
[ -d "${TMP_IFACE_PATH}" ] && {
for iface in $(ls ${TMP_IFACE_PATH}); do
$ipt_n -A PSW2_OUTPUT -o $iface -p tcp -j RETURN
$ipt_m -A PSW2_OUTPUT -o $iface -p tcp -j RETURN
done
}
log 2 "${msg2}"
fi
# Loading local router proxy UDP
if [ -n "$node" ] && [ -z "$no_udp_local_proxy" ]; then
msg2="${msg}$(i18n "Use the %s node [%s]" "UDP" "${node_remarks}")(TPROXY:${redir_port})"
$ipt_m -A PSW2_OUTPUT -p udp -d $FAKE_IP -j PSW2_RULE
add_shunt_t_rule "${shunt_list4}" "$ipt_m -A PSW2_OUTPUT -p udp" "-j PSW2_RULE" $udp_redir_ports
add_port_rules "$ipt_m -A PSW2_OUTPUT -p udp" $udp_redir_ports "-j PSW2_RULE"
$ipt_m -A PSW2 $(comment "${comment_l}") -p udp -i lo $(REDIRECT $redir_port TPROXY)
$ipt_m -A PSW2 $(comment "${comment_l}") -p udp -i lo -j RETURN
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT !) -p udp -j PSW2_OUTPUT"
[ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2_OUTPUT -p udp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${shunt_list6}" "$ip6t_m -A PSW2_OUTPUT -p udp" "-j PSW2_RULE" $udp_redir_ports
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p udp" $udp_redir_ports "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "${comment_l}") -p udp -i lo $(REDIRECT $redir_port TPROXY)
$ip6t_m -A PSW2 $(comment "${comment_l}") -p udp -i lo -j RETURN
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT6 !) -p udp -j PSW2_OUTPUT"
}
[ -d "${TMP_IFACE_PATH}" ] && {
for iface in $(ls ${TMP_IFACE_PATH}); do
$ipt_n -A PSW2_OUTPUT -o $iface -p udp -j RETURN
$ipt_m -A PSW2_OUTPUT -o $iface -p udp -j RETURN
done
}
log 2 "${msg2}"
fi
$ipt_m -I OUTPUT $(comment "mangle-OUTPUT-PSW2") -o lo -j RETURN
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark ${FWMARK} -j RETURN"
$ip6t_m -I OUTPUT $(comment "mangle-OUTPUT-PSW2") -o lo -j RETURN
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark ${FWMARK} -j RETURN"
$ipt_m -A PSW2 -p tcp --dport 53 -j ACCEPT
$ipt_m -A PSW2 -p udp --dport 53 -j ACCEPT
$ip6t_m -A PSW2 -p tcp --dport 53 -j ACCEPT
$ip6t_m -A PSW2 -p udp --dport 53 -j ACCEPT
unset msg msg2 comment_l
}
unset dns_redirect_port ipt_tmp
unset $(cat "${TMP_ACL_PATH}/${sid}/var" | awk -F '=' '{print $1}' | tr "\n" " ")
done
}
filter_haproxy() {
@@ -684,15 +697,12 @@ add_firewall_rule() {
done
}
# Shunt rules IP list (import when use shunt node)
gen_shunt_list "${NODE}" SHUNT_LIST4 SHUNT_LIST6
# Filter all node IPs
filter_vpsip > /dev/null 2>&1 &
filter_haproxy > /dev/null 2>&1 &
accept_icmp=$(config_t_get global_forwarding accept_icmp 0)
accept_icmpv6=$(config_t_get global_forwarding accept_icmpv6 0)
accept_icmp=$(config_n_get @global_forwarding[0] accept_icmp 0)
accept_icmpv6=$(config_n_get @global_forwarding[0] accept_icmpv6 0)
if [ "${TCP_PROXY_WAY}" = "redirect" ]; then
unset is_tproxy
@@ -720,7 +730,7 @@ add_firewall_rule() {
$ipt_n -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
$ipt_n -N PSW2_DNS
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
if [ $(config_n_get @global[0] dns_redirect "1") = "0" ]; then
#Only hijack when dest address is local IP
$ipt_n -I PREROUTING -m set --match-set $IPSET_DIRECT src $(dst $IPSET_LOCAL) -j PSW2_DNS
else
@@ -763,7 +773,7 @@ add_firewall_rule() {
}
$ip6t_n -N PSW2_DNS
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
if [ $(config_n_get @global[0] dns_redirect "1") = "0" ]; then
#Only hijack when dest address is local IP
$ip6t_n -I PREROUTING -m set --match-set $IPSET_DIRECT6 src $(dst $IPSET_LOCAL6) -j PSW2_DNS
else
@@ -809,134 +819,6 @@ add_firewall_rule() {
ip -6 rule add fwmark ${FWMARK} table 999 priority 999
ip -6 route add local ::/0 dev lo table 999
[ "$ENABLED_DEFAULT_ACL" == 1 ] && {
local ipt_tmp=$ipt_n
[ -n "${is_tproxy}" ] && ipt_tmp=$ipt_m
TCP_LOCALHOST_PROXY=$LOCALHOST_PROXY
UDP_LOCALHOST_PROXY=$LOCALHOST_PROXY
msg="$(i18n "[Local],")"
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && {
add_port_rules "$ipt_tmp -A PSW2_OUTPUT -p tcp" $TCP_NO_REDIR_PORTS "-j RETURN"
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p tcp" $TCP_NO_REDIR_PORTS "-j RETURN"
if ! has_1_65535 "$TCP_NO_REDIR_PORTS"; then
log 1 "${msg}$(i18n "not proxy %s port [%s]" "TCP" "${TCP_NO_REDIR_PORTS}")"
else
unset TCP_LOCALHOST_PROXY
log 1 "${msg}$(i18n "not proxy all %s" "TCP")"
fi
}
[ "$UDP_NO_REDIR_PORTS" != "disable" ] && {
add_port_rules "$ipt_m -A PSW2_OUTPUT -p udp" $UDP_NO_REDIR_PORTS "-j RETURN"
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p udp" $UDP_NO_REDIR_PORTS "-j RETURN"
if ! has_1_65535 "$UDP_NO_REDIR_PORTS"; then
log 1 "${msg}$(i18n "not proxy %s port [%s]" "UDP" "${UDP_NO_REDIR_PORTS}")"
else
unset UDP_LOCALHOST_PROXY
log 1 "${msg}$(i18n "not proxy all %s" "UDP")"
fi
}
if [ -n "$NODE" ] && ([ "$TCP_LOCALHOST_PROXY" = "1" ] || [ "$UDP_LOCALHOST_PROXY" = "1" ]); then
[ -n "$DNS_REDIRECT_PORT" ] && {
$ipt_n -A OUTPUT $(comment "PSW2_DNS") -p udp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
$ip6t_n -A OUTPUT $(comment "PSW2_DNS") -p udp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null
$ipt_n -A OUTPUT $(comment "PSW2_DNS") -p tcp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT
$ip6t_n -A OUTPUT $(comment "PSW2_DNS") -p tcp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null
}
fi
local comment_l="$(i18n "Local")"
# Loading local router proxy TCP
if [ -n "$NODE" ] && [ "$TCP_LOCALHOST_PROXY" = "1" ]; then
[ "$accept_icmp" = "1" ] && {
$ipt_n -A OUTPUT $(dst $IPSET_DIRECT !) -p icmp -j PSW2_OUTPUT
$ipt_n -A PSW2_OUTPUT -p icmp -d $FAKE_IP $(REDIRECT)
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_n -A PSW2_OUTPUT -p icmp" "$(REDIRECT)"
$ipt_n -A PSW2_OUTPUT -p icmp $(REDIRECT)
}
[ "$accept_icmpv6" = "1" ] && {
$ip6t_n -A OUTPUT $(dst $IPSET_DIRECT6 !) -p ipv6-icmp -j PSW2_OUTPUT
$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp -d $FAKE_IP_6 $(REDIRECT)
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp" "$(REDIRECT)"
$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp $(REDIRECT)
}
if [ -n "${is_tproxy}" ]; then
ipt_j="-j PSW2_RULE"
else
ipt_j="$(REDIRECT $REDIR_PORT)"
fi
$ipt_tmp -A PSW2_OUTPUT -p tcp -d $FAKE_IP ${ipt_j}
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_tmp -A PSW2_OUTPUT -p tcp" "${ipt_j}" $TCP_REDIR_PORTS
add_port_rules "$ipt_tmp -A PSW2_OUTPUT -p tcp" $TCP_REDIR_PORTS "${ipt_j}"
[ -z "${is_tproxy}" ] && $ipt_n -A OUTPUT $(dst $IPSET_DIRECT !) -p tcp -j PSW2_OUTPUT
[ -n "${is_tproxy}" ] && {
$ipt_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY)
$ipt_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo -j RETURN
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT !) -p tcp -j PSW2_OUTPUT"
}
[ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2_OUTPUT -p tcp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2_OUTPUT -p tcp" "-j PSW2_RULE" $TCP_REDIR_PORTS
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p tcp" $TCP_REDIR_PORTS "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY)
$ip6t_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo -j RETURN
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT6 !) -p tcp -j PSW2_OUTPUT"
}
[ -d "${TMP_IFACE_PATH}" ] && {
for iface in $(ls ${TMP_IFACE_PATH}); do
$ipt_n -A PSW2_OUTPUT -o $iface -p tcp -j RETURN
$ipt_m -A PSW2_OUTPUT -o $iface -p tcp -j RETURN
done
}
fi
# Loading local router proxy UDP
if [ -n "$NODE" ] && [ "$UDP_LOCALHOST_PROXY" = "1" ]; then
$ipt_m -A PSW2_OUTPUT -p udp -d $FAKE_IP -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_m -A PSW2_OUTPUT -p udp" "-j PSW2_RULE" $UDP_REDIR_PORTS
add_port_rules "$ipt_m -A PSW2_OUTPUT -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
$ipt_m -A PSW2 $(comment "${comment_l}") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY)
$ipt_m -A PSW2 $(comment "${comment_l}") -p udp -i lo -j RETURN
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT !) -p udp -j PSW2_OUTPUT"
[ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2_OUTPUT -p udp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2_OUTPUT -p udp" "-j PSW2_RULE" $UDP_REDIR_PORTS
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "${comment_l}") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY)
$ip6t_m -A PSW2 $(comment "${comment_l}") -p udp -i lo -j RETURN
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT6 !) -p udp -j PSW2_OUTPUT"
}
[ -d "${TMP_IFACE_PATH}" ] && {
for iface in $(ls ${TMP_IFACE_PATH}); do
$ipt_n -A PSW2_OUTPUT -o $iface -p udp -j RETURN
$ipt_m -A PSW2_OUTPUT -o $iface -p udp -j RETURN
done
}
fi
$ipt_m -I OUTPUT $(comment "mangle-OUTPUT-PSW2") -o lo -j RETURN
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark ${FWMARK} -j RETURN"
$ip6t_m -I OUTPUT $(comment "mangle-OUTPUT-PSW2") -o lo -j RETURN
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark ${FWMARK} -j RETURN"
$ipt_m -A PSW2 -p tcp --dport 53 -j ACCEPT
$ipt_m -A PSW2 -p udp --dport 53 -j ACCEPT
$ip6t_m -A PSW2 -p tcp --dport 53 -j ACCEPT
$ip6t_m -A PSW2 -p udp --dport 53 -j ACCEPT
}
load_acl
filter_direct_node_list > /dev/null 2>&1 &
@@ -1062,7 +944,7 @@ start() {
stop() {
[ -z "$(command -v log_i18n)" ] && . "$UTILS_PATH"
del_firewall_rule
[ $(config_t_get global flush_set "0") = "1" ] && {
[ $(config_n_get @global[0] flush_set "0") = "1" ] && {
uci -q delete ${CONFIG}.@global[0].flush_set
uci -q commit ${CONFIG}
flush_ipset
@@ -3,9 +3,9 @@
. /usr/share/passwall2/utils.sh
LOCK_FILE=${LOCK_PATH}/${CONFIG}_monitor.lock
ENABLED=$(config_t_get global enabled 0)
ENABLED=$(config_n_get @global[0] enabled 0)
[ "$ENABLED" != 1 ] && return 1
ENABLED=$(config_t_get global_delay start_daemon 0)
ENABLED=$(config_n_get @global_delay[0] start_daemon 0)
[ "$ENABLED" != 1 ] && return 1
sleep 58s
while [ "$ENABLED" -eq 1 ]; do
@@ -252,7 +252,7 @@ gen_shunt_list() {
[ -n "$_geoip_code" ] && {
get_geoip $_geoip_code ipv4 | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $nftset_v4 "0"
get_geoip $_geoip_code ipv6 | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $nftset_v6 "0"
log 1 "$(i18n "parse the traffic splitting rules[%s]-[geoip:%s] add to %s to complete." "${shunt_id}" "${_geoip_code}" "NFTSET")"
#log 3 "$(i18n "parse the traffic splitting rules[%s]-[geoip:%s] add to %s to complete." "${shunt_id}" "${_geoip_code}" "NFTSET[${nftset_v4},${nftset_v6}]")"
}
}
}
@@ -271,6 +271,7 @@ gen_shunt_list() {
}
[ -n "${_SHUNT_LIST4}" ] && eval ${shunt_list4_var_name}=\"${_SHUNT_LIST4}\"
[ -n "${_SHUNT_LIST6}" ] && eval ${shunt_list6_var_name}=\"${_SHUNT_LIST6}\"
set_cache_var "${node}_gen_shunt_list" "1"
}
add_shunt_t_rule() {
@@ -293,45 +294,18 @@ add_shunt_t_rule() {
}
load_acl() {
[ "$ENABLED_ACLS" == 1 ] && {
log_i18n 1 "Access Control:"
acl_app
for sid in $(ls -F ${TMP_ACL_PATH} | grep '/$' | awk -F '/' '{print $1}' | grep -v 'default'); do
eval $(uci -q show "${CONFIG}.${sid}" | cut -d'.' -sf 3-)
acl_json=$(lua $APP_PATH/app_acl.lua)
acl_node
log_i18n 1 "Access Control:"
for sid in $(jsonfilter -s "${acl_json}" -e '$.acl[*].flag'); do
eval $(cat "${TMP_ACL_PATH}/${sid}/var")
mode=${mode:-0}
tcp_no_redir_ports=${tcp_no_redir_ports:-default}
udp_no_redir_ports=${udp_no_redir_ports:-default}
tcp_proxy_mode="global"
udp_proxy_mode="global"
tcp_redir_ports=${tcp_redir_ports:-default}
udp_redir_ports=${udp_redir_ports:-default}
node=${node:-default}
[ "$mode" = "0" ] && {
tcp_no_redir_ports="1:65535"
udp_no_redir_ports="1:65535"
}
[ "$tcp_no_redir_ports" = "default" ] && tcp_no_redir_ports=$TCP_NO_REDIR_PORTS
[ "$udp_no_redir_ports" = "default" ] && udp_no_redir_ports=$UDP_NO_REDIR_PORTS
[ "$tcp_redir_ports" = "default" ] && tcp_redir_ports=$TCP_REDIR_PORTS
[ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS
[ -z "$(get_cache_var "${node}_gen_shunt_list")" ] && [ -n "${node}" ] && gen_shunt_list "${node}" shunt_list4 shunt_list6
[ -n "${use}" ] && local dns_redirect_port=$(get_cache_var "ACL_${use}_dns_port")
[ -n "$(get_cache_var "ACL_${sid}_node")" ] && node=$(get_cache_var "ACL_${sid}_node")
[ -n "$(get_cache_var "ACL_${sid}_redir_port")" ] && redir_port=$(get_cache_var "ACL_${sid}_redir_port")
[ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port")
[ -n "$node" ] && node_remark=$(config_n_get $node remarks)
if [ -n "$(get_cache_var "ACL_${sid}_default")" ]; then
shunt_list4=${SHUNT_LIST4}
shunt_list6=${SHUNT_LIST6}
else
# Shunt rules IP list (import when use shunt node)
gen_shunt_list "${node}" shunt_list4 shunt_list6
fi
_acl_list=${TMP_ACL_PATH}/${sid}/source_list
for i in $(cat $_acl_list); do
[ "${client_proxy}" = "1" ] && {
msg1="$(i18n "[%s]," "${remarks}")"
for i in $(cat ${TMP_ACL_PATH}/${sid}/source_list); do
local _ipt_source _ipv4
local msg
if [ -n "${interface}" ]; then
@@ -375,40 +349,38 @@ load_acl() {
else
continue
fi
msg="$(i18n "[%s]," "${remarks}")${msg}"
msg="${msg1}${msg}"
[ "$tcp_no_redir_ports" != "disable" ] && {
[ -n "$tcp_no_redir_ports" ] && {
if ! has_1_65535 "$tcp_no_redir_ports"; then
nft "add rule $NFTABLE_NAME $nft_prerouting_chain ${_ipt_source} ip protocol tcp $(factor $tcp_no_redir_ports "tcp dport") counter return comment \"$remarks\""
[ "$_ipv4" != "1" ] && nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 ${_ipt_source} meta l4proto tcp $(factor $tcp_no_redir_ports "tcp dport") counter return comment \"$remarks\""
log 2 "${msg}$(i18n "not proxy %s port [%s]" "TCP" "${tcp_no_redir_ports}")"
else
# It will return when it ends, so no extra rules are needed.
tcp_proxy_mode="disable"
no_tcp_proxy="1"
log 2 "${msg}$(i18n "not proxy all %s" "TCP")"
fi
}
[ "$udp_no_redir_ports" != "disable" ] && {
[ -n "$udp_no_redir_ports" ] && {
if ! has_1_65535 "$udp_no_redir_ports"; then
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp ${_ipt_source} $(factor $udp_no_redir_ports "udp dport") counter return comment \"$remarks\""
[ "$_ipv4" != "1" ] && nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp ${_ipt_source} $(factor $udp_no_redir_ports "udp dport") counter return comment \"$remarks\"" 2>/dev/null
log 2 "${msg}$(i18n "not proxy %s port [%s]" "UDP" "${udp_no_redir_ports}")"
else
# It will return when it ends, so no extra rules are needed.
udp_proxy_mode="disable"
no_udp_proxy="1"
log 2 "${msg}$(i18n "not proxy all %s" "UDP")"
fi
}
if ([ "$tcp_proxy_mode" != "disable" ] || [ "$udp_proxy_mode" != "disable" ]) && [ -n "$dns_redirect_port" ]; then
[ -n "$dns_redirect_port" ] && {
nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
[ -z "$(get_cache_var "ACL_${sid}_default")" ] && log 2 "${msg}$(i18n "Using a node that is different from the global configuration, DNS has been forcibly redirected to a dedicated DNS server.")"
}
if ([ -z "$no_tcp_proxy" ] || [ -z "$no_udp_proxy" ]) && [ -n "$dns_redirect_port" ]; then
nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\""
log 2 "${msg}$(i18n "DNS will redirected to the dedicated DNS server [%s]." "${dns_redirect_port}")"
else
nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\""
nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\""
@@ -416,8 +388,8 @@ load_acl() {
nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\""
fi
[ "$tcp_proxy_mode" != "disable" ] && [ -n "$redir_port" ] && {
msg2="${msg}$(i18n "Use the %s node [%s]" "TCP" "${node_remark}")"
[ -z "$no_tcp_proxy" ] && [ -n "$redir_port" ] && {
msg2="${msg}$(i18n "Use the %s node [%s]" "TCP" "${node_remarks}")"
if [ -n "${is_tproxy}" ]; then
msg2="${msg2}(TPROXY:${redir_port})"
nft_chain="PSW2_MANGLE"
@@ -458,8 +430,8 @@ load_acl() {
nft "add rule $NFTABLE_NAME $nft_prerouting_chain ip protocol tcp ${_ipt_source} counter return comment \"$remarks\""
[ "$_ipv4" != "1" ] && nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp ${_ipt_source} counter return comment \"$remarks\"" 2>/dev/null
[ "$udp_proxy_mode" != "disable" ] && [ -n "$redir_port" ] && {
msg2="${msg}$(i18n "Use the %s node [%s]" "UDP" "${node_remark}")(TPROXY:${redir_port})"
[ -z "$no_tcp_proxy" ] && [ -n "$redir_port" ] && {
msg2="${msg}$(i18n "Use the %s node [%s]" "UDP" "${node_remarks}")(TPROXY:${redir_port})"
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp ${_ipt_source} ip daddr $FAKE_IP counter jump PSW2_RULE comment \"$remarks\""
add_shunt_t_rule "${shunt_list4}" "nft add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp ${_ipt_source} $(factor $udp_redir_ports "udp dport") ip daddr" "counter jump PSW2_RULE" "$remarks"
@@ -476,108 +448,140 @@ load_acl() {
}
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp ${_ipt_source} counter return comment \"$remarks\""
[ "$_ipv4" != "1" ] && nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp ${_ipt_source} counter return comment \"$remarks\"" 2>/dev/null
unset nft_chain nft_j _ipt_source msg msg2 _ipv4
unset nft_chain nft_j _ipt_source msg msg2 _ipv4 no_tcp_proxy no_udp_proxy
done
unset enabled sid remarks sources tcp_proxy_mode udp_proxy_mode tcp_no_redir_ports udp_no_redir_ports tcp_redir_ports udp_redir_ports node interface
unset redir_port node_remark _acl_list
done
}
[ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ] && {
local comment="$(i18n "Default")"
msg="$(i18n "[%s]," ${comment})"
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && {
nft "add rule $NFTABLE_NAME $nft_prerouting_chain ip protocol tcp $(factor $TCP_NO_REDIR_PORTS "tcp dport") counter return comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp $(factor $TCP_NO_REDIR_PORTS "tcp dport") counter return comment \"${comment}\""
if ! has_1_65535 "$TCP_NO_REDIR_PORTS"; then
log 2 "${msg}$(i18n "not proxy %s port [%s]" "TCP" "${TCP_NO_REDIR_PORTS}")"
else
TCP_PROXY_MODE="disable"
log 2 "${msg}$(i18n "not proxy all %s" "TCP")"
fi
unset msg1
}
[ "${local_proxy}" = "1" ] && {
msg="$(i18n "[Local],")"
[ -n "$tcp_no_redir_ports" ] && {
nft "add rule $NFTABLE_NAME $nft_output_chain ip protocol tcp $(factor $tcp_no_redir_ports "tcp dport") counter return"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp $(factor $tcp_no_redir_ports "tcp dport") counter return"
if ! has_1_65535 "$tcp_no_redir_ports"; then
log 2 "${msg}$(i18n "not proxy %s port [%s]" "TCP" "${tcp_no_redir_ports}")"
else
no_tcp_local_proxy="1"
log 2 "${msg}$(i18n "not proxy all %s" "TCP")"
fi
}
[ -n "$udp_no_redir_ports" ] && {
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp $(factor $udp_no_redir_ports "udp dport") counter return"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp $(factor $udp_no_redir_ports "udp dport") counter return"
if ! has_1_65535 "$udp_no_redir_ports"; then
log 2 "${msg}$(i18n "not proxy %s port [%s]" "UDP" "${udp_no_redir_ports}")"
else
no_udp_local_proxy="1"
log 2 "${msg}$(i18n "not proxy all %s" "UDP")"
fi
}
[ "$UDP_NO_REDIR_PORTS" != "disable" ] && {
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp $(factor $UDP_NO_REDIR_PORTS "udp dport") counter return comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp $(factor $UDP_NO_REDIR_PORTS "udp dport") counter return comment \"${comment}\""
if ! has_1_65535 "$UDP_NO_REDIR_PORTS"; then
log 2 "${msg}$(i18n "not proxy %s port [%s]" "UDP" "${UDP_NO_REDIR_PORTS}")"
else
UDP_PROXY_MODE="disable"
log 2 "${msg}$(i18n "not proxy all %s" "UDP")"
if [ -n "$node" ] && ([ -z "$no_tcp_local_proxy" ] || [ -z "$no_udp_local_proxy" ]); then
[ -n "$dns_redirect_port" ] && {
nft "add rule $NFTABLE_NAME nat_output ip protocol udp oif lo udp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\""
nft "add rule $NFTABLE_NAME nat_output ip protocol tcp oif lo tcp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\""
nft "add rule $NFTABLE_NAME nat_output meta l4proto udp oif lo udp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\""
nft "add rule $NFTABLE_NAME nat_output meta l4proto tcp oif lo tcp dport 53 counter redirect to :$dns_redirect_port comment \"PSW2_DNS\""
log 2 "${msg}$(i18n "DNS will redirected to the dedicated DNS server [%s]." "${dns_redirect_port}")"
}
fi
local comment_l="$(i18n "Local")"
# Loading local router proxy TCP
if [ -n "$node" ] && [ -z "$no_tcp_local_proxy" ]; then
[ "$accept_icmp" = "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo ip protocol icmp ip daddr $FAKE_IP counter redirect"
add_shunt_t_rule "${shunt_list4}" "nft add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo ip protocol icmp ip daddr" "counter redirect"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo ip protocol icmp counter redirect"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo ip protocol icmp counter return"
}
[ "$accept_icmpv6" = "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo meta l4proto icmpv6 ip6 daddr $FAKE_IP_6 counter redirect"
add_shunt_t_rule "${shunt_list6}" "nft add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo meta l4proto icmpv6 ip6 daddr" "counter redirect"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo meta l4proto icmpv6 counter redirect"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo meta l4proto icmpv6 counter return"
}
msg2="${msg}$(i18n "Use the %s node [%s]" "TCP" "${node_remarks}")"
if [ -n "${is_tproxy}" ]; then
msg2="${msg2}(TPROXY:${redir_port})"
nft_chain="PSW2_OUTPUT_MANGLE"
nft_j="counter jump PSW2_RULE"
else
msg2="${msg2}(REDIRECT:${redir_port})"
nft_chain="PSW2_OUTPUT_NAT"
nft_j="$(REDIRECT $redir_port)"
fi
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp ip daddr $FAKE_IP ${nft_j}"
add_shunt_t_rule "${shunt_list4}" "nft add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $tcp_redir_ports "tcp dport") ip daddr" "${nft_j}"
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $tcp_redir_ports "tcp dport") ${nft_j}"
[ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME nat_output ip daddr != @$NFTSET_DIRECT ip protocol tcp counter jump PSW2_OUTPUT_NAT"
[ -n "${is_tproxy}" ] && {
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp iif lo $(REDIRECT $redir_port TPROXY4) comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp iif lo counter return comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT ip protocol tcp counter jump PSW2_OUTPUT_MANGLE comment \"PSW2_OUTPUT_MANGLE\""
}
[ "$PROXY_IPV6" == "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp ip6 daddr $FAKE_IP_6 jump PSW2_RULE"
add_shunt_t_rule "${shunt_list6}" "nft add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp $(factor $tcp_redir_ports "tcp dport") ip6 daddr" "counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp $(factor $tcp_redir_ports "tcp dport") counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp iif lo $(REDIRECT $redir_port TPROXY6) comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp iif lo counter return comment \"${comment_l}\""
}
[ -d "${TMP_IFACE_PATH}" ] && {
for iface in $(ls ${TMP_IFACE_PATH}); do
nft "add rule $NFTABLE_NAME $nft_output_chain ip protocol tcp oif $iface counter return"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ip protocol tcp oif $iface counter return"
done
}
log 2 "${msg2}"
fi
# Loading local router proxy UDP
if [ -n "$node" ] && [ -z "$no_udp_local_proxy" ]; then
msg2="${msg}$(i18n "Use the %s node [%s]" "UDP" "${node_remarks}")(TPROXY:${redir_port})"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp ip daddr $FAKE_IP counter jump PSW2_RULE"
add_shunt_t_rule "${shunt_list4}" "nft add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp $(factor $udp_redir_ports "udp dport") ip daddr" "counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp $(factor $udp_redir_ports "udp dport") counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp iif lo $(REDIRECT $redir_port TPROXY4) comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp iif lo counter return comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT ip protocol udp counter jump PSW2_OUTPUT_MANGLE comment \"PSW2_OUTPUT_MANGLE\""
[ "$PROXY_IPV6" == "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp ip6 daddr $FAKE_IP_6 jump PSW2_RULE"
add_shunt_t_rule "${shunt_list6}" "nft add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp $(factor $udp_redir_ports "udp dport") ip6 daddr" "counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp $(factor $udp_redir_ports "udp dport") counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp iif lo $(REDIRECT $redir_port TPROXY6) comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp iif lo counter return comment \"${comment_l}\""
}
[ -d "${TMP_IFACE_PATH}" ] && {
for iface in $(ls ${TMP_IFACE_PATH}); do
nft "add rule $NFTABLE_NAME $nft_output_chain ip protocol udp oif $iface counter return"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ip protocol udp oif $iface counter return"
done
}
log 2 "${msg2}"
fi
nft "add rule $NFTABLE_NAME mangle_output oif lo counter return comment \"PSW2_OUTPUT_MANGLE\""
nft "add rule $NFTABLE_NAME mangle_output meta mark ${FWMARK} counter return comment \"PSW2_OUTPUT_MANGLE\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp tcp dport 53 counter accept"
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp udp dport 53 counter accept"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp tcp dport 53 counter accept"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp udp dport 53 counter accept"
unset msg msg2 comment_l
}
if ([ "$TCP_PROXY_MODE" != "disable" ] || [ "$UDP_PROXY_MODE" != "disable" ]) && [ -n "$NODE" ]; then
[ -n "$DNS_REDIRECT_PORT" ] && {
nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol udp udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_DNS ip protocol tcp tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto udp udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_DNS meta l4proto tcp tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"${comment}\""
}
fi
if [ "$TCP_PROXY_MODE" != "disable" ] && [ -n "$NODE" ]; then
msg2="${msg}$(i18n "Use the %s node [%s]" "TCP" "$(config_n_get $NODE remarks)")"
if [ -n "${is_tproxy}" ]; then
msg2="${msg2}(TPROXY:${REDIR_PORT})"
nft_chain="PSW2_MANGLE"
nft_j="counter jump PSW2_RULE"
else
msg2="${msg2}(REDIRECT:${REDIR_PORT})"
nft_chain="PSW2_NAT"
nft_j="$(REDIRECT $REDIR_PORT)"
fi
[ "$accept_icmp" = "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip protocol icmp ip daddr $FAKE_IP $(REDIRECT) comment \"${comment}\""
add_shunt_t_rule "${SHUNT_LIST4}" "nft add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip protocol icmp ip daddr" "$(REDIRECT)" "${comment}"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip protocol icmp $(REDIRECT) comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip protocol icmp return comment \"${comment}\""
}
[ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" == "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT meta l4proto icmpv6 ip6 daddr $FAKE_IP_6 $(REDIRECT) comment \"${comment}\""
add_shunt_t_rule "${SHUNT_LIST6}" "nft add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT meta l4proto icmpv6 ip6 daddr" "$(REDIRECT)" "${comment}"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT meta l4proto icmpv6 $(REDIRECT) comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT meta l4proto icmpv6 return comment \"${comment}\""
}
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp ip daddr $FAKE_IP ${nft_j} comment \"${comment}\""
add_shunt_t_rule "${SHUNT_LIST4}" "nft add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $TCP_REDIR_PORTS "tcp dport") ip daddr" "${nft_j}" "${comment}"
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $TCP_REDIR_PORTS "tcp dport") ${nft_j} comment \"${comment}\""
[ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp $(REDIRECT $REDIR_PORT TPROXY4) comment \"${comment}\""
[ "$PROXY_IPV6" == "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp ip6 daddr $FAKE_IP_6 jump PSW2_RULE comment \"${comment}\""
add_shunt_t_rule "${SHUNT_LIST6}" "nft add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp $(factor $TCP_REDIR_PORTS "tcp dport") ip6 daddr" "${nft_j}" "${comment}"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp $(factor $TCP_REDIR_PORTS "tcp dport") counter jump PSW2_RULE comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp $(REDIRECT $REDIR_PORT TPROXY) comment \"${comment}\""
}
log 2 "${msg2}"
fi
if [ "$UDP_PROXY_MODE" != "disable" ] && [ -n "$NODE" ]; then
msg2="${msg}$(i18n "Use the %s node [%s]" "UDP" "$(config_n_get $NODE remarks)")(TPROXY:${REDIR_PORT})"
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp ip daddr $FAKE_IP counter jump PSW2_RULE comment \"${comment}\""
add_shunt_t_rule "${SHUNT_LIST4}" "nft add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp $(factor $UDP_REDIR_PORTS "udp dport") ip daddr" "counter jump PSW2_RULE" "${comment}"
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp $(factor $UDP_REDIR_PORTS "udp dport") counter jump PSW2_RULE comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp $(REDIRECT $REDIR_PORT TPROXY4) comment \"${comment}\""
[ "$PROXY_IPV6" == "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp ip6 daddr $FAKE_IP_6 jump PSW2_RULE comment \"${comment}\""
add_shunt_t_rule "${SHUNT_LIST6}" "nft add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp $(factor $UDP_REDIR_PORTS "udp dport") ip6 daddr" "counter jump PSW2_RULE" "${comment}"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp $(factor $UDP_REDIR_PORTS "udp dport") counter jump PSW2_RULE comment \"${comment}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp $(REDIRECT $REDIR_PORT TPROXY) comment \"${comment}\""
}
log 2 "${msg2}"
udp_flag=1
fi
}
unset dns_redirect_port
unset $(cat "${TMP_ACL_PATH}/${sid}/var" | awk -F '=' '{print $1}' | tr "\n" " ")
done
}
filter_haproxy() {
@@ -746,9 +750,6 @@ add_firewall_rule() {
done
}
# Shunt rules IP list (import when use shunt node)
gen_shunt_list "${NODE}" SHUNT_LIST4 SHUNT_LIST6
# Filter all node IPs
filter_vpsip > /dev/null 2>&1 &
filter_haproxy > /dev/null 2>&1 &
@@ -756,8 +757,8 @@ add_firewall_rule() {
filter_vps_addr $(config_n_get $NODE address) > /dev/null 2>&1 &
filter_vps_addr $(config_n_get $NODE download_address) > /dev/null 2>&1 &
accept_icmp=$(config_t_get global_forwarding accept_icmp 0)
accept_icmpv6=$(config_t_get global_forwarding accept_icmpv6 0)
accept_icmp=$(config_n_get @global_forwarding[0] accept_icmp 0)
accept_icmpv6=$(config_n_get @global_forwarding[0] accept_icmpv6 0)
if [ "${TCP_PROXY_WAY}" = "redirect" ]; then
unset is_tproxy
@@ -771,7 +772,7 @@ add_firewall_rule() {
nft "add chain $NFTABLE_NAME PSW2_DNS"
nft "flush chain $NFTABLE_NAME PSW2_DNS"
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
if [ $(config_n_get @global[0] dns_redirect "1") = "0" ]; then
#Only hijack when dest address is local IP
nft "insert rule $NFTABLE_NAME dstnat ip saddr @${NFTSET_DIRECT} ip daddr @${NFTSET_LOCAL} jump PSW2_DNS"
nft "insert rule $NFTABLE_NAME dstnat ip6 saddr @${NFTSET_DIRECT6} ip6 daddr @${NFTSET_LOCAL6} jump PSW2_DNS"
@@ -881,128 +882,6 @@ add_firewall_rule() {
ip -6 route add local ::/0 dev lo table 999
}
[ "$ENABLED_DEFAULT_ACL" == 1 ] && {
TCP_LOCALHOST_PROXY=$LOCALHOST_PROXY
UDP_LOCALHOST_PROXY=$LOCALHOST_PROXY
msg="$(i18n "[Local],")"
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && {
nft "add rule $NFTABLE_NAME $nft_output_chain ip protocol tcp $(factor $TCP_NO_REDIR_PORTS "tcp dport") counter return"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp $(factor $TCP_NO_REDIR_PORTS "tcp dport") counter return"
if ! has_1_65535 "$TCP_NO_REDIR_PORTS"; then
log 1 "${msg}$(i18n "not proxy %s port [%s]" "TCP" "${TCP_NO_REDIR_PORTS}")"
else
unset TCP_LOCALHOST_PROXY
log 1 "${msg}$(i18n "not proxy all %s" "TCP")"
fi
}
[ "$UDP_NO_REDIR_PORTS" != "disable" ] && {
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp $(factor $UDP_NO_REDIR_PORTS "udp dport") counter return"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp $(factor $UDP_NO_REDIR_PORTS "udp dport") counter return"
if ! has_1_65535 "$UDP_NO_REDIR_PORTS"; then
log 1 "${msg}$(i18n "not proxy %s port [%s]" "UDP" "${UDP_NO_REDIR_PORTS}")"
else
unset UDP_LOCALHOST_PROXY
log 1 "${msg}$(i18n "not proxy all %s" "UDP")"
fi
}
if [ -n "$NODE" ] && ([ "$TCP_LOCALHOST_PROXY" = "1" ] || [ "$UDP_LOCALHOST_PROXY" = "1" ]); then
[ -n "$DNS_REDIRECT_PORT" ] && {
nft "add rule $NFTABLE_NAME nat_output ip protocol udp oif lo udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW2_DNS\""
nft "add rule $NFTABLE_NAME nat_output ip protocol tcp oif lo tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW2_DNS\""
nft "add rule $NFTABLE_NAME nat_output meta l4proto udp oif lo udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW2_DNS\""
nft "add rule $NFTABLE_NAME nat_output meta l4proto tcp oif lo tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW2_DNS\""
}
fi
local comment_l="$(i18n "Local")"
# Loading local router proxy TCP
if [ -n "$NODE" ] && [ "$TCP_LOCALHOST_PROXY" = "1" ]; then
[ "$accept_icmp" = "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo ip protocol icmp ip daddr $FAKE_IP counter redirect"
add_shunt_t_rule "${SHUNT_LIST4}" "nft add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo ip protocol icmp ip daddr" "counter redirect"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo ip protocol icmp counter redirect"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo ip protocol icmp counter return"
}
[ "$accept_icmpv6" = "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo meta l4proto icmpv6 ip6 daddr $FAKE_IP_6 counter redirect"
add_shunt_t_rule "${SHUNT_LIST6}" "nft add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo meta l4proto icmpv6 ip6 daddr" "counter redirect"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo meta l4proto icmpv6 counter redirect"
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT oif lo meta l4proto icmpv6 counter return"
}
if [ -n "${is_tproxy}" ]; then
nft_chain="PSW2_OUTPUT_MANGLE"
nft_j="counter jump PSW2_RULE"
else
nft_chain="PSW2_OUTPUT_NAT"
nft_j="$(REDIRECT $REDIR_PORT)"
fi
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp ip daddr $FAKE_IP ${nft_j}"
add_shunt_t_rule "${SHUNT_LIST4}" "nft add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $TCP_REDIR_PORTS "tcp dport") ip daddr" "${nft_j}"
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $TCP_REDIR_PORTS "tcp dport") ${nft_j}"
[ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME nat_output ip daddr != @$NFTSET_DIRECT ip protocol tcp counter jump PSW2_OUTPUT_NAT"
[ -n "${is_tproxy}" ] && {
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp iif lo $(REDIRECT $REDIR_PORT TPROXY4) comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp iif lo counter return comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT ip protocol tcp counter jump PSW2_OUTPUT_MANGLE comment \"PSW2_OUTPUT_MANGLE\""
}
[ "$PROXY_IPV6" == "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp ip6 daddr $FAKE_IP_6 jump PSW2_RULE"
add_shunt_t_rule "${SHUNT_LIST6}" "nft add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp $(factor $TCP_REDIR_PORTS "tcp dport") ip6 daddr" "counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto tcp $(factor $TCP_REDIR_PORTS "tcp dport") counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp iif lo $(REDIRECT $REDIR_PORT TPROXY6) comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp iif lo counter return comment \"${comment_l}\""
}
[ -d "${TMP_IFACE_PATH}" ] && {
for iface in $(ls ${TMP_IFACE_PATH}); do
nft "add rule $NFTABLE_NAME $nft_output_chain ip protocol tcp oif $iface counter return"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ip protocol tcp oif $iface counter return"
done
}
fi
# Loading local router proxy UDP
if [ -n "$NODE" ] && [ "$UDP_LOCALHOST_PROXY" = "1" ]; then
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp ip daddr $FAKE_IP counter jump PSW2_RULE"
add_shunt_t_rule "${SHUNT_LIST4}" "nft add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp $(factor $UDP_REDIR_PORTS "udp dport") ip daddr" "counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp $(factor $UDP_REDIR_PORTS "udp dport") counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp iif lo $(REDIRECT $REDIR_PORT TPROXY4) comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp iif lo counter return comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT ip protocol udp counter jump PSW2_OUTPUT_MANGLE comment \"PSW2_OUTPUT_MANGLE\""
[ "$PROXY_IPV6" == "1" ] && {
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp ip6 daddr $FAKE_IP_6 jump PSW2_RULE"
add_shunt_t_rule "${SHUNT_LIST6}" "nft add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp $(factor $UDP_REDIR_PORTS "udp dport") ip6 daddr" "counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp $(factor $UDP_REDIR_PORTS "udp dport") counter jump PSW2_RULE"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp iif lo $(REDIRECT $REDIR_PORT TPROXY6) comment \"${comment_l}\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp iif lo counter return comment \"${comment_l}\""
}
[ -d "${TMP_IFACE_PATH}" ] && {
for iface in $(ls ${TMP_IFACE_PATH}); do
nft "add rule $NFTABLE_NAME $nft_output_chain ip protocol udp oif $iface counter return"
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ip protocol udp oif $iface counter return"
done
}
fi
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT oif lo counter return comment \"PSW2_OUTPUT_MANGLE\""
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT meta mark ${FWMARK} counter return comment \"PSW2_OUTPUT_MANGLE\""
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp tcp dport 53 counter accept"
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp udp dport 53 counter accept"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp tcp dport 53 counter accept"
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp udp dport 53 counter accept"
}
load_acl
filter_direct_node_list > /dev/null 2>&1 &
@@ -1093,7 +972,7 @@ start() {
stop() {
[ -z "$(command -v log_i18n)" ] && . "$UTILS_PATH"
del_firewall_rule
[ $(config_t_get global flush_set "0") = "1" ] && {
[ $(config_n_get @global[0] flush_set "0") = "1" ] && {
uci -q delete ${CONFIG}.@global[0].flush_set
uci -q commit ${CONFIG}
#flush_table
@@ -75,7 +75,7 @@ test_node() {
local _type=$(echo $(config_n_get ${node_id} type) | tr 'A-Z' 'a-z')
[ -n "${_type}" ] && {
check_process
local _tmp_port=$(get_new_port 48800 tcp,udp)
local _tmp_port=$(get_new_port 48800)
NO_REC_PROCESS=1 $APP_FILE run_socks flag="test_node_${node_id}" node=${node_id} bind=127.0.0.1 socks_port=${_tmp_port} config_file=test_node_${node_id}.json
sleep 2s
local curlx="socks5h://127.0.0.1:${_tmp_port}"
@@ -29,7 +29,6 @@ local has_ss_rust = api.is_finded("sslocal")
local has_ssr = api.is_finded("ssr-local") and api.is_finded("ssr-redir")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
local has_hysteria2 = api.finded_com("hysteria")
local DEFAULT_ALLOWINSECURE = true
local DEFAULT_FILTER_KEYWORD_MODE = uci_get("@global_subscribe[0]", "filter_keyword_mode") or "0"
local DEFAULT_FILTER_KEYWORD_DISCARD_LIST = uci_get("@global_subscribe[0]", "filter_discard_list") or {}
@@ -39,12 +38,11 @@ local DEFAULT_SS_TYPE = api.get_core("ss_type", {{has_ss_rust,"shadowsocks-rust"
local DEFAULT_TROJAN_TYPE = api.get_core("trojan_type", {{has_singbox,"sing-box"},{has_xray,"xray"}})
local DEFAULT_VMESS_TYPE = api.get_core("vmess_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local DEFAULT_VLESS_TYPE = api.get_core("vless_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local DEFAULT_HYSTERIA2_TYPE = api.get_core("hysteria2_type", {{has_hysteria2,"hysteria2"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local DEFAULT_HYSTERIA2_TYPE = api.get_core("hysteria2_type", {{has_singbox,"sing-box"},{has_xray,"xray"}})
local core_has = {
["xray"] = has_xray,
["sing-box"] = has_singbox,
["shadowsocks-rust"] = has_ss_rust,
["hysteria2"] = has_hysteria2
}
-- Determine whether to filter node keywords
local function is_filter_keyword(sub_cfg, value)
@@ -1771,15 +1769,6 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.protocol = "hysteria2"
result.use_finalmask = (params.fm and params.fm ~= "") and "1" or nil
result.finalmask = (params.fm and params.fm ~= "") and api.base64Encode(params.fm) or nil
elseif has_hysteria2 then
result.type = "Hysteria2"
for k1, v1 in pairs(result) do
if k1:find("hysteria2_") == 1 then
local s = split(k1, "hysteria2_")
result[s[2]] = v1
result[k1] = nil
end
end
else
log(2, i18n.translatef("Skipping the %s node is due to incompatibility with the %s core program or incorrect node usage type settings.", "Hysteria2", "Hysteria2"))
return nil
@@ -17,8 +17,8 @@ do
if [ "$CFG_UPDATE_INT" -ne 0 ]; then
restart_week_mode=$(config_t_get global_delay restart_week_mode)
restart_interval_mode=$(config_t_get global_delay restart_interval_mode)
restart_week_mode=$(config_n_get @global_delay[0] restart_week_mode)
restart_interval_mode=$(config_n_get @global_delay[0] restart_interval_mode)
restart_interval_mode=$(expr "$restart_interval_mode" \* 60)
if [ -n "$restart_week_mode" ]; then
[ "$restart_week_mode" = "8" ] && {
@@ -26,8 +26,8 @@ do
}
fi
rules_update_week_mode=$(config_t_get global_rules update_week_mode)
rules_update_interval_mode=$(config_t_get global_rules update_interval_mode)
rules_update_week_mode=$(config_n_get @global_rules[0] update_week_mode)
rules_update_interval_mode=$(config_n_get @global_rules[0] update_interval_mode)
rules_update_interval_mode=$(expr "$rules_update_interval_mode" \* 60)
if [ -n "$rules_update_week_mode" ]; then
[ "$rules_update_week_mode" = "8" ] && {
@@ -46,11 +46,11 @@ url_test_node() {
local node_id=$1
local _type=$(echo $(config_n_get ${node_id} type) | tr 'A-Z' 'a-z')
[ -n "${_type}" ] && {
local _tmp_port=$(get_new_port 48900 tcp,udp)
local _tmp_port=$(get_new_port 48900)
NO_REC_PROCESS=1 /usr/share/${CONFIG}/app.sh run_socks flag="url_test_${node_id}" node=${node_id} bind=127.0.0.1 socks_port=${_tmp_port} config_file=url_test_${node_id}.json
sleep 2s
local curlx="socks5h://127.0.0.1:${_tmp_port}"
local probeUrl=$(config_t_get global_other url_test_url https://www.google.com/generate_204)
local probeUrl=$(config_n_get @global_other[0] url_test_url https://www.google.com/generate_204)
result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_pretransfer}" -x ${curlx} "${probeUrl}")
# End the SS plugin process
local pid_file="${TMP_PATH}/url_test_${node_id}_plugin.pid"
@@ -33,11 +33,6 @@ config_t_get() {
echo "${ret:=${3}}"
}
config_t_set() {
local index=${4:-0}
local ret=$(uci -q set "${CONFIG}.@${1}[${index}].${2}=${3}" 2>/dev/null)
}
eval_set_val() {
for i in $@; do
for j in $i; do
@@ -157,9 +152,9 @@ get_geoip() {
local geoip_type_flag=""
local output_path="${geo_output_path}/geoip-${geoip_code}-$2"
[ ! -s "${output_path}" ] && {
local geoip_path="$(config_t_get global_rules v2ray_location_asset)"
local geoip_path="$(config_n_get @global_rules[0] v2ray_location_asset)"
geoip_path="${geoip_path%*/}/geoip.dat"
local bin="$(first_type $(config_t_get global_app geoview_file) geoview)"
local bin="$(first_type $(config_n_get @global_app[0] geoview_file) geoview)"
[ -n "$bin" ] && [ -s "$geoip_path" ] || { echo ""; return; }
case "$2" in
"ipv4") geoip_type_flag="-ipv6=false" ;;
@@ -299,7 +294,7 @@ get_new_port() {
local default_start_port=2001
local min_port=1025
local max_port=49151
local port=$1
local port=$1 #Required parameter; please pass "auto" if you want it to be automatic.
local last_get_new_port_auto
if [ "$1" == "auto" ]; then
last_get_new_port_auto=$(get_cache_var "last_get_new_port_auto")
@@ -313,17 +308,28 @@ get_new_port() {
[ "$port" -lt $min_port -o "$port" -gt $max_port ] && port=$default_start_port
local protocol=$(echo $2 | tr 'A-Z' 'a-z')
local result=$(check_port_exists $port $protocol)
[ -n "$(get_cache_var "get_port_${port}")" ] && {
# exist, continue get.
# Make the following result logic true.
result=1
}
if [ "$result" != 0 ]; then
local temp=
if [ "$port" -lt $max_port ]; then
# If the port is smaller than the maximum port, then increment by 1 and continue.
temp=$(expr $port + 1)
elif [ "$port" -gt $min_port ]; then
# If the port is greater than the minimum port, then decrement by 1 and continue.
temp=$(expr $port - 1)
else
# Otherwise, reassign the default starting port.
temp=$default_start_port
fi
# Recursion, until it obtains an unused port.
get_new_port $temp $protocol
else
# Set cache, mark this port as already obtained, so it should not be obtained again.
set_cache_var "get_port_${port}" "1"
[ "$1" == "auto" ] && set_cache_var "last_get_new_port_auto" "$port"
echo $port
fi
+2 -2
View File
@@ -2,8 +2,8 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.1.8-r1
PKG_RELEASE:=4
PKG_VERSION:=1.2.0-r1
PKG_RELEASE:=5
LUCI_TITLE:=LuCI support for shadowrt
LUCI_PKGARCH:=all
@@ -0,0 +1,98 @@
#!/bin/sh
# Copyright (C) 2022 jjm2473@gmail.com
DEFAULT_OVERLAY_FS="ext4"
OVERLAY_LABEL="etc"
OVERLAY_FS=${DEFAULT_OVERLAY_FS}
OVERLAY_DEV=
log() {
echo "$1" >&2
}
inlog() {
$@ >&2
}
. /lib/functions/istoreos-boot.sh
CONFIRM=n
REBOOT=n
confirm()
{
[ "$1" = "y" ] && return 0
echo "This will erase all settings and remove any installed packages. Are you sure? [N/y]"
read CONFIRM
[ "$CONFIRM" = "y" -o "$CONFIRM" = "Y" ] && return 0
return 1
}
do_reset_nofs()
{
get_overlay_partition || exit 1
if [ -z "$OVERLAY_DEV" ]; then
echo "Unable to determine overlay partition" >&2
return 1
fi
if [ "RESET" = "$FSTYPE" ]; then
echo "Already resetted" >&2
return 1
fi
if [ "DIR" = "$FSTYPE" ]; then
touch /$OVERLAY_DEV/.reset
sync /$OVERLAY_DEV
return 0
fi
# if ! blkid -o device -t LABEL=$OVERLAY_LABEL "$OVERLAY_DEV" >/dev/null; then
# echo "Overlay partition $OVERLAY_DEV not labeled $OVERLAY_LABEL" >&2
# return 1
# fi
echo "RESET000" | dd of="$OVERLAY_DEV" bs=512 count=1 conv=notrunc,sync,fsync 2>/dev/null
echo 3 > /proc/sys/vm/drop_caches
return 0
}
do_reset_ext_overlay()
{
[ -d /ext_overlay ] && mountpoint -q /ext_overlay || return 0
rm -f /ext_overlay/etc/.extroot-uuid
touch /ext_overlay/.reset
sync /ext_overlay
}
do_reset()
{
if [ -f /.recovery_mode ]; then
mount_root || ( echo "/overlay mount failed!" ; exit 1 )
rm -rf /overlay/upper
mkdir /overlay/upper
sync /overlay
else
do_reset_nofs
do_reset_ext_overlay
fi
if [ -f /lib/upgrade/keep.d/grub ]; then
cat /lib/upgrade/keep.d/grub | while read; do
rm -f "$REPLY"
done
fi
[ "$REBOOT" = "y" ] && reboot
exit 0
}
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-y) CONFIRM=y ;;
-r) REBOOT=y ;;
esac
shift
done
confirm $CONFIRM && do_reset
exit 0
@@ -1,98 +1,3 @@
#!/bin/sh
# Copyright (C) 2022 jjm2473@gmail.com
DEFAULT_OVERLAY_FS="ext4"
OVERLAY_LABEL="etc"
OVERLAY_FS=${DEFAULT_OVERLAY_FS}
OVERLAY_DEV=
log() {
echo "$1" >&2
}
inlog() {
$@ >&2
}
. /lib/functions/istoreos-boot.sh
CONFIRM=n
REBOOT=n
confirm()
{
[ "$1" = "y" ] && return 0
echo "This will erase all settings and remove any installed packages. Are you sure? [N/y]"
read CONFIRM
[ "$CONFIRM" = "y" -o "$CONFIRM" = "Y" ] && return 0
return 1
}
do_reset_nofs()
{
get_overlay_partition || exit 1
if [ -z "$OVERLAY_DEV" ]; then
echo "Unable to determine overlay partition" >&2
return 1
fi
if [ "RESET" = "$FSTYPE" ]; then
echo "Already resetted" >&2
return 1
fi
if [ "DIR" = "$FSTYPE" ]; then
touch /$OVERLAY_DEV/.reset
sync /$OVERLAY_DEV
return 0
fi
# if ! blkid -o device -t LABEL=$OVERLAY_LABEL "$OVERLAY_DEV" >/dev/null; then
# echo "Overlay partition $OVERLAY_DEV not labeled $OVERLAY_LABEL" >&2
# return 1
# fi
echo "RESET000" | dd of="$OVERLAY_DEV" bs=512 count=1 conv=notrunc,sync,fsync 2>/dev/null
echo 3 > /proc/sys/vm/drop_caches
return 0
}
do_reset_ext_overlay()
{
[ -d /ext_overlay ] && mountpoint -q /ext_overlay || return 0
rm -f /ext_overlay/etc/.extroot-uuid
touch /ext_overlay/.reset
sync /ext_overlay
}
do_reset()
{
if [ -f /.recovery_mode ]; then
mount_root || ( echo "/overlay mount failed!" ; exit 1 )
rm -rf /overlay/upper
mkdir /overlay/upper
sync /overlay
else
do_reset_nofs
do_reset_ext_overlay
fi
if [ -f /lib/upgrade/keep.d/grub ]; then
cat /lib/upgrade/keep.d/grub | while read; do
rm -f "$REPLY"
done
fi
[ "$REBOOT" = "y" ] && reboot
exit 0
}
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-y) CONFIRM=y ;;
-r) REBOOT=y ;;
esac
shift
done
confirm $CONFIRM && do_reset
exit 0
/sbin/factoryreset $@
@@ -8,6 +8,13 @@ OVERLAY_LABEL="etc"
OVERLAY_FS=${DEFAULT_OVERLAY_FS}
OVERLAY_DEV=
APK=false
PKG_BASE=usr/lib/opkg/info
[ -s /etc/apk/arch ] && {
APK=true
PKG_BASE=lib/apk/packages
}
log() {
echo "<1>mount_root: $1" >/dev/kmsg
}
@@ -136,6 +143,28 @@ update_overlay_lower_uuid() {
return 1
}
OPENWRT_RELEASE=""
openwrt_release() {
if [ -z "$OPENWRT_RELEASE" ]; then
OPENWRT_RELEASE=`grep 'DISTRIB_RELEASE=' /etc/openwrt_release 2>/dev/null | sed -E "s/.*='(.+)'.*/\1/"`
[ -z "$OPENWRT_RELEASE" ] && OPENWRT_RELEASE="UNKNOWN"
fi
echo "$OPENWRT_RELEASE"
}
update_overlay_lower_release() {
local realrelease=`openwrt_release`
local lastrelease="NULL"
if [ -f "$1/.rootfs-release" ]; then
lastrelease=`cat "$1/.rootfs-release"`
fi
if [ "$realrelease" != "$lastrelease" ]; then
echo "$realrelease" >"$1/.rootfs-release"
return 0
fi
return 1
}
clean_overlayfs_origin() {
local line
cd "$1"
@@ -172,11 +201,11 @@ clean_overlayfs_redundant_whiteout_marker()
clean_overlayfs_redundant_whiteout_marker_luci()
{
local line
[ -d "$1/upper/usr/lib/lua/luci" ] || return 0
cd "$1/upper/usr/lib/lua"
find luci -xdev -type c -perm 0 -user 0 -group 0 | while read; do
[ -d "$1/upper/usr/lib/lua/luci" ] || [ -d "$1/upper/usr/share/luci/menu.d" ] || return 0
cd "$1/upper"
find usr/lib/lua/luci usr/share/luci/menu.d -xdev -type c -perm 0 -user 0 -group 0 | while read; do
line="$REPLY"
[ ! -e "/usr/lib/lua/$line" -a \( -z "$2" -o ! -e "$2/upper/usr/lib/lua/$line" \) ] && \
[ ! -e "/$line" -a \( -z "$2" -o ! -e "$2/upper/$line" \) ] && \
rm -f "$line"
done
cd - >/dev/null 2>&1
@@ -193,28 +222,38 @@ clean_os_version_files()
nonconf_files_of_pkg() {
local pkgname="$1"
if [ -s /usr/lib/opkg/info/${pkgname}.conffiles ]; then
grep -hvxFf /usr/lib/opkg/info/${pkgname}.conffiles \
/usr/lib/opkg/info/${pkgname}.list
if [ -s /$PKG_BASE/${pkgname}.conffiles ]; then
grep -hvxFf /$PKG_BASE/${pkgname}.conffiles \
/$PKG_BASE/${pkgname}.list
else
cat /usr/lib/opkg/info/${pkgname}.list
cat /$PKG_BASE/${pkgname}.list
fi
}
_pkg_exists() {
local pkgname="$1"
if $APK; then
[ -f "/$PKG_BASE/${pkgname}.list" ] && return 0
else
[ -f "/$PKG_BASE/${pkgname}.control" ] && return 0
fi
return 1
}
clean_pkg_content() {
local overlay="$1"
local pkgname="$2"
local line
if [ -f /usr/lib/opkg/info/${pkgname}.control ]; then
if [ -f /usr/lib/opkg/info/${pkgname}.list ]; then
if _pkg_exists ${pkgname} ; then
if [ -f /$PKG_BASE/${pkgname}.list ]; then
nonconf_files_of_pkg "${pkgname}" | grep -v '^/etc/uci-defaults/' | while read; do
line="$REPLY"
rm -f "$overlay/upper/${line}"
done
rm -f $overlay/upper/usr/lib/opkg/info/${pkgname}.list
rm -f "$overlay/upper/$PKG_BASE/${pkgname}.list"
fi
rm -f $overlay/upper/usr/lib/opkg/info/${pkgname}.*
rm -f "$overlay/upper/$PKG_BASE/${pkgname}.*"
fi
}
@@ -225,10 +264,17 @@ pkg_depends_rec() {
local deps
echo "${pkgname}" | grep -q '^kmod-' && return
_pkg_exists ${pkgname} && [ ! -f /tmp/reset_core_packages/${pkgname} ] || return
touch /tmp/reset_core_packages/${pkgname}
if [ -f /usr/lib/opkg/info/${pkgname}.control -a ! -f /tmp/reset_core_packages/${pkgname} ]; then
if $APK; then
deps=`apk info --installed --recursive -R "${pkgname}" | grep -v 'depends on:' | grep . | sort -u`
for dep in $deps ; do
dep=${dep%%[@=<>~]*}
[ -f /tmp/reset_core_packages/${dep} ] || echo "${dep}" | grep -q '^kmod-' || touch /tmp/reset_core_packages/${dep}
done
else
deps=`grep '^Depends: ' /usr/lib/opkg/info/${pkgname}.control | sed -e 's/^Depends: //' -e 's/ ([^)]*)//g' -e 's/,/ /g'`
touch /tmp/reset_core_packages/${pkgname}
for dep in $deps ; do
pkg_depends_rec "$dep"
done
@@ -254,8 +300,7 @@ list_core_packages()
reset_core_packages()
{
local overlay="$1"
local running_ver=$(grep 'DISTRIB_RELEASE=' /etc/openwrt_release 2>/dev/null | sed -E "s/.*='(.+)'.*/\1/")
[ "v$(cat "$overlay/.upgrading" 2>/dev/null)" = "v$running_ver" ] && return
update_overlay_lower_release "$overlay" || return
local pkg
[ -d /tmp/reset_core_packages ] || list_core_packages
echo "Reset packages in $overlay: `ls /tmp/reset_core_packages/ | xargs echo`" | dd bs=960 2>/dev/null
@@ -267,6 +312,8 @@ reset_core_packages()
clean_kmods()
{
# apk system will clean kmods on isos_upgrade
$APK && return 0
local DUMMY_VERSION=0.0.0-r1
if [ -d "$1/upper/usr/lib/opkg/info" ]; then
local compat=`grep -m1 '^Version: ' /usr/lib/opkg/info/kernel.control | sed 's/^Version: //'`
@@ -320,13 +367,17 @@ prepare_primary_overlay()
prepare_primary_overlay_after_merge()
{
local upgrading=false
update_overlay_lower_uuid /overlay && upgrading=true
if [ -d /overlay/upper ]; then
if update_overlay_lower_uuid /overlay || [ -f /overlay/.upgrading ] ; then
if $upgrading ; then
clean_os_version_files /overlay
reset_core_packages /overlay
touch /overlay/.upgrading
mkdir -p /overlay/upper/etc/uci-defaults
rm -f /overlay/upper/etc/uci-defaults/.upgrading
touch /overlay/upper/etc/uci-defaults/.upgrading
fi
if [ -f /overlay/.upgrading -o -f /overlay/.merged ] ; then
if $upgrading || [ -f /overlay/.merged ] ; then
if is_overlayfs_use_xattr ; then
clean_overlayfs_origin /overlay/upper
clean_overlayfs_redundant_opaque /overlay/upper
@@ -336,13 +387,13 @@ prepare_primary_overlay_after_merge()
clean_overlayfs_redundant_whiteout_marker_luci /overlay
fi
else
update_overlay_lower_uuid /overlay
update_overlay_lower_release "/overlay"
fi
if [ -f /overlay/upper/usr/lib/opkg/.upgrading ]; then
if [ -f /overlay/upper/etc/uci-defaults/.upgrading ]; then
clean_kmods /overlay
fi
rm -f /overlay/.upgrading /overlay/.merged
rm -f /overlay/.merged
mkdir -p /overlay/upper /overlay/work
}
@@ -393,10 +444,13 @@ prepare_ext_overlay()
{
local newoverlaydir=$1
local overlaydir=$2
local upgrading=false
update_overlay_lower_uuid "$newoverlaydir" && upgrading=true
if [ -f "$newoverlaydir/.reset" ]; then
rm -rf "$newoverlaydir/upper"
rm -f "$newoverlaydir/.commit" "$newoverlaydir/.reset"
update_overlay_lower_release "$newoverlaydir"
elif [ -f "$newoverlaydir/.commit" ]; then
if [ -d "$newoverlaydir/upper" ]; then
apply_overlayfs_opaque "$newoverlaydir" "$overlaydir"
@@ -406,28 +460,35 @@ prepare_ext_overlay()
rmdir "$overlaydir/upper/ext_overlay"
rm -rf "$newoverlaydir/upper"
mkdir -m 0755 -p "$newoverlaydir/upper/ext_overlay"
rm -f "$overlaydir/upper/etc/uci-defaults/.upgrading" "$overlaydir/.rootfs-uuid" "$overlaydir/.rootfs-release"
update_overlay_lower_release "$newoverlaydir"
}
rm -f "$newoverlaydir/.commit"
else
prepare_primary_overlay_after_merge
touch "$overlaydir/.clean"
if [ -f "$newoverlaydir/upper/usr/lib/opkg/.upgrading" ]; then
clean_kmods "$newoverlaydir"
fi
if [ -f "$newoverlaydir/.upgrading" ]; then
clean_os_version_files "$newoverlaydir"
reset_core_packages "$newoverlaydir"
is_overlayfs_use_xattr && clean_overlayfs_origin "$newoverlaydir/upper"
fi
if [ -d "$newoverlaydir/upper" -a \( -f "$newoverlaydir/upper/usr/lib/opkg/.upgrading" -o ! -f "$overlaydir/.sandbox" \) ]; then
clean_overlayfs_redundant_whiteout_marker "$newoverlaydir" "$overlaydir"
if [ -d "$newoverlaydir/upper" ]; then
if $upgrading; then
clean_kmods "$newoverlaydir"
clean_os_version_files "$newoverlaydir"
reset_core_packages "$newoverlaydir"
mkdir -p "$newoverlaydir/upper/etc/uci-defaults"
rm -f "$newoverlaydir/upper/etc/uci-defaults/.upgrading"
touch "$newoverlaydir/upper/etc/uci-defaults/.upgrading"
is_overlayfs_use_xattr && clean_overlayfs_origin "$newoverlaydir/upper"
elif [ -c "$newoverlaydir/upper/etc/uci-defaults/.upgrading" -a ! -f "$overlaydir/upper/etc/uci-defaults/.upgrading" ]; then
rm -f "$newoverlaydir/upper/etc/uci-defaults/.upgrading"
fi
if $upgrading || [ ! -f "$overlaydir/.sandbox" ]; then
clean_overlayfs_redundant_whiteout_marker "$newoverlaydir" "$overlaydir"
else
clean_overlayfs_redundant_whiteout_marker_luci "$newoverlaydir" "$overlaydir"
fi
else
clean_overlayfs_redundant_whiteout_marker_luci "$newoverlaydir" "$overlaydir"
update_overlay_lower_release "$newoverlaydir"
fi
fi
rm -f "$newoverlaydir/.upgrading"
( mkdir -m 0755 -p $newoverlaydir/upper/ext_overlay && \
mkdir -m 0755 -p $newoverlaydir/work ) || return 1
@@ -23,6 +23,7 @@ for file in \
/lib/board \
/sbin/ujail \
/usr/lib/opkg/info/luci-app-oaf.control \
/lib/apk/packages/luci-app-oaf.list \
/usr/libexec/fan-control \
/usr/sbin/sandbox
do
@@ -117,6 +117,7 @@ sh -c 'mount --bind /tmp/proconly.txt /proc/$$/mounts && exec mount -o rw,remoun
rm -f /tmp/proconly.txt
# Apk system means that openwrt version is newer than 24.10, there is not such issue on newer openwrt version, so we just check opkg system.
PROCD_VER=`grep -o '^Version: [0-9]*' /rom/usr/lib/opkg/info/procd.control | cut -d' ' -f2`
if [ -n "$PROCD_VER" -a "$PROCD_VER" -lt 2024 ]; then
# workaround procd < 2024 infite loop on resolving rootfs type, e.g. `ubus call system board`
+2 -2
View File
@@ -2,8 +2,8 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.0.18-r1
PKG_RELEASE:=2
PKG_VERSION:=1.1.0-r1
PKG_RELEASE:=3
LUCI_TITLE:=LuCI support for SysTools
LUCI_PKGARCH:=all
@@ -158,6 +158,7 @@ level=$1
echo "Try Level $level"
# Apk system means that openwrt is newer enough, so we don't need to check the odhcpd version on apk system
odhcpd_version=$(grep -o 'Version: [0-9]*' /usr/lib/opkg/info/odhcpd-ipv6only.control | cut -d' ' -f2)
if [ -n "$odhcpd_version" -a "$odhcpd_version" -lt 2025 ]; then
echo "odhcpd version $odhcpd_version detected, enabling NDP bug workaround"
@@ -166,7 +167,10 @@ fi
# nat
if [ "$level" = $LEVEL_NAT ]; then
if opkg status kmod-ipt-nat6 | grep '^Status: ' | grep -Fwq installed ; then
if [ -f /etc/apk/arch ]; then
apk query --installed --field version kmod-ipt-nat6 | grep -q 'Version:\s*[1-9]' || \
apk add kmod-ipt-nat6 || exit 1
elif opkg status kmod-ipt-nat6 | grep '^Status: ' | grep -Fwq installed ; then
echo "kmod-ipt-nat6 found"
else
echo "kmod-ipt-nat6 not found, installing"
@@ -1,18 +1,33 @@
#!/bin/sh
# Copyright (C) 2025 jjm2473@gmail.com
(
cd /usr/lib/opkg/info
grep -lm1 '^Version: 0.0.0-r1$' kmod-*.control 2>/dev/null | sed 's/.control$//'
) > /tmp/incompat_kmods.txt
APK=false
[ -f /etc/apk/arch ] && APK=true
if $APK; then
apk list --installed --manifest 'kmod-*' | grep ' 0.0.0-r1$' | cut -d' ' -f1 > /tmp/incompat_kmods.txt
else
(
cd /usr/lib/opkg/info
grep -lm1 '^Version: 0.0.0-r1$' kmod-*.control 2>/dev/null | sed 's/.control$//'
) > /tmp/incompat_kmods.txt
fi
if [ -s /tmp/incompat_kmods.txt ]; then
echo "The following incompatible kernel modules were found:"
cat /tmp/incompat_kmods.txt
echo "=====END====="
echo "Try installing from opkg"
opkg update
opkg install $(cat /tmp/incompat_kmods.txt)
if $APK; then
echo "Try installing from apk"
# doing `apk fix` twice, because the first time install the version 0.0.0-r1, which is always not exist, but it's side effect mark the package uninstalled, the second time will install the latest version.
# `apk add --force-reinstall` works too, but it will change world file, which may not be desired.
apk fix -r $(cat /tmp/incompat_kmods.txt) >/dev/null 2>&1
apk fix -r $(cat /tmp/incompat_kmods.txt)
else
echo "Try installing from opkg"
opkg update
opkg install $(cat /tmp/incompat_kmods.txt)
fi
rm -f /tmp/incompat_kmods.txt
echo "If you encounter network problems, please try again"
echo "If it says some packages are unknown, it may be because they have been removed. Just ignore it."
@@ -1,48 +1,49 @@
#!/bin/sh
APK=false
PKG_BASE=usr/lib/opkg/info
PKG_EXT=control
[ -s /etc/apk/arch ] && {
APK=true
PKG_BASE=lib/apk/packages
PKG_EXT=list
}
nonconf_files_of_pkg() {
local pkgname="$1"
if [ -s /rom/usr/lib/opkg/info/${pkgname}.conffiles ]; then
grep -hvxFf /rom/usr/lib/opkg/info/${pkgname}.conffiles \
/rom/usr/lib/opkg/info/${pkgname}.list
if [ -s /rom/$PKG_BASE/${pkgname}.conffiles ]; then
grep -hvxFf /rom/$PKG_BASE/${pkgname}.conffiles \
/rom/$PKG_BASE/${pkgname}.list
else
cat /rom/usr/lib/opkg/info/${pkgname}.list
cat /rom/$PKG_BASE/${pkgname}.list
fi
}
reset_pkg() {
local pkgname="$1"
local line
local dep
local deps
echo "${pkgname}" | grep -q '^kernel$
^libc$
^libgcc1$
^libatomic1$
^busybox$' && return
if [ -f /rom/usr/lib/opkg/info/${pkgname}.control -a \
\( -e /overlay/upper/usr/lib/opkg/info/${pkgname}.control -o \
-e /ext_overlay/upper/usr/lib/opkg/info/${pkgname}.control \) ]; then
if [ -f /rom/$PKG_BASE/${pkgname}.$PKG_EXT -a \
\( -e /overlay/upper/$PKG_BASE/${pkgname}.$PKG_EXT -o \
-e /ext_overlay/upper/$PKG_BASE/${pkgname}.$PKG_EXT \) ]; then
echo "reset ${pkgname}"
if [ -f /rom/usr/lib/opkg/info/${pkgname}.list ]; then
if [ -f /rom/$PKG_BASE/${pkgname}.list ]; then
nonconf_files_of_pkg "${pkgname}" | while read; do
line="$REPLY"
line="$REPLY"
rm -f "/overlay/upper/${line}" "/ext_overlay/upper/${line}"
done
rm -f /overlay/upper/usr/lib/opkg/info/${pkgname}.list /ext_overlay/upper/usr/lib/opkg/info/${pkgname}.list
rm -f /overlay/upper/$PKG_BASE/${pkgname}.list /ext_overlay/upper/$PKG_BASE/${pkgname}.list
fi
deps=`grep '^Depends: ' /rom/usr/lib/opkg/info/${pkgname}.control | sed -e 's/^Depends: //' -e 's/ ([^)]*)//g' -e 's/,/ /g'`
# avoid loop deps
rm -f /overlay/upper/usr/lib/opkg/info/${pkgname}.control /ext_overlay/upper/usr/lib/opkg/info/${pkgname}.control
for dep in $deps ; do
reset_pkg "$dep"
done
rm -f /overlay/upper/usr/lib/opkg/info/${pkgname}.* /ext_overlay/upper/usr/lib/opkg/info/${pkgname}.*
fi
}
ls_all_rom_pkgs() {
( cd /rom/usr/lib/opkg/info ; find . -maxdepth 1 -name '*.control' | sed -E 's#./(.*).control#\1#g' )
( cd /rom/$PKG_BASE ; find . -maxdepth 1 -name "*.$PKG_EXT" | sed -E 's#./(.*).'"$PKG_EXT"'#\1#g' )
}
reset_all_rom() {
@@ -55,7 +56,13 @@ reset_all_rom() {
reset_all_rom
touch /overlay/upper/usr/lib/opkg/.upgrading
if $APK; then
rm -f /overlay/upper/etc/uci-defaults/.upgrading /ext_overlay/upper/etc/uci-defaults/.upgrading
touch /overlay/upper/etc/uci-defaults/.upgrading 2>/dev/null
else
rm -f /overlay/upper/usr/lib/opkg/.upgrading /ext_overlay/upper/usr/lib/opkg/.upgrading
touch /overlay/upper/usr/lib/opkg/.upgrading 2>/dev/null
fi
echo "done, please reboot, it will reboot in 10s"
+3 -3
View File
@@ -15,12 +15,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-wwand
PKG_RELEASE:=2
PKG_RELEASE:=3
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/ddimension/luci-app-wwand.git
PKG_SOURCE_VERSION:=b4dcc07ae3ebae8fcc80a335de35f6fde19fbd85
PKG_SOURCE_DATE:=2026-08-21
PKG_SOURCE_VERSION:=c9c2e1870b094cdc7bdd9013a7e4862e030b9500
PKG_SOURCE_DATE:=2026-08-23
PKG_MIRROR_HASH:=skip
PKG_LICENSE:=GPL-2.0-only
Loaded 100 of 119 files, more files were not shown because too many files have changed in this diff. Show more