From 38be921226b55d067455ed25d3e02e023e03f2e2 Mon Sep 17 00:00:00 2001 From: kenzok8 Date: Sat, 9 Aug 2025 00:28:54 +0800 Subject: [PATCH] update 2025-08-09 00:28:54 --- alist/Makefile | 8 +- .../files/root/etc/init.d/dnsmasq-ipset | 2 +- luci-app-eqosplus/Makefile | 6 +- .../luasrc/model/cbi/eqosplus.lua | 118 +++- luci-app-eqosplus/root/etc/init.d/eqosplus | 2 +- luci-app-eqosplus/root/usr/bin/eqosplus | 538 +++++++++++------- luci-app-eqosplus/root/usr/bin/eqosplusctrl | 2 +- luci-app-passwall/Makefile | 1 - .../model/cbi/passwall/client/global.lua | 14 +- luci-app-passwall/po/zh-cn/passwall.po | 3 + .../usr/share/passwall/socks_auto_switch.sh | 89 +-- .../model/cbi/shadowsocksr/advanced.lua | 129 +++-- luci-app-ssr-plus/po/templates/ssr-plus.pot | 36 +- luci-app-ssr-plus/po/zh_Hans/ssr-plus.po | 36 +- .../usr/share/shadowsocksr/gen_config.lua | 6 +- 15 files changed, 636 insertions(+), 354 deletions(-) diff --git a/alist/Makefile b/alist/Makefile index 75db19377..493005672 100644 --- a/alist/Makefile +++ b/alist/Makefile @@ -7,13 +7,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=alist -PKG_VERSION:=3.48.0 -PKG_WEB_VERSION:=3.48.0 +PKG_VERSION:=3.49.0 +PKG_WEB_VERSION:=3.49.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/alist-org/alist/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=fb01566b5c69b388cab8425fc3cd82d859e0227c5f4d6df35200b69c5deccae3 +PKG_HASH:=62d0a2f5547245b48c9e6dd201593f11dd8c4d54aba76d8fa4d3de8a12cb0abe PKG_LICENSE:=GPL-3.0 PKG_LICENSE_FILE:=LICENSE @@ -23,7 +23,7 @@ define Download/$(PKG_NAME)-web FILE:=$(PKG_NAME)-web-$(PKG_WEB_VERSION).tar.gz URL_FILE:=dist.tar.gz URL:=https://github.com/alist-org/alist-web/releases/download/$(PKG_WEB_VERSION)/ - HASH:=759779d2027e03e6bf9f0f6ea9cb45c849f235f8d24c4e21b5ffb78782303821 + HASH:=ded80edc57355747d367c5be8d9b734286f9fdca02c4ddbc46be9bf480c7a245 endef PKG_BUILD_DEPENDS:=golang/host diff --git a/luci-app-dnsmasq-ipset/files/root/etc/init.d/dnsmasq-ipset b/luci-app-dnsmasq-ipset/files/root/etc/init.d/dnsmasq-ipset index 08348a15b..c940d77e9 100755 --- a/luci-app-dnsmasq-ipset/files/root/etc/init.d/dnsmasq-ipset +++ b/luci-app-dnsmasq-ipset/files/root/etc/init.d/dnsmasq-ipset @@ -1,7 +1,7 @@ #!/bin/sh /etc/rc.common # Author Qier LU -START=18 +START=19 gen_config_file() { local section="${1}" diff --git a/luci-app-eqosplus/Makefile b/luci-app-eqosplus/Makefile index e4deead9c..6cc7478a3 100644 --- a/luci-app-eqosplus/Makefile +++ b/luci-app-eqosplus/Makefile @@ -1,6 +1,6 @@ # # Copyright (C) 2006-2017 OpenWrt.org -# Copyright (C) 2022-2023 sirpdboy +# Copyright (C) 2022-2025 sirpdboy # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # @@ -17,8 +17,8 @@ LUCI_DESCRIPTION:=LuCI support for Easy eqosplus(Support speed limit based on IP LUCI_DEPENDS:=+bash +tc +kmod-sched-core +kmod-ifb +kmod-sched +iptables-mod-filter +iptables-mod-nat-extra LUCI_PKGARCH:=all -PKG_VERSION:=1.2.5 -PKG_RELEASE:=20231205 +PKG_VERSION:=1.2.8 +PKG_RELEASE:=20250723 PKG_MAINTAINER:=sirpdboy define Build/Compile diff --git a/luci-app-eqosplus/luasrc/model/cbi/eqosplus.lua b/luci-app-eqosplus/luasrc/model/cbi/eqosplus.lua index b3ce35bad..bbe054dbd 100644 --- a/luci-app-eqosplus/luasrc/model/cbi/eqosplus.lua +++ b/luci-app-eqosplus/luasrc/model/cbi/eqosplus.lua @@ -21,12 +21,37 @@ e.value = translate("Collecting data...") ipi = t:option(ListValue, "ifname", translate("Interface"), translate("Set the interface used for restriction, use pppoe-wan for dialing, use WAN hardware interface for DHCP mode (such as eth1), and use br-lan for bypass mode")) ipi.default = "1" ipi:value(1,translate("Automatic settings")) -ipi.rmempty = false -for _, v in pairs(ifaces) do - net = WADM.iface_get_network(v) - if net and net ~= "loopback" then - ipi:value(v) - end +ipi:value("br-lan", translate("br-lan (LAN Bridge)")) +local function get_wan_interfaces() + local result = {} + local ubus = require "ubus" + + local conn = ubus.connect() + if not conn then + return result + end + + local network_status = conn:call("network.interface", "dump", {}) + for _, iface in ipairs(network_status.interface) do + if iface.interface:match("^wan") or iface.interface:match("^pppoe") or iface.proto == "pppoe" then + local dev = iface.l3_device or iface.device + if dev then + table.insert(result, { + name = dev, + proto = iface.proto, + logical_name = iface.interface + }) + end + end + end + + conn:close() + return result +end + +local wan_ifaces = get_wan_interfaces() +for _, iface in ipairs(wan_ifaces) do + ipi:value(iface.name, translate(iface.name) .. (iface.proto == "pppoe" and " (PPPoE)" or " (WAN)")) end t = a:section(TypedSection, "device") @@ -42,19 +67,78 @@ e.rmempty = false e.size = 4 ip = t:option(Value, "mac", translate("IP/MAC")) +ip.size = 8 -ipc.neighbors({family = 4, dev = "br-lan"}, function(n) - if n.mac and n.dest then - ip:value(n.dest:string(), "%s (%s)" %{ n.dest:string(), n.mac }) - end -end) -ipc.neighbors({family = 4, dev = "br-lan"}, function(n) - if n.mac and n.dest then - ip:value(n.mac, "%s (%s)" %{n.mac, n.dest:string() }) - end -end) +local function get_devices() + local devices = {} + local seen_ips = {} + local ubus = require "ubus" + local conn = ubus.connect() + + local function get_hostname(ip) + local f = io.popen("nslookup "..ip.." 2>/dev/null | grep 'name =' | cut -d'=' -f2 | sed 's/\\.$//'") + if f then + local name = f:read("*l") + f:close() + if name and name ~= "" then + return name:match("^%s*(.-)%s*$") + end + end + local leases_file = io.open("/tmp/dhcp.leases", "r") + if leases_file then + for line in leases_file:lines() do + local mac, ip_lease, _, hostname = line:match("^(%S+)%s+(%S+)%s+(%S+)%s+(%S+)") + if ip_lease == ip and hostname ~= "*" then + leases_file:close() + return hostname + end + end + leases_file:close() + end + return "unknown" + end + if conn then + local leases = conn:call("dhcp", "ipv4leases", {}) or {} + for _, lease in ipairs(leases) do + if lease.ipaddr and lease.mac then + local hostname = lease.hostname or get_hostname(lease.ipaddr) + devices[#devices+1] = { + ip = lease.ipaddr, + mac = lease.mac:upper(), + hostname = hostname, + display = string.format("%s (%s) - %s", lease.ipaddr, lease.mac:upper(), hostname) + } + seen_ips[lease.ipaddr] = true + end + end + conn:close() + end + local arp_cmd = io.popen("ip -4 neigh show dev br-lan 2>/dev/null") + if arp_cmd then + for line in arp_cmd:lines() do + local ip_addr, mac = line:match("^(%S+)%s+.+%s+(%S+)%s+") + if ip_addr and mac and mac ~= "00:00:00:00:00:00" and not seen_ips[ip_addr] then + mac = mac:upper() + local hostname = get_hostname(ip_addr) + devices[#devices+1] = { + ip = ip_addr, + mac = mac, + hostname = hostname, + display = string.format("%s (%s) - %s", ip_addr, mac, hostname) + } + seen_ips[ip_addr] = true + end + end + arp_cmd:close() + end + table.sort(devices, function(a, b) return a.ip < b.ip end) + return devices +end -e.size = 8 +local devices = get_devices() +for _, dev in ipairs(devices) do + ip:value(dev.ip, dev.display) +end dl = t:option(Value, "download", translate("Downloads")) dl.default = '0.1' dl.size = 4 diff --git a/luci-app-eqosplus/root/etc/init.d/eqosplus b/luci-app-eqosplus/root/etc/init.d/eqosplus index c3751d058..f74b5fdd0 100644 --- a/luci-app-eqosplus/root/etc/init.d/eqosplus +++ b/luci-app-eqosplus/root/etc/init.d/eqosplus @@ -1,6 +1,6 @@ #!/bin/sh /etc/rc.common # -# Copyright (C) 2023 sirpdboy herboy2008@gmail.com +# Copyright (C) 2025 sirpdboy herboy2008@gmail.com https://github.com/sirpdboy/luci-app-eqosplus # START=99 diff --git a/luci-app-eqosplus/root/usr/bin/eqosplus b/luci-app-eqosplus/root/usr/bin/eqosplus index 7eada2002..00318fdaa 100644 --- a/luci-app-eqosplus/root/usr/bin/eqosplus +++ b/luci-app-eqosplus/root/usr/bin/eqosplus @@ -1,7 +1,7 @@ -#!/bin/bash +#!/bin/bash # Copyright (C) 2006 OpenWrt.org -# Copyright 2022-2023 sirpdboy +# Copyright 2022-2025 sirpdboy crrun=$1 crid=$2 @@ -9,43 +9,65 @@ NAME=eqosplus IDLIST="/var/$NAME.idlist" LOCK="/var/lock/$NAME.lock" TMPID="/var/$NAME.tmpid" -if [ x$(uci get $NAME.@$NAME[0].ifname) = 'x1' ] ;then - # dev=`ifconfig | grep "Point-to-Point" | cut -d " " -f1` - ifname=$(uci -q get network.lan.ifname ) - [ "x$ifname" = "x" ] && ifname="device" || ifname="ifname" - [ ! ${dev} ] && dev=` uci -q get network.wan.$ifname ` - [ ! ${dev} ] && dev=br-lan - dev=br-lan - #ALL_DEVICES=$(echo $(ifconfig | grep 'Point-to-Point' | cut -d ' ' -f1) $(uci -q get network.wan.$ifname) $(ports_for_device $(uci -q get network.wan.device)) | tr ' ' '\n' | sort -u) + +# 获取网络接口配置 +if [ x$(uci get $NAME.@$NAME[0].ifname) = 'x1' ]; then + ifname=$(uci -q get network.lan.ifname) + [ "x$ifname" = "x" ] && ifname="device" || ifname="ifname" + dev=$(uci -q get network.wan.$ifname) + [ ! "$dev" ] && dev=br-lan else - dev=`uci -q get $NAME.@$NAME[0].ifname ` + dev=$(uci -q get $NAME.@$NAME[0].ifname) fi -# [ x$(uci get eqosplus.@eqosplus[0].forced) = 'x1' ] && forced="default $id" || forced='default 999' + +# 工具路径 +bin_nft=$(which nft) bin_iptables=$(which iptables) bin_ip6tables=$(which ip6tables) bin_tc=$(which tc) bin_ip=$(which ip) -# Uncomment this to debug commands -DEBUG=0 -## End +DEBUG=1 + +# 检测nftables类型 +nft_type() { + if command -v nft >/dev/null; then + nftables_ver="true" + fi +} + +# 检测iptables类型 +ipt_type() { + if command -v iptables >/dev/null; then + iptables_ver="true" + fi +} + # Debug functions - echo + run dbg_iptables() { - [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: iptables $*" - $bin_iptables "$*" + [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: iptables $*" + $bin_iptables "$*" } + dbg_ip6tables() { - [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: ip6tables $*" - $bin_ip6tables "$*" + [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: ip6tables $*" + $bin_ip6tables "$*" +} + +dbg_nft() { + [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: nft $*" + $bin_nft "$@" } dbg_tc() { - [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: tc $*" - $bin_tc $* + [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: tc $*" + $bin_tc "$@" } + dbg_ip() { - [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: ip $*" - $bin_ip $* + [ "${DEBUG:-0}" -eq 0 ] || echo "DEBUG: ip $*" + $bin_ip "$@" } + is_macaddr() { ret=1 if echo "$1" | grep -qE '^([0-9A-Fa-f]{2}[-:]){5}[0-9A-Fa-f]{2}$'; then @@ -59,206 +81,324 @@ iptables="dbg_iptables" ip6tables="dbg_ip6tables" tc="dbg_tc" ip="dbg_ip" -ipt=$iptables -ipt6=$ip6tables +ipt="dbg_iptables" +ipt6="dbg_ip6tables" +nft="dbg_nft" + +# 检测防火墙类型 +nft_type +ipt_type + ipt(){ - $iptables $* - $ip6tables $* + $iptables $* + $ip6tables $* } - iptm(){ - $iptables "-t mangle $*" - $ip6tables "-t mangle $*" + $iptables "-t mangle $*" + $ip6tables "-t mangle $*" } stop_qos() { - + # 清理所有HTB队列 + for face in $(tc qdisc show | grep htb | awk '{print $5}'); do + $tc qdisc del dev $face root 2>/dev/null + done - for face in $( tc qdisc show | grep htb | awk '{print $5}');do - $tc qdisc del dev $face root - done - - $tc qdisc del dev ${dev} root 2>/dev/null - $tc qdisc del dev ${dev}_ifb root 2>/dev/null - $tc qdisc del dev ${dev} ingress 2>/dev/null - $ip link del dev ${dev}_ifb 2>/dev/null + # 清理特定设备的队列 + $tc qdisc del dev ${dev} root 2>/dev/null + $tc qdisc del dev ${dev}_ifb root 2>/dev/null + $tc qdisc del dev ${dev} ingress 2>/dev/null + $ip link del dev ${dev}_ifb 2>/dev/null 2>&1 + + # 清理nftables规则 + if [ -n "$nftables_ver" ]; then + $nft flush table inet ${NAME} 2>/dev/null + $nft delete table inet ${NAME} 2>/dev/null + fi + + # 清理iptables标记规则 + if [ -n "$iptables_ver" ]; then + $iptables -t mangle -F ${NAME}_mark 2>/dev/null + $iptables -t mangle -X ${NAME}_mark 2>/dev/null + $ip6tables -t mangle -F ${NAME}_mark 2>/dev/null + $ip6tables -t mangle -X ${NAME}_mark 2>/dev/null + fi + echo "" > "$IDLIST" } init_qosplus() { - insmod sch_htb 2> /dev/null - $ip link add dev ${dev}_ifb name ${dev}_ifb type ifb - $ip link set dev ${dev}_ifb up - $tc qdisc add dev ${dev} root handle 1:0 htb default 1 - $tc class add dev ${dev} parent 1:0 classid 1:1 htb rate 80gbit prio 0 quantum 1500 - - $tc qdisc add dev ${dev}_ifb root handle 1:0 htb default 1 - $tc class add dev ${dev}_ifb parent 1:0 classid 1:1 htb rate 80gbit prio 0 quantum 1500 - - lanipaddr=$(uci -q get network.lan.ipaddr 2>/dev/null | awk -F '.' '{print $1"."$2"."$3".0/24"}') - $tc filter add dev $dev parent 1:0 protocol ipv4 prio 1 u32 match ip src "$lanipaddr" match ip dst "$lanipaddr" flowid 1:1 - $tc filter add dev ${dev}_ifb parent 1:0 protocol ipv4 prio 1 u32 match ip src "$lanipaddr" match ip dst "$lanipaddr" flowid 1:1 + # 加载内核模块 + insmod sch_htb 2>/dev/null + insmod act_mirred 2>/dev/null + insmod ifb 2>/dev/null - $tc qdisc add dev ${dev} ingress - $tc filter add dev ${dev} parent ffff: protocol all prio 2 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ${dev}_ifb + # 创建IFB虚拟接口用于上传限速 + $ip link add dev ${dev}_ifb name ${dev}_ifb type ifb 2>/dev/null + $ip link set dev ${dev}_ifb up 2>/dev/null + + # 下载限速设置(原始接口) + $tc qdisc add dev ${dev} root handle 1:0 htb default 1 + $tc class add dev ${dev} parent 1:0 classid 1:1 htb rate 80gbit prio 0 quantum 1500 + + # 上传限速设置(IFB接口) + $tc qdisc add dev ${dev}_ifb root handle 1:0 htb default 1 + $tc class add dev ${dev}_ifb parent 1:0 classid 1:1 htb rate 80gbit prio 0 quantum 1500 + + # 排除本地网络流量 + lanipaddr=$(uci -q get network.lan.ipaddr 2>/dev/null | awk -F '.' '{print $1"."$2"."$3".0/24"}') + $tc filter add dev $dev parent 1:0 protocol ip prio 1 u32 match ip src "$lanipaddr" match ip dst "$lanipaddr" flowid 1:1 + $tc filter add dev ${dev}_ifb parent 1:0 protocol ip prio 1 u32 match ip src "$lanipaddr" match ip dst "$lanipaddr" flowid 1:1 + + # 设置入口流量重定向到IFB + $tc qdisc add dev ${dev} ingress + $tc filter add dev ${dev} parent ffff: protocol all prio 2 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ${dev}_ifb + + # 初始化nftables表 + if [ -n "$nftables_ver" ]; then + $nft add table inet ${NAME} 2>/dev/null + $nft add chain inet ${NAME} mark_traffic { type filter hook postrouting priority -150 \; } + fi + + # 添加iptables标记规则(用于更精确的上传控制) + if [ -n "$iptables_ver" ]; then + $iptables -t mangle -N ${NAME}_mark 2>/dev/null + $iptables -t mangle -F ${NAME}_mark + $iptables -t mangle -A POSTROUTING -j ${NAME}_mark + $ip6tables -t mangle -N ${NAME}_mark 2>/dev/null + $ip6tables -t mangle -F ${NAME}_mark + $ip6tables -t mangle -A POSTROUTING -j ${NAME}_mark + fi } + del_id() { - id=`expr $1 + 11 ` - [ "${DEBUG:-0}" -eq 0 ] || echo "D: del_id $@" "--$id --$mac" - $tc qd del dev ${dev} parent 1:$id 2>/dev/null - $tc qd del dev ${dev}_ifb parent 1:$id 2>/dev/null - - $tc class del dev ${dev} parent 1:1 classid 1:$id 2>/dev/null - $tc class del dev ${dev}_ifb parent 1:1 classid 1:$id 2>/dev/null - - $tc filter del dev ${dev}_ifb pref $id 2>/dev/null - $tc filter del dev ${dev} pref $id 2>/dev/null - - $tc filter del dev ${dev}_ifb pref 6 2>/dev/null - $tc filter del dev ${dev} pref 6 2>/dev/null - $tc filter del dev ${dev}_ifb pref 5 2>/dev/null - $tc filter del dev ${dev} pref 5 2>/dev/null - -} -### https://openwrt.org/docs/guide-user/network/traffic-shaping/packet.scheduler.example5 -filter_mac() { - M=`echo $mac | awk -F '[-:]' '{print $1$2}'` - M0=$(echo $1 | cut -d : -f 1)$(echo $1 | cut -d : -f 2) - M1=$(echo $1 | cut -d : -f 3)$(echo $1 | cut -d : -f 4) - M2=$(echo $1 | cut -d : -f 5)$(echo $1 | cut -d : -f 6) - TCF="${tc} filter add dev $3 parent 1: protocol ip prio 5 u32 match u16 0x0800 0xFFFF at -2" - $TCF match u16 0x${M2} 0xFFFF at -4 match u32 0x${M0}${M1} 0xFFFFFFFF at -8 flowid $2 - $TCF match u32 0x${M1}${M2} 0xFFFFFFFF at -12 match u16 0x${M0} 0xFFFF at -14 flowid $2 + id=$((id + 10)) + [ "${DEBUG:-0}" -eq 0 ] || echo "D: del_id $@ --$id --$mac" + + # 删除下载限速规则 + $tc qdisc del dev ${dev} parent 1:$id 2>/dev/null + $tc class del dev ${dev} parent 1:1 classid 1:$id 2>/dev/null + $tc filter del dev ${dev} pref $id 2>/dev/null + + # 删除上传限速规则 + $tc qdisc del dev ${dev}_ifb parent 1:$id 2>/dev/null + $tc class del dev ${dev}_ifb parent 1:1 classid 1:$id 2>/dev/null + $tc filter del dev ${dev}_ifb pref $id 2>/dev/null + + # 删除nftables/iptables标记规则 + mac=$(uci -q get $NAME.@device[$1].mac) + if is_macaddr "$mac"; then + + [ -n "$nftables_ver" ] && $nft delete rule inet ${NAME} mark_traffic ether saddr $mac counter 2>/dev/null + [ -n "$iptables_ver" ] && $iptables -t mangle -D ${NAME}_mark -m mac --mac-source $mac -j MARK --set-mark $id 2>/dev/null + else + [ -n "$nftables_ver" ] && $nft delete rule inet ${NAME} mark_traffic ip saddr $mac counter 2>/dev/null + [ -n "$iptables_ver" ] && $iptables -t mangle -D ${NAME}_mark -s $mac -j MARK --set-mark $id 2>/dev/null + fi } + add_mac() { - id=`expr $1 + 11 ` - M0=$(echo $mac | cut -d : -f 1)$(echo $mac | cut -d : -f 2) - M1=$(echo $mac | cut -d : -f 3)$(echo $mac | cut -d : -f 4) - M2=$(echo $mac | cut -d : -f 5)$(echo $mac | cut -d : -f 6) - [ "${DEBUG:-0}" -eq 0 ] || echo "D: add_mac $@ --id:$id --mac:$mac M012--$M0-$M1-$M2" - if [ "$UL" -gt 0 ]; then - $tc class add dev ${dev}_ifb parent 1:1 classid 1:$id htb rate "$UL"kbit ceil "$UL"kbit prio $id quantum 1500 - $tc qdisc add dev ${dev}_ifb parent 1:"$id" handle "$id": sfq perturb 1 - $tc filter add dev ${dev}_ifb parent 1: protocol ip prio $id u32 match u16 0x0800 0xFFFF at -2 match u16 0x"${M2}" 0xFFFF at -4 match u32 0x"${M0}${M1}" 0xFFFFFFFF at -8 flowid 1:$id - # filter_mac $mac 1:$id ${dev}_ifb - elif [ "$UL" == 0 ]; then - $tc filter add dev ${dev}_ifb parent 1: protocol ip prio 5 u32 match u16 0x0800 0xFFFF at -2 match u16 0x"${M2}" 0xFFFF at -4 match u32 0x"${M0}${M1}" 0xFFFFFFFF at -8 flowid 1:1 - fi - if [ "$DL" -gt 0 ]; then - $tc class add dev ${dev} parent 1:1 classid 1:$id htb rate "$DL"kbit ceil "$DL"kbit prio $id quantum 1500 - $tc qdisc add dev ${dev} parent 1:"$id" handle "$id": sfq perturb 1 - # filter_mac $mac 1:$id ${dev} - $tc filter add dev ${dev} parent 1: protocol ip prio $id u32 match u16 0x0800 0xFFFF at -2 match u32 0x${M1}${M2} 0xFFFFFFFF at -12 match u16 0x${M0} 0xFFFF at -14 flowid 1:$id - elif [ "$DL" == 0 ]; then - $tc filter add dev ${dev} parent 1: protocol ip prio 5 u32 match u16 0x0800 0xFFFF at -2 match u32 0x"${M1}${M2}" 0xFFFFFFFF at -12 match u16 0x"${M0}" 0xFFFF at -14 flowid 1:1 - fi + id=$((id + 10)) + M0=$(echo $mac | cut -d : -f 1)$(echo $mac | cut -d : -f 2) + M1=$(echo $mac | cut -d : -f 3)$(echo $mac | cut -d : -f 4) + M2=$(echo $mac | cut -d : -f 5)$(echo $mac | cut -d : -f 6) + [ "${DEBUG:-0}" -eq 0 ] || echo "D: add_mac $@ --id:$id --mac:$mac M012--$M0-$M1-$M2" + + # 添加上传限速规则(使用IFB接口) + if [ "$UL" -gt 0 ]; then + # 添加nftables标记规则 + [ -n "$nftables_ver" ] && $nft add rule inet ${NAME} mark_traffic ether saddr $mac counter meta mark set $id + [ -n "$iptables_ver" ] && $iptables -t mangle -A ${NAME}_mark -m mac --mac-source $mac -j MARK --set-mark $id + # 添加TC限速规则 + $tc class add dev ${dev}_ifb parent 1:1 classid 1:$id htb rate "${UL}kbit" ceil "${UL}kbit" prio $id quantum 1500 + $tc qdisc add dev ${dev}_ifb parent 1:$id handle $id: sfq perturb 1 + $tc filter add dev ${dev}_ifb parent 1: protocol ip prio $id handle $id fw flowid 1:$id + + # 原始MAC过滤 + $tc filter add dev ${dev}_ifb parent 1: protocol ip prio $(expr $id + 100) u32 \ + match u16 0x0800 0xFFFF at -2 \ + match u16 0x${M2} 0xFFFF at -4 \ + match u32 0x${M0}${M1} 0xFFFFFFFF at -8 \ + flowid 1:$id + elif [ "$UL" -eq 0 ]; then + $tc filter add dev ${dev}_ifb parent 1: protocol ip prio 5 u32 \ + match u16 0x0800 0xFFFF at -2 \ + match u16 0x${M2} 0xFFFF at -4 \ + match u32 0x${M0}${M1} 0xFFFFFFFF at -8 \ + flowid 1:1 + fi + + # 添加下载限速规则 + if [ "$DL" -gt 0 ]; then + $tc class add dev ${dev} parent 1:1 classid 1:$id htb rate "${DL}kbit" ceil "${DL}kbit" prio $id quantum 1500 + $tc qdisc add dev ${dev} parent 1:$id handle $id: sfq perturb 1 + $tc filter add dev ${dev} parent 1: protocol ip prio $id u32 \ + match u16 0x0800 0xFFFF at -2 \ + match u32 0x${M1}${M2} 0xFFFFFFFF at -12 \ + match u16 0x${M0} 0xFFFF at -14 \ + flowid 1:$id + elif [ "$DL" -eq 0 ]; then + $tc filter add dev ${dev} parent 1: protocol ip prio 5 u32 \ + match u16 0x0800 0xFFFF at -2 \ + match u32 0x${M1}${M2} 0xFFFFFFFF at -12 \ + match u16 0x${M0} 0xFFFF at -14 \ + flowid 1:1 + fi } + add_ip() { - id=`expr $1 + 11 ` - # id=printf "%x\n" "$1" - [ "${DEBUG:-0}" -eq 0 ] || echo "D: add_ip $@ --$id --$mac" - Z=`echo $mac |awk -F '[/]' '{print $2}' ` - [ -n "$Z" ] && mac=`echo $mac |awk -F '[/]' '{print $1}' `|| Z=32 - if [ "$UL" -gt 0 ]; then - $tc class add dev ${dev}_ifb parent 1:1 classid 1:$id htb rate "$UL"kbit ceil "$UL"kbit prio $id quantum 1500 - $tc qdisc add dev ${dev}_ifb parent 1:"$id" handle "$id": sfq perturb 1 - $tc filter add dev ${dev}_ifb parent 1:0 prio $id protocol ip u32 match ip src "$mac"/"$Z" classid 1:$id - elif [ "$UL" == 0 ]; then - $tc filter add dev ${dev}_ifb parent 1:0 prio 6 protocol ip u32 match ip src "$mac"/"$Z" classid 1:1 - fi - if [ "$DL" -gt 0 ]; then - $tc class add dev ${dev} parent 1:1 classid 1:$id htb rate "$DL"kbit ceil "$DL"kbit prio $id quantum 1500 - $tc qdisc add dev ${dev} parent 1:"$id" handle "$id": sfq perturb 1 - $tc filter add dev ${dev} parent 1:0 prio $id protocol ip u32 match ip dst "$mac"/"$Z" classid 1:$id - elif [ "$DL" == 0 ]; then - $tc filter add dev ${dev} parent 1:0 prio 6 protocol ip u32 match ip dst "$mac"/"$Z" classid 1:1 - fi - + id=$((id + 10)) + [ "${DEBUG:-0}" -eq 0 ] || echo "D: add_ip $@ --$id --$mac" + + Z=$(echo $mac | awk -F '[/]' '{print $2}') + [ -n "$Z" ] && mac=$(echo $mac | awk -F '[/]' '{print $1}') || Z=32 + + # 添加上传限速规则(使用IFB接口) + if [ "$UL" -gt 0 ]; then + # 添加nftables/iptables标记规则 + if [ -n "$nftables_ver" ]; then + $nft add rule inet ${NAME} mark_traffic ip saddr $mac/$Z counter meta mark set $id + fi + if [ -n "$iptables_ver" ]; then + $iptables -t mangle -A ${NAME}_mark -s $mac/$Z -j MARK --set-mark $id + fi + + # 添加TC限速规则 + $tc class add dev ${dev}_ifb parent 1:1 classid 1:$id htb rate "${UL}kbit" ceil "${UL}kbit" prio $id quantum 1500 + $tc qdisc add dev ${dev}_ifb parent 1:$id handle $id: sfq perturb 1 + $tc filter add dev ${dev}_ifb parent 1: protocol ip prio $id handle $id fw flowid 1:$id + + # 原始IP过滤 + $tc filter add dev ${dev}_ifb parent 1:0 prio $(expr $id + 100) protocol ip u32 \ + match ip src "$mac"/"$Z" \ + classid 1:$id + elif [ "$UL" -eq 0 ]; then + $tc filter add dev ${dev}_ifb parent 1:0 prio 6 protocol ip u32 \ + match ip src "$mac"/"$Z" \ + classid 1:1 + fi + + # 添加下载限速规则 + if [ "$DL" -gt 0 ]; then + $tc class add dev ${dev} parent 1:1 classid 1:$id htb rate "${DL}kbit" ceil "${DL}kbit" prio $id quantum 1500 + $tc qdisc add dev ${dev} parent 1:$id handle $id: sfq perturb 1 + $tc filter add dev ${dev} parent 1:0 prio $id protocol ip u32 \ + match ip dst "$mac"/"$Z" \ + classid 1:$id + elif [ "$DL" -eq 0 ]; then + $tc filter add dev ${dev} parent 1:0 prio 6 protocol ip u32 \ + match ip dst "$mac"/"$Z" \ + classid 1:1 + fi +} +check_time() { + local start=$1 + local end=$2 + local current=$(date +%H%M) + local start_min=$((10#${start:0:2}*60 + 10#${start:3:2})) + local end_min=$((10#${end:0:2}*60 + 10#${end:3:2})) + local current_min=$((10#${current:0:2}*60 + 10#${current:2:2})) + + if [[ $start_min -lt $end_min ]]; then + [[ $current_min -ge $start_min && $current_min -lt $end_min ]] + else + [[ $current_min -ge $start_min || $current_min -lt $end_min ]] + fi } check_list() { - i=$1 - checki='0' - start_time=$(uci -q get $NAME.@device[$i].timestart 2>/dev/null) - end_time=$(uci -q get $NAME.@device[$i].timeend 2>/dev/null) - wweek=`uci -q get $NAME.@device[$i].week ` - current_time=$(date +%H:%M) - current_weekday=$(date +%u) - [ "$start_time" = "$end_time" ] || { - [[ "$start_time" < "$end_time" ]] && { [[ "$current_time" > "$start_time" ]] && [[ "$current_time" < "$end_time" ]] || return ; } - [[ "$start_time" > "$end_time" ]] && { [[ "$current_time" < "$start_time" ]] && [[ "$current_time" > "$end_time" ]] || return ; } - } - for ww in `echo $wweek | sed 's/,/ /g' `; do - if [ $current_weekday = $ww ] || [ "x0" = "x$ww" ] ; then - checki='1' - fi - done - return + local i=$1 + local start_time=$(uci -q get $NAME.@device[$i].timestart 2>/dev/null) + local end_time=$(uci -q get $NAME.@device[$i].timeend 2>/dev/null) + local wweek=$(uci -q get $NAME.@device[$i].week 2>/dev/null) + local current_weekday=$(date +%u) + [ -z "$start_time" ] && [ -z "$end_time" ] && [ -z "$wweek" ] && return 0 + + if [ -n "$wweek" ] && [ "$wweek" != "0" ]; then + local day_match=0 + for day in $(echo $wweek | tr ',' ' '); do + [ "$day" -eq "$current_weekday" ] && day_match=1 && break + done + [ "$day_match" -eq 0 ] && return 1 + fi + + if [ -n "$start_time" ] && [ -n "$end_time" ]; then + check_time "$start_time" "$end_time" || return 1 + fi + + return 0 } case "$crrun" in - "stop") - stop_qos - touch $IDLIST - ;; - "start") - idlist=`uci show $NAME | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' | sed -e 's/^/!/g' -e 's/$/!/g' > $IDLIST ;cat $IDLIST | sed -e 's/!//g' ` - # [ $idlist ] || /etc/init.d/eqosplus stop - init_qosplus - checki='0' - for list in `echo $idlist | sed -e 's/!//g' ` ;do - check_list $list - if [ $checki == '1' ] ; then - mac=$(uci -q get $NAME.@device[$list].mac ) - DL=$(uci -q get $NAME.@device[$list].download 2>/dev/null | awk '{print $1*8*10^3}') - UL=$(uci -q get $NAME.@device[$list].upload 2>/dev/null | awk '{print $1*8*10^3}') - if is_macaddr $mac; then - add_mac $list - else - add_ip $list - fi - else - [ `cat $IDLIST 2>/dev/null | grep "!${list}!" | wc -l ` -gt 0 ] && { - del_id $list - sed -i "/!$list!/d" $IDLIST >/dev/null 2>&1 - } - fi - done - ;; - "add") - for list in `echo $crid | sed -e 's/!//g' | sed 's/,/ /g' ` ;do - mac=$(uci -q get $NAME.@device[$list].mac ) - DL=$(uci -q get $NAME.@device[$list].download 2>/dev/null | awk '{print $1*8*10^3}') - UL=$(uci -q get $NAME.@device[$list].upload 2>/dev/null | awk '{print $1*8*10^3}') - if is_macaddr $mac; then - add_mac $list - else - add_ip $list - fi - done - ;; - "del") - for list in `echo $crid | sed -e 's/!//g' | sed 's/,/ /g' ` ;do del_id $list; done - ;; - "status") - echo "### Statistics $dev ###" - echo "# qdiscs #" - tc -s qdisc show dev $dev - echo "# class #" - tc -s class show dev $dev - echo "# filter #" - tc -s filter show dev $dev root - tc -s filter show dev $dev parent 1: - echo "### Statistics ${dev}_ifb ###" - echo "# qdiscs #" - tc -s qdisc show dev ${dev}_ifb - echo "# class #" - tc -s class show dev ${dev}_ifb - echo "# filter #" - tc -s filter show dev ${dev}_ifb root - tc -s filter show dev ${dev}_ifb parent 1: - ;; + "stop") + stop_qos + ;; + "start") + init_qosplus + idlist=$(uci show $NAME | grep "enable='1'" | grep "device" | grep -oE '\[.*?\]' | grep -o '[0-9]' | sed -e 's/^/!/g' -e 's/$/!/g' > $IDLIST; cat $IDLIST | sed -e 's/!//g') + if [ ! -s "$IDLIST" ]; then + stop_qos + return 1 + fi -esac + for list in $(echo $idlist | sed -e 's/!//g'); do + if check_list $list; then + mac=$(uci -q get $NAME.@device[$list].mac) + DL=$(uci -q get $NAME.@device[$list].download 2>/dev/null | awk '{print $1*1000/8}') + UL=$(uci -q get $NAME.@device[$list].upload 2>/dev/null | awk '{print $1*1000/8}') + if is_macaddr $mac; then + add_mac $list + else + add_ip $list + fi + else + [ $(cat $IDLIST 2>/dev/null | grep "!${list}!" | wc -l) -gt 0 ] && { + del_id $list + sed -i "/!$list!/d" $IDLIST >/dev/null 2>&1 + } + fi + done + ;; + "add") + for list in $(echo $crid | sed -e 's/!//g' | sed 's/,/ /g'); do + mac=$(uci -q get $NAME.@device[$list].mac) + DL=$(uci -q get $NAME.@device[$list].download 2>/dev/null | awk '{print $1*1000/8}') + UL=$(uci -q get $NAME.@device[$list].upload 2>/dev/null | awk '{print $1*1000/8}') + if is_macaddr $mac; then + add_mac $list + else + add_ip $list + fi + done + ;; + "del") + for list in $(echo $crid | sed -e 's/!//g' | sed 's/,/ /g'); do + del_id $list + done + ;; + "status") + echo "### Statistics $dev ###" + echo "# qdiscs #" + tc -s qdisc show dev $dev + echo "# class #" + tc -s class show dev $dev + echo "# filter #" + tc -s filter show dev $dev root + tc -s filter show dev $dev parent 1: + echo "### Statistics ${dev}_ifb ###" + echo "# qdiscs #" + tc -s qdisc show dev ${dev}_ifb + echo "# class #" + tc -s class show dev ${dev}_ifb + echo "# filter #" + tc -s filter show dev ${dev}_ifb root + tc -s filter show dev ${dev}_ifb parent 1: + echo "### NFTables Rules ###" + nft list table inet ${NAME} 2>/dev/null + echo "### IPTables Rules ###" + iptables -t mangle -L ${NAME}_mark -n 2>/dev/null + ip6tables -t mangle -L ${NAME}_mark -n 2>/dev/null + ;; +esac \ No newline at end of file diff --git a/luci-app-eqosplus/root/usr/bin/eqosplusctrl b/luci-app-eqosplus/root/usr/bin/eqosplusctrl index cff09ce9c..9b5721d6b 100644 --- a/luci-app-eqosplus/root/usr/bin/eqosplusctrl +++ b/luci-app-eqosplus/root/usr/bin/eqosplusctrl @@ -1,7 +1,7 @@ #!/bin/sh # Copyright (C) 2006 OpenWrt.org -# Copyright 2022-2023 sirpdboy +# Copyright 2022-2025 sirpdboy NAME=eqosplus IDLIST="/var/$NAME.idlist" TMPID="/var/$NAME.tmpid" diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index 161284768..93fffe0ab 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -128,7 +128,6 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadow_TLS config PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs bool "Include Simple-Obfs (Shadowsocks Plugin)" - select PACKAGE_simple-obfs select PACKAGE_simple-obfs-client default y diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua index 93ba2b83b..d3b16f760 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua @@ -774,6 +774,18 @@ o.rmempty = false o = s2:option(ListValue, "node", translate("Socks Node")) +o = s2:option(DummyValue, "now_node", translate("Current Node")) +o.rawhtml = true +o.cfgvalue = function(_, n) + local current_node = api.get_cache_var("socks_" .. n) + if current_node then + local node = m:get(current_node) + if node then + return (api.get_node_remarks(node) or ""):gsub("(:)%[", "%1
[") + end + end +end + local n = 1 m.uci:foreach(appname, "socks", function(s) if s[".name"] == section then @@ -788,7 +800,7 @@ o.datatype = "port" o.rmempty = false if has_singbox or has_xray then - o = s2:option(Value, "http_port", "HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use")) + o = s2:option(Value, "http_port", "HTTP " .. translate("Listen Port")) o.default = 0 o.datatype = "port" end diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index 2163e7978..92c3ad032 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -100,6 +100,9 @@ msgstr "Socks 配置" msgid "Socks Node" msgstr "Socks 节点" +msgid "Current Node" +msgstr "当前节点" + msgid "Listen Port" msgstr "监听端口" diff --git a/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh b/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh index 91c69c355..ef4733d2a 100755 --- a/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh +++ b/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh @@ -31,7 +31,7 @@ test_url() { if /usr/bin/curl --help all | grep -q "\-\-retry-all-errors"; then extra_params="--retry-all-errors ${extra_params}" fi - status=$(/usr/bin/curl -I -o /dev/null -skL ${extra_params} --connect-timeout ${timeout} --retry ${try} -w %{http_code} "$url") + local status=$(/usr/bin/curl -I -o /dev/null -skL ${extra_params} --connect-timeout ${timeout} --retry ${try} -w %{http_code} "$url") case "$status" in 204) status=200 @@ -41,12 +41,12 @@ test_url() { } test_proxy() { - result=0 - status=$(test_url "${probe_url}" ${retry_num} ${connect_timeout} "-x socks5h://127.0.0.1:${socks_port}") + local result=0 + local status=$(test_url "${probe_url}" ${retry_num} ${connect_timeout} "-x socks5h://127.0.0.1:${socks_port}") if [ "$status" = "200" ]; then result=0 else - status2=$(test_url "https://www.baidu.com" ${retry_num} ${connect_timeout}) + local status2=$(test_url "https://www.baidu.com" ${retry_num} ${connect_timeout}) if [ "$status2" = "200" ]; then result=1 else @@ -68,7 +68,7 @@ test_node() { /usr/share/${CONFIG}/app.sh 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 local curlx="socks5h://127.0.0.1:${_tmp_port}" sleep 1s - _proxy_status=$(test_url "${probe_url}" ${retry_num} ${connect_timeout} "-x $curlx") + local _proxy_status=$(test_url "${probe_url}" ${retry_num} ${connect_timeout} "-x $curlx") # 结束 SS 插件进程 local pid_file="/tmp/etc/${CONFIG}/test_node_${node_id}_plugin.pid" [ -s "$pid_file" ] && kill -9 "$(head -n 1 "$pid_file")" >/dev/null 2>&1 @@ -82,14 +82,14 @@ test_node() { } test_auto_switch() { - flag=$(expr $flag + 1) + flag=$((flag + 1)) local b_nodes=$1 local now_node=$2 [ -z "$now_node" ] && { if [ -n "$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}")" ]; then now_node=$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") else - #echolog "自动切换检测:未知错误" + #echolog "Socks切换检测:未知错误" return 1 fi } @@ -98,58 +98,59 @@ test_auto_switch() { main_node=$now_node } - status=$(test_proxy) - if [ "$status" == 2 ]; then - echolog "自动切换检测:无法连接到网络,请检查网络是否正常!" + local status=$(test_proxy) + if [ "$status" = "2" ]; then + echolog "Socks切换检测:无法连接到网络,请检查网络是否正常!" return 2 fi #检测主节点是否能使用 - if [ "$restore_switch" == "1" ] && [ -n "$main_node" ] && [ "$now_node" != "$main_node" ]; then + if [ "$restore_switch" = "1" ] && [ -n "$main_node" ] && [ "$now_node" != "$main_node" ]; then test_node ${main_node} [ $? -eq 0 ] && { #主节点正常,切换到主节点 - echolog "自动切换检测:${id}主节点【$(config_n_get $main_node type):[$(config_n_get $main_node remarks)]】正常,切换到主节点!" + echolog "Socks切换检测:${id}主节点【$(config_n_get $main_node type):[$(config_n_get $main_node remarks)]】正常,切换到主节点!" /usr/share/${CONFIG}/app.sh socks_node_switch flag=${id} new_node=${main_node} [ $? -eq 0 ] && { - echolog "自动切换检测:${id}节点切换完毕!" + echolog "Socks切换检测:${id}节点切换完毕!" } return 0 } fi - if [ "$status" == 0 ]; then - #echolog "自动切换检测:${id}【$(config_n_get $now_node type):[$(config_n_get $now_node remarks)]】正常。" + if [ "$status" = "0" ]; then + #echolog "Socks切换检测:${id}【$(config_n_get $now_node type):[$(config_n_get $now_node remarks)]】正常。" return 0 - elif [ "$status" == 1 ]; then - echolog "自动切换检测:${id}【$(config_n_get $now_node type):[$(config_n_get $now_node remarks)]】异常,切换到下一个备用节点检测!" - local new_node - in_backup_nodes=$(echo $b_nodes | grep $now_node) - # 判断当前节点是否存在于备用节点列表里 - if [ -z "$in_backup_nodes" ]; then - # 如果不存在,设置第一个节点为新的节点 - new_node=$(echo $b_nodes | awk -F ' ' '{print $1}') + elif [ "$status" = "1" ]; then + local new_node msg + if [ "$backup_node_num" -gt 1 ]; then + # 有多个后备节点时 + local first_node found node + for node in $b_nodes; do + [ -z "$first_node" ] && first_node="$node" # 记录第一个节点 + [ "$found" = "1" ] && { new_node="$node"; break; } # 找到当前节点后取下一个 + [ "$node" = "$now_node" ] && found=1 # 标记找到当前节点 + done + # 如果没找到当前节点,或者当前节点是最后一个,就取第一个节点 + [ -z "$new_node" ] && new_node="$first_node" + msg="切换到$([ "$now_node" = "$main_node" ] && echo 备用节点 || echo 下一个备用节点)检测!" else - # 如果存在,设置下一个备用节点为新的节点 - #local count=$(expr $(echo $b_nodes | grep -o ' ' | wc -l) + 1) - local next_node=$(echo $b_nodes | awk -F "$now_node" '{print $2}' | awk -F " " '{print $1}') - if [ -z "$next_node" ]; then - new_node=$(echo $b_nodes | awk -F ' ' '{print $1}') - else - new_node=$next_node - fi + # 只有一个后备节点时,与主节点轮询 + new_node=$([ "$now_node" = "$main_node" ] && echo "$b_nodes" || echo "$main_node") + msg="切换到$([ "$now_node" = "$main_node" ] && echo 备用节点 || echo 主节点)检测!" fi + echolog "Socks切换检测:${id}【$(config_n_get $now_node type):[$(config_n_get $now_node remarks)]】异常,$msg" test_node ${new_node} if [ $? -eq 0 ]; then - [ "$restore_switch" == "0" ] && { - uci set $CONFIG.${id}.node=$new_node - [ -z "$(echo $b_nodes | grep $main_node)" ] && uci add_list $CONFIG.${id}.autoswitch_backup_node=$main_node - uci commit $CONFIG - } - echolog "自动切换检测:${id}【$(config_n_get $new_node type):[$(config_n_get $new_node remarks)]】正常,切换到此节点!" +# [ "$restore_switch" = "0" ] && { +# uci set $CONFIG.${id}.node=$new_node +# [ -z "$(echo $b_nodes | grep $main_node)" ] && uci add_list $CONFIG.${id}.autoswitch_backup_node=$main_node +# uci commit $CONFIG +# } + echolog "Socks切换检测:${id}【$(config_n_get $new_node type):[$(config_n_get $new_node remarks)]】正常,切换到此节点!" /usr/share/${CONFIG}/app.sh socks_node_switch flag=${id} new_node=${new_node} [ $? -eq 0 ] && { - echolog "自动切换检测:${id}节点切换完毕!" + echolog "Socks切换检测:${id}节点切换完毕!" } return 0 else @@ -166,12 +167,20 @@ start() { main_node=$(config_n_get $id node) socks_port=$(config_n_get $id port 0) delay=$(config_n_get $id autoswitch_testing_time 30) - sleep 5s connect_timeout=$(config_n_get $id autoswitch_connect_timeout 3) retry_num=$(config_n_get $id autoswitch_retry_num 1) restore_switch=$(config_n_get $id autoswitch_restore_switch 0) probe_url=$(config_n_get $id autoswitch_probe_url "https://www.google.com/generate_204") backup_node=$(config_n_get $id autoswitch_backup_node) + if [ -n "$backup_node" ]; then + backup_node=$(echo "$backup_node" | tr -s ' ' '\n' | uniq | tr -s '\n' ' ') + backup_node_num=$(printf "%s\n" "$backup_node" | wc -w) + if [ "$backup_node_num" -eq 1 ]; then + [ "$main_node" = "$backup_node" ] && return + fi + else + return + fi while [ -n "$backup_node" ]; do [ -f "$LOCK_FILE" ] && { sleep 6s @@ -183,7 +192,6 @@ start() { continue } touch $LOCK_FILE - backup_node=$(echo $backup_node | tr -s ' ' '\n' | uniq | tr -s '\n' ' ') test_auto_switch "$backup_node" rm -f $LOCK_FILE sleep ${delay} @@ -191,4 +199,3 @@ start() { } start $@ - diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua index 95aad5832..a5d7c4d21 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua @@ -344,78 +344,89 @@ o.rmempty = false -- [[ fragmen Settings ]]-- if is_finded("xray") then -s = m:section(TypedSection, "global_xray_fragment", translate("Xray Fragment Settings")) -s.anonymous = true + s = m:section(TypedSection, "global_xray_fragment", translate("Xray Fragment Settings")) + s.anonymous = true -o = s:option(Flag, "fragment", translate("Fragment"), translate("TCP fragments, which can deceive the censorship system in some cases, such as bypassing SNI blacklists.")) -o.default = 0 + o = s:option(Flag, "fragment", translate("Fragment"), translate("TCP fragments, which can deceive the censorship system in some cases, such as bypassing SNI blacklists.")) + o.default = 0 -o = s:option(ListValue, "fragment_packets", translate("Fragment Packets"), translate("\"1-3\" is for segmentation at TCP layer, applying to the beginning 1 to 3 data writes by the client. \"tlshello\" is for TLS client hello packet fragmentation.")) -o.default = "tlshello" -o:value("tlshello", "tlshello") -o:value("1-1", "1-1") -o:value("1-2", "1-2") -o:value("1-3", "1-3") -o:value("1-5", "1-5") -o:depends("fragment", true) + o = s:option(ListValue, "fragment_packets", translate("Fragment Packets"), translate("\"1-3\" is for segmentation at TCP layer, applying to the beginning 1 to 3 data writes by the client. \"tlshello\" is for TLS client hello packet fragmentation.")) + o.default = "tlshello" + o:value("tlshello", "tlshello") + o:value("1-1", "1-1") + o:value("1-2", "1-2") + o:value("1-3", "1-3") + o:value("1-5", "1-5") + o:depends("fragment", true) -o = s:option(Value, "fragment_length", translate("Fragment Length"), translate("Fragmented packet length (byte)")) -o.default = "100-200" -o:depends("fragment", true) + o = s:option(Value, "fragment_length", translate("Fragment Length"), translate("Fragmented packet length (byte)")) + o.default = "100-200" + o:depends("fragment", true) -o = s:option(Value, "fragment_interval", translate("Fragment Interval"), translate("Fragmentation interval (ms)")) -o.default = "10-20" -o:depends("fragment", true) + o = s:option(Value, "fragment_interval", translate("Fragment Interval"), translate("Fragmentation interval (ms)")) + o.default = "10-20" + o:depends("fragment", true) -o = s:option(Flag, "noise", translate("Noise"), translate("UDP noise, Under some circumstances it can bypass some UDP based protocol restrictions.")) -o.default = 0 + o = s:option(Value, "fragment_maxsplit", translate("Fragment maxSplit"), translate("Fragmented maxSplit (byte)")) + o.default = "100-200" + o:depends("fragment", true) -s = m:section(TypedSection, "xray_noise_packets", translate("Xray Noise Packets")) -s.description = translate( - "" .. translate("To send noise packets, select \"Noise\" in Xray Settings.") .. "" .. - "
" .. translate("For specific usage, see:") .. "" .. - "" .. - "" .. translate("Click to the page") .. "") -s.template = "cbi/tblsection" -s.sortable = true -s.anonymous = true -s.addremove = true + o = s:option(Flag, "noise", translate("Noise"), translate("UDP noise, Under some circumstances it can bypass some UDP based protocol restrictions.")) + o.default = 0 -s.remove = function(self, section) - for k, v in pairs(self.children) do - v.rmempty = true - v.validate = nil + s = m:section(TypedSection, "xray_noise_packets", translate("Xray Noise Packets")) + s.description = translate( + "" .. translate("To send noise packets, select \"Noise\" in Xray Settings.") .. "" .. + "
" .. translate("For specific usage, see:") .. "" .. + "" .. + "" .. translate("Click to the page") .. "") + s.template = "cbi/tblsection" + s.sortable = true + s.anonymous = true + s.addremove = true + + s.remove = function(self, section) + for k, v in pairs(self.children) do + v.rmempty = true + v.validate = nil + end + TypedSection.remove(self, section) end - TypedSection.remove(self, section) -end -o = s:option(Flag, "enabled", translate("Enable")) -o.default = 1 -o.rmempty = false + o = s:option(Flag, "enabled", translate("Enable")) + o.default = 1 + o.rmempty = false -o = s:option(ListValue, "type", translate("Type")) -o.default = "base64" -o:value("rand", "rand") -o:value("str", "str") -o:value("hex", "hex") -o:value("base64", "base64") + o = s:option(ListValue, "type", translate("Type")) + o.default = "base64" + o:value("rand", "rand") + o:value("str", "str") + o:value("hex", "hex") + o:value("base64", "base64") -o = s:option(Value, "domainStrategy", translate("Domain Strategy")) -o.default = "UseIP" -o:value("AsIs", "AsIs") -o:value("UseIP", "UseIP") -o:value("UseIPv4", "UseIPv4") -o:value("ForceIP", "ForceIP") -o:value("ForceIPv4", "ForceIPv4") -o.rmempty = false + o = s:option(Value, "domainStrategy", translate("Domain Strategy")) + o.default = "UseIP" + o:value("AsIs", "AsIs") + o:value("UseIP", "UseIP") + o:value("UseIPv4", "UseIPv4") + o:value("ForceIP", "ForceIP") + o:value("ForceIPv4", "ForceIPv4") + o.rmempty = false -o = s:option(Value, "packet", translate("Packet")) -o.datatype = "minlength(1)" -o.rmempty = false + o = s:option(Value, "packet", translate("Packet")) + o.datatype = "minlength(1)" + o.rmempty = false -o = s:option(Value, "delay", translate("Delay (ms)")) -o.datatype = "or(uinteger,portrange)" -o.rmempty = false + o = s:option(Value, "delay", translate("Delay (ms)")) + o.datatype = "or(uinteger,portrange)" + o.rmempty = false + + o = s:option(Value, "applyto", translate("ApplyTo (IP type)")) + o.default = "IP" + o:value("IP", "IP") + o:value("IPV4", "IPv4") + o:value("IPV6", "IPv6") + o.rmempty = false end return m diff --git a/luci-app-ssr-plus/po/templates/ssr-plus.pot b/luci-app-ssr-plus/po/templates/ssr-plus.pot index 7ad8e5a91..55f7c2a16 100644 --- a/luci-app-ssr-plus/po/templates/ssr-plus.pot +++ b/luci-app-ssr-plus/po/templates/ssr-plus.pot @@ -64,7 +64,7 @@ msgstr "" msgid "8 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:375 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:379 msgid "" msgstr "" @@ -173,6 +173,10 @@ msgstr "" msgid "Apply" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:424 +msgid "ApplyTo (IP type)" +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:133 msgid "Are you sure you want to restore the client to default settings?" msgstr "" @@ -313,7 +317,7 @@ msgstr "" msgid "Click here to view or manage the DNS list file" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:378 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:382 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:833 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1138 msgid "Click to the page" @@ -477,7 +481,7 @@ msgid "" "fastest_addr (default: load_balance)." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:416 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:420 msgid "Delay (ms)" msgstr "" @@ -542,7 +546,7 @@ msgstr "" msgid "DoT upstream (Need use wolfssl version)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:403 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:407 msgid "Domain Strategy" msgstr "" @@ -568,7 +572,7 @@ msgid "Edit ShadowSocksR Server" msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:263 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:392 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:396 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:82 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:101 msgid "Enable" @@ -741,7 +745,7 @@ msgid "" "Chinese CDN IP addresses" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:376 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:380 msgid "For specific usage, see:" msgstr "" @@ -771,10 +775,18 @@ msgstr "" msgid "Fragment Packets" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 +msgid "Fragment maxSplit" +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:366 msgid "Fragmentation interval (ms)" msgstr "" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 +msgid "Fragmented maxSplit (byte)" +msgstr "" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:362 msgid "Fragmented packet length (byte)" msgstr "" @@ -1223,7 +1235,7 @@ msgstr "" msgid "No specify upload file." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:374 msgid "Noise" msgstr "" @@ -1323,7 +1335,7 @@ msgstr "" msgid "Oversea Mode DNS-2 (114.114.115.115)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:416 msgid "Packet" msgstr "" @@ -1857,7 +1869,7 @@ msgstr "" msgid "Tips: Dnsproxy DNS Parse List Path:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:375 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:379 msgid "To send noise packets, select \"Noise\" in Xray Settings." msgstr "" @@ -1878,7 +1890,7 @@ msgstr "" msgid "Trojan" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:396 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:400 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:185 msgid "Type" msgstr "" @@ -1887,7 +1899,7 @@ msgstr "" msgid "UDP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:374 msgid "" "UDP noise, Under some circumstances it can bypass some UDP based protocol " "restrictions." @@ -2160,7 +2172,7 @@ msgstr "" msgid "Xray Fragment Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:377 msgid "Xray Noise Packets" msgstr "" diff --git a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po index c96ef4af3..ee2ff5996 100644 --- a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po +++ b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po @@ -66,7 +66,7 @@ msgstr "" msgid "8 Threads" msgstr "8 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:375 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:379 msgid "" msgstr "" @@ -175,6 +175,10 @@ msgstr "Apple 域名解析优化" msgid "Apply" msgstr "应用" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:424 +msgid "ApplyTo (IP type)" +msgstr "ApplyTo(IP 类型)" + #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm:133 msgid "Are you sure you want to restore the client to default settings?" msgstr "是否真的要恢复客户端默认配置?" @@ -315,7 +319,7 @@ msgstr "清空日志" msgid "Click here to view or manage the DNS list file" msgstr "点击此处查看或管理 DNS 列表文件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:378 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:382 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:833 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1138 msgid "Click to the page" @@ -487,7 +491,7 @@ msgstr "" "定义上游逻辑模式,可选择值:负载均衡、并行查询、最快响应(默认值:负载均" "衡)。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:416 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:420 msgid "Delay (ms)" msgstr "延迟(ms)" @@ -552,7 +556,7 @@ msgstr "是否要恢复客户端默认配置?" msgid "DoT upstream (Need use wolfssl version)" msgstr "DoT 上游(需使用 wolfssl 版本)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:403 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:407 msgid "Domain Strategy" msgstr "域名解析策略" @@ -578,7 +582,7 @@ msgid "Edit ShadowSocksR Server" msgstr "编辑服务器配置" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:263 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:392 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:396 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:82 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:101 msgid "Enable" @@ -751,7 +755,7 @@ msgid "" "Chinese CDN IP addresses" msgstr "配备中国大陆 CDN 的 Apple 域名,始终应答中国大陆 CDN 地址" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:376 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:380 msgid "For specific usage, see:" msgstr "具体使用方法,请参见:" @@ -781,10 +785,18 @@ msgstr "分片包长" msgid "Fragment Packets" msgstr "分片方式" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 +msgid "Fragment maxSplit" +msgstr "分片数据包拆分" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:366 msgid "Fragmentation interval (ms)" msgstr "分片间隔(ms)" +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 +msgid "Fragmented maxSplit (byte)" +msgstr "分片数据包的拆分数量 (byte)" + #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:362 msgid "Fragmented packet length (byte)" msgstr "分片包长 (byte)" @@ -1236,7 +1248,7 @@ msgstr "你已经是最新数据,无需更新!" msgid "No specify upload file." msgstr "没有上传证书。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:374 msgid "Noise" msgstr "噪声" @@ -1336,7 +1348,7 @@ msgstr "" msgid "Oversea Mode DNS-2 (114.114.115.115)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:416 msgid "Packet" msgstr "数据包" @@ -1873,7 +1885,7 @@ msgstr "连接超时时间(单位:秒)" msgid "Tips: Dnsproxy DNS Parse List Path:" msgstr "提示:Dnsproxy 的 DNS 解析列表路径:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:375 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:379 msgid "To send noise packets, select \"Noise\" in Xray Settings." msgstr "在 Xray 设置中勾选 “噪声” 以发送噪声包。" @@ -1894,7 +1906,7 @@ msgstr "传输协议" msgid "Trojan" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:396 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:400 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:185 msgid "Type" msgstr "类型" @@ -1903,7 +1915,7 @@ msgstr "类型" msgid "UDP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:370 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:374 msgid "" "UDP noise, Under some circumstances it can bypass some UDP based protocol " "restrictions." @@ -2178,7 +2190,7 @@ msgstr "XHTTP 路径" msgid "Xray Fragment Settings" msgstr "Xray 分片设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:377 msgid "Xray Noise Packets" msgstr "Xray 噪声数据包" diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua index d5bc9804b..f919f7277 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua @@ -338,13 +338,15 @@ if xray_fragment.fragment ~= "0" or (xray_fragment.noise ~= "0" and xray_noise.e fragment = (xray_fragment.fragment == "1") and { packets = (xray_fragment.fragment_packets ~= "") and xray_fragment.fragment_packets or nil, length = (xray_fragment.fragment_length ~= "") and xray_fragment.fragment_length or nil, - interval = (xray_fragment.fragment_interval ~= "") and xray_fragment.fragment_interval or nil + interval = (xray_fragment.fragment_interval ~= "") and xray_fragment.fragment_interval or nil, + maxSplit = (xray_fragment.fragment_maxsplit ~= "") and xray_fragment.fragment_maxsplit or nil } or nil, noises = (xray_fragment.noise == "1" and xray_noise.enabled == "1") and { { type = xray_noise.type, packet = xray_noise.packet, - delay = xray_noise.delay:find("-") and xray_noise.delay or tonumber(xray_noise.delay) + delay = xray_noise.delay:find("-") and xray_noise.delay or tonumber(xray_noise.delay), + applyTo = xray_noise.applyto } } or nil },