Browse Source

Merge pull request #1816 from zxlhhyccc/tuic

luci-app-ssr-plus: Add missing `nft` support and optimize code
zxl hhyccc 4 days ago
parent
commit
9c374823d8

+ 99 - 46
luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua

@@ -28,8 +28,9 @@ function index()
 	entry({"admin", "services", "shadowsocksr", "reset"}, call("act_reset"))
 	entry({"admin", "services", "shadowsocksr", "reset"}, call("act_reset"))
 	entry({"admin", "services", "shadowsocksr", "restart"}, call("act_restart"))
 	entry({"admin", "services", "shadowsocksr", "restart"}, call("act_restart"))
 	entry({"admin", "services", "shadowsocksr", "delete"}, call("act_delete"))
 	entry({"admin", "services", "shadowsocksr", "delete"}, call("act_delete"))
-	--[[Backup]]
+		--[[Backup]]
 	entry({"admin", "services", "shadowsocksr", "backup"}, call("create_backup")).leaf = true
 	entry({"admin", "services", "shadowsocksr", "backup"}, call("create_backup")).leaf = true
+	
 end
 end
 
 
 function subscribe()
 function subscribe()
@@ -46,40 +47,74 @@ function act_status()
 end
 end
 
 
 function act_ping()
 function act_ping()
-	local e = {}
-	local domain = luci.http.formvalue("domain")
-	local port = luci.http.formvalue("port")
-	local transport = luci.http.formvalue("transport")
-	local wsPath = luci.http.formvalue("wsPath")
-	local tls = luci.http.formvalue("tls")
-	e.index = luci.http.formvalue("index")
-	local iret = luci.sys.call("ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null")
-	if transport == "ws" then
-		local prefix = tls=='1' and "https://" or "http://"
-		local address = prefix..domain..':'..port..wsPath
-		local result = luci.sys.exec("curl --http1.1 -m 2 -ksN -o /dev/null -w 'time_connect=%{time_connect}\nhttp_code=%{http_code}' -H 'Connection: Upgrade' -H 'Upgrade: websocket' -H 'Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==' -H 'Sec-WebSocket-Version: 13' "..address)
-		e.socket = string.match(result,"http_code=(%d+)")=="101"
-		e.ping = tonumber(string.match(result, "time_connect=(%d+.%d%d%d)"))*1000
-	else
-		local socket = nixio.socket("inet", "stream")
-		socket:setopt("socket", "rcvtimeo", 3)
-		socket:setopt("socket", "sndtimeo", 3)
-		e.socket = socket:connect(domain, port)
-		socket:close()
-		e.ping = luci.sys.exec(string.format("echo -n $(tcping -q -c 1 -i 1 -t 2 -p %s %s 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null", port, domain))
-		if (e.ping == "") then
-			e.ping = luci.sys.exec("echo -n $(ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null" % domain)
-			if (e.ping == "") then
-				-- UDP ping test using nping
-				e.ping = luci.sys.exec(string.format("echo -n $(nping --udp -c 1 -p %s %s 2>/dev/null | grep -o 'Avg rtt: [0-9.]*ms' | awk '{print $3}' | sed 's/ms//' | head -1) 2>/dev/null", port, domain))
-			end
-		end
-	end
-	if (iret == 0) then
-		luci.sys.call(" ipset del ss_spec_wan_ac " .. domain)
-	end
-	luci.http.prepare_content("application/json")
-	luci.http.write_json(e)
+    local e = {}
+    local domain = luci.http.formvalue("domain")
+    local port = tonumber(luci.http.formvalue("port") or 0)
+    local transport = luci.http.formvalue("transport")
+    local wsPath = luci.http.formvalue("wsPath") or ""
+    local tls = luci.http.formvalue("tls")
+    e.index = luci.http.formvalue("index")
+
+    local use_nft = luci.sys.call("command -v nft >/dev/null") == 0
+    local iret = false
+
+    if use_nft then
+        iret = luci.sys.call("nft add element inet ss_spec ss_spec_wan_ac { " .. domain .. " } 2>/dev/null") == 0
+    else
+        iret = luci.sys.call("ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null") == 0
+    end
+
+    if transport == "ws" then
+        local prefix = tls == '1' and "https://" or "http://"
+        local address = prefix .. domain .. ':' .. port .. wsPath
+        local result = luci.sys.exec(
+            "curl --http1.1 -m 2 -ksN -o /dev/null " ..
+            "-w 'time_connect=%{time_connect}\nhttp_code=%{http_code}' " ..
+            "-H 'Connection: Upgrade' -H 'Upgrade: websocket' " ..
+            "-H 'Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==' " ..
+            "-H 'Sec-WebSocket-Version: 13' " .. address
+        )
+        e.socket = string.match(result,"http_code=(%d+)") == "101"
+        local ping_time = tonumber(string.match(result, "time_connect=(%d+.%d%d%d)"))
+        e.ping = ping_time and ping_time * 1000 or nil
+    else
+        -- TCP ping
+        local socket = nixio.socket("inet", "stream")
+        socket:setopt("socket", "rcvtimeo", 3)
+        socket:setopt("socket", "sndtimeo", 3)
+        e.socket = socket:connect(domain, port)
+        socket:close()
+
+        e.ping = tonumber(luci.sys.exec(string.format(
+            "tcping -q -c 1 -i 1 -t 2 -p %d %s 2>/dev/null | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}'",
+            port, domain
+        )))
+
+        if not e.ping then
+            e.ping = tonumber(luci.sys.exec(string.format(
+                "ping -c 1 -W 1 %s 2>/dev/null | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}'",
+                domain
+            )))
+        end
+
+        if not e.ping then
+            e.ping = tonumber(luci.sys.exec(string.format(
+                "nping --udp -c 1 -p %d %s 2>/dev/null | grep -o 'Avg rtt: [0-9.]*ms' | awk '{print $3}' | sed 's/ms//' | head -1",
+                port, domain
+            )))
+        end
+    end
+
+    if iret then
+        if use_nft then
+            luci.sys.call("nft delete element inet ss_spec ss_spec_wan_ac { " .. domain .. " } 2>/dev/null")
+        else
+            luci.sys.call("ipset del ss_spec_wan_ac " .. domain .. " 2>/dev/null")
+        end
+    end
+
+    luci.http.prepare_content("application/json")
+    luci.http.write_json(e)
 end
 end
 
 
 function check_status()
 function check_status()
