| 
					
				 | 
			
			
				@@ -28,8 +28,9 @@ function index() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	entry({"admin", "services", "shadowsocksr", "reset"}, call("act_reset")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	entry({"admin", "services", "shadowsocksr", "restart"}, call("act_restart")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	entry({"admin", "services", "shadowsocksr", "delete"}, call("act_delete")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	--[[Backup]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		--[[Backup]] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	entry({"admin", "services", "shadowsocksr", "backup"}, call("create_backup")).leaf = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 end 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 function subscribe() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -46,40 +47,74 @@ function act_status() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 end 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 function check_status() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -101,28 +136,46 @@ function check_port() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	local s 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	local server_name = "" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if s.alias then 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			server_name = s.alias 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		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", "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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			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 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		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) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	luci.http.prepare_content("application/json") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	luci.http.write_json({ret = retstring}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 end 
			 |