@@ -101,28 +136,46 @@ function check_port()
 	local s
 	local s
 	local server_name = ""
 	local server_name = ""
 	local uci = require "luci.model.uci".cursor()
 	local uci = require "luci.model.uci".cursor()
-	local iret = 1
+	local use_nft = luci.sys.call("command -v nft >/dev/null") == 0
+
 	uci:foreach("shadowsocksr", "servers", function(s)
 	uci:foreach("shadowsocksr", "servers", function(s)
 		if s.alias then
 		if s.alias then
 			server_name = s.alias
 			server_name = s.alias
 		elseif s.server and s.server_port then
 		elseif s.server and s.server_port then
-			server_name = "%s:%s" % {s.server, s.server_port}
+			server_name = s.server .. ":" .. s.server_port
+		end
+
+		-- 临时加入 set
+		local iret = false
+		if use_nft then
+			iret = luci.sys.call("nft add element inet ss_spec ss_spec_wan_ac { " .. s.server .. " } 2>/dev/null") == 0
+		else
+			iret = luci.sys.call("ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null") == 0
 		end
 		end
-		iret = luci.sys.call("ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null")
-		socket = nixio.socket("inet", "stream")
+
+		-- TCP 测试
+		local socket = nixio.socket("inet", "stream")
 		socket:setopt("socket", "rcvtimeo", 3)
 		socket:setopt("socket", "rcvtimeo", 3)
 		socket:setopt("socket", "sndtimeo", 3)
 		socket:setopt("socket", "sndtimeo", 3)
-		ret = socket:connect(s.server, s.server_port)
-		if tostring(ret) == "true" then
-			socket:close()
-			retstring = retstring .. "<font><b style='color:green'>[" .. server_name .. "] OK.</b></font><br />"
+		local ret = socket:connect(s.server, s.server_port)
+		socket:close()
+
+		if ret then
+			retstring = retstring .. string.format("<font><b style='color:green'>[%s] OK.</b></font><br />", server_name)
 		else
 		else
-			retstring = retstring .. "<font><b style='color:red'>[" .. server_name .. "] Error.</b></font><br />"
+			retstring = retstring .. string.format("<font><b style='color:red'>[%s] Error.</b></font><br />", server_name)
 		end
 		end
-		if iret == 0 then
-			luci.sys.call("ipset del ss_spec_wan_ac " .. s.server)
+
+		-- 删除临时 set
+		if iret then
+			if use_nft then
+				luci.sys.call("nft delete element inet ss_spec ss_spec_wan_ac { " .. s.server .. " } 2>/dev/null")
+			else
+				luci.sys.call("ipset del ss_spec_wan_ac " .. s.server)
+			end
 		end
 		end
 	end)
 	end)
+
 	luci.http.prepare_content("application/json")
 	luci.http.prepare_content("application/json")
 	luci.http.write_json({ret = retstring})
 	luci.http.write_json({ret = retstring})
 end
 end

+ 11 - 3
luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua

@@ -4,14 +4,22 @@ local uci = require "luci.model.uci".cursor()
 -- 获取 LAN IP 地址
 -- 获取 LAN IP 地址
 function lanip()
 function lanip()
 	local lan_ip
 	local lan_ip
-	lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' | tr -d '\n'")
 
 
+	-- 尝试从 UCI 直接读取
+	lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F'/' '{print $1}' | tr -d '\\n'")
+
+	-- 尝试从 LAN 接口信息中读取(优先 ifname,再 fallback 到 device)
 	if not lan_ip or lan_ip == "" then
 	if not lan_ip or lan_ip == "" then
-    	lan_ip = luci.sys.exec("ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w 'inet' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n'")
+		lan_ip = luci.sys.exec([[
+ip -4 addr show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) 2>/dev/null \
+  | grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
 	end
 	end
 
 
+	-- 取任意一个 global IPv4 地址
 	if not lan_ip or lan_ip == "" then
 	if not lan_ip or lan_ip == "" then
-    	lan_ip = luci.sys.exec("ip addr show | grep -w 'inet' | grep 'global' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n'")
+		lan_ip = luci.sys.exec([[
+ip -4 addr show scope global 2>/dev/null \
+  | grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
 	end
 	end
 
 
 	return lan_ip
 	return lan_ip

+ 11 - 3
luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua

@@ -8,14 +8,22 @@ local uci = require "luci.model.uci".cursor()
 -- 获取 LAN IP 地址
 -- 获取 LAN IP 地址
 function lanip()
 function lanip()
 	local lan_ip
 	local lan_ip
-	lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' | tr -d '\n'")
 
 
+	-- 尝试从 UCI 直接读取
+	lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F'/' '{print $1}' | tr -d '\\n'")
+
+	-- 尝试从 LAN 接口信息中读取(优先 ifname,再 fallback 到 device)
 	if not lan_ip or lan_ip == "" then
 	if not lan_ip or lan_ip == "" then
-    	lan_ip = luci.sys.exec("ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w 'inet' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n'")
+		lan_ip = luci.sys.exec([[
+ip -4 addr show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) 2>/dev/null \
+  | grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
 	end
 	end
 
 
+	-- 取任意一个 global IPv4 地址
 	if not lan_ip or lan_ip == "" then
 	if not lan_ip or lan_ip == "" then
-    	lan_ip = luci.sys.exec("ip addr show | grep -w 'inet' | grep 'global' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n'")
+		lan_ip = luci.sys.exec([[
+ip -4 addr show scope global 2>/dev/null \
+  | grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
 	end
 	end
 
 
 	return lan_ip
 	return lan_ip