Merge Mainline
This commit is contained in:
commit
d6d3518a46
@ -14,7 +14,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/lrinQVQ/openwrt-chinadns/releases/download/v$(PKG_VERSION)
|
||||
PKG_MD5SUM:=5c7aa6a89a969a1dd6469b4808b0759b
|
||||
PKG_HASH:=caab37a27c444d917f0b92c65d7082543dc22acc7c24322be07a108a44794369
|
||||
|
||||
PKG_LICENSE:=GPLv3
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
@ -11,6 +11,7 @@ PKG_VERSION:=1.2.2
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/cbeuw/GoQuiet.git
|
||||
PKG_MIRROR_HASH:=d16557d89ac909877128729590e34a3c7a9b430000525ed133e2fffb56a0310a
|
||||
PKG_SOURCE_VERSION:=013cdfdf72000dcd4691799c37a0cf960ab4c82f
|
||||
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)
|
||||
|
||||
@ -13,6 +13,7 @@ PKG_RELEASE:=1
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_DATE:=2020-12-15
|
||||
PKG_SOURCE_URL:=https://github.com/iawia002/annie.git
|
||||
PKG_MIRROR_HASH:=7ee175f0dec4ca2efbaaca746f33ab3f138d70c76eca1f87d1e3950478f4e110
|
||||
PKG_SOURCE_VERSION:=abc3c9df18173c91a5ca7a77fecc0665dea01aa1
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION)
|
||||
|
||||
@ -13,7 +13,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=@SF/cups-bjnp
|
||||
PKG_MD5SUM:=8a337091b65abfdd70191129efefb9b3
|
||||
PKG_HASH:=2acb716680d66f1378cf8dcd45fedf7f72ccc9b66fa80214d6dcb042b5e3c9ab
|
||||
|
||||
PKG_BUILD_DEPENDS:=cups
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-source.tar.gz
|
||||
PKG_SOURCE_URL:=http://www.cups.org/software/$(PKG_VERSION)
|
||||
PKG_MD5SUM:=9f9bf6e3b9c20a3519b4dc409666d6e7
|
||||
PKG_HASH:=4b14fd833180ac529ebebea766a09094c2568bf8426e219cb3a1715304ef728d
|
||||
|
||||
TARGET_LDFLAGS+=-Wl,-rpath-link=$(STAGING_DIR)/usr/lib
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/svaarala/duktape.git
|
||||
PKG_MIRROR_HASH:=7e9caaf9c7e82bc01f859019359b3a13fa038f0e5e82a6541687a30c1ccfa604
|
||||
PKG_SOURCE_VERSION:=19cc8f5bb855791ff55cbf60d2cea72df485e86f
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
|
||||
@ -6,6 +6,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/ginuerzh/gost.git
|
||||
PKG_MIRROR_HASH:=dfe0d9b548a71b1d476cecf434cce094594ee46a7b0563284c902bec4fc01a3f
|
||||
PKG_SOURCE_VERSION:=2707a8f0a90e111fc009791a6a911405939a25fb
|
||||
PKG_MAINTAINER:=[CTCGFW] Project OpenWrt
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/xxxserxxx/gotop.git
|
||||
PKG_MIRROR_HASH:=b4de9c3fdd144f57dfd713471c9ac7e99ff82b110e1dc0d7ecf1e3d0aaf5058d
|
||||
PKG_SOURCE_VERSION:=a8a238ac18725e377addae8a23bf08cf476b404c
|
||||
PKG_MAINTAINER:=[CTCGFW] Project OpenWrt
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/1715173329/gowebdav.git
|
||||
PKG_MIRROR_HASH:=6917c641ede5edc31de16b38686c8d42b1d327fe99d744972eafc544750c4c0f
|
||||
PKG_SOURCE_VERSION:=8b30e5453e959fd9911a90f2d4f7421616285ffa
|
||||
PKG_MAINTAINER:=CN_SZTL <cnsztl@project-openwrt.eu.org>
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ PKG_MAINTAINER:=fabled
|
||||
PKG_LICENSE:=MIT
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=f9b870968f75c8020a311cca2482139ac8b2b55d4f1b5b0ce00f7844b083c866
|
||||
PKG_MIRROR_HASH:=8aff0958546e4082d48854fdeb32f4fd1ef6a9f78ef066a1886f4d9569898d0e
|
||||
PKG_SOURCE_URL:=https://github.com/fabled/lua-maxminddb.git
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_VERSION:=93da9f4e6c814c3a23044dd2cdd22d4a6b4f665b
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-diskman
|
||||
PKG_VERSION:=v0.2.10
|
||||
PKG_VERSION:=v0.2.11
|
||||
PKG_RELEASE:=beta
|
||||
PKG_MAINTAINER:=lisaac <https://github.com/lisaac/luci-app-diskman>
|
||||
PKG_LICENSE:=AGPL-3.0
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/lisaac/luci-app-diskman.git
|
||||
PKG_MIRROR_HASH:=b5ece7cb3918b9ca7ea0aabbf2e7b637ebf2b71ea2654117065c57079fad7df3
|
||||
PKG_SOURCE_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)
|
||||
|
||||
@ -1 +0,0 @@
|
||||
e2fsprogs parted smartmontools blkid mdadm btrfs-progs util-linux
|
||||
@ -1,155 +0,0 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
|
||||
]]--
|
||||
|
||||
require "luci.util"
|
||||
module("luci.controller.diskman",package.seeall)
|
||||
|
||||
function index()
|
||||
-- check all used executables in disk management are existed
|
||||
local CMD = {"parted", "blkid", "smartctl"}
|
||||
local executables_all_existed = true
|
||||
for _, cmd in ipairs(CMD) do
|
||||
local command = luci.sys.exec("/usr/bin/which " .. cmd)
|
||||
if not command:match(cmd) then
|
||||
executables_all_existed = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not executables_all_existed then return end
|
||||
-- entry(path, target, title, order)
|
||||
-- set leaf attr to true to pass argument throughe url (e.g. admin/system/disk/partition/sda)
|
||||
entry({"admin", "system", "diskman"}, alias("admin", "system", "diskman", "disks"), _("Disk Man"), 55)
|
||||
entry({"admin", "system", "diskman", "disks"}, form("diskman/disks"), nil).leaf = true
|
||||
entry({"admin", "system", "diskman", "partition"}, form("diskman/partition"), nil).leaf = true
|
||||
entry({"admin", "system", "diskman", "btrfs"}, form("diskman/btrfs"), nil).leaf = true
|
||||
entry({"admin", "system", "diskman", "format_partition"}, call("format_partition"), nil).leaf = true
|
||||
entry({"admin", "system", "diskman", "get_disk_info"}, call("get_disk_info"), nil).leaf = true
|
||||
entry({"admin", "system", "diskman", "mk_p_table"}, call("mk_p_table"), nil).leaf = true
|
||||
entry({"admin", "system", "diskman", "smartdetail"}, call("smart_detail"), nil).leaf = true
|
||||
entry({"admin", "system", "diskman", "smartattr"}, call("smart_attr"), nil).leaf = true
|
||||
end
|
||||
|
||||
function format_partition()
|
||||
local partation_name = luci.http.formvalue("partation_name")
|
||||
local fs = luci.http.formvalue("file_system")
|
||||
if not partation_name then
|
||||
luci.http.status(500, "Partition NOT found!")
|
||||
luci.http.write_json("Partition NOT found!")
|
||||
return
|
||||
elseif not nixio.fs.access("/dev/"..partation_name) then
|
||||
luci.http.status(500, "Partition NOT found!")
|
||||
luci.http.write_json("Partition NOT found!")
|
||||
return
|
||||
elseif not fs then
|
||||
luci.http.status(500, "no file system")
|
||||
luci.http.write_json("no file system")
|
||||
return
|
||||
end
|
||||
local dm = require "luci.model.diskman"
|
||||
code, msg = dm.format_partition(partation_name, fs)
|
||||
luci.http.status(code, msg)
|
||||
luci.http.write_json(msg)
|
||||
end
|
||||
|
||||
function get_disk_info(dev)
|
||||
if not dev then
|
||||
luci.http.status(500, "no device")
|
||||
luci.http.write_json("no device")
|
||||
return
|
||||
elseif not nixio.fs.access("/dev/"..dev) then
|
||||
luci.http.status(500, "no device")
|
||||
luci.http.write_json("no device")
|
||||
return
|
||||
end
|
||||
local dm = require "luci.model.diskman"
|
||||
local device_info = dm.get_disk_info(dev)
|
||||
luci.http.status(200, "ok")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(device_info)
|
||||
end
|
||||
|
||||
function mk_p_table()
|
||||
local p_table = luci.http.formvalue("p_table")
|
||||
local dev = luci.http.formvalue("dev")
|
||||
if not dev then
|
||||
luci.http.status(500, "no device")
|
||||
luci.http.write_json("no device")
|
||||
return
|
||||
elseif not nixio.fs.access("/dev/"..dev) then
|
||||
luci.http.status(500, "no device")
|
||||
luci.http.write_json("no device")
|
||||
return
|
||||
end
|
||||
local dm = require "luci.model.diskman"
|
||||
if p_table == "GPT" or p_table == "MBR" then
|
||||
p_table = p_table == "MBR" and "msdos" or "gpt"
|
||||
local res = luci.sys.call(dm.command.parted .. " -s /dev/" .. dev .. " mktable ".. p_table)
|
||||
if res == 0 then
|
||||
luci.http.status(200, "ok")
|
||||
else
|
||||
luci.http.status(500, "command exec error")
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({code=res})
|
||||
else
|
||||
luci.http.status(404, "not support")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({code="1"})
|
||||
end
|
||||
end
|
||||
|
||||
function smart_detail(dev)
|
||||
luci.template.render("diskman/smart_detail", {dev=dev})
|
||||
end
|
||||
|
||||
function smart_attr(dev)
|
||||
local dm = require "luci.model.diskman"
|
||||
local cmd = io.popen(dm.command.smartctl .. " --attributes /dev/%s" % dev)
|
||||
if cmd then
|
||||
local attr = { }
|
||||
if dev:match("nvme")then
|
||||
while true do
|
||||
local ln = cmd:read("*l")
|
||||
if not ln then
|
||||
break
|
||||
elseif ln:match("^(.-):%s+(.+)") then
|
||||
local key, value = ln:match("^(.-):%s+(.+)")
|
||||
attr[#attr+1]= {
|
||||
key = key,
|
||||
value = value
|
||||
}
|
||||
end
|
||||
end
|
||||
else
|
||||
while true do
|
||||
local ln = cmd:read("*l")
|
||||
if not ln then
|
||||
break
|
||||
elseif ln:match("^.*%d+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+") then
|
||||
local id,attrbute,flag,value,worst,thresh,type,updated,raw = ln:match("^%s*(%d+)%s+([%a%p]+)%s+(%w+)%s+(%d+)%s+(%d+)%s+(%d+)%s+([%a%p]+)%s+(%a+)%s+[%w%p]+%s+(.+)")
|
||||
id= "%x" % id
|
||||
if not id:match("^%w%w") then
|
||||
id = "0%s" % id
|
||||
end
|
||||
attr[#attr+1]= {
|
||||
id = id:upper(),
|
||||
attrbute = attrbute,
|
||||
flag = flag,
|
||||
value = value,
|
||||
worst = worst,
|
||||
thresh = thresh,
|
||||
type = type,
|
||||
updated = updated,
|
||||
raw = raw
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
cmd:close()
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(attr)
|
||||
end
|
||||
end
|
||||
@ -1,210 +0,0 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
|
||||
]]--
|
||||
|
||||
require "luci.util"
|
||||
require("luci.tools.webadmin")
|
||||
local dm = require "luci.model.diskman"
|
||||
local uuid = arg[1]
|
||||
|
||||
if not uuid then luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) end
|
||||
|
||||
-- mount subv=/ to tempfs
|
||||
mount_point = "/tmp/.btrfs_tmp"
|
||||
nixio.fs.mkdirr(mount_point)
|
||||
luci.util.exec(dm.command.umount .. " "..mount_point .. " >/dev/null 2>&1")
|
||||
luci.util.exec(dm.command.mount .. " -t btrfs -o subvol=/ UUID="..uuid.." "..mount_point)
|
||||
|
||||
m = SimpleForm("btrfs", translate("Btrfs"), translate("Manage Btrfs"))
|
||||
m.template = "diskman/cbi/xsimpleform"
|
||||
m.redirect = luci.dispatcher.build_url("admin/system/diskman")
|
||||
m.submit = false
|
||||
m.reset = false
|
||||
|
||||
-- info
|
||||
local btrfs_info = dm.get_btrfs_info(mount_point)
|
||||
local table_btrfs_info = m:section(Table, {btrfs_info}, translate("Btrfs Info"))
|
||||
table_btrfs_info:option(DummyValue, "uuid", translate("UUID"))
|
||||
table_btrfs_info:option(DummyValue, "members", translate("Members"))
|
||||
table_btrfs_info:option(DummyValue, "data_raid_level", translate("Data"))
|
||||
table_btrfs_info:option(DummyValue, "metadata_raid_lavel", translate("Metadata"))
|
||||
table_btrfs_info:option(DummyValue, "size_formated", translate("Size"))
|
||||
table_btrfs_info:option(DummyValue, "used_formated", translate("Used"))
|
||||
table_btrfs_info:option(DummyValue, "free_formated", translate("Free Space"))
|
||||
table_btrfs_info:option(DummyValue, "usage", translate("Usage"))
|
||||
local v_btrfs_label = table_btrfs_info:option(Value, "label", translate("Label"))
|
||||
local value_btrfs_label = ""
|
||||
v_btrfs_label.write = function(self, section, value)
|
||||
value_btrfs_label = value or ""
|
||||
end
|
||||
local btn_update_label = table_btrfs_info:option(Button, "_update_label")
|
||||
btn_update_label.inputtitle = translate("Update")
|
||||
btn_update_label.inputstyle = "edit"
|
||||
btn_update_label.write = function(self, section, value)
|
||||
local cmd = dm.command.btrfs .. " filesystem label " .. mount_point .. " " .. value_btrfs_label
|
||||
local res = luci.util.exec(cmd)
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
|
||||
end
|
||||
-- subvolume
|
||||
local subvolume_list = dm.get_btrfs_subv(mount_point)
|
||||
subvolume_list["_"] = { ID = 0 }
|
||||
table_subvolume = m:section(Table, subvolume_list, translate("SubVolumes"))
|
||||
table_subvolume:option(DummyValue, "id", translate("ID"))
|
||||
table_subvolume:option(DummyValue, "top_level", translate("Top Level"))
|
||||
table_subvolume:option(DummyValue, "uuid", translate("UUID"))
|
||||
table_subvolume:option(DummyValue, "otime", translate("Otime"))
|
||||
table_subvolume:option(DummyValue, "snapshots", translate("Snapshots"))
|
||||
local v_path = table_subvolume:option(Value, "path", translate("Path"))
|
||||
v_path.forcewrite = true
|
||||
v_path.render = function(self, section, scope)
|
||||
if subvolume_list[section].ID == 0 then
|
||||
self.template = "cbi/value"
|
||||
self.placeholder = "/my_subvolume"
|
||||
self.forcewrite = true
|
||||
Value.render(self, section, scope)
|
||||
else
|
||||
self.template = "cbi/dvalue"
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
local value_path
|
||||
v_path.write = function(self, section, value)
|
||||
value_path = value
|
||||
end
|
||||
local btn_set_default = table_subvolume:option(Button, "_subv_set_default", translate("Set Default"))
|
||||
btn_set_default.forcewrite = true
|
||||
btn_set_default.inputstyle = "edit"
|
||||
btn_set_default.template = "diskman/cbi/disabled_button"
|
||||
btn_set_default.render = function(self, section, scope)
|
||||
if subvolume_list[section].default_subvolume then
|
||||
self.view_disabled = true
|
||||
self.inputtitle = translate("Set Default")
|
||||
elseif subvolume_list[section].ID == 0 then
|
||||
self.template = "cbi/dvalue"
|
||||
else
|
||||
self.inputtitle = translate("Set Default")
|
||||
self.view_disabled = false
|
||||
end
|
||||
Button.render(self, section, scope)
|
||||
end
|
||||
btn_set_default.write = function(self, section, value)
|
||||
local cmd
|
||||
if value == translate("Set Default") then
|
||||
cmd = dm.command.btrfs .. " subvolume set-default " .. mount_point..subvolume_list[section].path
|
||||
else
|
||||
cmd = dm.command.btrfs .. " subvolume set-default " .. mount_point.."/"
|
||||
end
|
||||
local res = luci.util.exec(cmd.. " 2>&1")
|
||||
if res and (res:match("ERR") or res:match("not enough arguments")) then
|
||||
m.errmessage = res
|
||||
else
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
|
||||
end
|
||||
end
|
||||
local btn_remove = table_subvolume:option(Button, "_subv_remove")
|
||||
btn_remove.template = "diskman/cbi/disabled_button"
|
||||
btn_remove.forcewrite = true
|
||||
btn_remove.render = function(self, section, scope)
|
||||
if subvolume_list[section].ID == 0 then
|
||||
btn_remove.inputtitle = translate("Create")
|
||||
btn_remove.inputstyle = "add"
|
||||
self.view_disabled = false
|
||||
elseif subvolume_list[section].path == "/" or subvolume_list[section].default_subvolume then
|
||||
btn_remove.inputtitle = translate("Delete")
|
||||
btn_remove.inputstyle = "remove"
|
||||
self.view_disabled = true
|
||||
else
|
||||
btn_remove.inputtitle = translate("Delete")
|
||||
btn_remove.inputstyle = "remove"
|
||||
self.view_disabled = false
|
||||
end
|
||||
Button.render(self, section, scope)
|
||||
end
|
||||
|
||||
btn_remove.write = function(self, section, value)
|
||||
local cmd
|
||||
if value == translate("Delete") then
|
||||
cmd = dm.command.btrfs .. " subvolume delete " .. mount_point .. subvolume_list[section].path
|
||||
elseif value == translate("Create") then
|
||||
if value_path and value_path:match("^/") then
|
||||
cmd = dm.command.btrfs .. " subvolume create " .. mount_point .. value_path
|
||||
else
|
||||
m.errmessage = translate("Please input Subvolume Path, Subvolume must start with '/'")
|
||||
return
|
||||
end
|
||||
end
|
||||
local res = luci.util.exec(cmd.. " 2>&1")
|
||||
if res and (res:match("ERR") or res:match("not enough arguments")) then
|
||||
m.errmessage = luci.util.pcdata(res)
|
||||
else
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
|
||||
end
|
||||
end
|
||||
-- snapshot
|
||||
-- local snapshot_list = dm.get_btrfs_subv(mount_point, 1)
|
||||
-- table_snapshot = m:section(Table, snapshot_list, translate("Snapshots"))
|
||||
-- table_snapshot:option(DummyValue, "id", translate("ID"))
|
||||
-- table_snapshot:option(DummyValue, "top_level", translate("Top Level"))
|
||||
-- table_snapshot:option(DummyValue, "uuid", translate("UUID"))
|
||||
-- table_snapshot:option(DummyValue, "otime", translate("Otime"))
|
||||
-- table_snapshot:option(DummyValue, "path", translate("Path"))
|
||||
-- local snp_remove = table_snapshot:option(Button, "_snp_remove")
|
||||
-- snp_remove.inputtitle = translate("Delete")
|
||||
-- snp_remove.inputstyle = "remove"
|
||||
-- snp_remove.write = function(self, section, value)
|
||||
-- local cmd = dm.command.btrfs .. " subvolume delete " .. mount_point .. snapshot_list[section].path
|
||||
-- local res = luci.util.exec(cmd.. " 2>&1")
|
||||
-- if res and (res:match("ERR") or res:match("not enough arguments")) then
|
||||
-- m.errmessage = luci.util.pcdata(res)
|
||||
-- else
|
||||
-- luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- new snapshots
|
||||
local s_snapshot = m:section(SimpleSection, translate("New Snapshot"))
|
||||
local value_sorce, value_dest, value_readonly
|
||||
local v_sorce = s_snapshot:option(Value, "_source", translate("Source Path"), translate("The source path for create the snapshot"))
|
||||
v_sorce.placeholder = "/data"
|
||||
v_sorce.forcewrite = true
|
||||
v_sorce.write = function(self, section, value)
|
||||
value_sorce = value
|
||||
end
|
||||
|
||||
local v_readonly = s_snapshot:option(Flag, "_readonly", translate("Readonly"), translate("The path where you want to store the snapshot"))
|
||||
v_readonly.forcewrite = true
|
||||
v_readonly.rmempty = false
|
||||
v_readonly.disabled = 0
|
||||
v_readonly.enabled = 1
|
||||
v_readonly.default = 1
|
||||
v_readonly.write = function(self, section, value)
|
||||
value_readonly = value
|
||||
end
|
||||
local v_dest = s_snapshot:option(Value, "_dest", translate("Destination Path (optional)"))
|
||||
v_dest.forcewrite = true
|
||||
v_dest.placeholder = "/.snapshot/202002051538"
|
||||
v_dest.write = function(self, section, value)
|
||||
value_dest = value
|
||||
end
|
||||
local btn_snp_create = s_snapshot:option(Button, "_snp_create")
|
||||
btn_snp_create.title = " "
|
||||
btn_snp_create.inputtitle = translate("New Snapshot")
|
||||
btn_snp_create.inputstyle = "add"
|
||||
btn_snp_create.write = function(self, section, value)
|
||||
if value_sorce and value_sorce:match("^/") then
|
||||
if not value_dest then value_dest = "/.snapshot"..value_sorce.."/"..os.date("%Y%m%d%H%M%S") end
|
||||
nixio.fs.mkdirr(mount_point..value_dest:match("(.-)[^/]+$"))
|
||||
local cmd = dm.command.btrfs .. " subvolume snapshot" .. (value_readonly == 1 and " -r " or " ") .. mount_point..value_sorce .. " " .. mount_point..value_dest
|
||||
local res = luci.util.exec(cmd .. " 2>&1")
|
||||
if res and (res:match("ERR") or res:match("not enough arguments")) then
|
||||
m.errmessage = luci.util.pcdata(res)
|
||||
else
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
|
||||
end
|
||||
else
|
||||
m.errmessage = translate("Please input Source Path of snapshot, Source Path must start with '/'")
|
||||
end
|
||||
end
|
||||
|
||||
return m
|
||||
@ -1,327 +0,0 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
|
||||
]]--
|
||||
|
||||
require "luci.util"
|
||||
require("luci.tools.webadmin")
|
||||
local dm = require "luci.model.diskman"
|
||||
|
||||
-- Use (non-UCI) SimpleForm since we have no related config file
|
||||
m = SimpleForm("diskman", translate("DiskMan"), translate("Manage Disks over LuCI."))
|
||||
m.template = "diskman/cbi/xsimpleform"
|
||||
m:append(Template("diskman/disk_info"))
|
||||
-- disable submit and reset button
|
||||
m.submit = false
|
||||
m.reset = false
|
||||
-- rescan disks
|
||||
rescan = m:section(SimpleSection)
|
||||
rescan_button = rescan:option(Button, "_rescan")
|
||||
rescan_button.inputtitle= translate("Rescan Disks")
|
||||
rescan_button.template = "diskman/cbi/inlinebutton"
|
||||
rescan_button.inputstyle = "add"
|
||||
rescan_button.forcewrite = true
|
||||
rescan_button.write = function(self, section, value)
|
||||
luci.util.exec("echo '- - -' | tee /sys/class/scsi_host/host*/scan > /dev/null")
|
||||
if dm.command.mdadm then
|
||||
luci.util.exec(dm.command.mdadm .. " --assemble --scan")
|
||||
end
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman"))
|
||||
end
|
||||
|
||||
-- disks
|
||||
local disks = dm.list_devices()
|
||||
d = m:section(Table, disks, translate("Disks"))
|
||||
d.config = "disk"
|
||||
-- option(type, id(key of table), text)
|
||||
d:option(DummyValue, "path", translate("Path"))
|
||||
d:option(DummyValue, "model", translate("Model"))
|
||||
d:option(DummyValue, "sn", translate("Serial Number"))
|
||||
d:option(DummyValue, "size_formated", translate("Size"))
|
||||
d:option(DummyValue, "temp", translate("Temp"))
|
||||
-- d:option(DummyValue, "sec_size", translate("Sector Size "))
|
||||
d:option(DummyValue, "p_table", translate("Partition Table"))
|
||||
d:option(DummyValue, "sata_ver", translate("SATA Version"))
|
||||
-- d:option(DummyValue, "rota_rate", translate("Rotation Rate"))
|
||||
d:option(DummyValue, "health", translate("Health"))
|
||||
d:option(DummyValue, "status", translate("Status"))
|
||||
|
||||
d.extedit = luci.dispatcher.build_url("admin/system/diskman/partition/%s")
|
||||
|
||||
-- raid devices
|
||||
if dm.command.mdadm then
|
||||
local raid_devices = dm.list_raid_devices()
|
||||
-- raid_devices = diskmanager.getRAIDdevices()
|
||||
if next(raid_devices) ~= nil then
|
||||
local r = m:section(Table, raid_devices, translate("RAID Devices"))
|
||||
r.config = "_raid"
|
||||
r:option(DummyValue, "path", translate("Path"))
|
||||
r:option(DummyValue, "level", translate("RAID mode"))
|
||||
r:option(DummyValue, "size_formated", translate("Size"))
|
||||
r:option(DummyValue, "p_table", translate("Partition Table"))
|
||||
r:option(DummyValue, "status", translate("Status"))
|
||||
r:option(DummyValue, "members_str", translate("Members"))
|
||||
r:option(DummyValue, "active", translate("Active"))
|
||||
r.extedit = luci.dispatcher.build_url("admin/system/diskman/partition/%s")
|
||||
end
|
||||
end
|
||||
|
||||
-- btrfs devices
|
||||
if dm.command.btrfs then
|
||||
btrfs_devices = dm.list_btrfs_devices()
|
||||
if next(btrfs_devices) ~= nil then
|
||||
local table_btrfs = m:section(Table, btrfs_devices, translate("Btrfs"))
|
||||
table_btrfs:option(DummyValue, "uuid", translate("UUID"))
|
||||
table_btrfs:option(DummyValue, "label", translate("Label"))
|
||||
table_btrfs:option(DummyValue, "members", translate("Members"))
|
||||
-- sieze is error, since there is RAID
|
||||
-- table_btrfs:option(DummyValue, "size_formated", translate("Size"))
|
||||
table_btrfs:option(DummyValue, "used_formated", translate("Usage"))
|
||||
table_btrfs.extedit = luci.dispatcher.build_url("admin/system/diskman/btrfs/%s")
|
||||
end
|
||||
end
|
||||
|
||||
-- mount point
|
||||
local mount_point = dm.get_mount_points()
|
||||
local _mount_point = {}
|
||||
table.insert( mount_point, { device = 0 } )
|
||||
local table_mp = m:section(Table, mount_point, translate("Mount Point"))
|
||||
local v_device = table_mp:option(Value, "device", translate("Device"))
|
||||
v_device.render = function(self, section, scope)
|
||||
if mount_point[section].device == 0 then
|
||||
self.template = "cbi/value"
|
||||
self.forcewrite = true
|
||||
for dev, info in pairs(disks) do
|
||||
for i, v in ipairs(info.partitions) do
|
||||
self:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated)
|
||||
end
|
||||
end
|
||||
Value.render(self, section, scope)
|
||||
else
|
||||
self.template = "cbi/dvalue"
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
v_device.write = function(self, section, value)
|
||||
_mount_point.device = value and value:gsub("%s+", "") or ""
|
||||
end
|
||||
local v_fs = table_mp:option(Value, "fs", translate("File System"))
|
||||
v_fs.render = function(self, section, scope)
|
||||
if mount_point[section].device == 0 then
|
||||
self.template = "cbi/value"
|
||||
self:value("auto", "auto")
|
||||
self.default = "auto"
|
||||
self.forcewrite = true
|
||||
Value.render(self, section, scope)
|
||||
else
|
||||
self.template = "cbi/dvalue"
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
v_fs.write = function(self, section, value)
|
||||
_mount_point.fs = value and value:gsub("%s+", "") or ""
|
||||
end
|
||||
local v_mount_option = table_mp:option(Value, "mount_options", translate("Mount Options"))
|
||||
v_mount_option.render = function(self, section, scope)
|
||||
if mount_point[section].device == 0 then
|
||||
self.template = "cbi/value"
|
||||
self.placeholder = "rw,noauto"
|
||||
self.forcewrite = true
|
||||
Value.render(self, section, scope)
|
||||
else
|
||||
self.template = "cbi/dvalue"
|
||||
local mp = mount_point[section].mount_options
|
||||
mount_point[section].mount_options = nil
|
||||
local length = 0
|
||||
for k in mp:gmatch("([^,]+)") do
|
||||
mount_point[section].mount_options = mount_point[section].mount_options and (mount_point[section].mount_options .. ",") or ""
|
||||
if length > 20 then
|
||||
mount_point[section].mount_options = mount_point[section].mount_options.. " <br>"
|
||||
length = 0
|
||||
end
|
||||
mount_point[section].mount_options = mount_point[section].mount_options .. k
|
||||
length = length + #k
|
||||
end
|
||||
self.rawhtml = true
|
||||
-- mount_point[section].mount_options = #mount_point[section].mount_options > 50 and mount_point[section].mount_options:sub(1,50) .. "..." or mount_point[section].mount_options
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
v_mount_option.write = function(self, section, value)
|
||||
_mount_point.mount_options = value and value:gsub("%s+", "") or ""
|
||||
end
|
||||
local v_mount_point = table_mp:option(Value, "mount_point", translate("Mount Point"))
|
||||
v_mount_point.render = function(self, section, scope)
|
||||
if mount_point[section].device == 0 then
|
||||
self.template = "cbi/value"
|
||||
self.placeholder = "/media/diskX"
|
||||
self.forcewrite = true
|
||||
Value.render(self, section, scope)
|
||||
else
|
||||
self.template = "cbi/dvalue"
|
||||
local new_mp = ""
|
||||
local v_mp_d
|
||||
for v_mp_d in self["section"]["data"][section]["mount_point"]:gmatch('[^/]+') do
|
||||
if #v_mp_d > 12 then
|
||||
new_mp = new_mp .. "/" .. v_mp_d:sub(1,7) .. ".." .. v_mp_d:sub(-4)
|
||||
else
|
||||
new_mp = new_mp .."/".. v_mp_d
|
||||
end
|
||||
end
|
||||
self["section"]["data"][section]["mount_point"] = '<span title="'..self["section"]["data"][section]["mount_point"] .. '" >'..new_mp..'</span>'
|
||||
self.rawhtml = true
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
v_mount_point.write = function(self, section, value)
|
||||
_mount_point.mount_point = value
|
||||
end
|
||||
local btn_umount = table_mp:option(Button, "_mount", translate("Mount"))
|
||||
btn_umount.forcewrite = true
|
||||
btn_umount.render = function(self, section, scope)
|
||||
if mount_point[section].device == 0 then
|
||||
self.inputtitle = translate("Mount")
|
||||
btn_umount.inputstyle = "add"
|
||||
else
|
||||
self.inputtitle = translate("Umount")
|
||||
btn_umount.inputstyle = "remove"
|
||||
end
|
||||
Button.render(self, section, scope)
|
||||
end
|
||||
btn_umount.write = function(self, section, value)
|
||||
local res
|
||||
if value == translate("Mount") then
|
||||
if not _mount_point.mount_point or not _mount_point.device then return end
|
||||
luci.util.exec("mkdir -p ".. _mount_point.mount_point)
|
||||
res = luci.util.exec(dm.command.mount .. " ".. _mount_point.device .. (_mount_point.fs and (" -t ".. _mount_point.fs )or "") .. (_mount_point.mount_options and (" -o " .. _mount_point.mount_options.. " ") or " ").._mount_point.mount_point .. " 2>&1")
|
||||
elseif value == translate("Umount") then
|
||||
res = luci.util.exec(dm.command.umount .. " "..mount_point[section].mount_point .. " 2>&1")
|
||||
end
|
||||
if res:match("^mount:") or res:match("^umount:") then
|
||||
m.errmessage = luci.util.pcdata(res)
|
||||
else
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman"))
|
||||
end
|
||||
end
|
||||
|
||||
if dm.command.mdadm or dm.command.btrfs then
|
||||
local creation_section = m:section(TypedSection, "_creation")
|
||||
creation_section.cfgsections=function()
|
||||
return {translate("Creation")}
|
||||
end
|
||||
creation_section:tab("raid", translate("RAID"), translate("RAID Creation"))
|
||||
creation_section:tab("btrfs", translate("Btrfs"), translate("Multiple Devices Btrfs Creation"))
|
||||
|
||||
-- raid functions
|
||||
if dm.command.mdadm then
|
||||
|
||||
local rname, rmembers, rlevel
|
||||
local r_name = creation_section:taboption("raid", Value, "_rname", translate("Raid Name"))
|
||||
r_name.placeholder = "/dev/md0"
|
||||
r_name.write = function(self, section, value)
|
||||
rname = value
|
||||
end
|
||||
local r_level = creation_section:taboption("raid", ListValue, "_rlevel", translate("Raid Level"))
|
||||
local valid_raid = luci.util.exec("lsmod | grep md_mod")
|
||||
if valid_raid:match("linear") then
|
||||
r_level:value("linear", "Linear")
|
||||
end
|
||||
if valid_raid:match("raid456") then
|
||||
r_level:value("5", "Raid 5")
|
||||
r_level:value("6", "Raid 6")
|
||||
end
|
||||
if valid_raid:match("raid1") then
|
||||
r_level:value("1", "Raid 1")
|
||||
end
|
||||
if valid_raid:match("raid0") then
|
||||
r_level:value("0", "Raid 0")
|
||||
end
|
||||
if valid_raid:match("raid10") then
|
||||
r_level:value("10", "Raid 10")
|
||||
end
|
||||
r_level.write = function(self, section, value)
|
||||
rlevel = value
|
||||
end
|
||||
local r_member = creation_section:taboption("raid", DynamicList, "_rmember", translate("Raid Member"))
|
||||
for dev, info in pairs(disks) do
|
||||
if not info.inuse and #info.partitions == 0 then
|
||||
r_member:value(info.path, info.path.. " ".. info.size_formated)
|
||||
end
|
||||
for i, v in ipairs(info.partitions) do
|
||||
if not v.inuse then
|
||||
r_member:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated)
|
||||
end
|
||||
end
|
||||
end
|
||||
r_member.write = function(self, section, value)
|
||||
rmembers = value
|
||||
end
|
||||
local r_create = creation_section:taboption("raid", Button, "_rcreate")
|
||||
r_create.render = function(self, section, scope)
|
||||
self.title = " "
|
||||
self.inputtitle = translate("Create Raid")
|
||||
self.inputstyle = "add"
|
||||
Button.render(self, section, scope)
|
||||
end
|
||||
r_create.write = function(self, section, value)
|
||||
-- mdadm --create --verbose /dev/md0 --level=stripe --raid-devices=2 /dev/sdb6 /dev/sdc5
|
||||
local res = dm.create_raid(rname, rlevel, rmembers)
|
||||
if res and res:match("^ERR") then
|
||||
m.errmessage = luci.util.pcdata(res)
|
||||
return
|
||||
end
|
||||
dm.gen_mdadm_config()
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman"))
|
||||
end
|
||||
end
|
||||
|
||||
-- btrfs
|
||||
if dm.command.btrfs then
|
||||
local blabel, bmembers, blevel
|
||||
local btrfs_label = creation_section:taboption("btrfs", Value, "_blabel", translate("Btrfs Label"))
|
||||
btrfs_label.write = function(self, section, value)
|
||||
blabel = value
|
||||
end
|
||||
local btrfs_level = creation_section:taboption("btrfs", ListValue, "_blevel", translate("Btrfs Raid Level"))
|
||||
btrfs_level:value("single", "Single")
|
||||
btrfs_level:value("raid0", "Raid 0")
|
||||
btrfs_level:value("raid1", "Raid 1")
|
||||
btrfs_level:value("raid10", "Raid 10")
|
||||
btrfs_level.write = function(self, section, value)
|
||||
blevel = value
|
||||
end
|
||||
|
||||
local btrfs_member = creation_section:taboption("btrfs", DynamicList, "_bmember", translate("Btrfs Member"))
|
||||
for dev, info in pairs(disks) do
|
||||
if not info.inuse and #info.partitions == 0 then
|
||||
btrfs_member:value(info.path, info.path.. " ".. info.size_formated)
|
||||
end
|
||||
for i, v in ipairs(info.partitions) do
|
||||
if not v.inuse then
|
||||
btrfs_member:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated)
|
||||
end
|
||||
end
|
||||
end
|
||||
btrfs_member.write = function(self, section, value)
|
||||
bmembers = value
|
||||
end
|
||||
local btrfs_create = creation_section:taboption("btrfs", Button, "_bcreate")
|
||||
btrfs_create.render = function(self, section, scope)
|
||||
self.title = " "
|
||||
self.inputtitle = translate("Create Btrfs")
|
||||
self.inputstyle = "add"
|
||||
Button.render(self, section, scope)
|
||||
end
|
||||
btrfs_create.write = function(self, section, value)
|
||||
-- mkfs.btrfs -L label -d blevel /dev/sda /dev/sdb
|
||||
local res = dm.create_btrfs(blabel, blevel, bmembers)
|
||||
if res and res:match("^ERR") then
|
||||
m.errmessage = luci.util.pcdata(res)
|
||||
return
|
||||
end
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return m
|
||||
@ -1,366 +0,0 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
|
||||
]]--
|
||||
|
||||
require "luci.util"
|
||||
require("luci.tools.webadmin")
|
||||
local dm = require "luci.model.diskman"
|
||||
local dev = arg[1]
|
||||
|
||||
if not dev then
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman"))
|
||||
elseif not nixio.fs.access("/dev/"..dev) then
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman"))
|
||||
end
|
||||
|
||||
m = SimpleForm("partition", translate("Partition Management"), translate("Partition Disk over LuCI."))
|
||||
m.template = "diskman/cbi/xsimpleform"
|
||||
m.redirect = luci.dispatcher.build_url("admin/system/diskman")
|
||||
m:append(Template("diskman/partition_info"))
|
||||
-- disable submit and reset button
|
||||
m.submit = false
|
||||
m.reset = false
|
||||
|
||||
local disk_info = dm.get_disk_info(dev, true)
|
||||
local format_cmd = dm.get_format_cmd()
|
||||
|
||||
s = m:section(Table, {disk_info}, translate("Device Info"))
|
||||
-- s:option(DummyValue, "key")
|
||||
-- s:option(DummyValue, "value")
|
||||
s:option(DummyValue, "path", translate("Path"))
|
||||
s:option(DummyValue, "model", translate("Model"))
|
||||
s:option(DummyValue, "sn", translate("Serial Number"))
|
||||
s:option(DummyValue, "size_formated", translate("Size"))
|
||||
s:option(DummyValue, "sec_size", translate("Sector Size"))
|
||||
local dv_p_table = s:option(ListValue, "p_table", translate("Partition Table"))
|
||||
dv_p_table.render = function(self, section, scope)
|
||||
-- create table only if not used by raid and no partitions on disk
|
||||
if not disk_info.p_table:match("Raid") and (#disk_info.partitions == 0 or (#disk_info.partitions == 1 and disk_info.partitions[1].number == -1) or (disk_info.p_table:match("LOOP") and not disk_info.partitions[1].inuse)) then
|
||||
self:value(disk_info.p_table, disk_info.p_table)
|
||||
self:value("GPT", "GPT")
|
||||
self:value("MBR", "MBR")
|
||||
self.default = disk_info.p_table
|
||||
ListValue.render(self, section, scope)
|
||||
else
|
||||
self.template = "cbi/dvalue"
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
if disk_info.type:match("md") then
|
||||
s:option(DummyValue, "level", translate("Level"))
|
||||
s:option(DummyValue, "members_str", translate("Members"))
|
||||
else
|
||||
s:option(DummyValue, "temp", translate("Temp"))
|
||||
s:option(DummyValue, "sata_ver", translate("SATA Version"))
|
||||
s:option(DummyValue, "rota_rate", translate("Rotation Rate"))
|
||||
end
|
||||
s:option(DummyValue, "status", translate("Status"))
|
||||
local btn_health = s:option(Button, "health", translate("Health"))
|
||||
btn_health.render = function(self, section, scope)
|
||||
if disk_info.health then
|
||||
self.inputtitle = disk_info.health
|
||||
if disk_info.health == "PASSED" then
|
||||
self.inputstyle = "add"
|
||||
else
|
||||
self.inputstyle = "remove"
|
||||
end
|
||||
Button.render(self, section, scope)
|
||||
else
|
||||
self.template = "cbi/dvalue"
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
|
||||
local btn_eject = s:option(Button, "_eject")
|
||||
btn_eject.template = "diskman/cbi/disabled_button"
|
||||
btn_eject.inputstyle = "remove"
|
||||
btn_eject.render = function(self, section, scope)
|
||||
for i, p in ipairs(disk_info.partitions) do
|
||||
if p.mount_point ~= "-" then
|
||||
self.view_disabled = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if disk_info.p_table:match("Raid") then
|
||||
self.view_disabled = true
|
||||
end
|
||||
if disk_info.type:match("md") then
|
||||
btn_eject.inputtitle = translate("Remove")
|
||||
else
|
||||
btn_eject.inputtitle = translate("Eject")
|
||||
end
|
||||
Button.render(self, section, scope)
|
||||
end
|
||||
btn_eject.forcewrite = true
|
||||
btn_eject.write = function(self, section, value)
|
||||
for i, p in ipairs(disk_info.partitions) do
|
||||
if p.mount_point ~= "-" then
|
||||
m.errmessage = p.name .. translate("is in use! please unmount it first!")
|
||||
return
|
||||
end
|
||||
end
|
||||
if disk_info.type:match("md") then
|
||||
luci.util.exec(dm.command.mdadm .. " --stop /dev/" .. dev)
|
||||
luci.util.exec(dm.command.mdadm .. " --remove /dev/" .. dev)
|
||||
for _, disk in ipairs(disk_info.members) do
|
||||
luci.util.exec(dm.command.mdadm .. " --zero-superblock " .. disk)
|
||||
end
|
||||
dm.gen_mdadm_config()
|
||||
else
|
||||
luci.util.exec("echo 1 > /sys/block/" .. dev .. "/device/delete")
|
||||
end
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman"))
|
||||
end
|
||||
-- eject: echo 1 > /sys/block/(device)/device/delete
|
||||
-- rescan: echo '- - -' | tee /sys/class/scsi_host/host*/scan > /dev/null
|
||||
|
||||
|
||||
-- partitions info
|
||||
if not disk_info.p_table:match("Raid") then
|
||||
s_partition_table = m:section(Table, disk_info.partitions, translate("Partitions Info"), translate("Default 2048 sector alignment, support +size{b,k,m,g,t} in End Sector"))
|
||||
|
||||
-- s_partition_table:option(DummyValue, "number", translate("Number"))
|
||||
s_partition_table:option(DummyValue, "name", translate("Name"))
|
||||
local val_sec_start = s_partition_table:option(Value, "sec_start", translate("Start Sector"))
|
||||
val_sec_start.render = function(self, section, scope)
|
||||
-- could create new partition
|
||||
if disk_info.partitions[section].number == -1 and disk_info.partitions[section].size > 1 * 1024 * 1024 then
|
||||
self.template = "cbi/value"
|
||||
Value.render(self, section, scope)
|
||||
else
|
||||
self.template = "cbi/dvalue"
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
local val_sec_end = s_partition_table:option(Value, "sec_end", translate("End Sector"))
|
||||
val_sec_end.render = function(self, section, scope)
|
||||
-- could create new partition
|
||||
if disk_info.partitions[section].number == -1 and disk_info.partitions[section].size > 1 * 1024 * 1024 then
|
||||
self.template = "cbi/value"
|
||||
Value.render(self, section, scope)
|
||||
else
|
||||
self.template = "cbi/dvalue"
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
val_sec_start.forcewrite = true
|
||||
val_sec_start.write = function(self, section, value)
|
||||
disk_info.partitions[section]._sec_start = value
|
||||
end
|
||||
val_sec_end.forcewrite = true
|
||||
val_sec_end.write = function(self, section, value)
|
||||
disk_info.partitions[section]._sec_end = value
|
||||
end
|
||||
s_partition_table:option(DummyValue, "size_formated", translate("Size"))
|
||||
if disk_info.p_table == "MBR" then
|
||||
s_partition_table:option(DummyValue, "type", translate("Type"))
|
||||
end
|
||||
s_partition_table:option(DummyValue, "used_formated", translate("Used"))
|
||||
s_partition_table:option(DummyValue, "free_formated", translate("Free Space"))
|
||||
s_partition_table:option(DummyValue, "usage", translate("Usage"))
|
||||
local dv_mount_point = s_partition_table:option(DummyValue, "mount_point", translate("Mount Point"))
|
||||
dv_mount_point.rawhtml = true
|
||||
dv_mount_point.render = function(self, section, scope)
|
||||
local new_mp = ""
|
||||
local v_mp_d
|
||||
for line in self["section"]["data"][section]["mount_point"]:gmatch("[^%s]+") do
|
||||
if line == '-' then
|
||||
new_mp = line
|
||||
break
|
||||
end
|
||||
for v_mp_d in line:gmatch('[^/]+') do
|
||||
if #v_mp_d > 12 then
|
||||
new_mp = new_mp .. "/" .. v_mp_d:sub(1,7) .. ".." .. v_mp_d:sub(-4)
|
||||
else
|
||||
new_mp = new_mp .."/".. v_mp_d
|
||||
end
|
||||
end
|
||||
new_mp = '<span title="'.. line .. '" >' ..new_mp ..'</span>' .. "<br/>"
|
||||
end
|
||||
self["section"]["data"][section]["mount_point"] = new_mp
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
local val_fs = s_partition_table:option(Value, "fs", translate("File System"))
|
||||
val_fs.forcewrite = true
|
||||
val_fs.partitions = disk_info.partitions
|
||||
for k, v in pairs(format_cmd) do
|
||||
val_fs.format_cmd = val_fs.format_cmd and (val_fs.format_cmd .. "," .. k) or k
|
||||
end
|
||||
|
||||
val_fs.write = function(self, section, value)
|
||||
disk_info.partitions[section]._fs = value
|
||||
end
|
||||
val_fs.render = function(self, section, scope)
|
||||
-- use listvalue when partition not mounted
|
||||
if disk_info.partitions[section].mount_point == "-" and disk_info.partitions[section].number ~= -1 and disk_info.partitions[section].type ~= "extended" then
|
||||
self.template = "diskman/cbi/format_button"
|
||||
self.inputstyle = "reset"
|
||||
self.inputtitle = disk_info.partitions[section].fs == "raw" and translate("Format") or disk_info.partitions[section].fs
|
||||
Button.render(self, section, scope)
|
||||
-- self:reset_values()
|
||||
-- self.keylist = {}
|
||||
-- self.vallist = {}
|
||||
-- for k, v in pairs(format_cmd) do
|
||||
-- self:value(k,k)
|
||||
-- end
|
||||
-- self.default = disk_info.partitions[section].fs
|
||||
else
|
||||
-- self:reset_values()
|
||||
-- self.keylist = {}
|
||||
-- self.vallist = {}
|
||||
self.template = "cbi/dvalue"
|
||||
DummyValue.render(self, section, scope)
|
||||
end
|
||||
end
|
||||
-- btn_format = s_partition_table:option(Button, "_format")
|
||||
-- btn_format.template = "diskman/cbi/format_button"
|
||||
-- btn_format.partitions = disk_info.partitions
|
||||
-- btn_format.render = function(self, section, scope)
|
||||
-- if disk_info.partitions[section].mount_point == "-" and disk_info.partitions[section].number ~= -1 and disk_info.partitions[section].type ~= "extended" then
|
||||
-- self.inputtitle = translate("Format")
|
||||
-- self.template = "diskman/cbi/disabled_button"
|
||||
-- self.view_disabled = false
|
||||
-- self.inputstyle = "reset"
|
||||
-- for k, v in pairs(format_cmd) do
|
||||
-- self:depends("val_fs", "k")
|
||||
-- end
|
||||
-- -- elseif disk_info.partitions[section].mount_point ~= "-" and disk_info.partitions[section].number ~= -1 then
|
||||
-- -- self.inputtitle = "Format"
|
||||
-- -- self.template = "diskman/cbi/disabled_button"
|
||||
-- -- self.view_disabled = true
|
||||
-- -- self.inputstyle = "reset"
|
||||
-- else
|
||||
-- self.inputtitle = ""
|
||||
-- self.template = "cbi/dvalue"
|
||||
-- end
|
||||
-- Button.render(self, section, scope)
|
||||
-- end
|
||||
-- btn_format.forcewrite = true
|
||||
-- btn_format.write = function(self, section, value)
|
||||
-- local partition_name = "/dev/".. disk_info.partitions[section].name
|
||||
-- if not nixio.fs.access(partition_name) then
|
||||
-- m.errmessage = translate("Partition NOT found!")
|
||||
-- return
|
||||
-- end
|
||||
-- local fs = disk_info.partitions[section]._fs
|
||||
-- if not format_cmd[fs] then
|
||||
-- m.errmessage = translate("Filesystem NOT support!")
|
||||
-- return
|
||||
-- end
|
||||
-- local cmd = format_cmd[fs].cmd .. " " .. format_cmd[fs].option .. " " .. partition_name
|
||||
-- local res = luci.util.exec(cmd .. " 2>&1")
|
||||
-- if res and res:lower():match("error+") then
|
||||
-- m.errmessage = luci.util.pcdata(res)
|
||||
-- else
|
||||
-- luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev))
|
||||
-- end
|
||||
-- end
|
||||
|
||||
local btn_action = s_partition_table:option(Button, "_action")
|
||||
btn_action.forcewrite = true
|
||||
btn_action.template = "diskman/cbi/disabled_button"
|
||||
btn_action.render = function(self, section, scope)
|
||||
-- if partition is mounted or the size < 1mb, then disable the add action
|
||||
if disk_info.partitions[section].mount_point ~= "-" or (disk_info.partitions[section].type ~= "extended" and disk_info.partitions[section].number == -1 and disk_info.partitions[section].size <= 1 * 1024 * 1024) then
|
||||
self.view_disabled = true
|
||||
-- self.inputtitle = ""
|
||||
-- self.template = "cbi/dvalue"
|
||||
elseif disk_info.partitions[section].type == "extended" and next(disk_info.partitions[section]["logicals"]) ~= nil then
|
||||
self.view_disabled = true
|
||||
else
|
||||
-- self.template = "diskman/cbi/disabled_button"
|
||||
self.view_disabled = false
|
||||
end
|
||||
if disk_info.partitions[section].number ~= -1 then
|
||||
self.inputtitle = translate("Remove")
|
||||
self.inputstyle = "remove"
|
||||
else
|
||||
self.inputtitle = translate("New")
|
||||
self.inputstyle = "add"
|
||||
end
|
||||
Button.render(self, section, scope)
|
||||
end
|
||||
btn_action.write = function(self, section, value)
|
||||
if value == translate("New") then
|
||||
local start_sec = disk_info.partitions[section]._sec_start and tonumber(disk_info.partitions[section]._sec_start) or tonumber(disk_info.partitions[section].sec_start)
|
||||
local end_sec = disk_info.partitions[section]._sec_end
|
||||
|
||||
if start_sec then
|
||||
-- for sector alignment
|
||||
local align = tonumber(disk_info.phy_sec) / tonumber(disk_info.logic_sec)
|
||||
align = (align < 2048) and 2048
|
||||
if start_sec < 2048 then
|
||||
start_sec = "2048" .. "s"
|
||||
elseif math.fmod( start_sec, align ) ~= 0 then
|
||||
start_sec = tostring(start_sec + align - math.fmod( start_sec, align )) .. "s"
|
||||
else
|
||||
start_sec = start_sec .. "s"
|
||||
end
|
||||
else
|
||||
m.errmessage = translate("Invalid Start Sector!")
|
||||
return
|
||||
end
|
||||
-- support +size format for End sector
|
||||
local end_size, end_unit = end_sec:match("^+(%d-)([bkmgtsBKMGTS])$")
|
||||
if tonumber(end_size) and end_unit then
|
||||
local unit ={
|
||||
B=1,
|
||||
S=512,
|
||||
K=1024,
|
||||
M=1048576,
|
||||
G=1073741824,
|
||||
T=1099511627776
|
||||
}
|
||||
end_unit = end_unit:upper()
|
||||
end_sec = tostring(tonumber(end_size) * unit[end_unit] / unit["S"] + tonumber(start_sec:sub(1,-2)) - 1 ) .. "s"
|
||||
elseif tonumber(end_sec) then
|
||||
end_sec = end_sec .. "s"
|
||||
else
|
||||
m.errmessage = translate("Invalid End Sector!")
|
||||
return
|
||||
end
|
||||
local part_type = "primary"
|
||||
|
||||
if disk_info.p_table == "MBR" and disk_info["extended_partition_index"] then
|
||||
if tonumber(disk_info.partitions[disk_info["extended_partition_index"]].sec_start) <= tonumber(start_sec:sub(1,-2)) and tonumber(disk_info.partitions[disk_info["extended_partition_index"]].sec_end) >= tonumber(end_sec:sub(1,-2)) then
|
||||
part_type = "logical"
|
||||
if tonumber(start_sec:sub(1,-2)) - tonumber(disk_info.partitions[section].sec_start) < 2048 then
|
||||
start_sec = tonumber(start_sec:sub(1,-2)) + 2048
|
||||
start_sec = start_sec .."s"
|
||||
end
|
||||
end
|
||||
elseif disk_info.p_table == "GPT" then
|
||||
-- AUTOMATIC FIX GPT PARTITION TABLE
|
||||
-- Not all of the space available to /dev/sdb appears to be used, you can fix the GPT to use all of the space (an extra 16123870 blocks) or continue with the current setting?
|
||||
local cmd = ' printf "ok\nfix\n" | parted ---pretend-input-tty /dev/'.. dev ..' print'
|
||||
luci.util.exec(cmd .. " 2>&1")
|
||||
end
|
||||
|
||||
-- partiton
|
||||
local cmd = dm.command.parted .. " -s -a optimal /dev/" .. dev .. " mkpart " .. part_type .." " .. start_sec .. " " .. end_sec
|
||||
local res = luci.util.exec(cmd .. " 2>&1")
|
||||
if res and res:lower():match("error+") then
|
||||
m.errmessage = luci.util.pcdata(res)
|
||||
else
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev))
|
||||
end
|
||||
elseif value == translate("Remove") then
|
||||
-- remove partition
|
||||
local number = tostring(disk_info.partitions[section].number)
|
||||
if (not number) or (number == "") then
|
||||
m.errmessage = translate("Partition not exists!")
|
||||
return
|
||||
end
|
||||
local cmd = dm.command.parted .. " -s /dev/" .. dev .. " rm " .. number
|
||||
local res = luci.util.exec(cmd .. " 2>&1")
|
||||
if res and res:lower():match("error+") then
|
||||
m.errmessage = luci.util.pcdata(res)
|
||||
else
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return m
|
||||
@ -1,736 +0,0 @@
|
||||
--[[
|
||||
LuCI - Lua Configuration Interface
|
||||
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
|
||||
]]--
|
||||
|
||||
require "luci.util"
|
||||
local ver = require "luci.version"
|
||||
|
||||
local CMD = {"parted", "mdadm", "blkid", "smartctl", "df", "btrfs", "lsblk"}
|
||||
|
||||
local d = {command ={}}
|
||||
for _, cmd in ipairs(CMD) do
|
||||
local command = luci.sys.exec("/usr/bin/which " .. cmd)
|
||||
d.command[cmd] = command:match("^.+"..cmd) or nil
|
||||
end
|
||||
|
||||
d.command.mount = nixio.fs.access("/usr/bin/mount") and "/usr/bin/mount" or "/bin/mount"
|
||||
d.command.umount = nixio.fs.access("/usr/bin/umount") and "/usr/bin/umount" or "/bin/umount"
|
||||
|
||||
local proc_mounts = nixio.fs.readfile("/proc/mounts") or ""
|
||||
local mounts = luci.util.exec(d.command.mount .. " 2>/dev/null") or ""
|
||||
local swaps = nixio.fs.readfile("/proc/swaps") or ""
|
||||
local df = luci.sys.exec(d.command.df .. " 2>/dev/null") or ""
|
||||
|
||||
function byte_format(byte)
|
||||
local suff = {"B", "KB", "MB", "GB", "TB"}
|
||||
for i=1, 5 do
|
||||
if byte > 1024 and i < 5 then
|
||||
byte = byte / 1024
|
||||
else
|
||||
return string.format("%.2f %s", byte, suff[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local get_smart_info = function(device)
|
||||
local section
|
||||
local smart_info = {}
|
||||
for _, line in ipairs(luci.util.execl(d.command.smartctl .. " -H -A -i -n standby -f brief /dev/" .. device)) do
|
||||
local attrib, val
|
||||
if section == 1 then
|
||||
attrib, val = line:match "^(.-):%s+(.+)"
|
||||
elseif section == 2 and device:match("nvme") then
|
||||
attrib, val = line:match("^(.-):%s+(.+)")
|
||||
if not smart_info.health then smart_info.health = line:match(".-overall%-health.-: (.+)") end
|
||||
elseif section == 2 then
|
||||
attrib, val = line:match("^([0-9 ]+)%s+[^ ]+%s+[POSRCK-]+%s+[0-9-]+%s+[0-9-]+%s+[0-9-]+%s+[0-9-]+%s+([0-9-]+)")
|
||||
if not smart_info.health then smart_info.health = line:match(".-overall%-health.-: (.+)") end
|
||||
else
|
||||
attrib = line:match "^=== START OF (.*) SECTION ==="
|
||||
if attrib and attrib:match("INFORMATION") then
|
||||
section = 1
|
||||
elseif attrib and attrib:match("SMART DATA") then
|
||||
section = 2
|
||||
elseif not smart_info.status then
|
||||
val = line:match "^Device is in (.*) mode"
|
||||
if val then smart_info.status = val end
|
||||
end
|
||||
end
|
||||
|
||||
if not attrib then
|
||||
if section ~= 2 then section = 0 end
|
||||
elseif (attrib == "Power mode is") or
|
||||
(attrib == "Power mode was") then
|
||||
smart_info.status = val:match("(%S+)")
|
||||
-- elseif attrib == "Sector Sizes" then
|
||||
-- -- 512 bytes logical, 4096 bytes physical
|
||||
-- smart_info.phy_sec = val:match "([0-9]*) bytes physical"
|
||||
-- smart_info.logic_sec = val:match "([0-9]*) bytes logical"
|
||||
-- elseif attrib == "Sector Size" then
|
||||
-- -- 512 bytes logical/physical
|
||||
-- smart_info.phy_sec = val:match "([0-9]*)"
|
||||
-- smart_info.logic_sec = smart_info.phy_sec
|
||||
elseif attrib == "Serial Number" then
|
||||
smart_info.sn = val
|
||||
elseif attrib == "194" or attrib == "Temperature" then
|
||||
smart_info.temp = val:match("(%d+)") .. "°C"
|
||||
elseif attrib == "Rotation Rate" then
|
||||
smart_info.rota_rate = val
|
||||
elseif attrib == "SATA Version is" then
|
||||
smart_info.sata_ver = val
|
||||
end
|
||||
end
|
||||
return smart_info
|
||||
end
|
||||
|
||||
local parse_parted_info = function(keys, line)
|
||||
-- parse the output of parted command (machine parseable format)
|
||||
-- /dev/sda:5860533168s:scsi:512:4096:gpt:ATA ST3000DM001-1ER1:;
|
||||
-- 1:34s:2047s:2014s:free;
|
||||
-- 1:2048s:1073743872s:1073741825s:ext4:primary:;
|
||||
local result = {}
|
||||
local values = {}
|
||||
|
||||
for value in line:gmatch("(.-)[:;]") do table.insert(values, value) end
|
||||
for i = 1,#keys do
|
||||
result[keys[i]] = values[i] or ""
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local is_raid_member = function(partition)
|
||||
-- check if inuse as raid member
|
||||
if nixio.fs.access("/proc/mdstat") then
|
||||
for _, result in ipairs(luci.util.execl("grep md /proc/mdstat | sed 's/[][]//g'")) do
|
||||
local md, buf
|
||||
md, buf = result:match("(md.-):(.+)")
|
||||
if buf:match(partition) then
|
||||
return "Raid Member: ".. md
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local get_mount_point = function(partition)
|
||||
local mount_point
|
||||
for m in mounts:gmatch("/dev/"..partition.." on ([^ ]*)") do
|
||||
mount_point = (mount_point and (mount_point .. " ") or "") .. m
|
||||
end
|
||||
if mount_point then return mount_point end
|
||||
-- result = luci.sys.exec('cat /proc/mounts | awk \'{if($1=="/dev/'.. partition ..'") print $2}\'')
|
||||
-- if result ~= "" then return result end
|
||||
|
||||
if swaps:match("\n/dev/" .. partition .."%s") then return "swap" end
|
||||
-- result = luci.sys.exec("cat /proc/swaps | grep /dev/" .. partition)
|
||||
-- if result ~= "" then return "swap" end
|
||||
|
||||
return is_raid_member(partition)
|
||||
|
||||
end
|
||||
|
||||
-- return used, free, usage
|
||||
local get_partition_usage = function(partition)
|
||||
if not nixio.fs.access("/dev/"..partition) then return false end
|
||||
local used, free, usage = df:match("\n/dev/" .. partition .. "%s+%d+%s+(%d+)%s+(%d+)%s+(%d+)%%%s-")
|
||||
|
||||
usage = usage and (usage .. "%") or "-"
|
||||
used = used and (tonumber(used) * 1024) or 0
|
||||
free = free and (tonumber(free) * 1024) or 0
|
||||
|
||||
return used, free, usage
|
||||
end
|
||||
|
||||
local get_parted_info = function(device)
|
||||
if not device then return end
|
||||
local result = {partitions={}}
|
||||
local DEVICE_INFO_KEYS = { "path", "size", "type", "logic_sec", "phy_sec", "p_table", "model", "flags" }
|
||||
local PARTITION_INFO_KEYS = { "number", "sec_start", "sec_end", "size", "fs", "tag_name", "flags" }
|
||||
local partition_temp
|
||||
local partitions_temp = {}
|
||||
local disk_temp
|
||||
|
||||
for line in luci.util.execi(d.command.parted .. " -s -m /dev/" .. device .. " unit s print free", "r") do
|
||||
if line:find("^/dev/"..device..":.+") then
|
||||
disk_temp = parse_parted_info(DEVICE_INFO_KEYS, line)
|
||||
disk_temp.partitions = {}
|
||||
if disk_temp["size"] then
|
||||
local length = disk_temp["size"]:gsub("^(%d+)s$", "%1")
|
||||
local newsize = tostring(tonumber(length)*tonumber(disk_temp["logic_sec"]))
|
||||
disk_temp["size"] = newsize
|
||||
end
|
||||
if disk_temp["p_table"] == "msdos" then
|
||||
disk_temp["p_table"] = "MBR"
|
||||
else
|
||||
disk_temp["p_table"] = disk_temp["p_table"]:upper()
|
||||
end
|
||||
elseif line:find("^%d-:.+") then
|
||||
partition_temp = parse_parted_info(PARTITION_INFO_KEYS, line)
|
||||
-- use human-readable form instead of sector number
|
||||
if partition_temp["size"] then
|
||||
local length = partition_temp["size"]:gsub("^(%d+)s$", "%1")
|
||||
local newsize = (tonumber(length) * tonumber(disk_temp["logic_sec"]))
|
||||
partition_temp["size"] = newsize
|
||||
partition_temp["size_formated"] = byte_format(newsize)
|
||||
end
|
||||
partition_temp["number"] = tonumber(partition_temp["number"]) or -1
|
||||
if partition_temp["fs"] == "free" then
|
||||
partition_temp["number"] = -1
|
||||
partition_temp["fs"] = "Free Space"
|
||||
partition_temp["name"] = "-"
|
||||
elseif device:match("sd") or device:match("sata") then
|
||||
partition_temp["name"] = device..partition_temp["number"]
|
||||
elseif device:match("mmcblk") or device:match("md") or device:match("nvme") then
|
||||
partition_temp["name"] = device.."p"..partition_temp["number"]
|
||||
end
|
||||
if partition_temp["number"] > 0 and partition_temp["fs"] == "" and d.command.lsblk then
|
||||
partition_temp["fs"] = luci.util.exec(d.command.lsblk .. " /dev/"..device.. tostring(partition_temp["number"]) .. " -no fstype"):match("([^%s]+)") or ""
|
||||
end
|
||||
partition_temp["fs"] = partition_temp["fs"] == "" and "raw" or partition_temp["fs"]
|
||||
partition_temp["sec_start"] = partition_temp["sec_start"] and partition_temp["sec_start"]:sub(1,-2)
|
||||
partition_temp["sec_end"] = partition_temp["sec_end"] and partition_temp["sec_end"]:sub(1,-2)
|
||||
partition_temp["mount_point"] = partition_temp["name"]~="-" and get_mount_point(partition_temp["name"]) or "-"
|
||||
if partition_temp["mount_point"]~="-" then
|
||||
partition_temp["used"], partition_temp["free"], partition_temp["usage"] = get_partition_usage(partition_temp["name"])
|
||||
partition_temp["used_formated"] = partition_temp["used"] and byte_format(partition_temp["used"]) or "-"
|
||||
partition_temp["free_formated"] = partition_temp["free"] and byte_format(partition_temp["free"]) or "-"
|
||||
else
|
||||
partition_temp["used"], partition_temp["free"], partition_temp["usage"] = 0,0,"-"
|
||||
partition_temp["used_formated"] = "-"
|
||||
partition_temp["free_formated"] = "-"
|
||||
end
|
||||
-- if disk_temp["p_table"] == "MBR" and (partition_temp["number"] < 4) and (partition_temp["number"] > 0) then
|
||||
-- local real_size_sec = tonumber(nixio.fs.readfile("/sys/block/"..device.."/"..partition_temp["name"].."/size")) * tonumber(disk_temp.phy_sec)
|
||||
-- if real_size_sec ~= partition_temp["size"] then
|
||||
-- disk_temp["extended_partition_index"] = partition_temp["number"]
|
||||
-- partition_temp["type"] = "extended"
|
||||
-- partition_temp["size"] = real_size_sec
|
||||
-- partition_temp["fs"] = "-"
|
||||
-- partition_temp["logicals"] = {}
|
||||
-- else
|
||||
-- partition_temp["type"] = "primary"
|
||||
-- end
|
||||
-- end
|
||||
|
||||
table.insert(partitions_temp, partition_temp)
|
||||
end
|
||||
end
|
||||
if disk_temp and disk_temp["p_table"] == "MBR" then
|
||||
for i, p in ipairs(partitions_temp) do
|
||||
if disk_temp["extended_partition_index"] and p["number"] > 4 then
|
||||
if tonumber(p["sec_end"]) <= tonumber(partitions_temp[disk_temp["extended_partition_index"]]["sec_end"]) and tonumber(p["sec_start"]) >= tonumber(partitions_temp[disk_temp["extended_partition_index"]]["sec_start"]) then
|
||||
p["type"] = "logical"
|
||||
table.insert(partitions_temp[disk_temp["extended_partition_index"]]["logicals"], i)
|
||||
end
|
||||
elseif (p["number"] < 4) and (p["number"] > 0) then
|
||||
local s = nixio.fs.readfile("/sys/block/"..device.."/"..p["name"].."/size")
|
||||
if s then
|
||||
local real_size_sec = tonumber(s) * tonumber(disk_temp.phy_sec)
|
||||
-- if size not equal, it's an extended
|
||||
if real_size_sec ~= p["size"] then
|
||||
disk_temp["extended_partition_index"] = i
|
||||
p["type"] = "extended"
|
||||
p["size"] = real_size_sec
|
||||
p["fs"] = "-"
|
||||
p["logicals"] = {}
|
||||
else
|
||||
p["type"] = "primary"
|
||||
end
|
||||
else
|
||||
-- if not found in "/sys/block"
|
||||
p["type"] = "primary"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
result = disk_temp
|
||||
result.partitions = partitions_temp
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local mddetail = function(mdpath)
|
||||
local detail = {}
|
||||
local path = mdpath:match("^/dev/md%d+$")
|
||||
if path then
|
||||
local mdadm = io.popen(d.command.mdadm .. " --detail "..path, "r")
|
||||
for line in mdadm:lines() do
|
||||
local key, value = line:match("^%s*(.+) : (.+)")
|
||||
if key then
|
||||
detail[key] = value
|
||||
end
|
||||
end
|
||||
mdadm:close()
|
||||
end
|
||||
return detail
|
||||
end
|
||||
|
||||
-- return {{device="", mount_points="", fs="", mount_options="", dump="", pass=""}..}
|
||||
d.get_mount_points = function()
|
||||
local mount
|
||||
local res = {}
|
||||
local h ={"device", "mount_point", "fs", "mount_options", "dump", "pass"}
|
||||
for mount in proc_mounts:gmatch("[^\n]+") do
|
||||
local device = mount:match("^([^%s]+)%s+.+")
|
||||
-- only show /dev/xxx device
|
||||
if device and device:match("/dev/") then
|
||||
res[#res+1] = {}
|
||||
local i = 0
|
||||
for v in mount:gmatch("[^%s]+") do
|
||||
i = i + 1
|
||||
res[#res][h[i]] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
d.get_disk_info = function(device, wakeup)
|
||||
--[[ return:
|
||||
{
|
||||
path, model, sn, size, size_mounted, flags, type, temp, p_table, logic_sec, phy_sec, sec_size, sata_ver, rota_rate, status, health,
|
||||
partitions = {
|
||||
1 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, usage, used, free, used_formated, free_formated},
|
||||
2 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, usage, used, free, used_formated, free_formated},
|
||||
...
|
||||
}
|
||||
--raid devices only
|
||||
level, members, members_str
|
||||
}
|
||||
--]]
|
||||
if not device then return end
|
||||
local disk_info
|
||||
local smart_info = get_smart_info(device)
|
||||
|
||||
-- check if divice is the member of raid
|
||||
smart_info["p_table"] = is_raid_member(device..'0')
|
||||
-- if status is not active(standby), only check smart_info.
|
||||
-- if only weakup == true, weakup the disk and check parted_info.
|
||||
if smart_info.status ~= "STANDBY" or wakeup or (smart_info["p_table"] and not smart_info["p_table"]:match("Raid")) or device:match("^md") then
|
||||
disk_info = get_parted_info(device)
|
||||
disk_info["sec_size"] = disk_info["logic_sec"] .. "/" .. disk_info["phy_sec"]
|
||||
disk_info["size_formated"] = byte_format(tonumber(disk_info["size"]))
|
||||
-- if status is standby, then get smart_info again
|
||||
if smart_info.status ~= "ACTIVE" then smart_info = get_smart_info(device) end
|
||||
else
|
||||
disk_info = {}
|
||||
end
|
||||
|
||||
for k, v in pairs(smart_info) do
|
||||
disk_info[k] = v
|
||||
end
|
||||
|
||||
if disk_info.type and disk_info.type:match("md") then
|
||||
local raid_info = d.list_raid_devices()[disk_info["path"]:match("/dev/(.+)")]
|
||||
for k, v in pairs(raid_info) do
|
||||
disk_info[k] = v
|
||||
end
|
||||
end
|
||||
return disk_info
|
||||
end
|
||||
|
||||
d.list_raid_devices = function()
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
local raid_devices = {}
|
||||
if not fs.access("/proc/mdstat") then return raid_devices end
|
||||
local mdstat = io.open("/proc/mdstat", "r")
|
||||
for line in mdstat:lines() do
|
||||
|
||||
-- md1 : active raid1 sdb2[1] sda2[0]
|
||||
-- md127 : active raid5 sdh1[6] sdg1[4] sdf1[3] sde1[2] sdd1[1] sdc1[0]
|
||||
local device_info = {}
|
||||
local mdpath, list = line:match("^(md%d+) : (.+)")
|
||||
if mdpath then
|
||||
local members = {}
|
||||
for member in string.gmatch(list, "%S+") do
|
||||
member_path = member:match("^(%S+)%[%d+%]")
|
||||
if member_path then
|
||||
member = '/dev/'..member_path
|
||||
end
|
||||
table.insert(members, member)
|
||||
end
|
||||
local active = table.remove(members, 1)
|
||||
local level = "-"
|
||||
if active == "active" then
|
||||
level = table.remove(members, 1)
|
||||
end
|
||||
|
||||
local size = tonumber(fs.readfile(string.format("/sys/class/block/%s/size", mdpath)))
|
||||
local ss = tonumber(fs.readfile(string.format("/sys/class/block/%s/queue/logical_block_size", mdpath)))
|
||||
|
||||
device_info["path"] = "/dev/"..mdpath
|
||||
device_info["size"] = size*ss
|
||||
device_info["size_formated"] = byte_format(size*ss)
|
||||
device_info["active"] = active:upper()
|
||||
device_info["level"] = level
|
||||
device_info["members"] = members
|
||||
device_info["members_str"] = table.concat(members, ", ")
|
||||
|
||||
-- Get more info from output of mdadm --detail
|
||||
local detail = mddetail(device_info["path"])
|
||||
device_info["status"] = detail["State"]:upper()
|
||||
|
||||
raid_devices[mdpath] = device_info
|
||||
end
|
||||
end
|
||||
mdstat:close()
|
||||
|
||||
return raid_devices
|
||||
end
|
||||
|
||||
-- Collect Devices information
|
||||
--[[ return:
|
||||
{
|
||||
sda={
|
||||
path, model, inuse, size_formated,
|
||||
partitions={
|
||||
{ name, inuse, size_formated }
|
||||
...
|
||||
}
|
||||
}
|
||||
..
|
||||
}
|
||||
--]]
|
||||
d.list_devices = function()
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
-- get all device names (sdX and mmcblkX)
|
||||
local target_devnames = {}
|
||||
for dev in fs.dir("/dev") do
|
||||
if dev:match("^sd[a-z]$")
|
||||
or dev:match("^mmcblk%d+$")
|
||||
or dev:match("^sata[a-z]$")
|
||||
or dev:match("^nvme%d+n%d+$")
|
||||
then
|
||||
table.insert(target_devnames, dev)
|
||||
end
|
||||
end
|
||||
|
||||
local devices = {}
|
||||
for i, bname in pairs(target_devnames) do
|
||||
local device_info = {}
|
||||
local device = "/dev/" .. bname
|
||||
local size = tonumber(fs.readfile(string.format("/sys/class/block/%s/size", bname)) or "0")
|
||||
local ss = tonumber(fs.readfile(string.format("/sys/class/block/%s/queue/logical_block_size", bname)) or "0")
|
||||
local model = fs.readfile(string.format("/sys/class/block/%s/device/model", bname))
|
||||
local partitions = {}
|
||||
for part in nixio.fs.glob("/sys/block/" .. bname .."/" .. bname .. "*") do
|
||||
local pname = nixio.fs.basename(part)
|
||||
local psize = byte_format(tonumber(nixio.fs.readfile(part .. "/size"))*ss)
|
||||
local mount_point = get_mount_point(pname)
|
||||
if mount_point then device_info["inuse"] = true end
|
||||
table.insert(partitions, {name = pname, size_formated = psize, inuse = mount_point})
|
||||
end
|
||||
|
||||
device_info["path"] = device
|
||||
device_info["size_formated"] = byte_format(size*ss)
|
||||
device_info["model"] = model
|
||||
device_info["partitions"] = partitions
|
||||
-- true or false
|
||||
device_info["inuse"] = device_info["inuse"] or get_mount_point(bname)
|
||||
|
||||
local udevinfo = {}
|
||||
if luci.sys.exec("which udevadm") ~= "" then
|
||||
local udevadm = io.popen("udevadm info --query=property --name="..device)
|
||||
for attr in udevadm:lines() do
|
||||
local k, v = attr:match("(%S+)=(%S+)")
|
||||
udevinfo[k] = v
|
||||
end
|
||||
udevadm:close()
|
||||
|
||||
device_info["info"] = udevinfo
|
||||
if udevinfo["ID_MODEL"] then device_info["model"] = udevinfo["ID_MODEL"] end
|
||||
end
|
||||
devices[bname] = device_info
|
||||
end
|
||||
-- luci.util.perror(luci.util.serialize_json(devices))
|
||||
return devices
|
||||
end
|
||||
|
||||
-- get formart cmd
|
||||
d.get_format_cmd = function()
|
||||
local AVAILABLE_FMTS = {
|
||||
ext2 = { cmd = "mkfs.ext2", option = "-F -E lazy_itable_init=1" },
|
||||
ext3 = { cmd = "mkfs.ext3", option = "-F -E lazy_itable_init=1" },
|
||||
ext4 = { cmd = "mkfs.ext4", option = "-F -E lazy_itable_init=1" },
|
||||
fat32 = { cmd = "mkfs.vfat", option = "-F" },
|
||||
exfat = { cmd = "mkexfat", option = "-f" },
|
||||
hfsplus = { cmd = "mkhfs", option = "-f" },
|
||||
ntfs = { cmd = "mkntfs", option = "-f" },
|
||||
swap = { cmd = "mkswap", option = "" },
|
||||
btrfs = { cmd = "mkfs.btrfs", option = "-f" }
|
||||
}
|
||||
result = {}
|
||||
for fmt, obj in pairs(AVAILABLE_FMTS) do
|
||||
local cmd = luci.sys.exec("/usr/bin/which " .. obj["cmd"])
|
||||
if cmd:match(obj["cmd"]) then
|
||||
result[fmt] = { cmd = cmd:match("^.+"..obj["cmd"]) ,option = obj["option"] }
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
d.create_raid = function(rname, rlevel, rmembers)
|
||||
local mb = {}
|
||||
for _, v in ipairs(rmembers) do
|
||||
mb[v]=v
|
||||
end
|
||||
rmembers = {}
|
||||
for _, v in pairs(mb) do
|
||||
table.insert(rmembers, v)
|
||||
end
|
||||
if type(rname) == "string" then
|
||||
if rname:match("^md%d-%s+") then
|
||||
rname = "/dev/"..rname:match("^(md%d-)%s+")
|
||||
elseif rname:match("^/dev/md%d-%s+") then
|
||||
rname = "/dev/"..rname:match("^(/dev/md%d-)%s+")
|
||||
elseif not rname:match("/") then
|
||||
rname = "/dev/md/".. rname
|
||||
else
|
||||
return "ERR: Invalid raid name"
|
||||
end
|
||||
else
|
||||
local mdnum = 0
|
||||
for num=1,127 do
|
||||
local md = io.open("/dev/md"..tostring(num), "r")
|
||||
if md == nil then
|
||||
mdnum = num
|
||||
break
|
||||
else
|
||||
io.close(md)
|
||||
end
|
||||
end
|
||||
if mdnum == 0 then return "ERR: Cannot find proper md number" end
|
||||
rname = "/dev/md"..mdnum
|
||||
end
|
||||
|
||||
if rlevel == "5" or rlevel == "6" then
|
||||
if #rmembers < 3 then return "ERR: Not enough members" end
|
||||
end
|
||||
if rlevel == "10" then
|
||||
if #rmembers < 4 then return "ERR: Not enough members" end
|
||||
end
|
||||
if #rmembers < 2 then return "ERR: Not enough members" end
|
||||
local cmd = d.command.mdadm .. " --create "..rname.." --run --assume-clean --homehost=any --level=" .. rlevel .. " --raid-devices=" .. #rmembers .. " " .. table.concat(rmembers, " ")
|
||||
local res = luci.util.exec(cmd)
|
||||
return res
|
||||
end
|
||||
|
||||
d.gen_mdadm_config = function()
|
||||
if not nixio.fs.access("/etc/config/mdadm") then return end
|
||||
local uci = require "luci.model.uci"
|
||||
local x = uci.cursor()
|
||||
-- delete all array sections
|
||||
x:foreach("mdadm", "array", function(s) x:delete("mdadm",s[".name"]) end)
|
||||
local cmd = d.command.mdadm .. " -D -s"
|
||||
--ARRAY /dev/md1 metadata=1.2 name=any:1 UUID=f998ae14:37621b27:5c49e850:051f6813
|
||||
--ARRAY /dev/md3 metadata=1.2 name=any:3 UUID=c068c141:4b4232ca:f48cbf96:67d42feb
|
||||
for _, v in ipairs(luci.util.execl(cmd)) do
|
||||
local device, uuid = v:match("^ARRAY%s-([^%s]+)%s-[^%s]-%s-[^%s]-%s-UUID=([^%s]+)%s-")
|
||||
if device and uuid then
|
||||
local section_name = x:add("mdadm", "array")
|
||||
x:set("mdadm", section_name, "device", device)
|
||||
x:set("mdadm", section_name, "uuid", uuid)
|
||||
end
|
||||
end
|
||||
x:commit("mdadm")
|
||||
-- enable mdadm
|
||||
luci.util.exec("/etc/init.d/mdadm enable")
|
||||
end
|
||||
|
||||
-- list btrfs filesystem device
|
||||
-- {uuid={uuid, label, members, size, used}...}
|
||||
d.list_btrfs_devices = function()
|
||||
local btrfs_device = {}
|
||||
if not d.command.btrfs then return btrfs_device end
|
||||
local line, _uuid
|
||||
for _, line in ipairs(luci.util.execl(d.command.btrfs .. " filesystem show -d --raw"))
|
||||
do
|
||||
local label, uuid = line:match("^Label:%s+([^%s]+)%s+uuid:%s+([^%s]+)")
|
||||
if label and uuid then
|
||||
_uuid = uuid
|
||||
local _label = label:match("^'([^']+)'")
|
||||
btrfs_device[_uuid] = {label = _label or label, uuid = uuid}
|
||||
-- table.insert(btrfs_device, {label = label, uuid = uuid})
|
||||
end
|
||||
local used = line:match("Total devices[%w%s]+used%s+(%d+)$")
|
||||
if used then
|
||||
btrfs_device[_uuid]["used"] = tonumber(used)
|
||||
btrfs_device[_uuid]["used_formated"] = byte_format(tonumber(used))
|
||||
end
|
||||
local size, device = line:match("devid[%w.%s]+size%s+(%d+)[%w.%s]+path%s+([^%s]+)$")
|
||||
if size and device then
|
||||
btrfs_device[_uuid]["size"] = btrfs_device[_uuid]["size"] and btrfs_device[_uuid]["size"] + tonumber(size) or tonumber(size)
|
||||
btrfs_device[_uuid]["size_formated"] = byte_format(btrfs_device[_uuid]["size"])
|
||||
btrfs_device[_uuid]["members"] = btrfs_device[_uuid]["members"] and btrfs_device[_uuid]["members"]..", "..device or device
|
||||
end
|
||||
end
|
||||
return btrfs_device
|
||||
end
|
||||
|
||||
d.create_btrfs = function(blabel, blevel, bmembers)
|
||||
-- mkfs.btrfs -L label -d blevel /dev/sda /dev/sdb
|
||||
if not d.command.btrfs or type(bmembers) ~= "table" or next(bmembers) == nil then return "ERR no btrfs support or no members" end
|
||||
local label = blabel and " -L " .. blabel or ""
|
||||
local cmd = "mkfs.btrfs -f " .. label .. " -d " .. blevel .. " " .. table.concat(bmembers, " ")
|
||||
return luci.util.exec(cmd)
|
||||
end
|
||||
|
||||
-- get btrfs info
|
||||
-- {uuid, label, members, data_raid_level,metadata_raid_lavel, size, used, size_formated, used_formated, free, free_formated, usage}
|
||||
d.get_btrfs_info = function(m_point)
|
||||
local btrfs_info = {}
|
||||
if not m_point or not d.command.btrfs then return btrfs_info end
|
||||
local cmd = d.command.btrfs .. " filesystem show --raw " .. m_point
|
||||
local _, line, uuid, _label, members
|
||||
for _, line in ipairs(luci.util.execl(cmd)) do
|
||||
if not uuid and not _label then
|
||||
_label, uuid = line:match("^Label:%s+([^%s]+)%s+uuid:%s+([^s]+)")
|
||||
else
|
||||
local mb = line:match("%s+devid.+path%s+([^%s]+)")
|
||||
if mb then
|
||||
members = members and (members .. ", ".. mb) or mb
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not _label or not uuid then return btrfs_info end
|
||||
local label = _label:match("^'([^']+)'")
|
||||
cmd = d.command.btrfs .. " filesystem usage -b " .. m_point
|
||||
local used, free, data_raid_level, metadata_raid_lavel
|
||||
for _, line in ipairs(luci.util.execl(cmd)) do
|
||||
if not used then
|
||||
used = line:match("^%s+Used:%s+(%d+)")
|
||||
elseif not free then
|
||||
free = line:match("^%s+Free %(estimated%):%s+(%d+)")
|
||||
elseif not data_raid_level then
|
||||
data_raid_level = line:match("^Data,%s-(%w+)")
|
||||
elseif not metadata_raid_lavel then
|
||||
metadata_raid_lavel = line:match("^Metadata,%s-(%w+)")
|
||||
end
|
||||
end
|
||||
if used and free and data_raid_level and metadata_raid_lavel then
|
||||
used = tonumber(used)
|
||||
free = tonumber(free)
|
||||
btrfs_info = {
|
||||
uuid = uuid,
|
||||
label = label,
|
||||
data_raid_level = data_raid_level,
|
||||
metadata_raid_lavel = metadata_raid_lavel,
|
||||
used = used,
|
||||
free = free,
|
||||
size = used + free,
|
||||
size_formated = byte_format(used + free),
|
||||
used_formated = byte_format(used),
|
||||
free_formated = byte_format(free),
|
||||
members = members,
|
||||
usage = string.format("%.2f",(used / (free+used) * 100)) .. "%"
|
||||
}
|
||||
end
|
||||
return btrfs_info
|
||||
end
|
||||
|
||||
-- get btrfs subvolume
|
||||
-- {id={id, gen, top_level, path, snapshots, otime, default_subvolume}...}
|
||||
d.get_btrfs_subv = function(m_point, snapshot)
|
||||
local subvolume = {}
|
||||
if not m_point or not d.command.btrfs then return subvolume end
|
||||
|
||||
-- get default subvolume
|
||||
local cmd = d.command.btrfs .. " subvolume get-default " .. m_point
|
||||
local res = luci.util.exec(cmd)
|
||||
local default_subvolume_id = res:match("^ID%s+([^%s]+)")
|
||||
|
||||
-- get the root subvolume
|
||||
if not snapshot then
|
||||
local _, line, section_snap, _uuid, _otime, _id, _snap
|
||||
cmd = d.command.btrfs .. " subvolume show ".. m_point
|
||||
for _, line in ipairs(luci.util.execl(cmd)) do
|
||||
if not section_snap then
|
||||
if not _uuid then
|
||||
_uuid = line:match("^%s-UUID:%s+([^%s]+)")
|
||||
elseif not _otime then
|
||||
_otime = line:match("^%s+Creation time:%s+(.+)")
|
||||
elseif not _id then
|
||||
_id = line:match("^%s+Subvolume ID:%s+([^%s]+)")
|
||||
elseif line:match("^%s+(Snapshot%(s%):)") then
|
||||
section_snap = true
|
||||
end
|
||||
else
|
||||
local snapshot = line:match("^%s+(.+)")
|
||||
if snapshot then
|
||||
_snap = _snap and (_snap ..", /".. snapshot) or ("/"..snapshot)
|
||||
end
|
||||
end
|
||||
end
|
||||
if _uuid and _otime and _id then
|
||||
subvolume["0".._id] = {id = _id , uuid = _uuid, otime = _otime, snapshots = _snap, path = "/"}
|
||||
if default_subvolume_id == _id then
|
||||
subvolume["0".._id].default_subvolume = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- get subvolume of btrfs
|
||||
cmd = d.command.btrfs .. " subvolume list -gcu" .. (snapshot and "s " or " ") .. m_point
|
||||
for _, line in ipairs(luci.util.execl(cmd)) do
|
||||
-- ID 259 gen 11 top level 258 uuid 26ae0c59-199a-cc4d-bd58-644eb4f65d33 path 1a/2b'
|
||||
local id, gen, top_level, uuid, path, otime, otime2
|
||||
if snapshot then
|
||||
id, gen, top_level, otime, otime2, uuid, path = line:match("^ID%s+([^%s]+)%s+gen%s+([^%s]+)%s+cgen.-top level%s+([^%s]+)%s+otime%s+([^%s]+)%s+([^%s]+)%s+uuid%s+([^%s]+)%s+path%s+([^%s]+)%s-$")
|
||||
else
|
||||
id, gen, top_level, uuid, path = line:match("^ID%s+([^%s]+)%s+gen%s+([^%s]+)%s+cgen.-top level%s+([^%s]+)%s+uuid%s+([^%s]+)%s+path%s+([^%s]+)%s-$")
|
||||
end
|
||||
if id and gen and top_level and uuid and path then
|
||||
subvolume[id] = {id = id, gen = gen, top_level = top_level, otime = (otime and otime or "") .." ".. (otime2 and otime2 or ""), uuid = uuid, path = '/'.. path}
|
||||
if not snapshot then
|
||||
-- use btrfs subv show to get snapshots
|
||||
local show_cmd = d.command.btrfs .. " subvolume show "..m_point.."/"..path
|
||||
local __, line_show, section_snap
|
||||
for __, line_show in ipairs(luci.util.execl(show_cmd)) do
|
||||
if not section_snap then
|
||||
local create_time = line_show:match("^%s+Creation time:%s+(.+)")
|
||||
if create_time then
|
||||
subvolume[id]["otime"] = create_time
|
||||
elseif line_show:match("^%s+(Snapshot%(s%):)") then
|
||||
section_snap = "true"
|
||||
end
|
||||
else
|
||||
local snapshot = line_show:match("^%s+(.+)")
|
||||
subvolume[id]["snapshots"] = subvolume[id]["snapshots"] and (subvolume[id]["snapshots"] .. ", /".. snapshot) or ("/"..snapshot)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if subvolume[default_subvolume_id] then
|
||||
subvolume[default_subvolume_id].default_subvolume = 1
|
||||
end
|
||||
-- if m_point == "/tmp/.btrfs_tmp" then
|
||||
-- luci.util.exec("umount " .. m_point)
|
||||
-- end
|
||||
return subvolume
|
||||
end
|
||||
|
||||
d.format_partition = function(partition, fs)
|
||||
local partition_name = "/dev/".. partition
|
||||
if not nixio.fs.access(partition_name) then
|
||||
return 500, "Partition NOT found!"
|
||||
end
|
||||
|
||||
local format_cmd = d.get_format_cmd()
|
||||
if not format_cmd[fs] then
|
||||
return 500, "Filesystem NOT support!"
|
||||
end
|
||||
local cmd = format_cmd[fs].cmd .. " " .. format_cmd[fs].option .. " " .. partition_name
|
||||
local res = luci.util.exec(cmd .. " 2>&1")
|
||||
if res and res:lower():match("error+") then
|
||||
return 500, res
|
||||
else
|
||||
return 200, "OK"
|
||||
end
|
||||
end
|
||||
|
||||
return d
|
||||
@ -1,7 +0,0 @@
|
||||
<%+cbi/valueheader%>
|
||||
<% if self:cfgvalue(section) ~= false then %>
|
||||
<input class="cbi-button cbi-button-<%=self.inputstyle or "button" %>" type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> <% if self.view_disabled then %> disabled <% end %>/>
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
<%+cbi/valuefooter%>
|
||||
@ -1,7 +0,0 @@
|
||||
<%+cbi/valueheader%>
|
||||
<% if self:cfgvalue(section) ~= false then %>
|
||||
<input class="cbi-button cbi-button-<%=self.inputstyle or "button" %>" onclick="event.preventDefault();partition_format('<%=self.partitions[section].name%>', '<%=self.format_cmd%>', '<%=self.inputtitle%>');" type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> <% if self.view_disabled then %> disabled <% end %>/>
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
<%+cbi/valuefooter%>
|
||||
@ -1,7 +0,0 @@
|
||||
<div style="display: inline-block;">
|
||||
<% if self:cfgvalue(section) ~= false then %>
|
||||
<input class="cbi-button cbi-button-<%=self.inputstyle or "button" %>" type="submit"" <% if self.disable then %>disabled <% end %><%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> />
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
</div>
|
||||
@ -1,37 +0,0 @@
|
||||
<div class="cbi-section" id="cbi-<%=self.config%>-section">
|
||||
<% if self.title and #self.title > 0 then -%>
|
||||
<legend><%=self.title%></legend>
|
||||
<%- end %>
|
||||
<% if self.description and #self.description > 0 then -%>
|
||||
<div class="cbi-section-descr"><%=self.description%></div>
|
||||
<%- end %>
|
||||
<div class="cbi-section-node">
|
||||
<div id="cbi-<%=self.config%>-<%=tostring(self):sub(8)%>">
|
||||
<% self:render_children(1, scope or {}) %>
|
||||
</div>
|
||||
<% if self.error and self.error[1] then -%>
|
||||
<div class="cbi-section-error">
|
||||
<ul><% for _, e in ipairs(self.error[1]) do -%>
|
||||
<li>
|
||||
<%- if e == "invalid" then -%>
|
||||
<%:One or more fields contain invalid values!%>
|
||||
<%- elseif e == "missing" then -%>
|
||||
<%:One or more required fields have no value!%>
|
||||
<%- else -%>
|
||||
<%=pcdata(e)%>
|
||||
<%- end -%>
|
||||
</li>
|
||||
<%- end %></ul>
|
||||
</div>
|
||||
<%- end %>
|
||||
</div>
|
||||
</div>
|
||||
<%-
|
||||
if type(self.hidden) == "table" then
|
||||
for k, v in pairs(self.hidden) do
|
||||
-%>
|
||||
<input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" />
|
||||
<%-
|
||||
end
|
||||
end
|
||||
%>
|
||||
@ -1,88 +0,0 @@
|
||||
<% if not self.embedded then %>
|
||||
<form method="post" enctype="multipart/form-data" action="<%=REQUEST_URI%>"<%=
|
||||
attr("data-strings", luci.util.serialize_json({
|
||||
label = {
|
||||
choose = translate('-- Please choose --'),
|
||||
custom = translate('-- custom --'),
|
||||
},
|
||||
path = {
|
||||
resource = resource,
|
||||
browser = url("admin/filebrowser")
|
||||
}
|
||||
}))
|
||||
%>>
|
||||
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
|
||||
<input type="hidden" name="token" value="<%=token%>" />
|
||||
<input type="hidden" name="cbi.submit" value="1" /><%
|
||||
end
|
||||
|
||||
%><div class="cbi-map" id="cbi-<%=self.config%>"><%
|
||||
|
||||
if self.title and #self.title > 0 then
|
||||
%><h2 name="content"><%=self.title%></h2><%
|
||||
end
|
||||
|
||||
if self.description and #self.description > 0 then
|
||||
%><div class="cbi-map-descr"><%=self.description%></div><%
|
||||
end
|
||||
|
||||
self:render_children()
|
||||
|
||||
%></div><%
|
||||
|
||||
if self.message then
|
||||
%><div class="alert-message notice"><%=self.message%></div><%
|
||||
end
|
||||
|
||||
if self.errmessage then
|
||||
%><div class="alert-message warning"><%=self.errmessage%></div><%
|
||||
end
|
||||
|
||||
if not self.embedded then
|
||||
if type(self.hidden) == "table" then
|
||||
local k, v
|
||||
for k, v in pairs(self.hidden) do
|
||||
%><input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" /><%
|
||||
end
|
||||
end
|
||||
|
||||
local display_back = (self.redirect)
|
||||
local display_cancel = (self.cancel ~= false and self.on_cancel)
|
||||
local display_skip = (self.flow and self.flow.skip)
|
||||
local display_submit = (self.submit ~= false)
|
||||
local display_reset = (self.reset ~= false)
|
||||
|
||||
if display_back or display_cancel or display_skip or display_submit or display_reset then
|
||||
%><div class="cbi-page-actions"><%
|
||||
|
||||
if display_back then
|
||||
%><input class="cbi-button cbi-button-link" type="button" value="<%:Back to Overview%>" onclick="location.href='<%=pcdata(self.redirect)%>'" /> <%
|
||||
end
|
||||
|
||||
if display_cancel then
|
||||
local label = pcdata(self.cancel or translate("Cancel"))
|
||||
%><input class="cbi-button cbi-button-link" type="button" value="<%=label%>" onclick="cbi_submit(this, 'cbi.cancel')" /> <%
|
||||
end
|
||||
|
||||
if display_skip then
|
||||
%><input class="cbi-button cbi-button-neutral" type="button" value="<%:Skip%>" onclick="cbi_submit(this, 'cbi.skip')" /> <%
|
||||
end
|
||||
|
||||
if display_submit then
|
||||
local label = pcdata(self.submit or translate("Submit"))
|
||||
%><input class="cbi-button cbi-button-save" type="submit" value="<%=label%>" /> <%
|
||||
end
|
||||
|
||||
if display_reset then
|
||||
local label = pcdata(self.reset or translate("Reset"))
|
||||
%><input class="cbi-button cbi-button-reset" type="reset" value="<%=label%>" /> <%
|
||||
end
|
||||
|
||||
%></div><%
|
||||
end
|
||||
|
||||
%></form><%
|
||||
end
|
||||
%>
|
||||
|
||||
<script type="text/javascript">cbi_init();</script>
|
||||
@ -1,108 +0,0 @@
|
||||
<script type="text/javascript">
|
||||
window.onload = function () {
|
||||
//disk partition info
|
||||
let p_colors = ["#c0c0ff", "#fbbd00", "#e97c30", "#a0e0a0", "#e0c0ff"]
|
||||
let lines = document.querySelectorAll('[id^=cbi-disk-]')
|
||||
lines.forEach((item) => {
|
||||
let dev = item.id.match(/cbi-disk-(.*)/)[1]
|
||||
if (dev == "table") { return }
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin/system/diskman/get_disk_info")%>/' + dev, null, (x, disk_info) => {
|
||||
// handle disk info
|
||||
item.childNodes.forEach((cell) => {
|
||||
if (cell && cell.attributes) {
|
||||
if (cell.getAttribute("data-name") == "sn" || cell.childNodes[1] && cell.childNodes[1].id.match(/sn/)) {
|
||||
cell.innerText = disk_info.sn || "-"
|
||||
} else if (cell.getAttribute("data-name") == "temp" || cell.childNodes[1] && cell.childNodes[1].id.match(/temp/)) {
|
||||
cell.innerText = disk_info.temp || "-"
|
||||
} else if (cell.getAttribute("data-name") == "p_table" || cell.childNodes[1] && cell.childNodes[1].id.match(/p_table/)) {
|
||||
cell.innerText = disk_info.p_table || "-"
|
||||
} else if (cell.getAttribute("data-name") == "sata_ver" || cell.childNodes[1] && cell.childNodes[1].id.match(/sata_ver/)) {
|
||||
cell.innerText = disk_info.sata_ver || "-"
|
||||
} else if (cell.getAttribute("data-name") == "health" || cell.childNodes[1] && cell.childNodes[1].id.match(/health/)) {
|
||||
cell.innerText = disk_info.health || "-"
|
||||
} else if (cell.getAttribute("data-name") == "status" || cell.childNodes[1] && cell.childNodes[1].id.match(/status/)) {
|
||||
cell.innerText = disk_info.status || "-"
|
||||
}
|
||||
}
|
||||
})
|
||||
// handle partitons info
|
||||
if (disk_info.partitions && disk_info.partitions.length > 0) {
|
||||
let partitons_div
|
||||
if (item.nodeName == "TR") {
|
||||
partitons_div = '<tr width="100%" style="white-space:nowrap;"><td style="margin:0px; padding:0px; border:0px; white-space:nowrap;" colspan="15">'
|
||||
} else if (item.nodeName == "DIV") {
|
||||
partitons_div = '<div class="tr cbi-section-table-row cbi-rowstyle-1"><div style="white-space:nowrap; position:absolute; width:100%">'
|
||||
}
|
||||
let expand = 0
|
||||
let need_expand = 0
|
||||
disk_info.partitions.forEach((part) => {
|
||||
let p = part.size / disk_info.size * 100
|
||||
if (p <= 8) {
|
||||
expand += 8
|
||||
need_expand += p
|
||||
part.part_percent = 8
|
||||
}
|
||||
})
|
||||
let n = 0
|
||||
disk_info.partitions.forEach((part) => {
|
||||
let p = part.size / disk_info.size * 100
|
||||
if (p > 8) {
|
||||
part.part_percent = p * (100 - expand) / (100 - need_expand)
|
||||
}
|
||||
let part_percent = part.part_percent + '%'
|
||||
let p_color = p_colors[n++]
|
||||
if (n > 4) { n = 0 }
|
||||
let inline_txt = (part.name != '-' && part.name || '') + ' ' + (part.fs != 'Free Space' && part.fs || '') + ' ' + part.size_formated + ' ' + (part.useage != '-' && part.useage || '')
|
||||
let partiton_div = '<div title="' + inline_txt + '" style="display:inline-block; text-align:center;background-color:' + p_color + '; width:' + part_percent + '">' + inline_txt + '</div>'
|
||||
partitons_div += partiton_div
|
||||
})
|
||||
if (item.nodeName == "TR") {
|
||||
partitons_div += '</td></tr>'
|
||||
} else if (item.nodeName == "DIV") {
|
||||
partitons_div += '</div><div> </div></div>'
|
||||
}
|
||||
item.insertAdjacentHTML('afterend', partitons_div);
|
||||
}
|
||||
})
|
||||
})
|
||||
//raid table
|
||||
lines = document.querySelectorAll('[id^=cbi-_raid-]')
|
||||
lines.forEach((item) => {
|
||||
let dev = item.id.match(/cbi-_raid-(.*)/)[1]
|
||||
if (dev == "table") { return }
|
||||
console.log(dev)
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin/system/diskman/get_disk_info")%>/' + dev, null, (x, disk_info) => {
|
||||
// handle raid info
|
||||
item.childNodes.forEach((cell) => {
|
||||
if (cell && cell.attributes) {
|
||||
if (cell.getAttribute("data-name") == "p_table" || cell.childNodes[1] && cell.childNodes[1].id.match(/p_table/)) {
|
||||
cell.innerText = disk_info.p_table || "-"
|
||||
}
|
||||
}
|
||||
})
|
||||
// handle partitons info
|
||||
let partitons_div
|
||||
if (item.nodeName == "TR") {
|
||||
partitons_div = '<tr width="100%" style="white-space:nowrap;"><td style="margin:0px; padding:0px; border:0px; white-space:nowrap;" colspan="15">'
|
||||
} else if (item.nodeName == "DIV") {
|
||||
partitons_div = '<div class="tr cbi-section-table-row cbi-rowstyle-1"><div style="white-space:nowrap; position:absolute; width:100%">'
|
||||
}
|
||||
let n = 0
|
||||
disk_info.partitions.forEach((part) => {
|
||||
let part_percent = part.size / disk_info.size * 100 + '%'
|
||||
let p_color = p_colors[n++]
|
||||
if (n > 4) { n = 0 }
|
||||
let inline_txt = (part.name != '-' && part.name || '') + ' ' + (part.fs != 'Free Space' && part.fs || '') + ' ' + part.size_formated + ' ' + (part.useage != '-' && part.useage || '')
|
||||
let partiton_div = '<div title="' + inline_txt + '" style="display:inline-block; text-align:center;background-color:' + p_color + '; width:' + part_percent + '">' + inline_txt + '</div>'
|
||||
partitons_div += partiton_div
|
||||
})
|
||||
if (item.nodeName == "TR") {
|
||||
partitons_div += '</td></tr>'
|
||||
} else if (item.nodeName == "DIV") {
|
||||
partitons_div += '</div><div> </div></div>'
|
||||
}
|
||||
item.insertAdjacentHTML('afterend', partitons_div);
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@ -1,129 +0,0 @@
|
||||
<style type="text/css">
|
||||
#dialog_format {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
display: none;
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
#dialog_format .dialog_box {
|
||||
position: relative;
|
||||
background: rgba(255, 255, 255);
|
||||
top: 35%;
|
||||
width: 40%;
|
||||
min-width: 20em;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height:auto;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#dialog_format .dialog_line {
|
||||
margin-top: .5em;
|
||||
margin-bottom: .5em;
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
#dialog_format .dialog_box>h4,
|
||||
#dialog_format .dialog_box>p,
|
||||
#dialog_format .dialog_box>div {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
#dialog_format .dialog_box>img {
|
||||
margin-right: 1em;
|
||||
flex-basis: 32px;
|
||||
}
|
||||
|
||||
body.dialog-format-active {
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body.dialog-format-active #dialog_format {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
function show_detail(dev, e) {
|
||||
e.preventDefault()
|
||||
window.open('<%=luci.dispatcher.build_url("admin/system/diskman/smartdetail")%>/' + dev,
|
||||
'newwindow', 'height=480,width=800,top=100,left=200,toolbar=no,menubar=no,scrollbars=yes, resizable=no,location=no, status=no')
|
||||
}
|
||||
window.onload = function () {
|
||||
// handle partition table
|
||||
const btn_p_table = document.getElementById("widget.cbid.table.1.p_table") || document.getElementById("cbid.table.1.p_table")
|
||||
const btn_p_table_raw_index = btn_p_table.selectedIndex
|
||||
const val_name = document.getElementById("cbi-table-1-path").innerText.split('/').pop()
|
||||
btn_p_table.onchange = function () {
|
||||
let btn_p_table_index = btn_p_table.selectedIndex
|
||||
if (btn_p_table_index != btn_p_table_raw_index) {
|
||||
if (confirm("<%:Warnning !! \nTHIS WILL OVERWRITE EXISTING PARTITIONS!! \nModify the partition table?%>")) {
|
||||
let p_table = btn_p_table.options[btn_p_table_index].value
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin/system/diskman/mk_p_table")%>', { dev: val_name, p_table: p_table }, (x, res) => {
|
||||
if (res.code == 0) {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle smartinfo
|
||||
const url = location.href.split('/')
|
||||
const dev = url[url.length - 1]
|
||||
const btn_smart_detail = document.getElementById("cbi-table-1-health")
|
||||
btn_smart_detail.children[0].onclick = show_detail.bind(this, dev)
|
||||
}
|
||||
function close_dialog() {
|
||||
document.body.classList.remove('dialog-format-active')
|
||||
document.documentElement.style.overflowY = 'scroll'
|
||||
}
|
||||
function do_format(partation_name){
|
||||
let fs = document.getElementById("filesystem_list").value
|
||||
let status = document.getElementById("format-status")
|
||||
if(!fs) {
|
||||
status.innerHTML = "<%:Please select file system!%>"
|
||||
return
|
||||
}
|
||||
status.innerHTML = "<%:Formatting..%>"
|
||||
let b = document.getElementById('btn_format')
|
||||
b.disabled = true
|
||||
let xhr = new XHR()
|
||||
xhr.post('<%=luci.dispatcher.build_url("admin/system/diskman/format_partition")%>', { partation_name: partation_name, file_system: fs }, (x, res) => {
|
||||
if (x.status == 200) {
|
||||
status.innerHTML = x.statusText
|
||||
location.reload();
|
||||
}else{
|
||||
status.innerHTML = x.statusText
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function clear_text(){
|
||||
let s = document.getElementById('format-status')
|
||||
s.innerHTML = ""
|
||||
let b = document.getElementById('btn_format')
|
||||
b.disabled = false
|
||||
}
|
||||
|
||||
function partition_format(partition_name, format_cmd, current_fs){
|
||||
let list = ''
|
||||
format_cmd.split(",").forEach(e => {
|
||||
list = list + '<option value="'+e+'">'+e+'</option>'
|
||||
});
|
||||
document.getElementById('dialog_format') || document.body.insertAdjacentHTML("beforeend", '<div id="dialog_format"><div class="dialog_box"><div class="dialog_line"></div><div class="dialog_line"><span><%:Format partation:%> <b>'+partition_name+'</b></span><br><span id="format-status" style="color: red;"></span></div><div class="dialog_line"><select id="filesystem_list" class="cbi-input-select" onchange="clear_text()">'+list+'</select></div><div class="dialog_line" style="text-align: right;"><input type="button" class="cbi-button cbi-button-apply" id="btn_format" type="submit" value="<%:Format%>" onclick="do_format(`'+partition_name+'`)" /> <input type="button"class="cbi-button cbi-button-reset" type="reset" value="<%:Cancel%>" onclick="close_dialog()" /></div><div class="dialog_line"></div></div></div>>')
|
||||
document.body.classList.add('dialog-format-active')
|
||||
document.documentElement.style.overflowY = 'hidden'
|
||||
let fs_list = document.getElementById("filesystem_list")
|
||||
fs_list.value = current_fs
|
||||
}
|
||||
</script>
|
||||
@ -1,79 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>S.M.A.R.T detail of <%=dev%></title>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<%=media%>/cascade.css" />
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
let formData = new FormData()
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.open("GET", '<%=luci.dispatcher.build_url("admin", "system", "diskman", "smartattr", dev)%>', true)
|
||||
xhr.onload = function () {
|
||||
let st = JSON.parse(xhr.responseText)
|
||||
let tb = document.getElementById('smart_attr_table');
|
||||
if (st && tb) {
|
||||
/* clear all rows */
|
||||
while (tb.rows.length > 1)
|
||||
tb.deleteRow(1);
|
||||
|
||||
for (var i = 0; i < st.length; i++) {
|
||||
var tr = tb.insertRow(-1);
|
||||
tr.className = 'cbi-section-table-row cbi-rowstyle-' + ((i % 2) + 1);
|
||||
var td = null
|
||||
<% if dev: match("nvme") then %>
|
||||
tr.insertCell(-1).innerHTML = st[i].key;
|
||||
tr.insertCell(-1).innerHTML = st[i].value;
|
||||
<% else %>
|
||||
tr.insertCell(-1).innerHTML = st[i].id;
|
||||
tr.insertCell(-1).innerHTML = st[i].attrbute;
|
||||
tr.insertCell(-1).innerHTML = st[i].flag;
|
||||
tr.insertCell(-1).innerHTML = st[i].value;
|
||||
tr.insertCell(-1).innerHTML = st[i].worst;
|
||||
tr.insertCell(-1).innerHTML = st[i].thresh;
|
||||
tr.insertCell(-1).innerHTML = st[i].type;
|
||||
tr.insertCell(-1).innerHTML = st[i].updated;
|
||||
tr.insertCell(-1).innerHTML = st[i].raw;
|
||||
if ((st[i].id == '05' || st[i].id == 'C5') && st[i].raw != '0') {
|
||||
tr.style.cssText = "background-color:red !important;";
|
||||
}
|
||||
<% end %>
|
||||
}
|
||||
if (tb.rows.length == 1) {
|
||||
var tr = tb.insertRow(-1);
|
||||
tr.className = 'cbi-section-table-row';
|
||||
var td = tr.insertCell(-1);
|
||||
td.colSpan = 4;
|
||||
td.innerHTML = '<em><br /><%:No Attrbute to display.%></em>';
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(formData)
|
||||
//]]></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="maincontainer">
|
||||
<fieldset class="cbi-section">
|
||||
<legend><%:S.M.A.R.T Attrbutes%>: /dev/<%=dev%></legend>
|
||||
<table class="cbi-section-table" id="smart_attr_table">
|
||||
<tr class="cbi-section-table-titles">
|
||||
<% if dev:match("nvme") then %>
|
||||
<!-- <th class="cbi-section-table-cell"><%:KEY%></th>
|
||||
<th class="cbi-section-table-cell"><%:VALUE%></th> -->
|
||||
<% else %>
|
||||
<th class="cbi-section-table-cell"><%:ID%></th>
|
||||
<th class="cbi-section-table-cell"><%:Attrbute%></th>
|
||||
<th class="cbi-section-table-cell"><%:Flag%></th>
|
||||
<th class="cbi-section-table-cell"><%:Value%></th>
|
||||
<th class="cbi-section-table-cell"><%:Worst%></th>
|
||||
<th class="cbi-section-table-cell"><%:Thresh%></th>
|
||||
<th class="cbi-section-table-cell"><%:Type%></th>
|
||||
<th class="cbi-section-table-cell"><%:Updated%></th>
|
||||
<th class="cbi-section-table-cell"><%:Raw%></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
<tr class="cbi-section-table-row">
|
||||
<td colspan="4"><em><br /><%:Collecting data...%></em></td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,239 +0,0 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
msgid "DiskMan"
|
||||
msgstr "Menadżer dysków"
|
||||
|
||||
msgid "Manage Disks over LuCI."
|
||||
msgstr "Zarządzaj dyskami przez LuCI."
|
||||
|
||||
msgid "Rescan Disks"
|
||||
msgstr "Skanuj dyski"
|
||||
|
||||
msgid "Disks"
|
||||
msgstr "Dyski"
|
||||
|
||||
msgid "Path"
|
||||
msgstr "Ścieżka"
|
||||
|
||||
msgid "Serial Number"
|
||||
msgstr "Numer seryjny"
|
||||
|
||||
msgid "Temp"
|
||||
msgstr "Temperatura"
|
||||
|
||||
msgid "Partition Table"
|
||||
msgstr "Tablica partycji"
|
||||
|
||||
msgid "SATA Version"
|
||||
msgstr "Wersja SATA"
|
||||
|
||||
msgid "Health"
|
||||
msgstr "Kondycja"
|
||||
|
||||
msgid "File System"
|
||||
msgstr "System plików"
|
||||
|
||||
msgid "Mount Options"
|
||||
msgstr "Opcje montowania"
|
||||
|
||||
msgid "Mount"
|
||||
msgstr "Montuj"
|
||||
|
||||
msgid "Umount"
|
||||
msgstr "Odmontuj"
|
||||
|
||||
msgid "Eject"
|
||||
msgstr "Wysuń"
|
||||
|
||||
msgid "New"
|
||||
msgstr "Nowa"
|
||||
|
||||
msgid "Remove"
|
||||
msgstr "Wysuń"
|
||||
|
||||
msgid "Format"
|
||||
msgstr "Formatuj"
|
||||
|
||||
msgid "Start Sector"
|
||||
msgstr "Sektor początkowy"
|
||||
|
||||
msgid "End Sector"
|
||||
msgstr "Sektor końcowy"
|
||||
|
||||
msgid "Usage"
|
||||
msgstr "Wykorzystane"
|
||||
|
||||
msgid "Used"
|
||||
msgstr "Zajęte"
|
||||
|
||||
msgid "Free Space"
|
||||
msgstr "Wolna przestrzeń"
|
||||
|
||||
msgid "Model"
|
||||
msgstr "Model urządzenia"
|
||||
|
||||
msgid "Size"
|
||||
msgstr "Rozmiar"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
msgid "Mount Point"
|
||||
msgstr "Punkt montowania"
|
||||
|
||||
msgid "Sector Size"
|
||||
msgstr "Rozmiar sektora"
|
||||
|
||||
msgid "Rotation Rate"
|
||||
msgstr "Obroty"
|
||||
|
||||
msgid "RAID Devices"
|
||||
msgstr "Urządzenia RAID"
|
||||
|
||||
msgid "RAID mode"
|
||||
msgstr "Tryb RAID"
|
||||
|
||||
msgid "Members"
|
||||
msgstr "Członkowie"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "Aktywny"
|
||||
|
||||
msgid "RAID Creation"
|
||||
msgstr "Kreator RAID"
|
||||
|
||||
msgid "Raid Name"
|
||||
msgstr "Nazwa RAID"
|
||||
|
||||
msgid "Raid Level"
|
||||
msgstr "Poziom RAID"
|
||||
|
||||
msgid "Raid Member"
|
||||
msgstr "Członek RAID"
|
||||
|
||||
msgid "Create Raid"
|
||||
msgstr "Utwórz RAID"
|
||||
|
||||
msgid "Partition Management"
|
||||
msgstr "Menadżer partycji"
|
||||
|
||||
msgid "Partition Disk over LuCI."
|
||||
msgstr "Zarządzaj partycjami przez LuCI."
|
||||
|
||||
msgid "Device Info"
|
||||
msgstr "Informacja o urządzeniu"
|
||||
|
||||
msgid "Disk Man"
|
||||
msgstr "Menadżer dysków"
|
||||
|
||||
msgid "Partitions Info"
|
||||
msgstr "Informacja o partycjach"
|
||||
|
||||
msgid "Default 2048 sector alignment, support +size{b,k,m,g,t} in End Sector"
|
||||
msgstr "Sektory wyrównywane są do wielokrotności 2048, sektor końcowy można podać jako rozmiar w postaci +size{b,k,m,g,t}"
|
||||
|
||||
msgid "Multiple Devices Btrfs Creation"
|
||||
msgstr "Kreator urządzeń Btrfs"
|
||||
|
||||
msgid "Label"
|
||||
msgstr "Etykieta"
|
||||
|
||||
msgid "Btrfs Label"
|
||||
msgstr "Etykieta Btrfs"
|
||||
|
||||
msgid "Btrfs Raid Level"
|
||||
msgstr "Poziom Raid Btrfs"
|
||||
|
||||
msgid "Btrfs Member"
|
||||
msgstr "Członek Btrfs"
|
||||
|
||||
msgid "Create Btrfs"
|
||||
msgstr "Utwórz Btrfs"
|
||||
|
||||
msgid "New Snapshot"
|
||||
msgstr "Nowy obraz"
|
||||
|
||||
msgid "SubVolumes"
|
||||
msgstr "Sub-wolumeny"
|
||||
|
||||
msgid "Top Level"
|
||||
msgstr "Top Level"
|
||||
|
||||
msgid "Manage Btrfs"
|
||||
msgstr "Zarządzaj Btrfs"
|
||||
|
||||
msgid "Otime"
|
||||
msgstr "Otime"
|
||||
|
||||
msgid "Snapshots"
|
||||
msgstr "Obrazy"
|
||||
|
||||
msgid "Set Default"
|
||||
msgstr "Ustaw domyślnie"
|
||||
|
||||
msgid "Source Path"
|
||||
msgstr "Ścieżka źródłowa"
|
||||
|
||||
msgid "Readonly"
|
||||
msgstr "Tylko do odczytu"
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "Usuń"
|
||||
|
||||
msgid "Create"
|
||||
msgstr "Utwórz"
|
||||
|
||||
msgid "Destination Path (optional)"
|
||||
msgstr "Ścieżka docelowa (opcjonalnie)"
|
||||
|
||||
msgid "Metadata"
|
||||
msgstr "Metadata"
|
||||
|
||||
msgid "Data"
|
||||
msgstr "Data"
|
||||
|
||||
msgid "Btrfs Info"
|
||||
msgstr "Informacja o Btrfs"
|
||||
|
||||
msgid "The source path for create the snapshot"
|
||||
msgstr "Ścieżka źródłowa do utworzenia obrazu"
|
||||
|
||||
msgid "The path where you want to store the snapshot"
|
||||
msgstr "Ścieżka w której chcesz przechowywać obraz"
|
||||
|
||||
msgid "Please input Source Path of snapshot, Source Path must start with '/'"
|
||||
msgstr "Proszę podać ścieżkę źródłową dla obrazu, ścieżka musi zaczynać się od '/'"
|
||||
|
||||
msgid "Please input Subvolume Path, Subvolume must start with '/'"
|
||||
msgstr "Proszę podać ścieżkę dla sub-wolumenu, sub-wolumen musi zaczynać się od '/'"
|
||||
|
||||
msgid "is in use! please unmount it first!"
|
||||
msgstr "aktualnie jest w użyciu, proszę najpierw odmontować!"
|
||||
|
||||
msgid "Partition NOT found!"
|
||||
msgstr "Nie znaleziono partycji!"
|
||||
|
||||
msgid "Filesystem NOT support!"
|
||||
msgstr "System plików nie jest obsługiwany!"
|
||||
|
||||
msgid "Invalid Start Sector!"
|
||||
msgstr "Nieprawidłowy sektor początkowy!"
|
||||
|
||||
msgid "Invalid End Sector"
|
||||
msgstr "Nieprawidłowy sektor końcowy!"
|
||||
|
||||
msgid "Partition not exists!"
|
||||
msgstr "Partycja nie istnieje!"
|
||||
|
||||
msgid "Creation"
|
||||
msgstr "Kreator"
|
||||
|
||||
msgid "Please select file system!"
|
||||
msgstr "Proszę wybrać system plików!"
|
||||
|
||||
msgid "Format partation:"
|
||||
msgstr "Format partycji:"
|
||||
|
||||
msgid "Warnning !! \nTHIS WILL OVERWRITE EXISTING PARTITIONS!! \nModify the partition table?"
|
||||
msgstr "Ostrzeżenie !! \nISTNIEJĄCE PARTYCJE ZOSTANĄ NADPISANE!! \nZmodyfikować tablicę partycji?"
|
||||
@ -1,239 +0,0 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
msgid "DiskMan"
|
||||
msgstr "DiskMan 磁盘管理"
|
||||
|
||||
msgid "Manage Disks over LuCI."
|
||||
msgstr "通过 LuCI 管理磁盘"
|
||||
|
||||
msgid "Rescan Disks"
|
||||
msgstr "重新扫描磁盘"
|
||||
|
||||
msgid "Disks"
|
||||
msgstr "磁盘"
|
||||
|
||||
msgid "Path"
|
||||
msgstr "路径"
|
||||
|
||||
msgid "Serial Number"
|
||||
msgstr "序列号"
|
||||
|
||||
msgid "Temp"
|
||||
msgstr "温度"
|
||||
|
||||
msgid "Partition Table"
|
||||
msgstr "分区表"
|
||||
|
||||
msgid "SATA Version"
|
||||
msgstr "SATA 版本"
|
||||
|
||||
msgid "Health"
|
||||
msgstr "健康"
|
||||
|
||||
msgid "File System"
|
||||
msgstr "文件系统"
|
||||
|
||||
msgid "Mount Options"
|
||||
msgstr "挂载选项"
|
||||
|
||||
msgid "Mount"
|
||||
msgstr "挂载"
|
||||
|
||||
msgid "Umount"
|
||||
msgstr "卸载"
|
||||
|
||||
msgid "Eject"
|
||||
msgstr "弹出"
|
||||
|
||||
msgid "New"
|
||||
msgstr "创建"
|
||||
|
||||
msgid "Remove"
|
||||
msgstr "移除"
|
||||
|
||||
msgid "Format"
|
||||
msgstr "格式化"
|
||||
|
||||
msgid "Start Sector"
|
||||
msgstr "起始扇区"
|
||||
|
||||
msgid "End Sector"
|
||||
msgstr "中止扇区"
|
||||
|
||||
msgid "Usage"
|
||||
msgstr "用量"
|
||||
|
||||
msgid "Used"
|
||||
msgstr "已使用"
|
||||
|
||||
msgid "Free Space"
|
||||
msgstr "空闲空间"
|
||||
|
||||
msgid "Model"
|
||||
msgstr "型号"
|
||||
|
||||
msgid "Size"
|
||||
msgstr "容量"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Mount Point"
|
||||
msgstr "挂载点"
|
||||
|
||||
msgid "Sector Size"
|
||||
msgstr "扇区/物理扇区大小"
|
||||
|
||||
msgid "Rotation Rate"
|
||||
msgstr "转速"
|
||||
|
||||
msgid "RAID Devices"
|
||||
msgstr "RAID 设备"
|
||||
|
||||
msgid "RAID mode"
|
||||
msgstr "RAID 模式"
|
||||
|
||||
msgid "Members"
|
||||
msgstr "成员"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "活动"
|
||||
|
||||
msgid "RAID Creation"
|
||||
msgstr "RAID 创建"
|
||||
|
||||
msgid "Raid Name"
|
||||
msgstr "RAID 名称"
|
||||
|
||||
msgid "Raid Level"
|
||||
msgstr "RAID 级别"
|
||||
|
||||
msgid "Raid Member"
|
||||
msgstr "磁盘阵列成员"
|
||||
|
||||
msgid "Create Raid"
|
||||
msgstr "创建 RAID"
|
||||
|
||||
msgid "Partition Management"
|
||||
msgstr "分区管理"
|
||||
|
||||
msgid "Partition Disk over LuCI."
|
||||
msgstr "通过LuCI分区磁盘。"
|
||||
|
||||
msgid "Device Info"
|
||||
msgstr "设备信息"
|
||||
|
||||
msgid "Disk Man"
|
||||
msgstr "磁盘管理"
|
||||
|
||||
msgid "Partitions Info"
|
||||
msgstr "分区信息"
|
||||
|
||||
msgid "Default 2048 sector alignment, support +size{b,k,m,g,t} in End Sector"
|
||||
msgstr "默认2048扇区对齐,【中止扇区】支持 +容量{b,k,m,g,t} 格式,例:+500m +10g +1t"
|
||||
|
||||
msgid "Multiple Devices Btrfs Creation"
|
||||
msgstr "Btrfs 阵列创建"
|
||||
|
||||
msgid "Label"
|
||||
msgstr "卷标"
|
||||
|
||||
msgid "Btrfs Label"
|
||||
msgstr "Btrfs 卷标"
|
||||
|
||||
msgid "Btrfs Raid Level"
|
||||
msgstr "Btrfs Raid 级别"
|
||||
|
||||
msgid "Btrfs Member"
|
||||
msgstr "Btrfs 整列成员"
|
||||
|
||||
msgid "Create Btrfs"
|
||||
msgstr "创建 Btrfs"
|
||||
|
||||
msgid "New Snapshot"
|
||||
msgstr "新建快照"
|
||||
|
||||
msgid "SubVolumes"
|
||||
msgstr "子卷"
|
||||
|
||||
msgid "Top Level"
|
||||
msgstr "父ID"
|
||||
|
||||
msgid "Manage Btrfs"
|
||||
msgstr "Btrfs 管理"
|
||||
|
||||
msgid "Otime"
|
||||
msgstr "创建时间"
|
||||
|
||||
msgid "Snapshots"
|
||||
msgstr "快照"
|
||||
|
||||
msgid "Set Default"
|
||||
msgstr "默认子卷"
|
||||
|
||||
msgid "Source Path"
|
||||
msgstr "源目录"
|
||||
|
||||
msgid "Readonly"
|
||||
msgstr "只读"
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "删除"
|
||||
|
||||
msgid "Create"
|
||||
msgstr "创建"
|
||||
|
||||
msgid "Destination Path (optional)"
|
||||
msgstr "目标目录(可选)"
|
||||
|
||||
msgid "Metadata"
|
||||
msgstr "元数据"
|
||||
|
||||
msgid "Data"
|
||||
msgstr "数据"
|
||||
|
||||
msgid "Btrfs Info"
|
||||
msgstr "Btrfs 信息"
|
||||
|
||||
msgid "The source path for create the snapshot"
|
||||
msgstr "创建快照的源数据目录"
|
||||
|
||||
msgid "The path where you want to store the snapshot"
|
||||
msgstr "存放快照数据目录"
|
||||
|
||||
msgid "Please input Source Path of snapshot, Source Path must start with '/'"
|
||||
msgstr "请输入快照源路径,源路径必须以'/'开头"
|
||||
|
||||
msgid "Please input Subvolume Path, Subvolume must start with '/'"
|
||||
msgstr "请输入子卷路径,子卷路径必须以'/'开头"
|
||||
|
||||
msgid "is in use! please unmount it first!"
|
||||
msgstr "正在被使用!请先卸载!"
|
||||
|
||||
msgid "Partition NOT found!"
|
||||
msgstr "分区未找到!"
|
||||
|
||||
msgid "Filesystem NOT support!"
|
||||
msgstr "文件系统不支持!"
|
||||
|
||||
msgid "Invalid Start Sector!"
|
||||
msgstr "无效的起始扇区!"
|
||||
|
||||
msgid "Invalid End Sector"
|
||||
msgstr "无效的终止扇区!"
|
||||
|
||||
msgid "Partition not exists!"
|
||||
msgstr "分区不存在!"
|
||||
|
||||
msgid "Creation"
|
||||
msgstr "创建"
|
||||
|
||||
msgid "Please select file system!"
|
||||
msgstr "请选择文件系统!"
|
||||
|
||||
msgid "Format partation:"
|
||||
msgstr "格式化分区:"
|
||||
|
||||
msgid "Warnning !! \nTHIS WILL OVERWRITE EXISTING PARTITIONS!! \nModify the partition table?"
|
||||
msgstr "警告!!\n此操作会覆盖现有分区\n确定修改分区表?"
|
||||
@ -8,6 +8,7 @@ PKG_LICENSE:=AGPL-3.0
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/lisaac/luci-lib-docker.git
|
||||
PKG_MIRROR_HASH:=2ae79a80856a29e86a77744fb226aec35d1776d922c9bb06d2b602735ebd71d3
|
||||
PKG_SOURCE_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)
|
||||
|
||||
@ -1,432 +0,0 @@
|
||||
require "nixio.util"
|
||||
require "luci.util"
|
||||
local jsonc = require "luci.jsonc"
|
||||
local nixio = require "nixio"
|
||||
local ltn12 = require "luci.ltn12"
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
local urlencode = luci.util.urlencode or luci.http and luci.http.protocol and luci.http.protocol.urlencode
|
||||
local json_stringify = jsonc.stringify
|
||||
local json_parse = jsonc.parse
|
||||
|
||||
local chunksource = function(sock, buffer)
|
||||
buffer = buffer or ""
|
||||
return function()
|
||||
local output
|
||||
local _, endp, count = buffer:find("^([0-9a-fA-F]+);?.-\r\n")
|
||||
if not count then -- lua ^ only match start of stirng,not start of line
|
||||
_, endp, count = buffer:find("\r\n([0-9a-fA-F]+);?.-\r\n")
|
||||
end
|
||||
while not count do
|
||||
local newblock, code = sock:recv(1024)
|
||||
if not newblock then
|
||||
return nil, code
|
||||
end
|
||||
buffer = buffer .. newblock
|
||||
_, endp, count = buffer:find("^([0-9a-fA-F]+);?.-\r\n")
|
||||
if not count then
|
||||
_, endp, count = buffer:find("\r\n([0-9a-fA-F]+);?.-\r\n")
|
||||
end
|
||||
end
|
||||
count = tonumber(count, 16)
|
||||
if not count then
|
||||
return nil, -1, "invalid encoding"
|
||||
elseif count == 0 then -- finial
|
||||
return nil
|
||||
elseif count + 2 <= #buffer - endp then
|
||||
output = buffer:sub(endp + 1, endp + count)
|
||||
buffer = buffer:sub(endp + count + 3) -- don't forget handle buffer
|
||||
return output
|
||||
else
|
||||
output = buffer:sub(endp + 1, endp + count)
|
||||
buffer = ""
|
||||
if count > #output then
|
||||
local remain, code = sock:recvall(count - #output) --need read remaining
|
||||
if not remain then
|
||||
return nil, code
|
||||
end
|
||||
output = output .. remain
|
||||
count, code = sock:recvall(2) --read \r\n
|
||||
else
|
||||
count, code = sock:recvall(count + 2 - #buffer + endp)
|
||||
end
|
||||
if not count then
|
||||
return nil, code
|
||||
end
|
||||
return output
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local chunksink = function (sock)
|
||||
return function(chunk, err)
|
||||
if not chunk then
|
||||
return sock:writeall("0\r\n\r\n")
|
||||
else
|
||||
return sock:writeall(("%X\r\n%s\r\n"):format(#chunk, tostring(chunk)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local docker_stream_filter = function(buffer)
|
||||
buffer = buffer or ""
|
||||
if #buffer < 8 then
|
||||
return ""
|
||||
end
|
||||
local stream_type = ((string.byte(buffer, 1) == 1) and "stdout") or ((string.byte(buffer, 1) == 2) and "stderr") or ((string.byte(buffer, 1) == 0) and "stdin") or "stream_err"
|
||||
local valid_length =
|
||||
tonumber(string.byte(buffer, 5)) * 256 * 256 * 256 + tonumber(string.byte(buffer, 6)) * 256 * 256 + tonumber(string.byte(buffer, 7)) * 256 + tonumber(string.byte(buffer, 8))
|
||||
if valid_length > #buffer + 8 then
|
||||
return ""
|
||||
end
|
||||
return stream_type .. ": " .. string.sub(buffer, 9, valid_length + 8)
|
||||
-- return string.sub(buffer, 9, valid_length + 8)
|
||||
end
|
||||
|
||||
local send_http_socket = function(socket_path, req_header, req_body, callback)
|
||||
local docker_socket = nixio.socket("unix", "stream")
|
||||
if docker_socket:connect(socket_path) ~= true then
|
||||
return {
|
||||
headers = {code=497, message="bad socket path", protocol="HTTP/1.1"},
|
||||
body = {message="can\'t connect to unix socket"}
|
||||
}
|
||||
end
|
||||
if docker_socket:send(req_header) == 0 then
|
||||
return {
|
||||
headers={code=498,message="bad socket path", protocol="HTTP/1.1"},
|
||||
body={message="can\'t send data to unix socket"}
|
||||
}
|
||||
end
|
||||
|
||||
if req_body and type(req_body) == "function" and req_header and req_header:match("chunked") then
|
||||
-- chunked send
|
||||
req_body(chunksink(docker_socket))
|
||||
elseif req_body and type(req_body) == "function" then
|
||||
-- normal send by req_body function
|
||||
req_body(docker_socket)
|
||||
elseif req_body and type(req_body) == "table" then
|
||||
-- json
|
||||
docker_socket:send(json_stringify(req_body))
|
||||
elseif req_body then
|
||||
docker_socket:send(req_body)
|
||||
end
|
||||
|
||||
local linesrc = docker_socket:linesource()
|
||||
-- read socket using source http://w3.impa.br/~diego/software/luasocket/ltn12.html
|
||||
--http://lua-users.org/wiki/FiltersSourcesAndSinks
|
||||
-- handle response header
|
||||
local line = linesrc()
|
||||
if not line then
|
||||
docker_socket:close()
|
||||
return {
|
||||
headers = {code=499, message="bad socket path", protocol="HTTP/1.1"},
|
||||
body = {message="no data receive from socket"}
|
||||
}
|
||||
end
|
||||
local response = {code = 0, headers = {}, body = {}}
|
||||
|
||||
local p, code, msg = line:match("^([%w./]+) ([0-9]+) (.*)")
|
||||
response.protocol = p
|
||||
response.code = tonumber(code)
|
||||
response.message = msg
|
||||
line = linesrc()
|
||||
while line and line ~= "" do
|
||||
local key, val = line:match("^([%w-]+)%s?:%s?(.*)")
|
||||
if key and key ~= "Status" then
|
||||
if type(response.headers[key]) == "string" then
|
||||
response.headers[key] = {response.headers[key], val}
|
||||
elseif type(response.headers[key]) == "table" then
|
||||
response.headers[key][#response.headers[key] + 1] = val
|
||||
else
|
||||
response.headers[key] = val
|
||||
end
|
||||
end
|
||||
line = linesrc()
|
||||
end
|
||||
-- handle response body
|
||||
local body_buffer = linesrc(true)
|
||||
response.body = {}
|
||||
if type(callback) ~= "function" then
|
||||
if response.headers["Transfer-Encoding"] == "chunked" then
|
||||
local source = chunksource(docker_socket, body_buffer)
|
||||
code = ltn12.pump.all(source, (ltn12.sink.table(response.body))) and response.code or 555
|
||||
response.code = code
|
||||
else
|
||||
local body_source = ltn12.source.cat(ltn12.source.string(body_buffer), docker_socket:blocksource())
|
||||
code = ltn12.pump.all(body_source, (ltn12.sink.table(response.body))) and response.code or 555
|
||||
response.code = code
|
||||
end
|
||||
else
|
||||
if response.headers["Transfer-Encoding"] == "chunked" then
|
||||
local source = chunksource(docker_socket, body_buffer)
|
||||
callback(response, source)
|
||||
else
|
||||
local body_source = ltn12.source.cat(ltn12.source.string(body_buffer), docker_socket:blocksource())
|
||||
callback(response, body_source)
|
||||
end
|
||||
end
|
||||
docker_socket:close()
|
||||
return response
|
||||
end
|
||||
|
||||
local gen_header = function(options, http_method, api_group, api_action, name_or_id, request)
|
||||
local header, query, path
|
||||
options = options or {}
|
||||
options.protocol = options.protocol or "HTTP/1.1"
|
||||
name_or_id = name_or_id ~= "" and name_or_id or nil
|
||||
|
||||
if request and type(request.query) == "table" then
|
||||
local k, v
|
||||
for k, v in pairs(request.query) do
|
||||
if type(v) == "table" then
|
||||
query = (query and query .. "&" or "?") .. k .. "=" .. urlencode(json_stringify(v))
|
||||
elseif type(v) == "boolean" then
|
||||
query = (query and query .. "&" or "?") .. k .. "=" .. (v and "true" or "false")
|
||||
elseif type(v) == "number" or type(v) == "string" then
|
||||
query = (query and query .. "&" or "?") .. k .. "=" .. v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
path = (api_group and ("/" .. api_group) or "") .. (name_or_id and ("/" .. name_or_id) or "") .. (api_action and ("/" .. api_action) or "") .. (query or "")
|
||||
header = (http_method or "GET") .. " " .. path .. " " .. options.protocol .. "\r\n"
|
||||
header = header .. "Host: " .. options.host .. "\r\n"
|
||||
header = header .. "User-Agent: " .. options.user_agent .. "\r\n"
|
||||
header = header .. "Connection: close\r\n"
|
||||
|
||||
if request and type(request.header) == "table" then
|
||||
local k, v
|
||||
for k, v in pairs(request.header) do
|
||||
header = header .. k .. ": " .. v .. "\r\n"
|
||||
end
|
||||
end
|
||||
|
||||
-- when requst_body is function, we need to custom header using custom header
|
||||
if request and request.body and type(request.body) == "function" then
|
||||
if not header:match("Content-Length:") then
|
||||
header = header .. "Transfer-Encoding: chunked\r\n"
|
||||
end
|
||||
elseif http_method == "POST" and request and request.body and type(request.body) == "table" then
|
||||
local conetnt_json = json_stringify(request.body)
|
||||
header = header .. "Content-Type: application/json\r\n"
|
||||
header = header .. "Content-Length: " .. #conetnt_json .. "\r\n"
|
||||
elseif request and request.body and type(request.body) == "string" then
|
||||
header = header .. "Content-Length: " .. #request.body .. "\r\n"
|
||||
end
|
||||
header = header .. "\r\n"
|
||||
if options.debug then io.popen("echo '".. header .. "' >> " .. options.debug_path) end
|
||||
return header
|
||||
end
|
||||
|
||||
local call_docker = function(options, http_method, api_group, api_action, name_or_id, request, callback)
|
||||
local req_options = setmetatable({}, {__index = options})
|
||||
|
||||
local req_header = gen_header(req_options, http_method, api_group, api_action, name_or_id, request)
|
||||
local req_body = request and request.body or nil
|
||||
|
||||
return send_http_socket(req_options.socket_path, req_header, req_body, callback)
|
||||
end
|
||||
|
||||
local gen_api = function(_table, http_method, api_group, api_action)
|
||||
local _api_action
|
||||
if api_action == "get_archive" or api_action == "put_archive" then
|
||||
_api_action = "archive"
|
||||
elseif api_action == "df" then
|
||||
_api_action = "system/df"
|
||||
elseif api_action ~= "list" and api_action ~= "inspect" and api_action ~= "remove" then
|
||||
_api_action = api_action
|
||||
elseif (api_group == "containers" or api_group == "images" or api_group == "exec") and (api_action == "list" or api_action == "inspect") then
|
||||
_api_action = "json"
|
||||
end
|
||||
|
||||
local fp = function(self, request, callback)
|
||||
local name_or_id = request and (request.name or request.id or request.name_or_id) or nil
|
||||
if api_action == "list" then
|
||||
if (name_or_id ~= "" and name_or_id ~= nil) then
|
||||
if api_group == "images" then
|
||||
name_or_id = nil
|
||||
else
|
||||
request.query = request and request.query or {}
|
||||
request.query.filters = request.query.filters or {}
|
||||
request.query.filters.name = request.query.filters.name or {}
|
||||
request.query.filters.name[#request.query.filters.name + 1] = name_or_id
|
||||
name_or_id = nil
|
||||
end
|
||||
end
|
||||
elseif api_action == "create" then
|
||||
if (name_or_id ~= "" and name_or_id ~= nil) then
|
||||
request.query = request and request.query or {}
|
||||
request.query.name = request.query.name or name_or_id
|
||||
name_or_id = nil
|
||||
end
|
||||
elseif api_action == "logs" then
|
||||
local body_buffer = ""
|
||||
local response = call_docker(self.options, http_method, api_group, _api_action, name_or_id, request, callback)
|
||||
if response.code >= 200 and response.code < 300 then
|
||||
for i, v in ipairs(response.body) do
|
||||
body_buffer = body_buffer .. docker_stream_filter(response.body[i])
|
||||
end
|
||||
response.body = body_buffer
|
||||
end
|
||||
return response
|
||||
end
|
||||
local response = call_docker(self.options, http_method, api_group, _api_action, name_or_id, request, callback)
|
||||
if response.headers and response.headers["Content-Type"] == "application/json" then
|
||||
if #response.body == 1 then
|
||||
response.body = json_parse(response.body[1])
|
||||
else
|
||||
local tmp = {}
|
||||
for _, v in ipairs(response.body) do
|
||||
tmp[#tmp+1] = json_parse(v)
|
||||
end
|
||||
response.body = tmp
|
||||
end
|
||||
end
|
||||
return response
|
||||
end
|
||||
|
||||
if api_group then
|
||||
_table[api_group][api_action] = fp
|
||||
else
|
||||
_table[api_action] = fp
|
||||
end
|
||||
end
|
||||
|
||||
local _docker = {containers = {}, exec = {}, images = {}, networks = {}, volumes = {}}
|
||||
|
||||
gen_api(_docker, "GET", "containers", "list")
|
||||
gen_api(_docker, "POST", "containers", "create")
|
||||
gen_api(_docker, "GET", "containers", "inspect")
|
||||
gen_api(_docker, "GET", "containers", "top")
|
||||
gen_api(_docker, "GET", "containers", "logs")
|
||||
gen_api(_docker, "GET", "containers", "changes")
|
||||
gen_api(_docker, "GET", "containers", "stats")
|
||||
gen_api(_docker, "POST", "containers", "resize")
|
||||
gen_api(_docker, "POST", "containers", "start")
|
||||
gen_api(_docker, "POST", "containers", "stop")
|
||||
gen_api(_docker, "POST", "containers", "restart")
|
||||
gen_api(_docker, "POST", "containers", "kill")
|
||||
gen_api(_docker, "POST", "containers", "update")
|
||||
gen_api(_docker, "POST", "containers", "rename")
|
||||
gen_api(_docker, "POST", "containers", "pause")
|
||||
gen_api(_docker, "POST", "containers", "unpause")
|
||||
gen_api(_docker, "POST", "containers", "update")
|
||||
gen_api(_docker, "DELETE", "containers", "remove")
|
||||
gen_api(_docker, "POST", "containers", "prune")
|
||||
gen_api(_docker, "POST", "containers", "exec")
|
||||
gen_api(_docker, "POST", "exec", "start")
|
||||
gen_api(_docker, "POST", "exec", "resize")
|
||||
gen_api(_docker, "GET", "exec", "inspect")
|
||||
gen_api(_docker, "GET", "containers", "get_archive")
|
||||
gen_api(_docker, "PUT", "containers", "put_archive")
|
||||
-- TODO: export,attch
|
||||
|
||||
gen_api(_docker, "GET", "images", "list")
|
||||
gen_api(_docker, "POST", "images", "create")
|
||||
gen_api(_docker, "GET", "images", "inspect")
|
||||
gen_api(_docker, "GET", "images", "history")
|
||||
gen_api(_docker, "POST", "images", "tag")
|
||||
gen_api(_docker, "DELETE", "images", "remove")
|
||||
gen_api(_docker, "GET", "images", "search")
|
||||
gen_api(_docker, "POST", "images", "prune")
|
||||
-- TODO: build clear push commit export import
|
||||
|
||||
gen_api(_docker, "GET", "networks", "list")
|
||||
gen_api(_docker, "GET", "networks", "inspect")
|
||||
gen_api(_docker, "DELETE", "networks", "remove")
|
||||
gen_api(_docker, "POST", "networks", "create")
|
||||
gen_api(_docker, "POST", "networks", "connect")
|
||||
gen_api(_docker, "POST", "networks", "disconnect")
|
||||
gen_api(_docker, "POST", "networks", "prune")
|
||||
|
||||
gen_api(_docker, "GET", "volumes", "list")
|
||||
gen_api(_docker, "GET", "volumes", "inspect")
|
||||
gen_api(_docker, "DELETE", "volumes", "remove")
|
||||
gen_api(_docker, "POST", "volumes", "create")
|
||||
|
||||
gen_api(_docker, "GET", nil, "events")
|
||||
gen_api(_docker, "GET", nil, "version")
|
||||
gen_api(_docker, "GET", nil, "info")
|
||||
gen_api(_docker, "GET", nil, "_ping")
|
||||
gen_api(_docker, "GET", nil, "df")
|
||||
|
||||
function _docker.new(options)
|
||||
local docker = {}
|
||||
local _options = options or {}
|
||||
docker.options = {
|
||||
socket_path = _options.socket_path or "/var/run/docker.sock",
|
||||
host = _options.host or "localhost",
|
||||
version = _options.version or "v1.40",
|
||||
user_agent = _options.user_agent or "LuCI",
|
||||
protocol = _options.protocol or "HTTP/1.1",
|
||||
-- status_enabled = _options.status_enabled or true,
|
||||
-- status_path = _options.status_path or "/tmp/.docker_action_status",
|
||||
debug = _options.debug or false,
|
||||
debug_path = _options.debug_path or "/tmp/.docker_debug"
|
||||
}
|
||||
setmetatable(
|
||||
docker,
|
||||
{
|
||||
__index = function(t, key)
|
||||
if _docker[key] ~= nil then
|
||||
return _docker[key]
|
||||
else
|
||||
return _docker.containers[key]
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
setmetatable(
|
||||
docker.containers,
|
||||
{
|
||||
__index = function(t, key)
|
||||
if key == "options" then
|
||||
return docker.options
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
setmetatable(
|
||||
docker.networks,
|
||||
{
|
||||
__index = function(t, key)
|
||||
if key == "options" then
|
||||
return docker.options
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
setmetatable(
|
||||
docker.images,
|
||||
{
|
||||
__index = function(t, key)
|
||||
if key == "options" then
|
||||
return docker.options
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
setmetatable(
|
||||
docker.volumes,
|
||||
{
|
||||
__index = function(t, key)
|
||||
if key == "options" then
|
||||
return docker.options
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
setmetatable(
|
||||
docker.exec,
|
||||
{
|
||||
__index = function(t, key)
|
||||
if key == "options" then
|
||||
return docker.options
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
return docker
|
||||
end
|
||||
|
||||
return _docker
|
||||
@ -7,7 +7,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=Edge Theme
|
||||
LUCI_DEPENDS:=
|
||||
LUCI_DEPENDS:=+curl
|
||||
PKG_VERSION:=2.4
|
||||
PKG_RELEASE:=20201128
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ if (/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent)) {
|
||||
|
||||
<%+footer%>
|
||||
<%
|
||||
luci.sys.exec("(sleep 1;curl -k -L https://source.unsplash.com/featured/1080x720/?wallpapers -o /www/luci-static/edge/background/1.jpg) &")
|
||||
luci.sys.exec("(sleep 1;curl -k -L https://source.unsplash.com/featured/1080x720/?wallpaper -o /www/luci-static/edge/background/1.jpg) &")
|
||||
luci.sys.exec("(sleep 1;curl -k -L https://source.unsplash.com/featured/1080x720/?fashion -o /www/luci-static/edge/background/2.jpg) &")
|
||||
luci.sys.exec("(sleep 1;curl -k -L https://source.unsplash.com/featured/1080x720/?nature -o /www/luci-static/edge/background/3.jpg) &")
|
||||
%>
|
||||
@ -13,6 +13,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/KyleRicardo/MentoHUST-OpenWrt-ipk.git
|
||||
PKG_MIRROR_HASH:=ac39a84247b2b976430b39a29667d136611252afbb32ac16d4f21831ce07c871
|
||||
PKG_REV:=557cffca8032b6d8ac948be8a79255dc64a1915d
|
||||
|
||||
PKG_SOURCE_VERSION:=$(PKG_REV)
|
||||
|
||||
@ -19,6 +19,7 @@ PKG_LICENSE_FILES:=COPYING
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/Mleaf/mwol.git
|
||||
PKG_MIRROR_HASH:=7684645b84abc1339d84bc0b87dd72ca99c501d1c77b10f7bd5379e6b49833e9
|
||||
PKG_SOURCE_VERSION:=59f9805901b4ac2916a0273ffbc29197fcd17a62
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ PKG_VERSION:=3.0
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE_URL:=https://github.com/destan19/OpenAppFilter.git
|
||||
PKG_MIRROR_HASH:=d8d71c8dcdd6e130d2e1b4cddf37781fb95c5d1b8e7090fe49c0e761490be324
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_DATE:=2020-10-20
|
||||
PKG_SOURCE_VERSION:=b235da54c45ac4cd16ec96e1ec832d3851a247da
|
||||
|
||||
@ -9,6 +9,7 @@ PKG_BUILD_PARALLEL:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/zfl9/chinadns-ng.git
|
||||
PKG_MIRROR_HASH:=52b31de1a0790d9b0c8a0118152c4b1a44013a8cfdeed16e5437052744886607
|
||||
PKG_SOURCE_VERSION:=748a043dd7fb7ec71efbb7306f9dd21db5ce560f
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
|
||||
@ -13,6 +13,7 @@ PKG_RELEASE:=5
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/shadowsocks/simple-obfs.git
|
||||
PKG_MIRROR_HASH:=ea8f2b9825bbb87d5d860524e29bade265141687338db2dbf7ecd32690cf02fc
|
||||
PKG_SOURCE_VERSION:=486bebd9208539058e57e23a12f23103016e09b4
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
|
||||
@ -13,7 +13,7 @@ PKG_RELEASE:=1
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/parted-$(PKG_VERSION)
|
||||
PKG_SOURCE:=parted-$(PKG_VERSION).tar.xz
|
||||
PKG_SOURCE_URL:=@GNU/parted
|
||||
PKG_MD5SUM:=090655d05f3c471aa8e15a27536889ec
|
||||
PKG_HASH:=57e2b4bd87018625c515421d4524f6e3b55175b472302056391c5f7eccb83d44
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
define Package/parted
|
||||
|
||||
@ -6,6 +6,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/boypt/simple-torrent.git
|
||||
PKG_MIRROR_HASH:=2eefc27ca66e2e2bad9950cd6059b5b4f25f3565319e22ac6b8d00e7cbd27938
|
||||
PKG_SOURCE_VERSION:=7d2662c35ac0a566b39b56c0d42de81067cc1670
|
||||
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
@ -13,6 +13,7 @@ PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/tostercx/ssocks.git
|
||||
PKG_MIRROR_HASH:=f9447b08d99ffeb2cac3eba1a7b07f5397935db7b7fa4a4e404fb695f13b76f9
|
||||
PKG_SOURCE_VERSION:=8d9a5d2f89e507c9ffebd838b3c7430f07a0f36c
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
|
||||
@ -12,6 +12,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/lzdnico/subweb.git
|
||||
PKG_MIRROR_HASH:=61855d9412056f2f0eb588840bb35b9b47dea97db887e47c15c52fe897f8b7bd
|
||||
PKG_SOURCE_VERSION:=9acc47d2e9cda1b16d7fe184a16f528848467810
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
|
||||
@ -17,7 +17,7 @@ PKG_SOURCE_DATE:=2020-12-18
|
||||
PKG_SOURCE_VERSION:=fca4e548391e8198d0a651a3f22af1ceee966d5c
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=510999ec95faef0f8d9d6e5d5f7813b10cc2432c1c859e342a7deabe8de3af2b
|
||||
PKG_MIRROR_HASH:=9462c77b95fee8f09391b3d88b196ec0232242486b181bb45e366963ae6bd7e5
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_MAINTAINER:=ElonH <elonhhuang@gmail.com>
|
||||
|
||||
@ -6,6 +6,7 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/cnsilvan/UnblockNeteaseMusic.git
|
||||
PKG_MIRROR_HASH:=d513c958d88452b9a521b9b0f896d1d7e2e6089b942aab3307ba4d63ab724598
|
||||
PKG_SOURCE_VERSION:=935a28125fc7eafaa8273a77352e6262b18efd5e
|
||||
PKG_MAINTAINER:=Silvan <cnsilvan@gmail.com>
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ PKG_LICENSE:=MIT
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/nondanee/UnblockNeteaseMusic.git
|
||||
PKG_MIRROR_HASH:=51422014ed1dd196a12950ac0db2bf88bae6516637440655d0899fac474fbf30
|
||||
PKG_SOURCE_VERSION:=1193e29a2c8f72c738d2988d5cf5afbb2fee7463
|
||||
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)
|
||||
|
||||
@ -18,6 +18,7 @@ PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_VERSION:=$(PKG_REV)
|
||||
PKG_SOURCE_URL:=https://github.com/amule-project/amule.git
|
||||
PKG_MIRROR_HASH:=7b1352dd50764844205610173091db146bd0aa02d215278742bc83138ab0852f
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DEPENDS:=libgd libcryptopp
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=antfs-mount
|
||||
PKG_RELEASE:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/antfs-mount
|
||||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
SUBMENU:=Filesystem
|
||||
TITLE:=NTFS mount script for AVM NTFS driver
|
||||
PKGARCH:=all
|
||||
DEPENDS:=+kmod-fs-antfs
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/antfs-mount/install
|
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_BIN) ./files/mount.ntfs $(1)/sbin
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,antfs-mount))
|
||||
@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
mount -t antfs $@
|
||||
@ -1,43 +0,0 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=antfs
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE_URL:=https://github.com/klukonin/antfs.git
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_DATE:=2020-02-10
|
||||
PKG_SOURCE_VERSION:=b41ba529f6b64b429527e09a06ce0326d5456c05
|
||||
|
||||
PKG_LICENSE:=GPL-2.0-only
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define KernelPackage/fs-antfs
|
||||
SUBMENU:=Filesystems
|
||||
TITLE:=AVM NTFS Read/Write Driver
|
||||
FILES:=$(PKG_BUILD_DIR)/antfs.ko
|
||||
AUTOLOAD:=$(call AutoLoad,30,antfs,1)
|
||||
DEPENDS:=+kmod-nls-base
|
||||
endef
|
||||
|
||||
define KernelPackage/fs-antfs/description
|
||||
Kernel module for NTFS Filesytem
|
||||
endef
|
||||
|
||||
MAKE_OPTS:= \
|
||||
ARCH="$(LINUX_KARCH)" \
|
||||
CROSS_COMPILE="$(TARGET_CROSS)" \
|
||||
M="$(PKG_BUILD_DIR)"
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C "$(LINUX_DIR)" \
|
||||
$(MAKE_OPTS) \
|
||||
CONFIG_ANTFS_FS=m \
|
||||
CONFIG_ANTFS_SYMLINKS=y \
|
||||
ANTFS_VERSION=07.19-$(call version_abbrev,$(PKG_SOURCE_VERSION)) \
|
||||
modules
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,fs-antfs))
|
||||
@ -1,49 +0,0 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=dns2socks
|
||||
PKG_VERSION:=2.1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/kongfl888/dns2socks.git
|
||||
PKG_SOURCE_VERSION:=1723dfaf96fcd5d9a392e9122a08b92a1248f88b
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
PKG_LICENSE:=GPL-3.0
|
||||
PKG_MAINTAINER:=kongfl888 <kongfl888@outlook.com>
|
||||
|
||||
PKG_USE_MIPS16:=0
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/dns2socks
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=IP Addresses and Names
|
||||
TITLE:=The utility to resolve DNS requests via a SOCKS5 tunnel.
|
||||
URL:=https://sourceforge.net/projects/dns2socks/
|
||||
DEPENDS:=+libpthread
|
||||
endef
|
||||
|
||||
define Package/dns2socks/description
|
||||
This is a utility to resolve DNS requests via a SOCKS5 tunnel and caches the answers.
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(TARGET_CC) \
|
||||
$(TARGET_CFLAGS) \
|
||||
$(TARGET_CPPFLAGS) \
|
||||
$(FPIC) \
|
||||
-o $(PKG_BUILD_DIR)/DNS2SOCKS/$(PKG_NAME) \
|
||||
$(PKG_BUILD_DIR)/DNS2SOCKS/DNS2SOCKS.c \
|
||||
$(TARGET_LDFLAGS) -pthread
|
||||
endef
|
||||
|
||||
define Package/dns2socks/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/DNS2SOCKS/$(PKG_NAME) $(1)/usr/bin/dns2socks
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,dns2socks))
|
||||
@ -6,6 +6,7 @@ PKG_RELEASE:=10
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/1715173329/dnsforwarder.git
|
||||
PKG_MIRROR_HASH:=d54eab3778475408b4b615fb5cd13d69b6e7ef1d795fc434427e43ede8ca7128
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_VERSION:=587e61ae4d75dc976f538088b715a3c8ee26c144
|
||||
|
||||
@ -13,6 +13,7 @@ PKG_RELEASE=$(PKG_SOURCE_VERSION)
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/hzeller/gmrender-resurrect.git
|
||||
PKG_MIRROR_HASH:=beed710b377845665e90c20ea734ed9fbb9d2105321b43b7d12dc5a142e4f392
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_VERSION:=26d8f7edf5336bc30f7334c6ad459bf7f4f90ff2
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
|
||||
@ -10,7 +10,7 @@ LUCI_DEPENDS:=+adbyby +wget +ipset +dnsmasq-full
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_NAME:=luci-app-adbyby-plus
|
||||
PKG_VERSION:=2.0
|
||||
PKG_RELEASE:=72
|
||||
PKG_RELEASE:=73
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
|
||||
@ -22,8 +22,8 @@ o.title = translate("Block Apple iOS OTA update")
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "block_douyin")
|
||||
o.title = translate("Block Douyin APP and Website")
|
||||
o = s:option(Flag, "block_cnshort")
|
||||
o.title = translate("Block CNshort APP and Website")
|
||||
o.default = 0
|
||||
o.rmempty = false
|
||||
|
||||
|
||||
@ -125,8 +125,8 @@ msgstr "手动更新规则"
|
||||
msgid "Block Apple iOS OTA update"
|
||||
msgstr "拦截 Apple iOS 的OTA更新"
|
||||
|
||||
msgid "Block Douyin APP and Website"
|
||||
msgstr "拦截 抖音 APP 和网站"
|
||||
msgid "Block CNshort APP and Website"
|
||||
msgstr "拦截 短视频 APP 和网站"
|
||||
|
||||
msgid "RAM Running Mode"
|
||||
msgstr "内存运行模式"
|
||||
|
||||
@ -36,7 +36,7 @@ get_config()
|
||||
config_get wan_mode $1 wan_mode 1
|
||||
config_get_bool block_ios $1 block_ios 0
|
||||
config_get_bool mem_mode $1 mem_mode 1
|
||||
config_get_bool block_douyin $1 block_douyin 0
|
||||
config_get_bool block_cnshort $1 block_cnshort 0
|
||||
}
|
||||
|
||||
add_rules()
|
||||
@ -85,8 +85,6 @@ ip_rule()
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
|
||||
case $wan_mode in
|
||||
0)
|
||||
;;
|
||||
@ -134,11 +132,34 @@ add_dns()
|
||||
echo 'conf-dir=/tmp/adbyby/rules/data' >> /tmp/dnsmasq.d/dnsmasq-adbyby.conf
|
||||
|
||||
[ $block_ios -eq 1 ] && echo 'address=/mesu.apple.com/0.0.0.0' >> /tmp/dnsmasq.d/dnsmasq-adbyby.conf
|
||||
if [ $block_douyin -eq 1 ]; then
|
||||
cat <<-EOF >/tmp/etc/dnsmasq-adbyby.d/08-dnsmasq.douyin
|
||||
if [ $block_cnshort -eq 1 ]; then
|
||||
cat <<-EOF >/tmp/etc/dnsmasq-adbyby.d/08-dnsmasq.cnshort
|
||||
address=/api.amemv.com/0.0.0.0
|
||||
address=/.amemv.com/0.0.0.0
|
||||
address=/.tiktokv.com/0.0.0.0
|
||||
address=/.snssdk.com/0.0.0.0
|
||||
address=/.douyin.com/0.0.0.0
|
||||
address=/.ixigua.com/0.0.0.0
|
||||
address=/.pstatp.com/0.0.0.0
|
||||
address=/.ixiguavideo.com/0.0.0.0
|
||||
address=/.v.kandian.qq.com/0.0.0.0
|
||||
address=/.yximgs.com/0.0.0.0
|
||||
address=/.gifshow.com/0.0.0.0
|
||||
address=/.ksapisrv.com/0.0.0.0
|
||||
address=/.kuaishoupay.com/0.0.0.0
|
||||
address=/.ksyun.com/0.0.0.0
|
||||
address=/.live.xycdn.com/0.0.0.0
|
||||
address=/.danuoyi.alicdn.com/0.0.0.0
|
||||
address=/.v.weishi.qq.com/0.0.0.0
|
||||
address=/.pearvideo.com/0.0.0.0
|
||||
address=/.miaopai.com/0.0.0.0
|
||||
address=/.kuaishou.com/0.0.0.0
|
||||
address=/.qupai.me/0.0.0.0
|
||||
address=/.meipai.com/0.0.0.0
|
||||
address=/.huoshan.com/0.0.0.0
|
||||
address=/.ergengtv.com/0.0.0.0
|
||||
address=/.baijiahao.baidu.com/0.0.0.0
|
||||
address=/.xiongzhang.baidu.com/0.0.0.0
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
0
package/lean/luci-app-adbyby-plus/root/usr/share/adbyby/dnsmasq.adblock
Executable file → Normal file
0
package/lean/luci-app-adbyby-plus/root/usr/share/adbyby/dnsmasq.adblock
Executable file → Normal file
0
package/lean/luci-app-adbyby-plus/root/usr/share/adbyby/dnsmasq.ads
Executable file → Normal file
0
package/lean/luci-app-adbyby-plus/root/usr/share/adbyby/dnsmasq.ads
Executable file → Normal file
0
package/lean/luci-app-adbyby-plus/root/usr/share/adbyby/dnsmasq.esc
Executable file → Normal file
0
package/lean/luci-app-adbyby-plus/root/usr/share/adbyby/dnsmasq.esc
Executable file → Normal file
@ -1,14 +1,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-ssr-plus
|
||||
PKG_VERSION:=181
|
||||
PKG_RELEASE:=2
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
PKG_VERSION:=182
|
||||
PKG_RELEASE:=1
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
/etc/config/shadowsocksr
|
||||
/etc/ssr/
|
||||
/etc/ssrplus/
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/config
|
||||
@ -56,7 +54,7 @@ PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server
|
||||
|
||||
LUCI_TITLE:=SS/SSR/V2Ray/Xray/Trojan/NaiveProxy/Socks5/Tun LuCI interface
|
||||
LUCI_TITLE:=SS/SSR/V2Ray/Trojan/NaiveProxy/Socks5/Tun LuCI interface
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:=+shadowsocksr-libev-alt +ipset +ip-full +iptables-mod-tproxy +dnsmasq-full +coreutils +coreutils-base64 +pdnsd-alt +wget +lua +libuci-lua \
|
||||
+microsocks +dns2socks +shadowsocks-libev-ss-local +shadowsocksr-libev-ssr-local +shadowsocks-libev-ss-redir +simple-obfs +tcping +resolveip\
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
-- Copyright (C) 2017 yushi studio <ywb94@qq.com>
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
module("luci.controller.shadowsocksr", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/shadowsocksr") then
|
||||
return
|
||||
end
|
||||
entry({"admin", "services", "shadowsocksr"}, alias("admin", "services", "shadowsocksr", "client"),_("ShadowSocksR Plus+"), 10).dependent = true
|
||||
entry({"admin", "services", "shadowsocksr", "client"}, cbi("shadowsocksr/client"),_("SSR Client"), 10).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "servers"}, arcombine(cbi("shadowsocksr/servers", {autoapply = true}), cbi("shadowsocksr/client-config")),_("Severs Nodes"), 20).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "control"},cbi("shadowsocksr/control"), _("Access Control"), 30).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "advanced"},cbi("shadowsocksr/advanced"),_("Advanced Settings"), 50).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "server"},arcombine(cbi("shadowsocksr/server"), cbi("shadowsocksr/server-config")),_("SSR Server"), 60).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "status"},form("shadowsocksr/status"),_("Status"), 70).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr"}, alias("admin", "services", "shadowsocksr", "client"), _("ShadowSocksR Plus+"), 10).dependent = true
|
||||
entry({"admin", "services", "shadowsocksr", "client"}, cbi("shadowsocksr/client"), _("SSR Client"), 10).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "servers"}, arcombine(cbi("shadowsocksr/servers", {autoapply = true}), cbi("shadowsocksr/client-config")), _("Severs Nodes"), 20).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "control"}, cbi("shadowsocksr/control"), _("Access Control"), 30).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "advanced"}, cbi("shadowsocksr/advanced"), _("Advanced Settings"), 50).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "server"}, arcombine(cbi("shadowsocksr/server"), cbi("shadowsocksr/server-config")), _("SSR Server"), 60).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "status"}, form("shadowsocksr/status"), _("Status"), 70).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "check"}, call("check_status"))
|
||||
entry({"admin", "services", "shadowsocksr", "refresh"}, call("refresh_data"))
|
||||
entry({"admin", "services", "shadowsocksr", "subscribe"}, call("subscribe"))
|
||||
entry({"admin", "services", "shadowsocksr", "checkport"}, call("check_port"))
|
||||
entry({"admin", "services", "shadowsocksr", "log"},form("shadowsocksr/log"),_("Log"), 80).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr","run"},call("act_status")).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "log"}, form("shadowsocksr/log"), _("Log"), 80).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "run"}, call("act_status")).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "ping"}, call("act_ping")).leaf = true
|
||||
entry({"admin", "services", "shadowsocksr", "reset"}, call("act_reset"))
|
||||
end
|
||||
|
||||
function subscribe()
|
||||
luci.sys.call("/usr/bin/lua /usr/share/shadowsocksr/subscribe.lua >> /tmp/ssrplus.log 2>&1")
|
||||
luci.sys.call("/usr/bin/lua /usr/share/shadowsocksr/subscribe.lua >>/var/log/ssrplus.log")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ret = 1})
|
||||
end
|
||||
@ -41,16 +41,16 @@ function act_ping()
|
||||
local domain = luci.http.formvalue("domain")
|
||||
local port = luci.http.formvalue("port")
|
||||
e.index = luci.http.formvalue("index")
|
||||
local iret = luci.sys.call(" ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null")
|
||||
local iret = luci.sys.call("ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null")
|
||||
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("ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*.[0-9]' | awk -F '=' '{print$2}'" % domain)
|
||||
if (e.ping == "") then
|
||||
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))
|
||||
end
|
||||
-- e.ping = luci.sys.exec("ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*.[0-9]' | awk -F '=' '{print$2}'" % domain)
|
||||
-- if (e.ping == "") then
|
||||
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))
|
||||
-- end
|
||||
if (iret == 0) then
|
||||
luci.sys.call(" ipset del ss_spec_wan_ac " .. domain)
|
||||
end
|
||||
@ -72,55 +72,9 @@ end
|
||||
|
||||
function refresh_data()
|
||||
local set = luci.http.formvalue("set")
|
||||
local uci = luci.model.uci.cursor()
|
||||
local icount = 0
|
||||
local retstring = 0
|
||||
local function update(url, file, type, file2)
|
||||
local Num = 1
|
||||
refresh_cmd = "wget-ssl --no-check-certificate -t 3 -T 10 -O- " .. url .. " > /tmp/ssr-update." .. type
|
||||
sret = luci.sys.call(refresh_cmd .. " 2>/dev/null")
|
||||
if sret == 0 then
|
||||
if type == "gfw_data" then
|
||||
luci.sys.call("/usr/bin/ssr-gfw " .. type)
|
||||
Num = 2
|
||||
end
|
||||
if type == "ad_data" then
|
||||
luci.sys.call("/usr/bin/ssr-ad " .. type)
|
||||
end
|
||||
local new_md5 = luci.sys.exec("echo -n $([ -f '/tmp/ssr-update." .. type .. "' ] && md5sum /tmp/ssr-update." .. type .. " | awk '{print $1}')")
|
||||
local old_md5 = luci.sys.exec("echo -n $([ -f '" .. file .. "' ] && md5sum " .. file .. " | awk '{print $1}')")
|
||||
if new_md5 == old_md5 then
|
||||
retstring = "0"
|
||||
else
|
||||
icount = luci.sys.exec("cat /tmp/ssr-update." .. type .. " | wc -l")
|
||||
luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file)
|
||||
if file2 then luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file2) end
|
||||
retstring = tostring(tonumber(icount)/Num)
|
||||
if type == "gfw_data" or type == "ad_data" then
|
||||
luci.sys.exec("/usr/share/shadowsocksr/gfw2ipset.sh")
|
||||
else
|
||||
luci.sys.exec("/usr/share/shadowsocksr/chinaipset.sh /tmp/etc/china_ssr.txt")
|
||||
end
|
||||
end
|
||||
else
|
||||
retstring = "-1"
|
||||
end
|
||||
luci.sys.exec("rm -f /tmp/ssr-update." .. type)
|
||||
end
|
||||
if set == "gfw_data" then
|
||||
update(uci:get_first("shadowsocksr", "global", "gfwlist_url", "https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt"), "/etc/ssr/gfw_list.conf", set, "/tmp/dnsmasq.ssr/gfw_list.conf")
|
||||
end
|
||||
if set == "ip_data" then
|
||||
update(uci:get_first("shadowsocksr", "global", "chnroute_url","https://ispip.clang.cn/all_cn.txt"), "/etc/ssr/china_ssr.txt", set, "/tmp/etc/china_ssr.txt")
|
||||
end
|
||||
if set == "ad_data" then
|
||||
update(uci:get_first("shadowsocksr", "global", "adblock_url","https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt"), "/etc/ssr/ad.conf", set, "/tmp/dnsmasq.ssr/ad.conf")
|
||||
end
|
||||
if set == "nfip_data" then
|
||||
update(uci:get_first("shadowsocksr", "global", "nfip_url","https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt"), "/etc/ssr/netflixip.list", set)
|
||||
end
|
||||
local retstring = luci.sys.exec("/usr/bin/lua /usr/share/shadowsocksr/update.lua " .. set)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ret = retstring,retcount = icount})
|
||||
luci.http.write_json({ret = tonumber(retstring)})
|
||||
end
|
||||
|
||||
function check_port()
|
||||
@ -134,13 +88,13 @@ function check_port()
|
||||
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:%s" % {s.server, s.server_port}
|
||||
end
|
||||
iret = luci.sys.call("ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null")
|
||||
socket = nixio.socket("inet", "stream")
|
||||
socket:setopt("socket", "rcvtimeo", 3)
|
||||
socket:setopt("socket", "sndtimeo", 3)
|
||||
ret = socket:connect(s.server,s.server_port)
|
||||
ret = socket:connect(s.server, s.server_port)
|
||||
if tostring(ret) == "true" then
|
||||
socket:close()
|
||||
retstring = retstring .. "<font color = 'green'>[" .. server_name .. "] OK.</font><br />"
|
||||
@ -154,3 +108,9 @@ function check_port()
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ret = retstring})
|
||||
end
|
||||
|
||||
function act_reset()
|
||||
nixio.exec("/etc/init.d/shadowsocksr", "reset")
|
||||
http.redirect(luci.dispatcher.build_url('admin/services/shadowsocksr'))
|
||||
return
|
||||
end
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
local shadowsocksr = "shadowsocksr"
|
||||
local uci = luci.model.uci.cursor()
|
||||
local server_table = {}
|
||||
|
||||
uci:foreach(shadowsocksr, "servers", function(s)
|
||||
uci:foreach("shadowsocksr", "servers", function(s)
|
||||
if s.alias then
|
||||
server_table[s[".name"]] = "[%s]:%s" %{string.upper(s.type), s.alias}
|
||||
server_table[s[".name"]] = "[%s]:%s" % {string.upper(s.type), s.alias}
|
||||
elseif s.server and s.server_port then
|
||||
server_table[s[".name"]] = "[%s]:%s:%s" %{string.upper(s.type), s.server, s.server_port}
|
||||
server_table[s[".name"]] = "[%s]:%s:%s" % {string.upper(s.type), s.server, s.server_port}
|
||||
end
|
||||
end)
|
||||
|
||||
local key_table = {}
|
||||
for key,_ in pairs(server_table) do
|
||||
table.insert(key_table,key)
|
||||
end
|
||||
local key_table = {}
|
||||
for key, _ in pairs(server_table) do
|
||||
table.insert(key_table, key)
|
||||
end
|
||||
|
||||
table.sort(key_table)
|
||||
|
||||
@ -49,14 +48,16 @@ o = s:option(Flag, "adblock", translate("Enable adblock"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "adblock_url", translate("adblock_url"))
|
||||
o:value("https://neodev.team/lite_host_dnsmasq.conf", translate("NEO DEV HOST Lite"))
|
||||
o:value("https://neodev.team/host_dnsmasq.conf", translate("NEO DEV HOST Full"))
|
||||
o:value("https://anti-ad.net/anti-ad-for-dnsmasq.conf", translate("anti-AD"))
|
||||
o:value("https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt", translate("Easylist China"))
|
||||
o.default = "https://anti-ad.net/anti-ad-for-dnsmasq.conf"
|
||||
o.default = "https://neodev.team/lite_host_dnsmasq.conf"
|
||||
o:depends("adblock", "1")
|
||||
o.description = translate("Support AdGuardHome and DNSMASQ format list")
|
||||
|
||||
o = s:option(Value, "gfwlist_url", translate("gfwlist Update url"))
|
||||
o:value("https://cdn.jsdelivr.net/gh/v2fly/domain-list-community@release/gfwlist.txt", translate("v2fly/domain-list-community"))
|
||||
o:value("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/gfw.txt", translate("Loyalsoldier/v2ray-rules-dat"))
|
||||
o:value("https://cdn.jsdelivr.net/gh/Loukky/gfwlist-by-loukky/gfwlist.txt", translate("Loukky/gfwlist-by-loukky"))
|
||||
o:value("https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt", translate("gfwlist/gfwlist"))
|
||||
o.default = "https://cdn.jsdelivr.net/gh/v2fly/domain-list-community@release/gfwlist.txt"
|
||||
@ -72,6 +73,10 @@ o:value("https://cdn.jsdelivr.net/gh/QiuSimons/Netflix_IP/getflix.txt", translat
|
||||
o.default = "https://cdn.jsdelivr.net/gh/QiuSimons/Netflix_IP/NF_only.txt"
|
||||
o.description = translate("Customize Netflix IP Url")
|
||||
|
||||
o = s:option(Button, "reset", translate("Reset to defaults"))
|
||||
o.rawhtml = true
|
||||
o.template = "shadowsocksr/reset"
|
||||
|
||||
-- [[ SOCKS5 Proxy ]]--
|
||||
s = m:section(TypedSection, "socks5_proxy", translate("Global SOCKS5 Proxy Server"))
|
||||
s.anonymous = true
|
||||
@ -79,7 +84,9 @@ s.anonymous = true
|
||||
o = s:option(ListValue, "server", translate("Server"))
|
||||
o:value("nil", translate("Disable"))
|
||||
o:value("same", translate("Same as Global Server"))
|
||||
for _,key in pairs(key_table) do o:value(key,server_table[key]) end
|
||||
for _, key in pairs(key_table) do
|
||||
o:value(key, server_table[key])
|
||||
end
|
||||
o.default = "nil"
|
||||
o.rmempty = false
|
||||
|
||||
|
||||
@ -1,118 +1,121 @@
|
||||
-- Copyright (C) 2017 yushi studio <ywb94@qq.com> github.com/ywb94
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
require "nixio.fs"
|
||||
require "luci.sys"
|
||||
require "luci.http"
|
||||
local m, s, o,kcp_enable
|
||||
local shadowsocksr = "shadowsocksr"
|
||||
local m, s, o, kcp_enable
|
||||
local sid = arg[1]
|
||||
local uuid = luci.sys.exec("cat /proc/sys/kernel/random/uuid")
|
||||
|
||||
local function isKcptun(file)
|
||||
if not nixio.fs.access(file, "rwx", "rx", "rx") then
|
||||
nixio.fs.chmod(file, 755)
|
||||
end
|
||||
local str = luci.sys.exec(file .. " -v | awk '{printf $1}'")
|
||||
return (str:lower() == "kcptun")
|
||||
if not nixio.fs.access(file, "rwx", "rx", "rx") then
|
||||
nixio.fs.chmod(file, 755)
|
||||
end
|
||||
local str = luci.sys.exec(file .. " -v | awk '{printf $1}'")
|
||||
return (str:lower() == "kcptun")
|
||||
end
|
||||
|
||||
local server_table = {}
|
||||
local encrypt_methods = {
|
||||
"none",
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5-6",
|
||||
"rc4-md5",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf",
|
||||
-- ssr
|
||||
"none",
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5-6",
|
||||
"rc4-md5",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
}
|
||||
|
||||
local encrypt_methods_ss = {
|
||||
-- aead
|
||||
"aes-128-gcm",
|
||||
"aes-192-gcm",
|
||||
"aes-256-gcm",
|
||||
"chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305",
|
||||
-- stream
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf",
|
||||
-- aead
|
||||
"aes-128-gcm",
|
||||
"aes-192-gcm",
|
||||
"aes-256-gcm",
|
||||
"chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305",
|
||||
-- stream
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
}
|
||||
|
||||
local protocol = {
|
||||
"origin",
|
||||
"verify_deflate",
|
||||
"auth_sha1_v4",
|
||||
"auth_aes128_sha1",
|
||||
"auth_aes128_md5",
|
||||
"auth_chain_a",
|
||||
"auth_chain_b",
|
||||
"auth_chain_c",
|
||||
"auth_chain_d",
|
||||
"auth_chain_e",
|
||||
"auth_chain_f",
|
||||
-- ssr
|
||||
"origin",
|
||||
"verify_deflate",
|
||||
"auth_sha1_v4",
|
||||
"auth_aes128_sha1",
|
||||
"auth_aes128_md5",
|
||||
"auth_chain_a",
|
||||
"auth_chain_b",
|
||||
"auth_chain_c",
|
||||
"auth_chain_d",
|
||||
"auth_chain_e",
|
||||
"auth_chain_f"
|
||||
}
|
||||
|
||||
obfs = {
|
||||
"plain",
|
||||
"http_simple",
|
||||
"http_post",
|
||||
"random_head",
|
||||
"tls1.2_ticket_auth",
|
||||
-- ssr
|
||||
"plain",
|
||||
"http_simple",
|
||||
"http_post",
|
||||
"random_head",
|
||||
"tls1.2_ticket_auth"
|
||||
}
|
||||
|
||||
local securitys = {
|
||||
"auto",
|
||||
"none",
|
||||
"aes-128-gcm",
|
||||
"chacha20-poly1305"
|
||||
-- vmess
|
||||
"auto",
|
||||
"none",
|
||||
"aes-128-gcm",
|
||||
"chacha20-poly1305"
|
||||
}
|
||||
|
||||
local flows = {
|
||||
"xtls-rprx-origin",
|
||||
"xtls-rprx-origin-udp443",
|
||||
"xtls-rprx-direct",
|
||||
"xtls-rprx-direct-udp443",
|
||||
"xtls-rprx-splice",
|
||||
"xtls-rprx-splice-udp443"
|
||||
-- xlts
|
||||
"xtls-rprx-origin",
|
||||
"xtls-rprx-origin-udp443",
|
||||
"xtls-rprx-direct",
|
||||
"xtls-rprx-direct-udp443",
|
||||
"xtls-rprx-splice",
|
||||
"xtls-rprx-splice-udp443"
|
||||
}
|
||||
|
||||
m = Map(shadowsocksr, translate("Edit ShadowSocksR Server"))
|
||||
m = Map("shadowsocksr", translate("Edit ShadowSocksR Server"))
|
||||
m.redirect = luci.dispatcher.build_url("admin/services/shadowsocksr/servers")
|
||||
if m.uci:get(shadowsocksr, sid) ~= "servers" then
|
||||
luci.http.redirect(m.redirect)
|
||||
return
|
||||
if m.uci:get("shadowsocksr", sid) ~= "servers" then
|
||||
luci.http.redirect(m.redirect)
|
||||
return
|
||||
end
|
||||
|
||||
-- [[ Servers Setting ]]--
|
||||
@ -120,29 +123,31 @@ s = m:section(NamedSection, sid, "servers")
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
o = s:option(DummyValue,"ssr_url","SS/SSR/V2RAY/TROJAN URL")
|
||||
o = s:option(DummyValue, "ssr_url", "SS/SSR/V2RAY/TROJAN URL")
|
||||
o.rawhtml = true
|
||||
o.template = "shadowsocksr/ssrurl"
|
||||
o.value =sid
|
||||
o.value = sid
|
||||
|
||||
o = s:option(ListValue, "type", translate("Server Node Type"))
|
||||
o:value("ssr", translate("ShadowsocksR"))
|
||||
if nixio.fs.access("/usr/bin/ss-redir") then
|
||||
o:value("ss", translate("Shadowsocks New Version"))
|
||||
if nixio.fs.access("/usr/bin/ssr-redir") then
|
||||
o:value("ssr", translate("ShadowsocksR"))
|
||||
end
|
||||
if nixio.fs.access("/usr/bin/xray") or nixio.fs.access("/usr/bin/xray/xray") or nixio.fs.access("/usr/bin/v2ray/v2ray") or nixio.fs.access("/usr/bin/v2ray") then
|
||||
o:value("v2ray", translate("V2Ray"))
|
||||
o:value("vless", translate("VLESS"))
|
||||
if nixio.fs.access("/usr/bin/ss-redir") then
|
||||
o:value("ss", translate("Shadowsocks New Version"))
|
||||
end
|
||||
if nixio.fs.access("/usr/bin/xray") or nixio.fs.access("/usr/bin/v2ray") then
|
||||
o:value("vmess", translate("Vmess"))
|
||||
o:value("vless", translate("VLESS"))
|
||||
end
|
||||
if nixio.fs.access("/usr/sbin/trojan") then
|
||||
o:value("trojan", translate("Trojan"))
|
||||
o:value("trojan", translate("Trojan"))
|
||||
end
|
||||
if nixio.fs.access("/usr/bin/naive") then
|
||||
o:value("naiveproxy", translate("NaiveProxy"))
|
||||
o:value("naiveproxy", translate("NaiveProxy"))
|
||||
end
|
||||
if nixio.fs.access("/usr/sbin/redsocks2") then
|
||||
o:value("socks5", translate("Socks5"))
|
||||
o:value("tun", translate("Network Tunnel"))
|
||||
o:value("socks5", translate("Socks5"))
|
||||
o:value("tun", translate("Network Tunnel"))
|
||||
end
|
||||
o.description = translate("Using incorrect encryption mothod may causes service fail to start")
|
||||
|
||||
@ -150,7 +155,9 @@ o = s:option(Value, "alias", translate("Alias(optional)"))
|
||||
|
||||
o = s:option(ListValue, "iface", translate("Network interface to use"))
|
||||
for _, e in ipairs(luci.sys.net.devices()) do
|
||||
if e ~= "lo" then o:value(e) end
|
||||
if e ~= "lo" then
|
||||
o:value(e)
|
||||
end
|
||||
end
|
||||
o:depends("type", "tun")
|
||||
o.description = translate("Redirect traffic to this network interface")
|
||||
@ -160,7 +167,7 @@ o.datatype = "host"
|
||||
o.rmempty = false
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "vmess")
|
||||
o:depends("type", "vless")
|
||||
o:depends("type", "trojan")
|
||||
o:depends("type", "naiveproxy")
|
||||
@ -171,7 +178,7 @@ o.datatype = "port"
|
||||
o.rmempty = false
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "vmess")
|
||||
o:depends("type", "vless")
|
||||
o:depends("type", "trojan")
|
||||
o:depends("type", "naiveproxy")
|
||||
@ -185,7 +192,7 @@ o:depends("type", "socks5")
|
||||
o = s:option(Value, "username", translate("Username"))
|
||||
o.rmempty = true
|
||||
o:depends("type", "naiveproxy")
|
||||
o:depends("type", "socks5")
|
||||
o:depends({type = "socks5", auth_enable = true})
|
||||
|
||||
o = s:option(Value, "password", translate("Password"))
|
||||
o.password = true
|
||||
@ -194,29 +201,57 @@ o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
o:depends("type", "trojan")
|
||||
o:depends("type", "naiveproxy")
|
||||
o:depends("type", "socks5")
|
||||
o:depends({type = "socks5", auth_enable = true})
|
||||
|
||||
o = s:option(ListValue, "encrypt_method", translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods) do o:value(v) end
|
||||
for _, v in ipairs(encrypt_methods) do
|
||||
o:value(v)
|
||||
end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ssr")
|
||||
|
||||
o = s:option(ListValue, "encrypt_method_ss", translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods_ss) do o:value(v) end
|
||||
for _, v in ipairs(encrypt_methods_ss) do
|
||||
o:value(v)
|
||||
end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ss")
|
||||
|
||||
-- Shadowsocks Plugin
|
||||
o = s:option(Value, "plugin", translate("Plugin"))
|
||||
o = s:option(ListValue, "plugin", translate("Obfs"))
|
||||
o:value("", translate("None"))
|
||||
if nixio.fs.access("/usr/bin/obfs-local") then
|
||||
o:value("obfs-local", translate("simple-obfs"))
|
||||
end
|
||||
if nixio.fs.access("/usr/bin/v2ray-plugin") then
|
||||
o:value("v2ray-plugin", translate("v2ray-plugin"))
|
||||
end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ss")
|
||||
|
||||
o = s:option(Value, "plugin_opts", translate("Plugin Opts"))
|
||||
o = s:option(ListValue, "simple_obfs", translate("Plugin Opts"))
|
||||
o:value("obfs=tls;obfs-host=", translate("TLS"))
|
||||
o:value("obfs=http;obfs-host=", translate("HTTP"))
|
||||
o:depends("plugin", "obfs-local")
|
||||
o.rmempty = true
|
||||
o:depends("type", "ss")
|
||||
|
||||
o = s:option(ListValue, "v2ray_plugin", translate("Plugin Opts"))
|
||||
o:value("tls;host=", translate("TLS"))
|
||||
o:value("mode=quic;host=", translate("QUIC"))
|
||||
o:value("none", translate("HTTP"))
|
||||
o:depends("plugin", "v2ray-plugin")
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "plugin_opts", translate("Plugin Opts"), translate("Please fill in the Host, for example: www.baidu.com"))
|
||||
o.rmempty = true
|
||||
o:depends({type = "ss", plugin = "obfs-local"})
|
||||
o:depends({type = "ss", v2ray_plugin = "tls;host="})
|
||||
o:depends({type = "ss", v2ray_plugin = "mode=quic;host="})
|
||||
|
||||
o = s:option(ListValue, "protocol", translate("Protocol"))
|
||||
for _, v in ipairs(protocol) do o:value(v) end
|
||||
for _, v in ipairs(protocol) do
|
||||
o:value(v)
|
||||
end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ssr")
|
||||
|
||||
@ -224,7 +259,9 @@ o = s:option(Value, "protocol_param", translate("Protocol param(optional)"))
|
||||
o:depends("type", "ssr")
|
||||
|
||||
o = s:option(ListValue, "obfs", translate("Obfs"))
|
||||
for _, v in ipairs(obfs) do o:value(v) end
|
||||
for _, v in ipairs(obfs) do
|
||||
o:value(v)
|
||||
end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ssr")
|
||||
|
||||
@ -236,13 +273,13 @@ o = s:option(Value, "alter_id", translate("AlterId"))
|
||||
o.datatype = "port"
|
||||
o.default = 16
|
||||
o.rmempty = true
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "vmess")
|
||||
|
||||
-- VmessId
|
||||
o = s:option(Value, "vmess_id", translate("Vmess/VLESS ID (UUID)"))
|
||||
o.rmempty = true
|
||||
o.default = uuid
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "vmess")
|
||||
o:depends("type", "vless")
|
||||
|
||||
-- VLESS Encryption
|
||||
@ -253,9 +290,11 @@ o:depends("type", "vless")
|
||||
|
||||
-- 加密方式
|
||||
o = s:option(ListValue, "security", translate("Encrypt Method"))
|
||||
for _, v in ipairs(securitys) do o:value(v, v:upper()) end
|
||||
for _, v in ipairs(securitys) do
|
||||
o:value(v, v:upper())
|
||||
end
|
||||
o.rmempty = true
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "vmess")
|
||||
|
||||
-- 传输协议
|
||||
o = s:option(ListValue, "transport", translate("Transport"))
|
||||
@ -265,11 +304,10 @@ o:value("ws", "WebSocket")
|
||||
o:value("h2", "HTTP/2")
|
||||
o:value("quic", "QUIC")
|
||||
o.rmempty = true
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "vmess")
|
||||
o:depends("type", "vless")
|
||||
|
||||
-- [[ TCP部分 ]]--
|
||||
|
||||
-- TCP伪装
|
||||
o = s:option(ListValue, "tcp_guise", translate("Camouflage Type"))
|
||||
o:depends("transport", "tcp")
|
||||
@ -288,10 +326,9 @@ o:depends("tcp_guise", "http")
|
||||
o.rmempty = true
|
||||
|
||||
-- [[ WS部分 ]]--
|
||||
|
||||
-- WS域名
|
||||
o = s:option(Value, "ws_host", translate("WebSocket Host"))
|
||||
o:depends("transport", "ws")
|
||||
o:depends({transport = "ws", tls = false})
|
||||
o.rmempty = true
|
||||
|
||||
-- WS路径
|
||||
@ -312,7 +349,6 @@ o:depends("transport", "h2")
|
||||
o.rmempty = true
|
||||
|
||||
-- [[ QUIC部分 ]]--
|
||||
|
||||
o = s:option(ListValue, "quic_security", translate("QUIC Security"))
|
||||
o:depends("transport", "quic")
|
||||
o:value("none", translate("None"))
|
||||
@ -331,19 +367,18 @@ o:value("none", translate("None"))
|
||||
o:value("srtp", translate("VideoCall (SRTP)"))
|
||||
o:value("utp", translate("BitTorrent (uTP)"))
|
||||
o:value("wechat-video", translate("WechatVideo"))
|
||||
o:value("dtls", "DTLS 1.2")
|
||||
o:value("wireguard", "WireGuard")
|
||||
o:value("dtls", translate("DTLS 1.2"))
|
||||
o:value("wireguard", translate("WireGuard"))
|
||||
|
||||
-- [[ mKCP部分 ]]--
|
||||
|
||||
o = s:option(ListValue, "kcp_guise", translate("Camouflage Type"))
|
||||
o:depends("transport", "kcp")
|
||||
o:value("none", translate("None"))
|
||||
o:value("srtp", translate("VideoCall (SRTP)"))
|
||||
o:value("utp", translate("BitTorrent (uTP)"))
|
||||
o:value("wechat-video", translate("WechatVideo"))
|
||||
o:value("dtls", "DTLS 1.2")
|
||||
o:value("wireguard", "WireGuard")
|
||||
o:value("dtls", translate("DTLS 1.2"))
|
||||
o:value("wireguard", translate("WireGuard"))
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "mtu", translate("MTU"))
|
||||
@ -383,55 +418,56 @@ o.default = 2
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "seed", translate("Obfuscate password (optional)"))
|
||||
o:depends({type="vless", transport="kcp"})
|
||||
o:depends({type = "vless", transport = "kcp"})
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Flag, "congestion", translate("Congestion"))
|
||||
o:depends("transport", "kcp")
|
||||
o.rmempty = true
|
||||
|
||||
-- [[ allowInsecure ]]--
|
||||
o = s:option(Flag, "insecure", translate("allowInsecure"))
|
||||
o.rmempty = false
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "vless")
|
||||
o:depends("type", "trojan")
|
||||
o.default = "0"
|
||||
o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.")
|
||||
-- [[ TLS ]]--
|
||||
o = s:option(Flag, "tls", translate("TLS"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "vless")
|
||||
o:depends("type", "vmess")
|
||||
o:depends({type = "vless", xtls = false})
|
||||
o:depends("type", "trojan")
|
||||
|
||||
o = s:option(Value, "tls_host", translate("TLS Host"))
|
||||
--o:depends("type", "trojan")
|
||||
o:depends("tls", "1")
|
||||
o.rmempty = true
|
||||
|
||||
-- XTLS
|
||||
if nixio.fs.access("/usr/bin/xray") or nixio.fs.access("/usr/bin/xray/xray") then
|
||||
o = s:option(Flag, "xtls", translate("XTLS"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends({type="vless", tls=true})
|
||||
if nixio.fs.access("/usr/bin/xray") then
|
||||
o = s:option(Flag, "xtls", translate("XTLS"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends({type = "vless", transport = "tcp", tls = false})
|
||||
end
|
||||
|
||||
-- Flow
|
||||
o = s:option(Value, "vless_flow", translate("Flow"))
|
||||
for _, v in ipairs(flows) do o:value(v, v) end
|
||||
for _, v in ipairs(flows) do
|
||||
o:value(v, v)
|
||||
end
|
||||
o.rmempty = true
|
||||
o.default = "xtls-rprx-origin"
|
||||
o:depends("xtls", "1")
|
||||
o.default = "xtls-rprx-splice"
|
||||
o:depends("xtls", true)
|
||||
|
||||
o = s:option(Value, "tls_host", translate("TLS Host"))
|
||||
o:depends("type", "trojan")
|
||||
o:depends("tls", true)
|
||||
o:depends("xtls", true)
|
||||
o.rmempty = true
|
||||
|
||||
-- [[ allowInsecure ]]--
|
||||
o = s:option(Flag, "insecure", translate("allowInsecure"))
|
||||
o.rmempty = false
|
||||
o:depends("tls", true)
|
||||
o:depends("xtls", true)
|
||||
o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.")
|
||||
|
||||
-- [[ Mux ]]--
|
||||
o = s:option(Flag, "mux", translate("Mux"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends("type", "v2ray")
|
||||
o:depends({type="vless", xtls=false})
|
||||
o.rmempty = false
|
||||
o:depends("type", "vmess")
|
||||
o:depends({type = "vless", xtls = false})
|
||||
|
||||
o = s:option(Value, "concurrency", translate("Concurrency"))
|
||||
o.datatype = "uinteger"
|
||||
@ -444,7 +480,7 @@ o = s:option(Flag, "certificate", translate("Self-signed Certificate"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends("type", "trojan")
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "vmess")
|
||||
o:depends("type", "vless")
|
||||
o.description = translate("If you have a self-signed certificate,please check the box")
|
||||
|
||||
@ -455,31 +491,31 @@ o:depends("certificate", 1)
|
||||
cert_dir = "/etc/ssl/private/"
|
||||
local path
|
||||
|
||||
luci.http.setfilehandler(
|
||||
function(meta, chunk, eof)
|
||||
if not fd then
|
||||
if (not meta) or (not meta.name) or (not meta.file) then return end
|
||||
fd = nixio.open(cert_dir .. meta.file, "w")
|
||||
if not fd then
|
||||
path = translate("Create upload file error.")
|
||||
return
|
||||
end
|
||||
end
|
||||
if chunk and fd then
|
||||
fd:write(chunk)
|
||||
end
|
||||
if eof and fd then
|
||||
fd:close()
|
||||
fd = nil
|
||||
path = '/etc/ssl/private/' .. meta.file .. ''
|
||||
end
|
||||
end
|
||||
)
|
||||
luci.http.setfilehandler(function(meta, chunk, eof)
|
||||
if not fd then
|
||||
if (not meta) or (not meta.name) or (not meta.file) then
|
||||
return
|
||||
end
|
||||
fd = nixio.open(cert_dir .. meta.file, "w")
|
||||
if not fd then
|
||||
path = translate("Create upload file error.")
|
||||
return
|
||||
end
|
||||
end
|
||||
if chunk and fd then
|
||||
fd:write(chunk)
|
||||
end
|
||||
if eof and fd then
|
||||
fd:close()
|
||||
fd = nil
|
||||
path = '/etc/ssl/private/' .. meta.file .. ''
|
||||
end
|
||||
end)
|
||||
if luci.http.formvalue("upload") then
|
||||
local f = luci.http.formvalue("ulfile")
|
||||
if #f <= 0 then
|
||||
path = translate("No specify upload file.")
|
||||
end
|
||||
local f = luci.http.formvalue("ulfile")
|
||||
if #f <= 0 then
|
||||
path = translate("No specify upload file.")
|
||||
end
|
||||
end
|
||||
|
||||
o = s:option(Value, "certpath", translate("Current Certificate Path"))
|
||||
@ -505,40 +541,40 @@ o.default = 1234
|
||||
o.rmempty = false
|
||||
|
||||
if nixio.fs.access("/usr/bin/kcptun-client") then
|
||||
kcp_enable = s:option(Flag, "kcp_enable", translate("KcpTun Enable"), translate("bin:/usr/bin/kcptun-client"))
|
||||
kcp_enable.rmempty = true
|
||||
kcp_enable.default = "0"
|
||||
kcp_enable:depends("type", "ssr")
|
||||
kcp_enable:depends("type", "ss")
|
||||
kcp_enable = s:option(Flag, "kcp_enable", translate("KcpTun Enable"), translate("bin:/usr/bin/kcptun-client"))
|
||||
kcp_enable.rmempty = true
|
||||
kcp_enable.default = "0"
|
||||
kcp_enable:depends("type", "ssr")
|
||||
kcp_enable:depends("type", "ss")
|
||||
|
||||
o = s:option(Value, "kcp_port", translate("KcpTun Port"))
|
||||
o.datatype = "port"
|
||||
o.default = 4000
|
||||
function o.validate(self, value, section)
|
||||
local kcp_file="/usr/bin/kcptun-client"
|
||||
local enable = kcp_enable:formvalue(section) or kcp_enable.disabled
|
||||
if enable == kcp_enable.enabled then
|
||||
if not nixio.fs.access(kcp_file) then
|
||||
return nil, translate("Haven't a Kcptun executable file")
|
||||
elseif not isKcptun(kcp_file) then
|
||||
return nil, translate("Not a Kcptun executable file")
|
||||
end
|
||||
end
|
||||
o = s:option(Value, "kcp_port", translate("KcpTun Port"))
|
||||
o.datatype = "port"
|
||||
o.default = 4000
|
||||
function o.validate(self, value, section)
|
||||
local kcp_file = "/usr/bin/kcptun-client"
|
||||
local enable = kcp_enable:formvalue(section) or kcp_enable.disabled
|
||||
if enable == kcp_enable.enabled then
|
||||
if not nixio.fs.access(kcp_file) then
|
||||
return nil, translate("Haven't a Kcptun executable file")
|
||||
elseif not isKcptun(kcp_file) then
|
||||
return nil, translate("Not a Kcptun executable file")
|
||||
end
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
return value
|
||||
end
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
|
||||
o = s:option(Value, "kcp_password", translate("KcpTun Password"))
|
||||
o.password = true
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
o = s:option(Value, "kcp_password", translate("KcpTun Password"))
|
||||
o.password = true
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
|
||||
o = s:option(Value, "kcp_param", translate("KcpTun Param"))
|
||||
o.default = "--nocomp"
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
o = s:option(Value, "kcp_param", translate("KcpTun Param"))
|
||||
o.default = "--nocomp"
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
end
|
||||
|
||||
return m
|
||||
|
||||
@ -1,27 +1,24 @@
|
||||
-- Copyright (C) 2017 yushi studio <ywb94@qq.com> github.com/ywb94
|
||||
-- Copyright (C) 2018 lean <coolsnowwolf@gmail.com> github.com/coolsnowwolf
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
local m, s, sec, o, kcp_enable
|
||||
local shadowsocksr = "shadowsocksr"
|
||||
local uci = luci.model.uci.cursor()
|
||||
m = Map(shadowsocksr, translate("ShadowSocksR Plus+ Settings"),
|
||||
translate("<h3>Support SS/SSR/V2RAY/TROJAN/NAIVEPROXY/SOCKS5/TUN etc.</h3>"))
|
||||
m = Map("shadowsocksr", translate("ShadowSocksR Plus+ Settings"), translate("<h3>Support SS/SSR/V2RAY/TROJAN/NAIVEPROXY/SOCKS5/TUN etc.</h3>"))
|
||||
|
||||
m:section(SimpleSection).template = "shadowsocksr/status"
|
||||
|
||||
local server_table = {}
|
||||
uci:foreach(shadowsocksr, "servers", function(s)
|
||||
uci:foreach("shadowsocksr", "servers", function(s)
|
||||
if s.alias then
|
||||
server_table[s[".name"]] = "[%s]:%s" %{string.upper(s.type), s.alias}
|
||||
server_table[s[".name"]] = "[%s]:%s" % {string.upper(s.type), s.alias}
|
||||
elseif s.server and s.server_port then
|
||||
server_table[s[".name"]] = "[%s]:%s:%s" %{string.upper(s.type), s.server, s.server_port}
|
||||
server_table[s[".name"]] = "[%s]:%s:%s" % {string.upper(s.type), s.server, s.server_port}
|
||||
end
|
||||
end)
|
||||
|
||||
local key_table = {}
|
||||
for key,_ in pairs(server_table) do
|
||||
table.insert(key_table,key)
|
||||
for key, _ in pairs(server_table) do
|
||||
table.insert(key_table, key)
|
||||
end
|
||||
|
||||
table.sort(key_table)
|
||||
@ -32,26 +29,32 @@ s.anonymous = true
|
||||
|
||||
o = s:option(ListValue, "global_server", translate("Main Server"))
|
||||
o:value("nil", translate("Disable"))
|
||||
for _,key in pairs(key_table) do o:value(key,server_table[key]) end
|
||||
for _, key in pairs(key_table) do
|
||||
o:value(key, server_table[key])
|
||||
end
|
||||
o.default = "nil"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "udp_relay_server", translate("Game Mode UDP Server"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("same", translate("Same as Global Server"))
|
||||
for _,key in pairs(key_table) do o:value(key,server_table[key]) end
|
||||
for _, key in pairs(key_table) do
|
||||
o:value(key, server_table[key])
|
||||
end
|
||||
|
||||
o = s:option(ListValue, "netflix_server", translate("Netflix Node"))
|
||||
o:value("nil", translate("Disable"))
|
||||
o:value("same", translate("Same as Global Server"))
|
||||
for _,key in pairs(key_table) do o:value(key,server_table[key]) end
|
||||
for _, key in pairs(key_table) do
|
||||
o:value(key, server_table[key])
|
||||
end
|
||||
o.default = "nil"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "netflix_proxy", translate("External Proxy Mode"))
|
||||
o.rmempty = false
|
||||
o.description = translate("Forward Netflix Proxy through Main Proxy")
|
||||
o.default="0"
|
||||
o.default = "0"
|
||||
|
||||
o = s:option(ListValue, "threads", translate("Multi Threads Option"))
|
||||
o:value("0", translate("Auto Threads"))
|
||||
|
||||
@ -36,7 +36,7 @@ o.rmempty = false
|
||||
|
||||
o = s:taboption("lan_ac", DynamicList, "lan_ac_ips", translate("LAN Host List"))
|
||||
o.datatype = "ipaddr"
|
||||
luci.ip.neighbors({ family = 4 }, function(entry)
|
||||
luci.ip.neighbors({family = 4}, function(entry)
|
||||
if entry.reachable then
|
||||
o:value(entry.dest:string())
|
||||
end
|
||||
@ -46,7 +46,7 @@ o:depends("lan_ac_mode", "b")
|
||||
|
||||
o = s:taboption("lan_ac", DynamicList, "lan_bp_ips", translate("LAN Bypassed Host List"))
|
||||
o.datatype = "ipaddr"
|
||||
luci.ip.neighbors({ family = 4 }, function(entry)
|
||||
luci.ip.neighbors({family = 4}, function(entry)
|
||||
if entry.reachable then
|
||||
o:value(entry.dest:string())
|
||||
end
|
||||
@ -54,7 +54,7 @@ end)
|
||||
|
||||
o = s:taboption("lan_ac", DynamicList, "lan_fp_ips", translate("LAN Force Proxy Host List"))
|
||||
o.datatype = "ipaddr"
|
||||
luci.ip.neighbors({ family = 4 }, function(entry)
|
||||
luci.ip.neighbors({family = 4}, function(entry)
|
||||
if entry.reachable then
|
||||
o:value(entry.dest:string())
|
||||
end
|
||||
@ -62,7 +62,7 @@ end)
|
||||
|
||||
o = s:taboption("lan_ac", DynamicList, "lan_gm_ips", translate("Game Mode Host List"))
|
||||
o.datatype = "ipaddr"
|
||||
luci.ip.neighbors({ family = 4 }, function(entry)
|
||||
luci.ip.neighbors({family = 4}, function(entry)
|
||||
if entry.reachable then
|
||||
o:value(entry.dest:string())
|
||||
end
|
||||
@ -77,7 +77,7 @@ end)
|
||||
-- o.rmempty = false
|
||||
|
||||
s:tab("esc", translate("Bypass Domain List"))
|
||||
local escconf = "/etc/ssr/white.list"
|
||||
local escconf = "/etc/ssrplus/white.list"
|
||||
o = s:taboption("esc", TextValue, "escconf")
|
||||
o.rows = 13
|
||||
o.wrap = "off"
|
||||
@ -93,7 +93,7 @@ o.remove = function(self, section, value)
|
||||
end
|
||||
|
||||
s:tab("block", translate("Black Domain List"))
|
||||
local blockconf = "/etc/ssr/black.list"
|
||||
local blockconf = "/etc/ssrplus/black.list"
|
||||
o = s:taboption("block", TextValue, "blockconf")
|
||||
o.rows = 13
|
||||
o.wrap = "off"
|
||||
@ -109,7 +109,7 @@ o.remove = function(self, section, value)
|
||||
end
|
||||
|
||||
s:tab("denydomain", translate("Deny Domain List"))
|
||||
local denydomainconf = "/etc/ssr/deny.list"
|
||||
local denydomainconf = "/etc/ssrplus/deny.list"
|
||||
o = s:taboption("denydomain", TextValue, "denydomainconf")
|
||||
o.rows = 13
|
||||
o.wrap = "off"
|
||||
@ -125,7 +125,7 @@ o.remove = function(self, section, value)
|
||||
end
|
||||
|
||||
s:tab("netflix", translate("Netflix Domain List"))
|
||||
local netflixconf = "/etc/ssr/netflix.list"
|
||||
local netflixconf = "/etc/ssrplus/netflix.list"
|
||||
o = s:taboption("netflix", TextValue, "netflixconf")
|
||||
o.rows = 13
|
||||
o.wrap = "off"
|
||||
|
||||
@ -7,8 +7,8 @@ t = f:field(TextValue, "conf")
|
||||
t.rmempty = true
|
||||
t.rows = 20
|
||||
function t.cfgvalue()
|
||||
if nixio.fs.access("/tmp/ssrplus.log") then
|
||||
local logs = luci.util.execi("cat /tmp/ssrplus.log")
|
||||
if nixio.fs.access("/var/log/ssrplus.log") then
|
||||
local logs = luci.util.execi("cat /var/log/ssrplus.log")
|
||||
local s = ""
|
||||
for line in logs do
|
||||
s = line .. "\n" .. s
|
||||
@ -16,5 +16,5 @@ function t.cfgvalue()
|
||||
return s
|
||||
end
|
||||
end
|
||||
t.readonly="readonly"
|
||||
t.readonly = "readonly"
|
||||
return f
|
||||
|
||||
@ -5,48 +5,41 @@ require "luci.dispatcher"
|
||||
require "nixio.fs"
|
||||
|
||||
local m, s, o
|
||||
local shadowsocksr = "shadowsocksr"
|
||||
local sid = arg[1]
|
||||
|
||||
local encrypt_methods = {
|
||||
"rc4-md5",
|
||||
"rc4-md5-6",
|
||||
"rc4",
|
||||
"table",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf",
|
||||
"rc4-md5",
|
||||
"rc4-md5-6",
|
||||
"rc4",
|
||||
"table",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
}
|
||||
|
||||
local protocol = {
|
||||
"origin",
|
||||
}
|
||||
local protocol = {"origin"}
|
||||
|
||||
obfs = {
|
||||
"plain",
|
||||
"http_simple",
|
||||
"http_post",
|
||||
}
|
||||
obfs = {"plain", "http_simple", "http_post"}
|
||||
|
||||
m = Map(shadowsocksr, translate("Edit ShadowSocksR Server"))
|
||||
m = Map("shadowsocksr", translate("Edit ShadowSocksR Server"))
|
||||
|
||||
m.redirect = luci.dispatcher.build_url("admin/services/shadowsocksr/server")
|
||||
if m.uci:get(shadowsocksr, sid) ~= "server_config" then
|
||||
if m.uci:get("shadowsocksr", sid) ~= "server_config" then
|
||||
luci.http.redirect(m.redirect)
|
||||
return
|
||||
end
|
||||
@ -70,7 +63,7 @@ o.default = "socks5"
|
||||
o = s:option(Value, "server_port", translate("Server Port"))
|
||||
o.datatype = "port"
|
||||
math.randomseed(tostring(os.time()):reverse():sub(1, 7))
|
||||
o.default = math.random(10240,20480)
|
||||
o.default = math.random(10240, 20480)
|
||||
o.rmempty = false
|
||||
o.description = translate("warning! Please do not reuse the port!")
|
||||
|
||||
@ -89,17 +82,23 @@ o.password = true
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "encrypt_method", translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods) do o:value(v) end
|
||||
for _, v in ipairs(encrypt_methods) do
|
||||
o:value(v)
|
||||
end
|
||||
o.rmempty = false
|
||||
o:depends("type", "ssr")
|
||||
|
||||
o = s:option(ListValue, "protocol", translate("Protocol"))
|
||||
for _, v in ipairs(protocol) do o:value(v) end
|
||||
for _, v in ipairs(protocol) do
|
||||
o:value(v)
|
||||
end
|
||||
o.rmempty = false
|
||||
o:depends("type", "ssr")
|
||||
|
||||
o = s:option(ListValue, "obfs", translate("Obfs"))
|
||||
for _, v in ipairs(obfs) do o:value(v) end
|
||||
for _, v in ipairs(obfs) do
|
||||
o:value(v)
|
||||
end
|
||||
o.rmempty = false
|
||||
o:depends("type", "ssr")
|
||||
|
||||
|
||||
@ -3,51 +3,50 @@
|
||||
require "luci.http"
|
||||
require "luci.dispatcher"
|
||||
local m, sec, o
|
||||
local shadowsocksr = "shadowsocksr"
|
||||
local encrypt_methods = {
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5",
|
||||
"rc4-md5-6",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf",
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5",
|
||||
"rc4-md5-6",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf"
|
||||
}
|
||||
|
||||
local protocol = {
|
||||
"origin",
|
||||
"verify_deflate",
|
||||
"auth_sha1_v4",
|
||||
"auth_aes128_sha1",
|
||||
"auth_aes128_md5",
|
||||
"auth_chain_a",
|
||||
"origin",
|
||||
"verify_deflate",
|
||||
"auth_sha1_v4",
|
||||
"auth_aes128_sha1",
|
||||
"auth_aes128_md5",
|
||||
"auth_chain_a"
|
||||
}
|
||||
|
||||
obfs = {
|
||||
"plain",
|
||||
"http_simple",
|
||||
"http_post",
|
||||
"random_head",
|
||||
"tls1.2_ticket_auth",
|
||||
"tls1.2_ticket_fastauth",
|
||||
"plain",
|
||||
"http_simple",
|
||||
"http_post",
|
||||
"random_head",
|
||||
"tls1.2_ticket_auth",
|
||||
"tls1.2_ticket_fastauth"
|
||||
}
|
||||
|
||||
m = Map(shadowsocksr)
|
||||
m = Map("shadowsocksr")
|
||||
-- [[ Global Setting ]]--
|
||||
sec = m:section(TypedSection, "server_global", translate("Global Setting"))
|
||||
sec.anonymous = true
|
||||
|
||||
@ -3,17 +3,15 @@ require "luci.http"
|
||||
require "luci.dispatcher"
|
||||
require "luci.model.uci"
|
||||
local m, s, o
|
||||
local shadowsocksr = "shadowsocksr"
|
||||
local uci = luci.model.uci.cursor()
|
||||
local server_count = 0
|
||||
uci:foreach("shadowsocksr", "servers", function(s)
|
||||
server_count = server_count + 1
|
||||
end)
|
||||
|
||||
m = Map(shadowsocksr, translate("Servers subscription and manage"))
|
||||
m = Map("shadowsocksr", translate("Servers subscription and manage"))
|
||||
|
||||
-- Server Subscribe
|
||||
|
||||
s = m:section(TypedSection, "server_subscribe")
|
||||
s.anonymous = true
|
||||
|
||||
@ -21,12 +19,11 @@ o = s:option(Flag, "auto_update", translate("Auto Update"))
|
||||
o.rmempty = false
|
||||
o.description = translate("Auto Update Server subscription, GFW list and CHN route")
|
||||
|
||||
|
||||
o = s:option(ListValue, "auto_update_time", translate("Update time (every day)"))
|
||||
for t = 0,23 do
|
||||
o:value(t, t..":00")
|
||||
for t = 0, 23 do
|
||||
o:value(t, t .. ":00")
|
||||
end
|
||||
o.default=2
|
||||
o.default = 2
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(DynamicList, "subscribe_url", translate("Subscribe URL"))
|
||||
@ -36,28 +33,28 @@ o = s:option(Value, "filter_words", translate("Subscribe Filter Words"))
|
||||
o.rmempty = true
|
||||
o.description = translate("Filter Words splited by /")
|
||||
|
||||
o = s:option(Button,"update_Sub",translate("Update Subscribe List"))
|
||||
o = s:option(Button, "update_Sub", translate("Update Subscribe List"))
|
||||
o.inputstyle = "reload"
|
||||
o.description = translate("Update subscribe url list first")
|
||||
o.write = function()
|
||||
uci:commit("shadowsocksr")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers"))
|
||||
end
|
||||
|
||||
o = s:option(Flag, "switch", translate("Subscribe Default Auto-Switch"))
|
||||
o.rmempty = false
|
||||
o.description = translate("Subscribe new add server default Auto-Switch on")
|
||||
o.default="1"
|
||||
o.default = "1"
|
||||
|
||||
o = s:option(Flag, "proxy", translate("Through proxy update"))
|
||||
o.rmempty = false
|
||||
o.description = translate("Through proxy update list, Not Recommended ")
|
||||
|
||||
|
||||
o = s:option(Button,"subscribe", translate("Update All Subscribe Severs"))
|
||||
o = s:option(Button, "subscribe", translate("Update All Subscribe Severs"))
|
||||
o.rawhtml = true
|
||||
o.template = "shadowsocksr/subscribe"
|
||||
|
||||
o = s:option(Button,"delete",translate("Delete All Subscribe Severs"))
|
||||
o = s:option(Button, "delete", translate("Delete All Subscribe Severs"))
|
||||
o.inputstyle = "reset"
|
||||
o.description = string.format(translate("Server Count") .. ": %d", server_count)
|
||||
o.write = function()
|
||||
@ -69,9 +66,7 @@ o.write = function()
|
||||
end
|
||||
end)
|
||||
uci:save("shadowsocksr")
|
||||
uci:commit("shadowsocksr")
|
||||
luci.sys.exec("/etc/init.d/shadowsocksr restart &")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers"))
|
||||
m.uci:commit("shadowsocksr")
|
||||
return
|
||||
end
|
||||
|
||||
@ -92,7 +87,7 @@ end
|
||||
|
||||
o = s:option(DummyValue, "type", translate("Type"))
|
||||
function o.cfgvalue(...)
|
||||
return (Value.cfgvalue(...) == "vless") and "VLESS" or Value.cfgvalue(...)
|
||||
return Value.cfgvalue(...)
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "alias", translate("Alias"))
|
||||
@ -106,21 +101,19 @@ function o.cfgvalue(...)
|
||||
end
|
||||
|
||||
o = s:option(DummyValue, "server_port", translate("Socket Connected"))
|
||||
o.template="shadowsocksr/socket"
|
||||
o.width="10%"
|
||||
o.template = "shadowsocksr/socket"
|
||||
o.width = "10%"
|
||||
|
||||
o = s:option(DummyValue, "server", translate("Ping Latency"))
|
||||
o.template="shadowsocksr/ping"
|
||||
o.width="10%"
|
||||
o.template = "shadowsocksr/ping"
|
||||
o.width = "10%"
|
||||
|
||||
node = s:option(Button,"apply_node",translate("Apply"))
|
||||
node = s:option(Button, "apply_node", translate("Apply"))
|
||||
node.inputstyle = "apply"
|
||||
node.write = function(self, section)
|
||||
uci:set("shadowsocksr", '@global[0]', 'global_server', section)
|
||||
uci:save("shadowsocksr")
|
||||
uci:commit("shadowsocksr")
|
||||
luci.sys.exec("/etc/init.d/shadowsocksr restart &")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "client"))
|
||||
m.uci:commit("shadowsocksr")
|
||||
end
|
||||
|
||||
o = s:option(Flag, "switch_enable", translate("Auto Switch"))
|
||||
|
||||
@ -4,177 +4,184 @@ require "nixio.fs"
|
||||
require "luci.sys"
|
||||
require "luci.model.uci"
|
||||
local m, s, o
|
||||
local redir_run=0
|
||||
local reudp_run=0
|
||||
local sock5_run=0
|
||||
local server_run=0
|
||||
local kcptun_run=0
|
||||
local tunnel_run=0
|
||||
local gfw_count=0
|
||||
local ad_count=0
|
||||
local ip_count=0
|
||||
local nfip_count=0
|
||||
local redir_run = 0
|
||||
local reudp_run = 0
|
||||
local sock5_run = 0
|
||||
local server_run = 0
|
||||
local kcptun_run = 0
|
||||
local tunnel_run = 0
|
||||
local gfw_count = 0
|
||||
local ad_count = 0
|
||||
local ip_count = 0
|
||||
local nfip_count = 0
|
||||
local Process_list = luci.sys.exec("busybox ps -w")
|
||||
local uci = luci.model.uci.cursor()
|
||||
local shadowsocksr = "shadowsocksr"
|
||||
-- html constants
|
||||
font_blue = [[<font color="green">]]
|
||||
font_off = [[</font>]]
|
||||
bold_on = [[<strong>]]
|
||||
bold_off = [[</strong>]]
|
||||
local kcptun_version=translate("Unknown")
|
||||
local kcp_file="/usr/bin/kcptun-client"
|
||||
local kcptun_version = translate("Unknown")
|
||||
local kcp_file = "/usr/bin/kcptun-client"
|
||||
if not nixio.fs.access(kcp_file) then
|
||||
kcptun_version=translate("Not exist")
|
||||
kcptun_version = translate("Not exist")
|
||||
else
|
||||
if not nixio.fs.access(kcp_file, "rwx", "rx", "rx") then
|
||||
nixio.fs.chmod(kcp_file, 755)
|
||||
end
|
||||
kcptun_version=luci.sys.exec(kcp_file .. " -v | awk '{printf $3}'")
|
||||
kcptun_version = luci.sys.exec(kcp_file .. " -v | awk '{printf $3}'")
|
||||
if not kcptun_version or kcptun_version == "" then
|
||||
kcptun_version = translate("Unknown")
|
||||
end
|
||||
end
|
||||
|
||||
if nixio.fs.access("/etc/ssr/gfw_list.conf") then
|
||||
gfw_count = tonumber(luci.sys.exec("cat /etc/ssr/gfw_list.conf | wc -l"))/2
|
||||
if nixio.fs.access("/etc/ssrplus/gfw_list.conf") then
|
||||
gfw_count = tonumber(luci.sys.exec("cat /etc/ssrplus/gfw_list.conf | wc -l")) / 2
|
||||
end
|
||||
|
||||
if nixio.fs.access("/etc/ssr/ad.conf") then
|
||||
ad_count = tonumber(luci.sys.exec("cat /etc/ssr/ad.conf | wc -l"))
|
||||
if nixio.fs.access("/etc/ssrplus/ad.conf") then
|
||||
ad_count = tonumber(luci.sys.exec("cat /etc/ssrplus/ad.conf | wc -l"))
|
||||
end
|
||||
|
||||
if nixio.fs.access("/etc/ssr/china_ssr.txt") then
|
||||
ip_count = tonumber(luci.sys.exec("cat /etc/ssr/china_ssr.txt | wc -l"))
|
||||
if nixio.fs.access("/etc/ssrplus/china_ssr.txt") then
|
||||
ip_count = tonumber(luci.sys.exec("cat /etc/ssrplus/china_ssr.txt | wc -l"))
|
||||
end
|
||||
|
||||
if nixio.fs.access("/etc/ssr/netflixip.list") then
|
||||
nfip_count = tonumber(luci.sys.exec("cat /etc/ssr/netflixip.list | wc -l"))
|
||||
if nixio.fs.access("/etc/ssrplus/netflixip.list") then
|
||||
nfip_count = tonumber(luci.sys.exec("cat /etc/ssrplus/netflixip.list | wc -l"))
|
||||
end
|
||||
|
||||
local icount=luci.sys.exec("busybox ps -w | grep ssr-reudp |grep -v grep| wc -l")
|
||||
if tonumber(icount)>0 then
|
||||
reudp_run=1
|
||||
else
|
||||
icount=luci.sys.exec("busybox ps -w | grep ssr-retcp |grep \"\\-u\"|grep -v grep| wc -l")
|
||||
if tonumber(icount)>0 then
|
||||
reudp_run=1
|
||||
end
|
||||
if Process_list:find("udp.only.ssr.reudp") then
|
||||
reudp_run = 1
|
||||
end
|
||||
|
||||
if luci.sys.call("busybox ps -w | grep ssr-retcp | grep -v grep >/dev/null") == 0 then
|
||||
redir_run=1
|
||||
if Process_list:find("tcp.only.ssr.retcp") then
|
||||
redir_run = 1
|
||||
end
|
||||
|
||||
if luci.sys.call("busybox ps -w | grep ssr-local | grep -v ssr-socksdns |grep -v grep >/dev/null") == 0 then
|
||||
sock5_run=1
|
||||
if Process_list:find("tcp.udp.ssr.local") then
|
||||
sock5_run = 1
|
||||
end
|
||||
|
||||
if luci.sys.call("pidof kcptun-client >/dev/null") == 0 then
|
||||
kcptun_run=1
|
||||
if Process_list:find("tcp.udp.ssr.retcp") then
|
||||
redir_run = 1
|
||||
reudp_run = 1
|
||||
end
|
||||
|
||||
if luci.sys.call("busybox ps -w | grep ssr-server | grep -v grep >/dev/null") == 0 then
|
||||
server_run=1
|
||||
if Process_list:find("local.ssr.retcp") then
|
||||
redir_run = 1
|
||||
sock5_run = 1
|
||||
end
|
||||
|
||||
-- if luci.sys.call("busybox ps -w | grep ssr-tunnel |grep -v grep >/dev/null") == 0 then
|
||||
-- tunnel_run=1
|
||||
-- end
|
||||
if luci.sys.call("pidof pdnsd >/dev/null") == 0 or (luci.sys.call("busybox ps -w | grep ssr-dns |grep -v grep >/dev/null") == 0 and luci.sys.call("pidof dns2socks >/dev/null") == 0)then
|
||||
pdnsd_run=1
|
||||
if Process_list:find("local.udp.ssr.retcp") then
|
||||
reudp_run = 1
|
||||
redir_run = 1
|
||||
sock5_run = 1
|
||||
end
|
||||
|
||||
if Process_list:find("kcptun.client") then
|
||||
kcptun_run = 1
|
||||
end
|
||||
|
||||
if Process_list:find("ssr.server") then
|
||||
server_run = 1
|
||||
end
|
||||
|
||||
if Process_list:find("ssrplus/bin/pdnsd") or (Process_list:find("ssrplus.dns") and Process_list:find("dns2socks 127.0.0.1:.*127.0.0.1:5335")) then
|
||||
pdnsd_run = 1
|
||||
end
|
||||
|
||||
m = SimpleForm("Version")
|
||||
m.reset = false
|
||||
m.submit = false
|
||||
|
||||
s=m:field(DummyValue,"redir_run",translate("Global Client"))
|
||||
s = m:field(DummyValue, "redir_run", translate("Global Client"))
|
||||
s.rawhtml = true
|
||||
if redir_run == 1 then
|
||||
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
s.value = font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
else
|
||||
s.value = translate("Not Running")
|
||||
end
|
||||
|
||||
s=m:field(DummyValue,"reudp_run",translate("Game Mode UDP Relay"))
|
||||
s = m:field(DummyValue, "reudp_run", translate("Game Mode UDP Relay"))
|
||||
s.rawhtml = true
|
||||
if reudp_run == 1 then
|
||||
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
s.value = font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
else
|
||||
s.value = translate("Not Running")
|
||||
end
|
||||
|
||||
if uci:get_first(shadowsocksr, 'global', 'pdnsd_enable', '0') ~= '0' then
|
||||
s=m:field(DummyValue,"pdnsd_run",translate("DNS Anti-pollution"))
|
||||
if uci:get_first("shadowsocksr", 'global', 'pdnsd_enable', '0') ~= '0' then
|
||||
s = m:field(DummyValue, "pdnsd_run", translate("DNS Anti-pollution"))
|
||||
s.rawhtml = true
|
||||
if pdnsd_run == 1 then
|
||||
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
s.value = font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
else
|
||||
s.value = translate("Not Running")
|
||||
end
|
||||
end
|
||||
|
||||
s=m:field(DummyValue,"sock5_run",translate("Global SOCKS5 Proxy Server"))
|
||||
s = m:field(DummyValue, "sock5_run", translate("Global SOCKS5 Proxy Server"))
|
||||
s.rawhtml = true
|
||||
if sock5_run == 1 then
|
||||
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
s.value = font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
else
|
||||
s.value = translate("Not Running")
|
||||
end
|
||||
|
||||
s=m:field(DummyValue,"server_run",translate("Local Servers"))
|
||||
s = m:field(DummyValue, "server_run", translate("Local Servers"))
|
||||
s.rawhtml = true
|
||||
if server_run == 1 then
|
||||
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
s.value = font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
else
|
||||
s.value = translate("Not Running")
|
||||
end
|
||||
|
||||
if nixio.fs.access("/usr/bin/kcptun-client") then
|
||||
s=m:field(DummyValue,"kcp_version",translate("KcpTun Version"))
|
||||
s = m:field(DummyValue, "kcp_version", translate("KcpTun Version"))
|
||||
s.rawhtml = true
|
||||
s.value =kcptun_version
|
||||
s=m:field(DummyValue,"kcptun_run",translate("KcpTun"))
|
||||
s.value = kcptun_version
|
||||
s = m:field(DummyValue, "kcptun_run", translate("KcpTun"))
|
||||
s.rawhtml = true
|
||||
if kcptun_run == 1 then
|
||||
s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
s.value = font_blue .. bold_on .. translate("Running") .. bold_off .. font_off
|
||||
else
|
||||
s.value = translate("Not Running")
|
||||
end
|
||||
end
|
||||
|
||||
s=m:field(DummyValue,"google",translate("Google Connectivity"))
|
||||
s = m:field(DummyValue, "google", translate("Google Connectivity"))
|
||||
s.value = translate("No Check")
|
||||
s.template = "shadowsocksr/check"
|
||||
|
||||
s=m:field(DummyValue,"baidu",translate("Baidu Connectivity"))
|
||||
s = m:field(DummyValue, "baidu", translate("Baidu Connectivity"))
|
||||
s.value = translate("No Check")
|
||||
s.template = "shadowsocksr/check"
|
||||
|
||||
s=m:field(DummyValue,"gfw_data",translate("GFW List Data"))
|
||||
s = m:field(DummyValue, "gfw_data", translate("GFW List Data"))
|
||||
s.rawhtml = true
|
||||
s.template = "shadowsocksr/refresh"
|
||||
s.value = gfw_count .. " " .. translate("Records")
|
||||
|
||||
s=m:field(DummyValue,"ip_data",translate("China IP Data"))
|
||||
s = m:field(DummyValue, "ip_data", translate("China IP Data"))
|
||||
s.rawhtml = true
|
||||
s.template = "shadowsocksr/refresh"
|
||||
s.value = ip_count .. " " .. translate("Records")
|
||||
|
||||
s=m:field(DummyValue,"nfip_data",translate("Netflix IP Data"))
|
||||
s = m:field(DummyValue, "nfip_data", translate("Netflix IP Data"))
|
||||
s.rawhtml = true
|
||||
s.template = "shadowsocksr/refresh"
|
||||
s.value = nfip_count .. " " .. translate("Records")
|
||||
|
||||
if uci:get_first(shadowsocksr, 'global', 'adblock', '0') == '1' then
|
||||
s=m:field(DummyValue,"ad_data",translate("Advertising Data"))
|
||||
if uci:get_first("shadowsocksr", 'global', 'adblock', '0') == '1' then
|
||||
s = m:field(DummyValue, "ad_data", translate("Advertising Data"))
|
||||
s.rawhtml = true
|
||||
s.template = "shadowsocksr/refresh"
|
||||
s.value = ad_count .. " " .. translate("Records")
|
||||
end
|
||||
|
||||
s=m:field(DummyValue,"check_port",translate("Check Server Port"))
|
||||
s = m:field(DummyValue, "check_port", translate("Check Server Port"))
|
||||
s.template = "shadowsocksr/checkport"
|
||||
s.value =translate("No Check")
|
||||
s.value = translate("No Check")
|
||||
|
||||
return m
|
||||
|
||||
@ -26,5 +26,4 @@
|
||||
//]]></script>
|
||||
<input type="button" class="cbi-button cbi-button-apply" value="<%:Check Connect%>" onclick="return check_connect(this,'<%=self.option%>')" />
|
||||
<span id="<%=self.option%>-status"><em><%=self.value%></em></span>
|
||||
|
||||
<%+cbi/valuefooter%>
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
<%+cbi/valueheader%>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
|
||||
function check_port(btn)
|
||||
{
|
||||
btn.disabled = true;
|
||||
@ -13,24 +11,15 @@
|
||||
var s = document.getElementById('<%=self.option%>-status');
|
||||
if (s)
|
||||
{
|
||||
|
||||
s.innerHTML =rv.ret;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
btn.disabled = false;
|
||||
btn.value = '<%:Check Server%>';
|
||||
}
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
//]]></script>
|
||||
<input type="button" class="cbi-button cbi-button-apply" value="<%:Check Server%>" onclick="return check_port(this)" />
|
||||
<span id="<%=self.option%>-status"><em><%=self.value%></em></span>
|
||||
|
||||
|
||||
|
||||
<%+cbi/valuefooter%>
|
||||
<%+cbi/valuefooter%>
|
||||
|
||||
@ -12,16 +12,18 @@
|
||||
var s = document.getElementById(dataname+'-status');
|
||||
if (s)
|
||||
{
|
||||
if (rv.ret=="0")
|
||||
s.innerHTML ="<font color='green'>"+"<%:No new data!%> "+"</font>";
|
||||
else if(rv.ret=="-1")
|
||||
if(rv.ret=="-1")
|
||||
{
|
||||
s.innerHTML ="<font color='red'>"+"<%:Refresh Error!%> "+"</font>";
|
||||
}
|
||||
if (rv.ret=="0")
|
||||
{
|
||||
s.innerHTML ="<font color='green'>"+"<%:No new data!%> "+"</font>";
|
||||
}
|
||||
else
|
||||
{
|
||||
s.innerHTML ="<font color='green'>"+"<%:Refresh OK!%> "+"<%:Total Records:%>"+rv.ret+"</font>";
|
||||
}
|
||||
{
|
||||
s.innerHTML ="<font color='green'>"+"<%:Refresh OK!%> "+"<%:Total Records:%>"+rv.ret+"</font>";
|
||||
}
|
||||
}
|
||||
btn.disabled = false;
|
||||
btn.value = '<%:Refresh Data %>';
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
<%+cbi/valueheader%>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
function subscribe(btn,dataname) {
|
||||
var s = document.getElementById(dataname + '-status');
|
||||
var reset = prompt('<%:Really reset all changes?%><%:Please fill in reset%>',"")
|
||||
if (reset == null || reset == "") {
|
||||
return false;
|
||||
}
|
||||
if (reset != "reset") {
|
||||
s.innerHTML = "<font color='red'><%:The content entered is incorrect!%></font>";
|
||||
return false;
|
||||
}
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:Perform reset%>';
|
||||
murl=dataname;
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "shadowsocksr","reset")%>', { set:murl }, function(x,rv) {
|
||||
btn.value = '<%:Reset complete%>';
|
||||
s.innerHTML = "<font color='green'><%:Reset complete%></font>";
|
||||
});
|
||||
return false;
|
||||
}
|
||||
//]]></script>
|
||||
<input type="button" class="cbi-button cbi-button-reset" value="<%:Perform reset%> " onclick="return subscribe(this,'<%=self.option%>')" />
|
||||
<span id="<%=self.option%>-status"></span>
|
||||
<%+cbi/valuefooter%>
|
||||
@ -2,9 +2,6 @@
|
||||
Copyright 2018-2019 Lienol <lawlienol@gmail.com>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-%>
|
||||
<%
|
||||
local dsp = require "luci.dispatcher"
|
||||
-%>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
const doms = document.getElementsByClassName('pingtime');
|
||||
@ -15,8 +12,7 @@ local dsp = require "luci.dispatcher"
|
||||
const port = ports[index];
|
||||
if (!dom) res()
|
||||
port.innerHTML = '<font color="#0072c3">connect</font>';
|
||||
|
||||
XHR.get('<%=dsp.build_url("admin/services/shadowsocksr/ping")%>', {
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin/services/shadowsocksr/ping")%>', {
|
||||
index,
|
||||
domain: dom.getAttribute("hint"),
|
||||
port: port.getAttribute("hint")
|
||||
@ -48,7 +44,6 @@ local dsp = require "luci.dispatcher"
|
||||
for (let i = 0; i < 20; i++) {
|
||||
thread()
|
||||
}
|
||||
|
||||
function cbi_row_drop(fromId, toId, store, isToBottom) {
|
||||
var fromNode = document.getElementById(fromId);
|
||||
var toNode = document.getElementById(toId);
|
||||
@ -65,7 +60,6 @@ local dsp = require "luci.dispatcher"
|
||||
} else {
|
||||
fromNode.parentNode.insertBefore(fromNode, toNode);
|
||||
}
|
||||
|
||||
for (var idx = 2; idx < table.rows.length; idx++) {
|
||||
table.rows[idx].className = table.rows[idx].className.replace(
|
||||
/cbi-rowstyle-[12]/,
|
||||
@ -75,53 +69,43 @@ local dsp = require "luci.dispatcher"
|
||||
if (table.rows[idx].id && table.rows[idx].id.match(/-([^\-]+)$/))
|
||||
ids.push(RegExp.$1);
|
||||
}
|
||||
|
||||
var input = document.getElementById(store);
|
||||
if (input) input.value = ids.join(" ");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// set tr draggable
|
||||
function enableDragForTable(table_selecter, store) {
|
||||
var trs = document.querySelectorAll(table_selecter + " tr");
|
||||
if (!trs || trs.length.length < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
function ondragstart(ev) {
|
||||
ev.dataTransfer.setData("Text", ev.target.id);
|
||||
}
|
||||
|
||||
function ondrop(ev) {
|
||||
var from = ev.dataTransfer.getData("Text");
|
||||
cbi_row_drop(from, this.id, store);
|
||||
}
|
||||
|
||||
function ondragover(ev) {
|
||||
ev.preventDefault();
|
||||
ev.dataTransfer.dropEffect = "move";
|
||||
}
|
||||
|
||||
function moveToTop(id) {
|
||||
var top = document.querySelectorAll(table_selecter + " tr")[2];
|
||||
cbi_row_drop(id, top.id, store);
|
||||
}
|
||||
|
||||
function moveToBottom(id) {
|
||||
console.log('moveToBottom:', id);
|
||||
var trList = document.querySelectorAll(table_selecter + " tr");
|
||||
var bottom = trList[trList.length - 1];
|
||||
cbi_row_drop(id, bottom.id, store, true);
|
||||
}
|
||||
|
||||
for (let index = 2; index < trs.length; index++) {
|
||||
const el = trs[index];
|
||||
el.setAttribute("draggable", true);
|
||||
el.ondragstart = ondragstart;
|
||||
el.ondrop = ondrop;
|
||||
el.ondragover = ondragover;
|
||||
|
||||
// reset the behaviors of the btns
|
||||
var upBtns = el.querySelectorAll(".cbi-button.cbi-button-up");
|
||||
if (upBtns && upBtns.length > 0) {
|
||||
@ -131,7 +115,6 @@ local dsp = require "luci.dispatcher"
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
var downBtns = el.querySelectorAll(".cbi-button.cbi-button-down");
|
||||
if (downBtns && downBtns.length > 0) {
|
||||
downBtns.forEach(function (_el) {
|
||||
@ -142,7 +125,6 @@ local dsp = require "luci.dispatcher"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// enable
|
||||
enableDragForTable(
|
||||
"#cbi-shadowsocksr-servers table",
|
||||
|
||||
@ -80,7 +80,6 @@
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function import_ssr_url(btn, urlname, sid) {
|
||||
var s = document.getElementById(urlname + '-status');
|
||||
if (!s)
|
||||
@ -98,7 +97,6 @@
|
||||
s.innerHTML = "<font color='red'>无效格式</font>";
|
||||
return false;
|
||||
}
|
||||
|
||||
var event = document.createEvent("HTMLEvents");
|
||||
event.initEvent("change", true, true);
|
||||
if (ssu[0] == "ssr") {
|
||||
@ -137,7 +135,6 @@
|
||||
s.innerHTML = "<font color='green'>导入ShadowsocksR配置信息成功</font>";
|
||||
return false;
|
||||
} else if (ssu[0] == "ss") {
|
||||
|
||||
var url0, param = "";
|
||||
var sipIndex = ssu[1].indexOf("@");
|
||||
var ploc = ssu[1].indexOf("#");
|
||||
@ -147,7 +144,6 @@
|
||||
} else {
|
||||
url0 = ssu[1];
|
||||
}
|
||||
|
||||
if (sipIndex != -1) {
|
||||
// SIP002
|
||||
var userInfo = b64decsafe(url0.substr(0, sipIndex));
|
||||
@ -163,7 +159,6 @@
|
||||
plugin = pluginNameInfo.substr(pluginNameInfo.indexOf("=") + 1)
|
||||
pluginOpts = pluginInfo.substr(pluginIndex + 1);
|
||||
}
|
||||
|
||||
var userInfoSplitIndex = userInfo.indexOf(":");
|
||||
if (userInfoSplitIndex != -1) {
|
||||
method = userInfo.substr(0, userInfoSplitIndex);
|
||||
@ -177,7 +172,6 @@
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = plugin || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = pluginOpts || "";
|
||||
|
||||
if (param != undefined) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param);
|
||||
}
|
||||
@ -212,7 +206,6 @@
|
||||
url0 = ssu[1]
|
||||
}
|
||||
var sstr = url0;
|
||||
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "trojan";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
var team = sstr.split('@');
|
||||
@ -229,7 +222,6 @@
|
||||
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = serverPart[0];
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password;
|
||||
@ -246,7 +238,7 @@
|
||||
} else if (ssu[0] == "vmess") {
|
||||
var sstr = b64DecodeUnicode(ssu[1]);
|
||||
var ploc = sstr.indexOf("/?");
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "vmess";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
var url0, param = "";
|
||||
if (ploc > 0) {
|
||||
|
||||
@ -690,3 +690,57 @@ msgstr "混淆密码(可选)"
|
||||
|
||||
msgid "Select the interface that needs to transmit data. If unchecked, all interfaces will pass data by default!"
|
||||
msgstr "选择需要传递数据的接口。如果未选择,则默认情况下所有接口都将传递数据!"
|
||||
|
||||
msgid "Please fill in the Host, for example: www.baidu.com"
|
||||
msgstr "请填写Host,例如:www.baidu.com"
|
||||
|
||||
msgid "Camouflage Type"
|
||||
msgstr "伪装类型"
|
||||
|
||||
msgid "VideoCall (SRTP)"
|
||||
msgstr "视频通话 (SRTP)"
|
||||
|
||||
msgid "BitTorrent (uTP)"
|
||||
msgstr "BT下载 (uTP)"
|
||||
|
||||
msgid "WechatVideo"
|
||||
msgstr "微信视频通话"
|
||||
|
||||
msgid "DTLS 1.2"
|
||||
msgstr "DTLS 1.2 数据包"
|
||||
|
||||
msgid "WireGuard"
|
||||
msgstr "WireGuard 数据包"
|
||||
|
||||
msgid "MTU"
|
||||
msgstr "最大传输单元"
|
||||
|
||||
msgid "TTI"
|
||||
msgstr "传输时间间隔"
|
||||
|
||||
msgid "Uplink Capacity"
|
||||
msgstr "上行链路容量"
|
||||
|
||||
msgid "Downlink Capacity"
|
||||
msgstr "下行链路容量"
|
||||
|
||||
msgid "Read Buffer Size"
|
||||
msgstr "读取缓冲区大小"
|
||||
|
||||
msgid "Write Buffer Size"
|
||||
msgstr "写入缓冲区大小"
|
||||
|
||||
msgid "Congestion"
|
||||
msgstr "拥塞控制"
|
||||
|
||||
msgid "Network interface to use"
|
||||
msgstr "使用的网络接口"
|
||||
|
||||
msgid "Please fill in reset"
|
||||
msgstr "请填写 reset"
|
||||
|
||||
msgid "The content entered is incorrect!"
|
||||
msgstr "输入的内容不正确!"
|
||||
|
||||
msgid "Reset complete"
|
||||
msgstr "重置完成"
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
|
||||
config global
|
||||
option global_server 'nil'
|
||||
option netflix_server 'nil'
|
||||
option netflix_proxy '0'
|
||||
option threads '0'
|
||||
option run_mode 'router'
|
||||
option dports '2'
|
||||
option pdnsd_enable '1'
|
||||
option tunnel_forward '8.8.4.4:53'
|
||||
option monitor_enable '1'
|
||||
option enable_switch '1'
|
||||
option switch_time '667'
|
||||
option switch_timeout '5'
|
||||
option switch_try_count '3'
|
||||
option gfwlist_url 'https://cdn.jsdelivr.net/gh/v2fly/domain-list-community@release/gfwlist.txt'
|
||||
option chnroute_url 'https://ispip.clang.cn/all_cn.txt'
|
||||
option nfip_url 'https://cdn.jsdelivr.net/gh/QiuSimons/Netflix_IP/getflix.txt'
|
||||
option adblock_url 'https://anti-ad.net/anti-ad-for-dnsmasq.conf'
|
||||
|
||||
config access_control
|
||||
option lan_ac_mode '0'
|
||||
option router_proxy '1'
|
||||
list wan_fw_ips '149.154.160.0/20'
|
||||
list wan_fw_ips '67.198.55.0/24'
|
||||
list wan_fw_ips '91.108.4.0/22'
|
||||
list wan_fw_ips '91.108.56.0/22'
|
||||
list wan_fw_ips '109.239.140.0/24'
|
||||
list Interface 'lan'
|
||||
|
||||
config server_subscribe
|
||||
option proxy '0'
|
||||
option auto_update_time '2'
|
||||
option auto_update '1'
|
||||
option filter_words '过期时间/剩余流量/QQ群/官网/防失联地址/回国'
|
||||
|
||||
config socks5_proxy
|
||||
option socks '0'
|
||||
option local_port '1080'
|
||||
|
||||
config server_global
|
||||
option enable_server '0'
|
||||
File diff suppressed because it is too large
Load Diff
@ -4104,6 +4104,13 @@
|
||||
103.158.224.0/23
|
||||
103.159.80.0/23
|
||||
103.159.122.0/23
|
||||
103.159.124.0/23
|
||||
103.159.134.0/23
|
||||
103.159.142.0/23
|
||||
103.160.32.0/23
|
||||
103.160.34.0/23
|
||||
103.160.112.0/23
|
||||
103.160.114.0/23
|
||||
103.192.0.0/22
|
||||
103.192.4.0/22
|
||||
103.192.8.0/22
|
||||
@ -4335,7 +4342,6 @@
|
||||
103.203.24.0/22
|
||||
103.203.28.0/22
|
||||
103.203.32.0/22
|
||||
103.203.52.0/22
|
||||
103.203.56.0/22
|
||||
103.203.96.0/22
|
||||
103.203.100.0/22
|
||||
@ -484,6 +484,8 @@ server=/airmax360.com/127.0.0.1#5335
|
||||
ipset=/airmax360.com/gfwlist
|
||||
server=/airmay.com/127.0.0.1#5335
|
||||
ipset=/airmay.com/gfwlist
|
||||
server=/airport-gov-cn.com/127.0.0.1#5335
|
||||
ipset=/airport-gov-cn.com/gfwlist
|
||||
server=/airport.brussels/127.0.0.1#5335
|
||||
ipset=/airport.brussels/gfwlist
|
||||
server=/airport.com/127.0.0.1#5335
|
||||
@ -2032,6 +2034,8 @@ server=/bandwagonhost.com/127.0.0.1#5335
|
||||
ipset=/bandwagonhost.com/gfwlist
|
||||
server=/bangbros.com/127.0.0.1#5335
|
||||
ipset=/bangbros.com/gfwlist
|
||||
server=/banned.video/127.0.0.1#5335
|
||||
ipset=/banned.video/gfwlist
|
||||
server=/barefootnetworks.com/127.0.0.1#5335
|
||||
ipset=/barefootnetworks.com/gfwlist
|
||||
server=/barrons.com/127.0.0.1#5335
|
||||
@ -2074,6 +2078,8 @@ server=/baxsound.com/127.0.0.1#5335
|
||||
ipset=/baxsound.com/gfwlist
|
||||
server=/bayareabmw.com/127.0.0.1#5335
|
||||
ipset=/bayareabmw.com/gfwlist
|
||||
server=/bayvoice.net/127.0.0.1#5335
|
||||
ipset=/bayvoice.net/gfwlist
|
||||
server=/bazel.build/127.0.0.1#5335
|
||||
ipset=/bazel.build/gfwlist
|
||||
server=/bbc.co.uk/127.0.0.1#5335
|
||||
@ -4696,8 +4702,6 @@ server=/chimeforchange.org/127.0.0.1#5335
|
||||
ipset=/chimeforchange.org/gfwlist
|
||||
server=/china-facebook.com/127.0.0.1#5335
|
||||
ipset=/china-facebook.com/gfwlist
|
||||
server=/china-internet-exchange.com/127.0.0.1#5335
|
||||
ipset=/china-internet-exchange.com/gfwlist
|
||||
server=/chinaclothesstore.com/127.0.0.1#5335
|
||||
ipset=/chinaclothesstore.com/gfwlist
|
||||
server=/chinadecoding.com/127.0.0.1#5335
|
||||
@ -4912,12 +4916,16 @@ server=/cmhalq.com/127.0.0.1#5335
|
||||
ipset=/cmhalq.com/gfwlist
|
||||
server=/cmpaas.com/127.0.0.1#5335
|
||||
ipset=/cmpaas.com/gfwlist
|
||||
server=/cmu.edu/127.0.0.1#5335
|
||||
ipset=/cmu.edu/gfwlist
|
||||
server=/cnbc.com/127.0.0.1#5335
|
||||
ipset=/cnbc.com/gfwlist
|
||||
server=/cnbcfm.com/127.0.0.1#5335
|
||||
ipset=/cnbcfm.com/gfwlist
|
||||
server=/cncrivals.com/127.0.0.1#5335
|
||||
ipset=/cncrivals.com/gfwlist
|
||||
server=/cnix-gov-cn.com/127.0.0.1#5335
|
||||
ipset=/cnix-gov-cn.com/gfwlist
|
||||
server=/cnn.com/127.0.0.1#5335
|
||||
ipset=/cnn.com/gfwlist
|
||||
server=/cnn.io/127.0.0.1#5335
|
||||
@ -5208,8 +5216,6 @@ server=/cutt.ly/127.0.0.1#5335
|
||||
ipset=/cutt.ly/gfwlist
|
||||
server=/cvnad.com/127.0.0.1#5335
|
||||
ipset=/cvnad.com/gfwlist
|
||||
server=/cxkcloud.com/127.0.0.1#5335
|
||||
ipset=/cxkcloud.com/gfwlist
|
||||
server=/cyber-bay.info/127.0.0.1#5335
|
||||
ipset=/cyber-bay.info/gfwlist
|
||||
server=/cyber-bay.org/127.0.0.1#5335
|
||||
@ -5510,6 +5516,8 @@ server=/digital-rb.com/127.0.0.1#5335
|
||||
ipset=/digital-rb.com/gfwlist
|
||||
server=/digitalassetlinks.org/127.0.0.1#5335
|
||||
ipset=/digitalassetlinks.org/gfwlist
|
||||
server=/digitalcertvalidation.com/127.0.0.1#5335
|
||||
ipset=/digitalcertvalidation.com/gfwlist
|
||||
server=/digitalhub.com/127.0.0.1#5335
|
||||
ipset=/digitalhub.com/gfwlist
|
||||
server=/digitalid.ch/127.0.0.1#5335
|
||||
@ -5822,6 +5830,8 @@ server=/dleris.best/127.0.0.1#5335
|
||||
ipset=/dleris.best/gfwlist
|
||||
server=/dlfacebook.com/127.0.0.1#5335
|
||||
ipset=/dlfacebook.com/gfwlist
|
||||
server=/dlgarenanow-a.akamaihd.net/127.0.0.1#5335
|
||||
ipset=/dlgarenanow-a.akamaihd.net/gfwlist
|
||||
server=/dlmobilegarena-a.akamaihd.net/127.0.0.1#5335
|
||||
ipset=/dlmobilegarena-a.akamaihd.net/gfwlist
|
||||
server=/dmgmediaprivacy.co.uk/127.0.0.1#5335
|
||||
@ -6672,6 +6682,8 @@ server=/edgefonts.net/127.0.0.1#5335
|
||||
ipset=/edgefonts.net/gfwlist
|
||||
server=/edisebay.com/127.0.0.1#5335
|
||||
ipset=/edisebay.com/gfwlist
|
||||
server=/edninfo.com/127.0.0.1#5335
|
||||
ipset=/edninfo.com/gfwlist
|
||||
server=/edu-research.org/127.0.0.1#5335
|
||||
ipset=/edu-research.org/gfwlist
|
||||
server=/edx-cdn.org/127.0.0.1#5335
|
||||
@ -6818,12 +6830,28 @@ server=/epinions.com/127.0.0.1#5335
|
||||
ipset=/epinions.com/gfwlist
|
||||
server=/episodic.com/127.0.0.1#5335
|
||||
ipset=/episodic.com/gfwlist
|
||||
server=/epoch.cloud/127.0.0.1#5335
|
||||
ipset=/epoch.cloud/gfwlist
|
||||
server=/epoch.org.il/127.0.0.1#5335
|
||||
ipset=/epoch.org.il/gfwlist
|
||||
server=/epochbuy.com/127.0.0.1#5335
|
||||
ipset=/epochbuy.com/gfwlist
|
||||
server=/epochcar.com/127.0.0.1#5335
|
||||
ipset=/epochcar.com/gfwlist
|
||||
server=/epochhk.com/127.0.0.1#5335
|
||||
ipset=/epochhk.com/gfwlist
|
||||
server=/epochmall.com/127.0.0.1#5335
|
||||
ipset=/epochmall.com/gfwlist
|
||||
server=/epochmediagroup.com/127.0.0.1#5335
|
||||
ipset=/epochmediagroup.com/gfwlist
|
||||
server=/epochshop.com/127.0.0.1#5335
|
||||
ipset=/epochshop.com/gfwlist
|
||||
server=/epochstories.com/127.0.0.1#5335
|
||||
ipset=/epochstories.com/gfwlist
|
||||
server=/epochtime.com/127.0.0.1#5335
|
||||
ipset=/epochtime.com/gfwlist
|
||||
server=/epochtimes-bg.com/127.0.0.1#5335
|
||||
ipset=/epochtimes-bg.com/gfwlist
|
||||
server=/epochtimes-romania.com/127.0.0.1#5335
|
||||
ipset=/epochtimes-romania.com/gfwlist
|
||||
server=/epochtimes.co.il/127.0.0.1#5335
|
||||
@ -6854,6 +6882,8 @@ server=/epochtimes.ru/127.0.0.1#5335
|
||||
ipset=/epochtimes.ru/gfwlist
|
||||
server=/epochtimes.se/127.0.0.1#5335
|
||||
ipset=/epochtimes.se/gfwlist
|
||||
server=/epochtimeshk.org/127.0.0.1#5335
|
||||
ipset=/epochtimeshk.org/gfwlist
|
||||
server=/epochtimestr.com/127.0.0.1#5335
|
||||
ipset=/epochtimestr.com/gfwlist
|
||||
server=/epochweek.com/127.0.0.1#5335
|
||||
@ -6892,6 +6922,8 @@ server=/ethereum.foundation/127.0.0.1#5335
|
||||
ipset=/ethereum.foundation/gfwlist
|
||||
server=/ethereum.org/127.0.0.1#5335
|
||||
ipset=/ethereum.org/gfwlist
|
||||
server=/etviet.com/127.0.0.1#5335
|
||||
ipset=/etviet.com/gfwlist
|
||||
server=/etvonline.hk/127.0.0.1#5335
|
||||
ipset=/etvonline.hk/gfwlist
|
||||
server=/eu-consumer-empowerment.com/127.0.0.1#5335
|
||||
@ -8692,6 +8724,8 @@ server=/goldnikeclub.com/127.0.0.1#5335
|
||||
ipset=/goldnikeclub.com/gfwlist
|
||||
server=/golos-ameriki.ru/127.0.0.1#5335
|
||||
ipset=/golos-ameriki.ru/gfwlist
|
||||
server=/golosameriki.com/127.0.0.1#5335
|
||||
ipset=/golosameriki.com/gfwlist
|
||||
server=/gonglchuangl.net/127.0.0.1#5335
|
||||
ipset=/gonglchuangl.net/gfwlist
|
||||
server=/gonike.com/127.0.0.1#5335
|
||||
@ -9212,6 +9246,8 @@ server=/handbagsoutletebay.com/127.0.0.1#5335
|
||||
ipset=/handbagsoutletebay.com/gfwlist
|
||||
server=/hanime.tv/127.0.0.1#5335
|
||||
ipset=/hanime.tv/gfwlist
|
||||
server=/hanime1.me/127.0.0.1#5335
|
||||
ipset=/hanime1.me/gfwlist
|
||||
server=/happymeal.co.nz/127.0.0.1#5335
|
||||
ipset=/happymeal.co.nz/gfwlist
|
||||
server=/happymeal.com.au/127.0.0.1#5335
|
||||
@ -10156,6 +10192,10 @@ server=/industrialtoys.com/127.0.0.1#5335
|
||||
ipset=/industrialtoys.com/gfwlist
|
||||
server=/informs.org/127.0.0.1#5335
|
||||
ipset=/informs.org/gfwlist
|
||||
server=/infowars.com/127.0.0.1#5335
|
||||
ipset=/infowars.com/gfwlist
|
||||
server=/infowarsmedia.com/127.0.0.1#5335
|
||||
ipset=/infowarsmedia.com/gfwlist
|
||||
server=/infrapedia.com/127.0.0.1#5335
|
||||
ipset=/infrapedia.com/gfwlist
|
||||
server=/ingads.com/127.0.0.1#5335
|
||||
@ -11034,6 +11074,8 @@ server=/jfrog.org/127.0.0.1#5335
|
||||
ipset=/jfrog.org/gfwlist
|
||||
server=/jgg18.xyz/127.0.0.1#5335
|
||||
ipset=/jgg18.xyz/gfwlist
|
||||
server=/jiayoulu.com/127.0.0.1#5335
|
||||
ipset=/jiayoulu.com/gfwlist
|
||||
server=/jibemobile.com/127.0.0.1#5335
|
||||
ipset=/jibemobile.com/gfwlist
|
||||
server=/jijiji.ca/127.0.0.1#5335
|
||||
@ -11126,6 +11168,8 @@ server=/keytransparency.foo/127.0.0.1#5335
|
||||
ipset=/keytransparency.foo/gfwlist
|
||||
server=/keytransparency.org/127.0.0.1#5335
|
||||
ipset=/keytransparency.org/gfwlist
|
||||
server=/kfs.io/127.0.0.1#5335
|
||||
ipset=/kfs.io/gfwlist
|
||||
server=/khanacademy.org/127.0.0.1#5335
|
||||
ipset=/khanacademy.org/gfwlist
|
||||
server=/kickshatchannel.com/127.0.0.1#5335
|
||||
@ -11210,6 +11254,12 @@ server=/kirbysuperstarultra.com/127.0.0.1#5335
|
||||
ipset=/kirbysuperstarultra.com/gfwlist
|
||||
server=/kissjav.com/127.0.0.1#5335
|
||||
ipset=/kissjav.com/gfwlist
|
||||
server=/kkbox.com/127.0.0.1#5335
|
||||
ipset=/kkbox.com/gfwlist
|
||||
server=/kktix.com/127.0.0.1#5335
|
||||
ipset=/kktix.com/gfwlist
|
||||
server=/kktv.me/127.0.0.1#5335
|
||||
ipset=/kktv.me/gfwlist
|
||||
server=/klik.me/127.0.0.1#5335
|
||||
ipset=/klik.me/gfwlist
|
||||
server=/knovel.com/127.0.0.1#5335
|
||||
@ -13218,12 +13268,12 @@ server=/mzed.com/127.0.0.1#5335
|
||||
ipset=/mzed.com/gfwlist
|
||||
server=/mzstatic.com/127.0.0.1#5335
|
||||
ipset=/mzstatic.com/gfwlist
|
||||
server=/n3ro.fun/127.0.0.1#5335
|
||||
ipset=/n3ro.fun/gfwlist
|
||||
server=/n3ro.live/127.0.0.1#5335
|
||||
ipset=/n3ro.live/gfwlist
|
||||
server=/n3ro.lol/127.0.0.1#5335
|
||||
ipset=/n3ro.lol/gfwlist
|
||||
server=/n3ro.net/127.0.0.1#5335
|
||||
ipset=/n3ro.net/gfwlist
|
||||
server=/n3ro.wtf/127.0.0.1#5335
|
||||
ipset=/n3ro.wtf/gfwlist
|
||||
server=/na-att-idns.net/127.0.0.1#5335
|
||||
ipset=/na-att-idns.net/gfwlist
|
||||
server=/nab.com.au/127.0.0.1#5335
|
||||
@ -13878,6 +13928,10 @@ server=/ntc.party/127.0.0.1#5335
|
||||
ipset=/ntc.party/gfwlist
|
||||
server=/ntd.com/127.0.0.1#5335
|
||||
ipset=/ntd.com/gfwlist
|
||||
server=/ntdca.com/127.0.0.1#5335
|
||||
ipset=/ntdca.com/gfwlist
|
||||
server=/ntdimg.com/127.0.0.1#5335
|
||||
ipset=/ntdimg.com/gfwlist
|
||||
server=/ntdtv.ca/127.0.0.1#5335
|
||||
ipset=/ntdtv.ca/gfwlist
|
||||
server=/ntdtv.co.kr/127.0.0.1#5335
|
||||
@ -14346,6 +14400,8 @@ server=/oxfordscholarship.com/127.0.0.1#5335
|
||||
ipset=/oxfordscholarship.com/gfwlist
|
||||
server=/oxfordwesternmusic.com/127.0.0.1#5335
|
||||
ipset=/oxfordwesternmusic.com/gfwlist
|
||||
server=/ozvoice.org/127.0.0.1#5335
|
||||
ipset=/ozvoice.org/gfwlist
|
||||
server=/p-events-delivery.akamaized.net/127.0.0.1#5335
|
||||
ipset=/p-events-delivery.akamaized.net/gfwlist
|
||||
server=/p16-tiktokcdn-com.akamaized.net/127.0.0.1#5335
|
||||
@ -14780,6 +14836,8 @@ server=/perl.org/127.0.0.1#5335
|
||||
ipset=/perl.org/gfwlist
|
||||
server=/persagg.com/127.0.0.1#5335
|
||||
ipset=/persagg.com/gfwlist
|
||||
server=/persianepochtimes.com/127.0.0.1#5335
|
||||
ipset=/persianepochtimes.com/gfwlist
|
||||
server=/personaltrainermath.com/127.0.0.1#5335
|
||||
ipset=/personaltrainermath.com/gfwlist
|
||||
server=/personeelsland.com/127.0.0.1#5335
|
||||
@ -15212,6 +15270,8 @@ server=/protonmail.com/127.0.0.1#5335
|
||||
ipset=/protonmail.com/gfwlist
|
||||
server=/protonstatus.com/127.0.0.1#5335
|
||||
ipset=/protonstatus.com/gfwlist
|
||||
server=/proxyrarbg.org/127.0.0.1#5335
|
||||
ipset=/proxyrarbg.org/gfwlist
|
||||
server=/pscdn.co/127.0.0.1#5335
|
||||
ipset=/pscdn.co/gfwlist
|
||||
server=/pscp.tv/127.0.0.1#5335
|
||||
@ -16014,6 +16074,8 @@ server=/securepaypal.info/127.0.0.1#5335
|
||||
ipset=/securepaypal.info/gfwlist
|
||||
server=/sensorynetworks.com/127.0.0.1#5335
|
||||
ipset=/sensorynetworks.com/gfwlist
|
||||
server=/seqingx.com/127.0.0.1#5335
|
||||
ipset=/seqingx.com/gfwlist
|
||||
server=/sequence.com/127.0.0.1#5335
|
||||
ipset=/sequence.com/gfwlist
|
||||
server=/serialssolutions.com/127.0.0.1#5335
|
||||
@ -16032,6 +16094,8 @@ server=/servicetalk.io/127.0.0.1#5335
|
||||
ipset=/servicetalk.io/gfwlist
|
||||
server=/seselah.com/127.0.0.1#5335
|
||||
ipset=/seselah.com/gfwlist
|
||||
server=/setapp.com/127.0.0.1#5335
|
||||
ipset=/setapp.com/gfwlist
|
||||
server=/sextop1.net/127.0.0.1#5335
|
||||
ipset=/sextop1.net/gfwlist
|
||||
server=/sexzy4.com/127.0.0.1#5335
|
||||
@ -16332,6 +16396,10 @@ server=/softether-download.com/127.0.0.1#5335
|
||||
ipset=/softether-download.com/gfwlist
|
||||
server=/softether.org/127.0.0.1#5335
|
||||
ipset=/softether.org/gfwlist
|
||||
server=/sohcradio.com/127.0.0.1#5335
|
||||
ipset=/sohcradio.com/gfwlist
|
||||
server=/sohfrance.org/127.0.0.1#5335
|
||||
ipset=/sohfrance.org/gfwlist
|
||||
server=/soirt4.fun/127.0.0.1#5335
|
||||
ipset=/soirt4.fun/gfwlist
|
||||
server=/solarcity.com/127.0.0.1#5335
|
||||
@ -16608,10 +16676,6 @@ server=/sslpaypal.org/127.0.0.1#5335
|
||||
ipset=/sslpaypal.org/gfwlist
|
||||
server=/ssplive.pw/127.0.0.1#5335
|
||||
ipset=/ssplive.pw/gfwlist
|
||||
server=/ssrcloud.com/127.0.0.1#5335
|
||||
ipset=/ssrcloud.com/gfwlist
|
||||
server=/ssrcloud.org/127.0.0.1#5335
|
||||
ipset=/ssrcloud.org/gfwlist
|
||||
server=/ssrpass.pw/127.0.0.1#5335
|
||||
ipset=/ssrpass.pw/gfwlist
|
||||
server=/sstatic.net/127.0.0.1#5335
|
||||
@ -18814,6 +18878,8 @@ server=/walmart.pharmacy/127.0.0.1#5335
|
||||
ipset=/walmart.pharmacy/gfwlist
|
||||
server=/walmartimages.com/127.0.0.1#5335
|
||||
ipset=/walmartimages.com/gfwlist
|
||||
server=/wanokokorosoh.com/127.0.0.1#5335
|
||||
ipset=/wanokokorosoh.com/gfwlist
|
||||
server=/wariolandshakeit.com/127.0.0.1#5335
|
||||
ipset=/wariolandshakeit.com/gfwlist
|
||||
server=/wariowarediy.com/127.0.0.1#5335
|
||||
@ -19370,6 +19436,8 @@ server=/xn--czrs0t4phtr3a.cn/127.0.0.1#5335
|
||||
ipset=/xn--czrs0t4phtr3a.cn/gfwlist
|
||||
server=/xn--d1acpjx3f.xn--p1ai/127.0.0.1#5335
|
||||
ipset=/xn--d1acpjx3f.xn--p1ai/gfwlist
|
||||
server=/xn--d4ty0ojsqzfd.com/127.0.0.1#5335
|
||||
ipset=/xn--d4ty0ojsqzfd.com/gfwlist
|
||||
server=/xn--fiqs8sxootzz.cn/127.0.0.1#5335
|
||||
ipset=/xn--fiqs8sxootzz.cn/gfwlist
|
||||
server=/xn--fiqs8sxootzz.xn--hxt814e/127.0.0.1#5335
|
||||
@ -19450,6 +19518,8 @@ server=/xposed.info/127.0.0.1#5335
|
||||
ipset=/xposed.info/gfwlist
|
||||
server=/xscale.com/127.0.0.1#5335
|
||||
ipset=/xscale.com/gfwlist
|
||||
server=/xtube.com/127.0.0.1#5335
|
||||
ipset=/xtube.com/gfwlist
|
||||
server=/xvideos-cdn.com/127.0.0.1#5335
|
||||
ipset=/xvideos-cdn.com/gfwlist
|
||||
server=/xvideos.com/127.0.0.1#5335
|
||||
@ -19756,6 +19826,8 @@ server=/youav.com/127.0.0.1#5335
|
||||
ipset=/youav.com/gfwlist
|
||||
server=/youjizz.com/127.0.0.1#5335
|
||||
ipset=/youjizz.com/gfwlist
|
||||
server=/youlucky.com/127.0.0.1#5335
|
||||
ipset=/youlucky.com/gfwlist
|
||||
server=/youporn.com/127.0.0.1#5335
|
||||
ipset=/youporn.com/gfwlist
|
||||
server=/yourfantasybeginsnow.com/127.0.0.1#5335
|
||||
@ -11,19 +11,19 @@ set firewall.shadowsocksr.path=/var/etc/shadowsocksr.include
|
||||
set firewall.shadowsocksr.reload=1
|
||||
commit firewall
|
||||
EOF
|
||||
rm -rf /etc/config/shadowsocksr-opkg /etc/ssr/*opkg
|
||||
touch /etc/ssr/china_ssr.txt
|
||||
touch /etc/ssr/deny.list
|
||||
touch /etc/ssr/white.list
|
||||
touch /etc/ssr/black.list
|
||||
touch /etc/ssr/netflix.list
|
||||
touch /etc/ssr/netflixip.list
|
||||
touch /etc/ssr/gfw_base.conf
|
||||
touch /etc/ssr/gfw_list.conf
|
||||
touch /etc/ssr/oversea_list.conf
|
||||
touch /etc/ssr/ad.conf
|
||||
rm -rf /etc/config/shadowsocksr-opkg /etc/ssrplus/*opkg
|
||||
touch /etc/ssrplus/china_ssr.txt
|
||||
touch /etc/ssrplus/deny.list
|
||||
touch /etc/ssrplus/white.list
|
||||
touch /etc/ssrplus/black.list
|
||||
touch /etc/ssrplus/netflix.list
|
||||
touch /etc/ssrplus/netflixip.list
|
||||
touch /etc/ssrplus/gfw_base.conf
|
||||
touch /etc/ssrplus/gfw_list.conf
|
||||
touch /etc/ssrplus/oversea_list.conf
|
||||
touch /etc/ssrplus/ad.conf
|
||||
touch /etc/config/shadowsocksr
|
||||
if [ ! -s "/etc/config/shadowsocksr" ] ; then
|
||||
if [ ! -s "/etc/config/shadowsocksr" ]; then
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
add shadowsocksr global
|
||||
set shadowsocksr.@global[0].global_server='nil'
|
||||
@ -42,7 +42,7 @@ set shadowsocksr.@global[0].switch_try_count='3'
|
||||
set shadowsocksr.@global[0].gfwlist_url='https://cdn.jsdelivr.net/gh/v2fly/domain-list-community@release/gfwlist.txt'
|
||||
set shadowsocksr.@global[0].chnroute_url='https://ispip.clang.cn/all_cn.txt'
|
||||
set shadowsocksr.@global[0].nfip_url='https://cdn.jsdelivr.net/gh/QiuSimons/Netflix_IP/getflix.txt'
|
||||
set shadowsocksr.@global[0].adblock_url='https://anti-ad.net/anti-ad-for-dnsmasq.conf'
|
||||
set shadowsocksr.@global[0].adblock_url='https://neodev.team/lite_host_dnsmasq.conf'
|
||||
add shadowsocksr server_subscribe
|
||||
set shadowsocksr.@server_subscribe[0].proxy='0'
|
||||
set shadowsocksr.@server_subscribe[0].auto_update_time='2'
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
if [ -f /tmp/ssr-update.$1 ]; then
|
||||
if (grep -wq "address=" /tmp/ssr-update.$1); then
|
||||
return $?
|
||||
else
|
||||
cp /tmp/ssr-update.$1 /tmp/adnew.conf
|
||||
cat /tmp/adnew.conf | grep ^\|\|[^\*]*\^$ | sed -e 's:||:address\=\/:' -e 's:\^:/0\.0\.0\.0:' >/tmp/ssr-update.$1
|
||||
rm -f /tmp/adnew.conf
|
||||
fi
|
||||
fi
|
||||
@ -1,23 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
generate_china_banned() {
|
||||
cat $1 | base64 -d >/tmp/gfwlist.txt
|
||||
rm -f $1
|
||||
sed -i '/^@@|/d' /tmp/gfwlist.txt
|
||||
cat /tmp/gfwlist.txt | sort -u |
|
||||
sed 's#!.\+##; s#|##g; s#@##g; s#http:\/\/##; s#https:\/\/##;' |
|
||||
sed '/\*/d; /apple\.com/d; /sina\.cn/d; /sina\.com\.cn/d; /baidu\.com/d; /byr\.cn/d; /jlike\.com/d; /weibo\.com/d; /zhongsou\.com/d; /youdao\.com/d; /sogou\.com/d; /so\.com/d; /soso\.com/d; /aliyun\.com/d; /taobao\.com/d; /jd\.com/d; /qq\.com/d' |
|
||||
sed '/^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$/d' |
|
||||
grep '^[0-9a-zA-Z\.-]\+$' | grep '\.' | sed 's#^\.\+##' | sort -u |
|
||||
awk 'BEGIN { prev = "________"; } {
|
||||
cur = $0;
|
||||
if (index(cur, prev) == 1 && substr(cur, 1 + length(prev) ,1) == ".") {
|
||||
} else {
|
||||
print cur;
|
||||
prev = cur;
|
||||
}
|
||||
}' | sort -u
|
||||
}
|
||||
generate_china_banned /tmp/ssr-update.$1 >/tmp/gfw.txt
|
||||
rm -f /tmp/gfwlist.txt
|
||||
sed '/.*/s/.*/server=\/&\/127.0.0.1#5335\nipset=\/&\/gfwlist/' /tmp/gfw.txt >/tmp/ssr-update.$1
|
||||
rm -f /tmp/gfw.txt
|
||||
@ -6,66 +6,36 @@
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
. $IPKG_INSTROOT/etc/init.d/shadowsocksr
|
||||
LOCK_FILE="/var/lock/ssr-monitor.lock"
|
||||
[ -f "$LOCK_FILE" ] && exit 2
|
||||
touch "$LOCK_FILE"
|
||||
NAME=shadowsocksr
|
||||
|
||||
uci_get_by_name() {
|
||||
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
uci_get_by_type() {
|
||||
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
get_host_ip() {
|
||||
local host=$1
|
||||
local isip=""
|
||||
local ip=$host
|
||||
isip=$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}")
|
||||
if [ -z "$isip" ]; then
|
||||
if [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then
|
||||
ip=$host
|
||||
else
|
||||
local ip=$(resolveip -4 -t 3 $host | awk 'NR==1{print}')
|
||||
# local hostip=$(ping $host -W 1 -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1)
|
||||
[ -z "$ip" ] && ip=$(wget -q -O- http://119.29.29.29/d?dn=$1 | awk -F ';' '{print $1}')
|
||||
fi
|
||||
fi
|
||||
echo ${ip:="ERROR"}
|
||||
}
|
||||
|
||||
server_process_count=$1
|
||||
redir_tcp_process=$2
|
||||
redir_udp_process=$3
|
||||
tunnel_process=$4
|
||||
kcp_process=$5
|
||||
local_process=$6
|
||||
pdnsd_process=$7
|
||||
kcp_process=$4
|
||||
local_process=$5
|
||||
pdnsd_process=$6
|
||||
if [ -z "$pdnsd_process" ]; then
|
||||
pdnsd_process=0
|
||||
fi
|
||||
i=0
|
||||
GLOBAL_SERVER=$(uci_get_by_type global global_server)
|
||||
server=$(get_host_ip $(uci_get_by_name $GLOBAL_SERVER server))
|
||||
[ "$server" == "ERROR" ] && hostip=$(uci_get_by_name $GLOBAL_SERVER ip)
|
||||
lkcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port)
|
||||
server=$(uci_get_by_name $GLOBAL_SERVER server)
|
||||
kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port)
|
||||
server_port=$(uci_get_by_name $GLOBAL_SERVER server_port)
|
||||
password=$(uci_get_by_name $GLOBAL_SERVER kcp_password)
|
||||
kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param)
|
||||
[ "$password" != "" ] && password="--key "${password}
|
||||
|
||||
while [ "1" == "1" ]; do #死循环
|
||||
sleep 30s
|
||||
sleep 000030s
|
||||
#redir tcp
|
||||
if [ "$redir_tcp_process" -gt 0 ]; then
|
||||
icount=$(busybox ps -w | grep ssr-retcp | grep -v grep | wc -l)
|
||||
if [ "$icount" == 0 ]; then
|
||||
logger -t "$NAME" "ssr redir tcp error.restart!"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") ssr redir tcp error.restart!" >>/tmp/ssrplus.log
|
||||
echolog "ssr redir tcp error.restart!"
|
||||
/etc/init.d/shadowsocksr restart
|
||||
exit 0
|
||||
fi
|
||||
@ -75,17 +45,7 @@ while [ "1" == "1" ]; do #死循环
|
||||
icount=$(busybox ps -w | grep ssr-reudp | grep -v grep | wc -l)
|
||||
if [ "$icount" == 0 ]; then
|
||||
logger -t "$NAME" "ssr redir udp error.restart!"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") ssr redir udp error.restart!" >>/tmp/ssrplus.log
|
||||
/etc/init.d/shadowsocksr restart
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
#tunnel
|
||||
if [ "$tunnel_process" -gt 0 ]; then
|
||||
icount=$(busybox ps -w | grep ssr-tunnel | grep -v grep | wc -l)
|
||||
if [ "$icount" == 0 ]; then
|
||||
logger -t "$NAME" "ssr tunnel error.restart!"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") ssr tunnel error.restart!" >>/tmp/ssrplus.log
|
||||
echolog "ssr redir udp error.restart!"
|
||||
/etc/init.d/shadowsocksr restart
|
||||
exit 0
|
||||
fi
|
||||
@ -95,7 +55,7 @@ while [ "1" == "1" ]; do #死循环
|
||||
icount=$(busybox ps -w | grep ssr-server | grep -v grep | wc -l)
|
||||
if [ "$icount" -lt "$server_process_count" ]; then #如果进程挂掉就重启它
|
||||
logger -t "$NAME" "ssr server error.restart!"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") ssr server error.restart!" >>/tmp/ssrplus.log
|
||||
echolog "ssr server error.restart!"
|
||||
kill -9 $(busybox ps -w | grep ssr-server | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
/etc/init.d/shadowsocksr restart
|
||||
exit 0
|
||||
@ -106,7 +66,7 @@ while [ "1" == "1" ]; do #死循环
|
||||
icount=$(busybox ps -w | grep kcptun-client | grep -v grep | wc -l)
|
||||
if [ "$icount" -lt "$kcp_process" ]; then #如果进程挂掉就重启它
|
||||
logger -t "$NAME" "ssr kcptun error.restart!"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") ssr kcptun error.restart!" >>/tmp/ssrplus.log
|
||||
echolog "ssr kcptun error.restart!"
|
||||
killall -q -9 kcptun-client
|
||||
(/usr/bin/kcptun-client -r $server:$kcp_port -l :$server_port $password $kcp_param &)
|
||||
fi
|
||||
@ -116,7 +76,7 @@ while [ "1" == "1" ]; do #死循环
|
||||
icount=$(busybox ps -w | grep ssr-local | grep -v grep | wc -l)
|
||||
if [ "$icount" -lt "$local_process" ]; then #如果进程挂掉就重启它
|
||||
logger -t "$NAME" "global socks server error.restart!"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") global socks server error.restart!" >>/tmp/ssrplus.log
|
||||
echolog "global socks server error.restart!"
|
||||
kill -9 $(busybox ps -w | grep ssr-local | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
/etc/init.d/shadowsocksr restart
|
||||
exit 0
|
||||
@ -124,31 +84,31 @@ while [ "1" == "1" ]; do #死循环
|
||||
fi
|
||||
#pdnsd
|
||||
if [ "$pdnsd_process" -eq 1 ]; then
|
||||
icount=$(busybox ps -w | grep pdnsd | grep -v grep | wc -l)
|
||||
icount=$(busybox ps -w | grep $TMP_BIN_PATH/pdnsd | grep -v grep | wc -l)
|
||||
if [ "$icount" -lt "$pdnsd_process" ]; then #如果进程挂掉就重启它
|
||||
logger -t "$NAME" "pdnsd tunnel error.restart!"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") pdnsd tunnel error.restart!" >>/tmp/ssrplus.log
|
||||
echolog "pdnsd tunnel error.restart!"
|
||||
if [ -f /var/run/pdnsd.pid ]; then
|
||||
kill $(cat /var/run/pdnsd.pid) >/dev/null 2>&1
|
||||
else
|
||||
kill -9 $(ps | grep pdnsd | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
kill -9 $(ps | grep $TMP_PATH/pdnsd.conf | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
fi
|
||||
(/usr/sbin/pdnsd -c /var/etc/pdnsd.conf >/dev/null 2>&1 &)
|
||||
ln_start_bin $(first_type pdnsd) pdnsd -c $TMP_PATH/pdnsd.conf
|
||||
fi
|
||||
fi
|
||||
#dns2socks
|
||||
if [ "$pdnsd_process" -eq 2 ]; then
|
||||
icount=$(busybox ps -w | grep -e ssr-dns -e dns2socks | grep -v grep | wc -l)
|
||||
icount=$(busybox ps -w | grep -e ssrplus-dns -e "dns2socks 127.0.0.1 $tmp_dns_port" | grep -v grep | wc -l)
|
||||
if [ "$icount" -lt 2 ]; then #如果进程挂掉就重启它
|
||||
logger -t "$NAME" "dns2socks $dnsstr tunnel error.restart!"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") dns2socks $dnsstr tunnel error.restart!" >>/tmp/ssrplus.log
|
||||
echolog "dns2socks $dnsstr tunnel error.restart!"
|
||||
dnsstr=$(uci_get_by_type global tunnel_forward 8.8.4.4:53)
|
||||
dnsserver=$(echo "$dnsstr" | awk -F ':' '{print $1}')
|
||||
dnsport=$(echo "$dnsstr" | awk -F ':' '{print $2}')
|
||||
killall -q -9 dns2socks
|
||||
kill -9 $(busybox ps -w | grep ssr-dns | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
microsocks -i 127.0.0.1 -p 10802 ssr-dns >/dev/null 2>&1 &
|
||||
dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 &
|
||||
kill -9 $(busybox ps -w | grep ssrplus-dns | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
kill -9 $(busybox ps -w | grep "dns2socks 127.0.0.1 $tmp_dns_port" | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
ln_start_bin $(first_type microsocks) microsocks -i 127.0.0.1 -p $tmp_dns_port ssrplus-dns
|
||||
ln_start_bin $(first_type dns2socks) dns2socks 127.0.0.1:$tmp_dns_port $dnsserver:$dnsport 127.0.0.1:5335 -q
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
@ -10,43 +10,43 @@ TAG="_SS_SPEC_RULE_" # comment tag
|
||||
IPT="iptables -t nat" # alias of iptables
|
||||
FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null) # firewall include file
|
||||
usage() {
|
||||
cat <<-EOF
|
||||
Usage: ssr-rules [options]
|
||||
cat <<-EOF
|
||||
Usage: ssr-rules [options]
|
||||
|
||||
Valid options are:
|
||||
Valid options are:
|
||||
|
||||
-s <server_ip> ip address of shadowsocksr remote server
|
||||
-l <local_port> port number of shadowsocksr local server
|
||||
-S <server_ip> ip address of shadowsocksr remote UDP server
|
||||
-L <local_port> port number of shadowsocksr local UDP server
|
||||
-i <ip_list_file> a file content is bypassed ip list
|
||||
-a <lan_ips> lan ip of access control, need a prefix to
|
||||
define access control mode
|
||||
-b <wan_ips> wan ip of will be bypassed
|
||||
-w <wan_ips> wan ip of will be forwarded
|
||||
-B <bp_lan_ips> lan ip of will be bypassed proxy
|
||||
-p <fp_lan_ips> lan ip of will be global proxy
|
||||
-G <gm_lan_ips> lan ip of will be game mode proxy
|
||||
-D <proxy_ports> proxy ports
|
||||
-F netflix mode
|
||||
-N netflix server IP
|
||||
-M netflix proxy mode
|
||||
-m <Interface> Interface name
|
||||
-I <ip_list_file> a file content is bypassed netflix ip list
|
||||
-e <extra_options> extra options for iptables
|
||||
-o apply the rules to the OUTPUT chain
|
||||
-O apply the global rules to the OUTPUT chain
|
||||
-u enable udprelay mode, TPROXY is required
|
||||
-U enable udprelay mode, using different IP
|
||||
and ports for TCP and UDP
|
||||
-f flush the rules
|
||||
-g gfwlist mode
|
||||
-r router mode
|
||||
-c oversea mode
|
||||
-z all mode
|
||||
-h show this help message and exit
|
||||
EOF
|
||||
exit $1
|
||||
-s <server_ip> ip address of shadowsocksr remote server
|
||||
-l <local_port> port number of shadowsocksr local server
|
||||
-S <server_ip> ip address of shadowsocksr remote UDP server
|
||||
-L <local_port> port number of shadowsocksr local UDP server
|
||||
-i <ip_list_file> a file content is bypassed ip list
|
||||
-a <lan_ips> lan ip of access control, need a prefix to
|
||||
define access control mode
|
||||
-b <wan_ips> wan ip of will be bypassed
|
||||
-w <wan_ips> wan ip of will be forwarded
|
||||
-B <bp_lan_ips> lan ip of will be bypassed proxy
|
||||
-p <fp_lan_ips> lan ip of will be global proxy
|
||||
-G <gm_lan_ips> lan ip of will be game mode proxy
|
||||
-D <proxy_ports> proxy ports
|
||||
-F shunt mode
|
||||
-N shunt server IP
|
||||
-M shunt proxy mode
|
||||
-m <Interface> Interface name
|
||||
-I <ip_list_file> a file content is bypassed shunt ip list
|
||||
-e <extra_options> extra options for iptables
|
||||
-o apply the rules to the OUTPUT chain
|
||||
-O apply the global rules to the OUTPUT chain
|
||||
-u enable udprelay mode, TPROXY is required
|
||||
-U enable udprelay mode, using different IP
|
||||
and ports for TCP and UDP
|
||||
-f flush the rules
|
||||
-g gfwlist mode
|
||||
-r router mode
|
||||
-c oversea mode
|
||||
-z all mode
|
||||
-h show this help message and exit
|
||||
EOF
|
||||
exit $1
|
||||
}
|
||||
|
||||
loger() {
|
||||
@ -94,15 +94,15 @@ ipset_r() {
|
||||
$(gen_spec_iplist | sed -e "s/^/add ss_spec_wan_ac /")
|
||||
EOF
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW
|
||||
$IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
|
||||
;;
|
||||
gfw)
|
||||
ipset -N gfwlist hash:net 2>/dev/null
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN
|
||||
;;
|
||||
oversea)
|
||||
ipset -N oversea hash:net 2>/dev/null
|
||||
@ -129,23 +129,24 @@ ipset_r() {
|
||||
fi
|
||||
for ip in $WAN_BP_IP; do ipset -! add whitelist $ip; done
|
||||
for ip in $WAN_FW_IP; do ipset -! add blacklist $ip; done
|
||||
if [ "$NETFLIX" != "0" ]; then
|
||||
if [ "$SHUNT_PORT" != "0" ]; then
|
||||
ipset -N netflix hash:net 2>/dev/null
|
||||
for ip in $(cat ${NETFLIX_LIST:=/dev/null} 2>/dev/null); do ipset -! add netflix $ip; done
|
||||
for ip in $(cat ${SHUNT_LIST:=/dev/null} 2>/dev/null); do ipset -! add netflix $ip; done
|
||||
case "$SHUNT_PORT" in
|
||||
0) ;;
|
||||
1)
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports $local_port
|
||||
;;
|
||||
*)
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports $SHUNT_PORT
|
||||
if [ "$SHUNT_PROXY" == "1" ]; then
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -d $SHUNT_IP -j REDIRECT --to-ports $local_port
|
||||
else
|
||||
ipset -! add whitelist $SHUNT_IP
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case "$NETFLIX" in
|
||||
1)
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports 4321
|
||||
if [ "$NETFLIX_PROXY" == "1" ]; then
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -d $NETFLIX_IP -j REDIRECT --to-ports $local_port
|
||||
else
|
||||
ipset -! add whitelist $NETFLIX_IP
|
||||
fi
|
||||
;;
|
||||
2)
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports $local_port
|
||||
;;
|
||||
esac
|
||||
return $?
|
||||
}
|
||||
|
||||
@ -159,8 +160,7 @@ fw_rule() {
|
||||
$IPT -A SS_SPEC_WAN_FW -d 192.168.0.0/16 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 224.0.0.0/4 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 240.0.0.0/4 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -p tcp $PROXY_PORTS \
|
||||
-j REDIRECT --to-ports $local_port 2>/dev/null || {
|
||||
$IPT -A SS_SPEC_WAN_FW -p tcp $PROXY_PORTS -j REDIRECT --to-ports $local_port 2>/dev/null || {
|
||||
loger 3 "Can't redirect, please check the iptables."
|
||||
exit 1
|
||||
}
|
||||
@ -189,24 +189,23 @@ ac_rule() {
|
||||
if [ -z "$Interface" ]; then
|
||||
$IPT -I PREROUTING 1 -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
|
||||
else
|
||||
for name in $Interface;do
|
||||
local IFNAME=$(uci -P /var/state get network.$name.ifname 2>/dev/null)
|
||||
[ -n "$IFNAME" ] && $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
|
||||
for name in $Interface; do
|
||||
local IFNAME=$(uci -P /var/state get network.$name.ifname 2>/dev/null)
|
||||
[ -n "$IFNAME" ] && $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
|
||||
done
|
||||
fi
|
||||
|
||||
case "$OUTPUT" in
|
||||
1)
|
||||
$IPT -I OUTPUT 1 -p tcp $EXT_ARGS \
|
||||
-m comment --comment "$TAG" -j SS_SPEC_WAN_AC
|
||||
$IPT -I OUTPUT 1 -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
|
||||
;;
|
||||
2)
|
||||
ipset -! -R <<-EOF || return 1
|
||||
create ssr_gen_router hash:net
|
||||
$(gen_spec_iplist | sed -e "s/^/add ssr_gen_router /")
|
||||
EOF
|
||||
$IPT -N SS_SPEC_ROUTER && \
|
||||
$IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN && \
|
||||
$IPT -N SS_SPEC_ROUTER
|
||||
$IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN
|
||||
$IPT -A SS_SPEC_ROUTER -j SS_SPEC_WAN_FW
|
||||
$IPT -I OUTPUT 1 -p tcp -m comment --comment "$TAG" -j SS_SPEC_ROUTER
|
||||
;;
|
||||
@ -234,25 +233,23 @@ tp_rule() {
|
||||
$ipt -A SS_SPEC_TPROXY -p udp ! --dport 53 -d $SERVER -j RETURN
|
||||
[ "$server" != "$SERVER" ] && ipset -! add whitelist $SERVER
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set bplan src -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set fplan src \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set fplan src -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
case "$RUNMODE" in
|
||||
router)
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set ! --match-set ss_spec_wan_ac dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$IPT -A SS_SPEC_TPROXY -p udp -m set --match-set ss_spec_wan_ac dst -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set ! --match-set ss_spec_wan_ac dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
;;
|
||||
gfw)
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set $PROXY_PORTS --match-set gfwlist dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set gfwlist dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
;;
|
||||
oversea)
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set china dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set oversea src -m dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
;;
|
||||
all)
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
@ -261,9 +258,9 @@ tp_rule() {
|
||||
if [ -z "$Interface" ]; then
|
||||
$ipt -I PREROUTING 1 -p udp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_TPROXY
|
||||
else
|
||||
for name in $Interface;do
|
||||
local IFNAME=$(uci -P /var/state get network.$name.ifname 2>/dev/null)
|
||||
[ -n "$IFNAME" ] && $ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_TPROXY
|
||||
for name in $Interface; do
|
||||
local IFNAME=$(uci -P /var/state get network.$name.ifname 2>/dev/null)
|
||||
[ -n "$IFNAME" ] && $ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_TPROXY
|
||||
done
|
||||
fi
|
||||
return $?
|
||||
@ -303,8 +300,7 @@ gen_include() {
|
||||
[ -n "$FWI" ] || return 0
|
||||
extract_rules() {
|
||||
echo "*$1"
|
||||
iptables-save -t $1 | grep SS_SPEC_ | \
|
||||
sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
|
||||
iptables-save -t $1 | grep SS_SPEC_ | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
|
||||
echo 'COMMIT'
|
||||
}
|
||||
cat <<-EOF >>$FWI
|
||||
@ -362,16 +358,16 @@ while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUfgrczh" arg; do
|
||||
PROXY_PORTS=$OPTARG
|
||||
;;
|
||||
F)
|
||||
NETFLIX=$OPTARG
|
||||
SHUNT_PORT=$OPTARG
|
||||
;;
|
||||
N)
|
||||
NETFLIX_IP=$OPTARG
|
||||
SHUNT_IP=$OPTARG
|
||||
;;
|
||||
M)
|
||||
NETFLIX_PROXY=$OPTARG
|
||||
SHUNT_PROXY=$OPTARG
|
||||
;;
|
||||
I)
|
||||
NETFLIX_LIST=$OPTARG
|
||||
SHUNT_LIST=$OPTARG
|
||||
;;
|
||||
o)
|
||||
OUTPUT=1
|
||||
@ -409,16 +405,16 @@ if [ -z "$server" -o -z "$local_port" ]; then
|
||||
usage 2
|
||||
fi
|
||||
|
||||
case "$TPROXY" in
|
||||
1)
|
||||
SERVER=$server
|
||||
LOCAL_PORT=$local_port
|
||||
;;
|
||||
2)
|
||||
: ${SERVER:?"You must assign an ip for the udp relay server."}
|
||||
: ${LOCAL_PORT:?"You must assign a port for the udp relay server."}
|
||||
case "$TPROXY" in
|
||||
1)
|
||||
SERVER=$server
|
||||
LOCAL_PORT=$local_port
|
||||
;;
|
||||
esac
|
||||
2)
|
||||
: ${SERVER:?"You must assign an ip for the udp relay server."}
|
||||
: ${LOCAL_PORT:?"You must assign a port for the udp relay server."}
|
||||
;;
|
||||
esac
|
||||
|
||||
flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include
|
||||
RET=$?
|
||||
|
||||
@ -7,51 +7,23 @@
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
. $IPKG_INSTROOT/etc/init.d/shadowsocksr
|
||||
LOCK_FILE="/var/lock/ssr-switch.lock"
|
||||
[ -f "$LOCK_FILE" ] && exit 2
|
||||
touch "$LOCK_FILE"
|
||||
LOG_FILE=/var/log/ssrplus.log
|
||||
|
||||
cycle_time=60
|
||||
switch_time=3
|
||||
normal_flag=0
|
||||
server_locate=0
|
||||
server_count=0
|
||||
NAME=shadowsocksr
|
||||
ENABLE_SERVER=nil
|
||||
CONFIG_SWTICH_FILE=/var/etc/${NAME}_t.json
|
||||
|
||||
[ -n "$1" ] && cycle_time=$1
|
||||
[ -n "$2" ] && switch_time=$2
|
||||
|
||||
uci_get_by_name() {
|
||||
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
uci_get_by_type() {
|
||||
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
DEFAULT_SERVER=$(uci_get_by_type global global_server)
|
||||
CURRENT_SERVER=$DEFAULT_SERVER
|
||||
|
||||
#解析ip
|
||||
get_host_ip() {
|
||||
local host=$1
|
||||
local isip=""
|
||||
local ip=$host
|
||||
isip=$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}")
|
||||
if [ -z "$isip" ]; then
|
||||
if [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then
|
||||
ip=$host
|
||||
else
|
||||
local ip=$(resolveip -4 -t 3 $host | awk 'NR==1{print}')
|
||||
[ -z "$ip" ] && ip=$(wget -q -O- http://119.29.29.29/d?dn=$1 | awk -F ';' '{print $1}')
|
||||
fi
|
||||
fi
|
||||
echo ${ip:="ERROR"}
|
||||
}
|
||||
|
||||
#判断代理是否正常
|
||||
check_proxy() {
|
||||
local result=0
|
||||
@ -59,11 +31,11 @@ check_proxy() {
|
||||
for i in $(seq 1 $try_count); do
|
||||
/usr/bin/ssr-check www.google.com 80 $switch_time 1
|
||||
if [ "$?" == "0" ]; then
|
||||
# echo "$(date "+%Y-%m-%d %H:%M:%S") Check Google Proxy Success, count=$i" >> /tmp/ssrplus.log
|
||||
# echolog "Check Google Proxy Success, count=$i"
|
||||
result=0
|
||||
break
|
||||
else
|
||||
# echo "$(date "+%Y-%m-%d %H:%M:%S") Check Google Proxy Fail, count=$i" >> /tmp/ssrplus.log
|
||||
# echolog "Check Google Proxy Fail, count=$i"
|
||||
/usr/bin/ssr-check www.baidu.com 80 $switch_time 1
|
||||
if [ "$?" == "0" ]; then
|
||||
result=1
|
||||
@ -77,19 +49,18 @@ check_proxy() {
|
||||
}
|
||||
|
||||
test_proxy() {
|
||||
local servername=$(get_host_ip $(uci_get_by_name $1 server))
|
||||
local servername=$(uci_get_by_name $1 server)
|
||||
local serverport=$(uci_get_by_name $1 server_port)
|
||||
ipset add ss_spec_wan_ac $servername 2>/dev/null
|
||||
ret1=$?
|
||||
ipset add whitelist $servername 2>/dev/null
|
||||
tcping -q -c 3 -i 1 -t 2 -p $serverport $servername
|
||||
if [ "$?" -gt "0" ]; then
|
||||
[ "$ret1" == "0" ] && ipset del ss_spec_wan_ac $servername 2>/dev/null
|
||||
ipset del whitelist $servername 2>/dev/null
|
||||
return 1
|
||||
fi
|
||||
/usr/bin/ssr-check $servername $serverport $switch_time
|
||||
local ret2=$?
|
||||
[ "$ret1" == "0" ] && ipset del ss_spec_wan_ac $servername 2>/dev/null
|
||||
if [ "$ret2" == "0" ]; then
|
||||
local ret=$?
|
||||
ipset del whitelist $servername 2>/dev/null
|
||||
if [ "$ret" == "0" ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
@ -102,14 +73,13 @@ search_proxy() {
|
||||
[ "$(uci_get_by_name $1 switch_enable 0)" != "1" ] && return 1
|
||||
[ $ENABLE_SERVER != nil ] && return 0
|
||||
[ "$1" == "$CURRENT_SERVER" ] && return 0
|
||||
local servername=$(get_host_ip $(uci_get_by_name $1 server))
|
||||
local servername=$(uci_get_by_name $1 server)
|
||||
local serverport=$(uci_get_by_name $1 server_port)
|
||||
ipset add ss_spec_wan_ac $servername 2>/dev/null
|
||||
ret=$?
|
||||
ipset add whitelist $servername 2>/dev/null
|
||||
/usr/bin/ssr-check $servername $serverport $switch_time
|
||||
local ret2=$?
|
||||
[ "$ret" == "0" ] && ipset del ss_spec_wan_ac $servername 2>/dev/null
|
||||
if [ "$ret2" == "0" ]; then
|
||||
local ret=$?
|
||||
ipset del whitelist $servername 2>/dev/null
|
||||
if [ "$ret" == "0" ]; then
|
||||
server_locate=$server_count
|
||||
ENABLE_SERVER=$1
|
||||
return 0
|
||||
@ -137,49 +107,49 @@ start() {
|
||||
#不支持kcptun启用时的切换
|
||||
[ $(uci_get_by_name $DEFAULT_SERVER kcp_enable) = "1" ] && return 1
|
||||
while [ "1" == "1" ]; do #死循环
|
||||
sleep $cycle_time
|
||||
sleep 0000$cycle_time
|
||||
LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
#判断当前代理是否为缺省服务器
|
||||
if [ "$CURRENT_SERVER" != "$DEFAULT_SERVER" ]; then
|
||||
#echo "not default proxy"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") Current server is not default Main server, try to switch back." >>/tmp/ssrplus.log
|
||||
echolog "Current server is not default Main server, try to switch back."
|
||||
#检查缺省服务器是否正常
|
||||
if test_proxy $DEFAULT_SERVER; then
|
||||
#echo "switch to default proxy"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") Main server is avilable." >>/tmp/ssrplus.log
|
||||
echolog "Main server is avilable."
|
||||
#缺省服务器正常,切换回来
|
||||
CURRENT_SERVER=$DEFAULT_SERVER
|
||||
switch_proxy $CURRENT_SERVER
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") switch to default "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!" >>/tmp/ssrplus.log
|
||||
echolog "switch to default "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!"
|
||||
else
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") Main server is NOT avilable.Continue using current server." >>/tmp/ssrplus.log
|
||||
echolog "Main server is NOT avilable.Continue using current server."
|
||||
fi
|
||||
fi
|
||||
#判断当前代理是否正常
|
||||
#echo "$(date "+%Y-%m-%d %H:%M:%S") Start checking if the current server is available." >>/tmp/ssrplus.log
|
||||
#echolog "Start checking if the current server is available."
|
||||
check_proxy
|
||||
current_ret=$?
|
||||
if [ "$current_ret" == "1" ]; then
|
||||
#当前代理错误,判断有无可用的服务器
|
||||
#echo "current error"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") Current server error, try to switch another server." >>/tmp/ssrplus.log
|
||||
echolog "Current server error, try to switch another server."
|
||||
select_proxy
|
||||
if [ "$ENABLE_SERVER" != nil ]; then
|
||||
#有其他服务器可用,进行切换
|
||||
#echo $(uci_get_by_name $new_proxy server)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") Another server is avilable, now switching server." >>/tmp/ssrplus.log
|
||||
echolog "Another server is avilable, now switching server."
|
||||
CURRENT_SERVER=$ENABLE_SERVER
|
||||
switch_proxy $CURRENT_SERVER
|
||||
normal_flag=1
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") Switch to "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!" >>/tmp/ssrplus.log
|
||||
echolog "Switch to "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!"
|
||||
else
|
||||
switch_proxy $CURRENT_SERVER
|
||||
normal_flag=1
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") Try restart current server." >>/tmp/ssrplus.log
|
||||
echolog "Try restart current server."
|
||||
fi
|
||||
else
|
||||
normal_flag=0
|
||||
# echo "$(date "+%Y-%m-%d %H:%M:%S") ShadowsocksR No Problem." >>/tmp/ssrplus.log
|
||||
# echolog "ShadowsocksR No Problem."
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@ -3,5 +3,5 @@
|
||||
ipset -! flush china 2>/dev/null
|
||||
ipset -! -R <<-EOF || exit 1
|
||||
create china hash:net
|
||||
$(cat ${china_ip:=/etc/ssr/china_ssr.txt} | sed -e "s/^/add china /")
|
||||
$(cat ${china_ip:=/etc/ssrplus/china_ssr.txt} | sed -e "s/^/add china /")
|
||||
EOF
|
||||
|
||||
@ -0,0 +1,171 @@
|
||||
local ucursor = require"luci.model.uci".cursor()
|
||||
local json = require "luci.jsonc"
|
||||
local server_section = arg[1]
|
||||
local proto = arg[2]
|
||||
local local_port = arg[3] or "0"
|
||||
local socks_port = arg[4] or "0"
|
||||
local server = ucursor:get_all("shadowsocksr", server_section)
|
||||
local Xray = {
|
||||
log = {
|
||||
-- error = "/var/ssrplus.log",
|
||||
loglevel = "warning"
|
||||
},
|
||||
-- 传入连接
|
||||
inbound = (local_port ~= "0") and {
|
||||
port = tonumber(local_port),
|
||||
protocol = "dokodemo-door",
|
||||
settings = {network = proto, followRedirect = true},
|
||||
sniffing = {enabled = true, destOverride = {"http", "tls"}}
|
||||
} or nil,
|
||||
-- 开启 socks 代理
|
||||
inboundDetour = (proto == "tcp" and socks_port ~= "0") and {
|
||||
{
|
||||
protocol = "socks",
|
||||
port = tonumber(socks_port),
|
||||
settings = {auth = "noauth", udp = true}
|
||||
}
|
||||
} or nil,
|
||||
-- 传出连接
|
||||
outbound = {
|
||||
protocol = server.type,
|
||||
settings = {
|
||||
vnext = {
|
||||
{
|
||||
address = server.server,
|
||||
port = tonumber(server.server_port),
|
||||
users = {
|
||||
{
|
||||
id = server.vmess_id,
|
||||
alterId = (server.type == "vmess") and tonumber(server.alter_id) or nil,
|
||||
security = (server.type == "vmess") and server.security or nil,
|
||||
encryption = (server.type == "vless") and server.vless_encryption or nil,
|
||||
flow = (server.xtls == '1') and (server.vless_flow and server.vless_flow or "xtls-rprx-splice") or nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
-- 底层传输配置
|
||||
streamSettings = {
|
||||
network = server.transport,
|
||||
security = (server.xtls == '1') and "xtls" or (server.tls == '1') and "tls" or "none",
|
||||
tlsSettings = (server.tls == '1' and (server.insecure == "1" or server.tls_host)) and {
|
||||
allowInsecure = (server.insecure == "1") and true or nil,
|
||||
serverName = server.tls_host
|
||||
} or nil,
|
||||
xtlsSettings = (server.xtls == '1' and (server.insecure == "1" or server.tls_host)) and {
|
||||
allowInsecure = (server.insecure == "1") and true or nil,
|
||||
serverName = server.tls_host
|
||||
} or nil,
|
||||
tcpSettings = (server.transport == "tcp" and server.tcp_guise == "http") and {
|
||||
header = {
|
||||
type = server.tcp_guise,
|
||||
request = {
|
||||
path = {server.http_path} or {"/"},
|
||||
headers = {Host = {server.http_host} or {}}
|
||||
}
|
||||
}
|
||||
} or nil,
|
||||
kcpSettings = (server.transport == "kcp") and {
|
||||
mtu = tonumber(server.mtu),
|
||||
tti = tonumber(server.tti),
|
||||
uplinkCapacity = tonumber(server.uplink_capacity),
|
||||
downlinkCapacity = tonumber(server.downlink_capacity),
|
||||
congestion = (server.congestion == "1") and true or false,
|
||||
readBufferSize = tonumber(server.read_buffer_size),
|
||||
writeBufferSize = tonumber(server.write_buffer_size),
|
||||
header = {type = server.kcp_guise},
|
||||
seed = server.seed or nil
|
||||
} or nil,
|
||||
wsSettings = (server.transport == "ws") and (server.ws_path or server.ws_host or server.tls_host) and {
|
||||
path = server.ws_path,
|
||||
headers = (server.ws_host or server.tls_host) and {
|
||||
Host = server.ws_host or server.tls_host
|
||||
} or nil
|
||||
} or nil,
|
||||
httpSettings = (server.transport == "h2") and {
|
||||
path = server.h2_path or "",
|
||||
host = {server.h2_host} or nil
|
||||
} or nil,
|
||||
quicSettings = (server.transport == "quic") and {
|
||||
security = server.quic_security,
|
||||
key = server.quic_key,
|
||||
header = {type = server.quic_guise}
|
||||
} or nil
|
||||
},
|
||||
mux = (server.mux == "1" and server.xtls ~= "1") and {
|
||||
enabled = true,
|
||||
concurrency = tonumber(server.concurrency)
|
||||
} or nil
|
||||
} or nil
|
||||
}
|
||||
local trojan = {
|
||||
log_level = 3,
|
||||
run_type = (proto == "nat" or proto == "tcp") and "nat" or "client",
|
||||
local_addr = "0.0.0.0",
|
||||
local_port = tonumber(local_port),
|
||||
remote_addr = server.server,
|
||||
remote_port = tonumber(server.server_port),
|
||||
udp_timeout = 60,
|
||||
-- 传入连接
|
||||
password = {server.password},
|
||||
-- 传出连接
|
||||
ssl = {
|
||||
verify = (server.insecure == "0") and true or false,
|
||||
verify_hostname = (server.tls == "1") and true or false,
|
||||
cert = "",
|
||||
cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA",
|
||||
cipher_tls13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
|
||||
sni = server.tls_host,
|
||||
alpn = {"h2", "http/1.1"},
|
||||
curve = "",
|
||||
reuse_session = true,
|
||||
session_ticket = false
|
||||
},
|
||||
tcp = {
|
||||
no_delay = true,
|
||||
keep_alive = true,
|
||||
reuse_port = true,
|
||||
fast_open = (server.fast_open == "1") and true or false,
|
||||
fast_open_qlen = 20
|
||||
}
|
||||
}
|
||||
local naiveproxy = {
|
||||
proxy = (server.username and server.password and server.server and server.server_port) and "https://" .. server.username .. ":" .. server.password .. "@" .. server.server .. ":" .. server.server_port,
|
||||
listen = (proto == "redir") and "redir" .. "://0.0.0.0:" .. tonumber(local_port) or "socks" .. "://0.0.0.0:" .. tonumber(local_port),
|
||||
concurrency = (socks_port ~= "0") and tonumber(socks_port) or "1"
|
||||
}
|
||||
local ss = {
|
||||
server = (server.kcp_enable == "1") and "127.0.0.1" or server.server,
|
||||
server_port = tonumber(server.server_port),
|
||||
local_address = "0.0.0.0",
|
||||
local_port = tonumber(local_port),
|
||||
password = server.password,
|
||||
method = server.encrypt_method,
|
||||
timeout = tonumber(server.timeout) or 60,
|
||||
fast_open = (server.fast_open == "1") and true or false,
|
||||
reuse_port = true
|
||||
}
|
||||
if server.type == "ss" then
|
||||
if server.plugin then
|
||||
ss.plugin = server.plugin
|
||||
ss.plugin_opts = (server.simple_obfs) and server.simple_obfs .. server.plugin_opts or (server.v2ray_plugin ~= "none") and server.v2ray_plugin .. server.plugin_opts or nil
|
||||
end
|
||||
print(json.stringify(ss, 1))
|
||||
end
|
||||
if server.type == "ssr" then
|
||||
ss.protocol = server.protocol
|
||||
ss.protocol_param = server.protocol_param
|
||||
ss.obfs = server.obfs
|
||||
ss.obfs_param = server.obfs_param
|
||||
print(json.stringify(ss, 1))
|
||||
end
|
||||
if server.type == "vless" or server.type == "vmess" then
|
||||
print(json.stringify(Xray, 1))
|
||||
end
|
||||
if server.type == "trojan" then
|
||||
print(json.stringify(trojan, 1))
|
||||
end
|
||||
if server.type == "naiveproxy" then
|
||||
print(json.stringify(naiveproxy, 1))
|
||||
end
|
||||
@ -1,72 +1,95 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat <<-EOF >$1
|
||||
base {
|
||||
argv1=$1
|
||||
argv2=$2
|
||||
argv3=$3
|
||||
argv4=$4
|
||||
argv5=$5
|
||||
argv6=$6
|
||||
argv7=$7
|
||||
argv8=$8
|
||||
argv9=$9
|
||||
cat <<-EOF >$argv1
|
||||
base {
|
||||
log_debug = off;
|
||||
log_info = off;
|
||||
log = stderr;
|
||||
daemon = on;
|
||||
redirector = iptables;
|
||||
reuseport = on;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
if [ "$2" == "socks5" ]; then
|
||||
if [ "$3" == "tcp" ]; then
|
||||
if [ "$7" == "0" ]; then
|
||||
cat <<-EOF >>$1
|
||||
redsocks {
|
||||
bind = "0.0.0.0:$4";
|
||||
relay = "$5:$6";
|
||||
type = socks5;
|
||||
autoproxy = 0;
|
||||
timeout = 10;
|
||||
tcp() {
|
||||
if [ "$argv7" == "0" ]; then
|
||||
cat <<-EOF >>$argv1
|
||||
redsocks {
|
||||
bind = "0.0.0.0:$argv4";
|
||||
relay = "$argv5:$argv6";
|
||||
type = socks5;
|
||||
autoproxy = 0;
|
||||
timeout = 10;
|
||||
}
|
||||
EOF
|
||||
else
|
||||
cat <<-EOF >>$argv1
|
||||
redsocks {
|
||||
bind = "0.0.0.0:$argv4";
|
||||
relay = "$argv5:$argv6";
|
||||
type = socks5;
|
||||
autoproxy = 0;
|
||||
timeout = 10;
|
||||
login = "$argv8";
|
||||
password = "$argv9";
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
EOF
|
||||
else
|
||||
cat <<-EOF >>$1
|
||||
redsocks {
|
||||
bind = "0.0.0.0:$4";
|
||||
relay = "$5:$6";
|
||||
type = socks5;
|
||||
autoproxy = 0;
|
||||
timeout = 10;
|
||||
login = "$8";
|
||||
password = "$9";
|
||||
udp() {
|
||||
if [ "$argv7" == "0" ]; then
|
||||
cat <<-EOF >>$argv1
|
||||
redudp {
|
||||
bind = "0.0.0.0:$argv4";
|
||||
relay = "$argv5:$argv6";
|
||||
type = socks5;
|
||||
udp_timeout = 10;
|
||||
}
|
||||
EOF
|
||||
else
|
||||
cat <<-EOF >>$argv1
|
||||
redudp {
|
||||
bind = "0.0.0.0:$argv4";
|
||||
relay = "$argv5:$argv6";
|
||||
type = socks5;
|
||||
udp_timeout = 10;
|
||||
login = "$argv8";
|
||||
password = "$argv9";
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
else
|
||||
if [ "$7" == "0" ]; then
|
||||
cat <<-EOF >>$1
|
||||
redudp {
|
||||
bind = "0.0.0.0:$4";
|
||||
relay = "$5:$6";
|
||||
type = socks5;
|
||||
udp_timeout = 10;
|
||||
}
|
||||
EOF
|
||||
else
|
||||
cat <<-EOF >>$1
|
||||
redudp {
|
||||
bind = "0.0.0.0:$4";
|
||||
relay = "$5:$6";
|
||||
type = socks5;
|
||||
udp_timeout = 10;
|
||||
login = "$8";
|
||||
password = "$9";
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
else
|
||||
cat <<-EOF >>$1
|
||||
redsocks {
|
||||
bind = "0.0.0.0:$4";
|
||||
type = direct;
|
||||
interface = $3;
|
||||
autoproxy = 0;
|
||||
timeout = 10;
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
case "$argv2" in
|
||||
socks5)
|
||||
case "$argv3" in
|
||||
tcp)
|
||||
tcp
|
||||
;;
|
||||
udp)
|
||||
udp
|
||||
;;
|
||||
*)
|
||||
tcp
|
||||
udp
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
cat <<-EOF >>$argv1
|
||||
redsocks {
|
||||
bind = "0.0.0.0:$argv4";
|
||||
type = direct;
|
||||
interface = $argv3;
|
||||
autoproxy = 0;
|
||||
timeout = 10;
|
||||
}
|
||||
EOF
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
local ucursor = require "luci.model.uci".cursor()
|
||||
local json = require "luci.jsonc"
|
||||
local server_section = arg[1]
|
||||
local proto = arg[2]
|
||||
local local_port = arg[3]
|
||||
|
||||
local server = ucursor:get_all("shadowsocksr", server_section)
|
||||
|
||||
local trojan = {
|
||||
log_level = 3,
|
||||
run_type = proto,
|
||||
local_addr = "0.0.0.0",
|
||||
local_port = tonumber(local_port),
|
||||
remote_addr = server.server,
|
||||
remote_port = tonumber(server.server_port),
|
||||
udp_timeout = 60,
|
||||
-- 传入连接
|
||||
password = {server.password},
|
||||
-- 传出连接
|
||||
ssl = {
|
||||
verify = (server.insecure == "0") and true or false,
|
||||
verify_hostname = (server.tls == "1") and true or false,
|
||||
cert = "",
|
||||
cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA",
|
||||
cipher_tls13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
|
||||
sni = server.tls_host,
|
||||
alpn = {"h2", "http/1.1"},
|
||||
curve = "",
|
||||
reuse_session = true,
|
||||
session_ticket = false,
|
||||
},
|
||||
tcp = {
|
||||
no_delay = true,
|
||||
keep_alive = true,
|
||||
reuse_port = true,
|
||||
fast_open = (server.fast_open == "1") and true or false,
|
||||
fast_open_qlen = 20
|
||||
}
|
||||
}
|
||||
print(json.stringify(trojan, 1))
|
||||
@ -1,111 +0,0 @@
|
||||
local ucursor = require "luci.model.uci".cursor()
|
||||
local json = require "luci.jsonc"
|
||||
local server_section = arg[1]
|
||||
local proto = arg[2]
|
||||
local local_port = arg[3] or "0"
|
||||
local socks_port = arg[4] or "0"
|
||||
local server = ucursor:get_all("shadowsocksr", server_section)
|
||||
local Xray = {
|
||||
log = {
|
||||
-- error = "/var/ssrplus.log",
|
||||
loglevel = "warning"
|
||||
},
|
||||
-- 传入连接
|
||||
inbound = (local_port ~= "0") and {
|
||||
port = local_port,
|
||||
protocol = "dokodemo-door",
|
||||
settings = {
|
||||
network = proto,
|
||||
followRedirect = true
|
||||
},
|
||||
sniffing = {
|
||||
enabled = true,
|
||||
destOverride = { "http", "tls" }
|
||||
}
|
||||
} or nil,
|
||||
-- 开启 socks 代理
|
||||
inboundDetour = (proto == "tcp" and socks_port ~= "0") and {
|
||||
{
|
||||
protocol = "socks",
|
||||
port = socks_port,
|
||||
settings = {
|
||||
auth = "noauth",
|
||||
udp = true
|
||||
}
|
||||
}
|
||||
} or nil,
|
||||
-- 传出连接
|
||||
outbound = {
|
||||
protocol = (server.type == "v2ray") and "vmess" or "vless",
|
||||
settings = {
|
||||
vnext = {
|
||||
{
|
||||
address = server.server,
|
||||
port = tonumber(server.server_port),
|
||||
users = {
|
||||
{
|
||||
id = server.vmess_id,
|
||||
alterId = (server.type == "v2ray") and tonumber(server.alter_id) or nil,
|
||||
security = (server.type == "v2ray") and server.security or nil,
|
||||
encryption = (server.type == "vless") and server.vless_encryption or nil,
|
||||
flow = (server.xtls == '1') and (server.vless_flow and server.vless_flow or "xtls-rprx-origin") or nil,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
-- 底层传输配置
|
||||
streamSettings = {
|
||||
network = server.transport,
|
||||
security = (server.tls == '1') and ((server.xtls == '1') and "xtls" or "tls") or "none",
|
||||
tlsSettings = (server.tls == '1' and server.xtls ~= '1') and {allowInsecure = (server.insecure ~= "0") and true or nil,serverName=server.tls_host,} or nil,
|
||||
xtlsSettings = (server.xtls == '1') and {allowInsecure = (server.insecure ~= "0") and true or nil,serverName=server.tls_host,} or nil,
|
||||
tcpSettings = (server.transport == "tcp" and server.tcp_guise == "http") and {
|
||||
header = {
|
||||
type = server.tcp_guise,
|
||||
request = {
|
||||
path = {server.http_path} or {"/"},
|
||||
headers = {
|
||||
Host = {server.http_host} or {}
|
||||
}
|
||||
}
|
||||
}
|
||||
} or nil,
|
||||
kcpSettings = (server.transport == "kcp") and {
|
||||
mtu = tonumber(server.mtu),
|
||||
tti = tonumber(server.tti),
|
||||
uplinkCapacity = tonumber(server.uplink_capacity),
|
||||
downlinkCapacity = tonumber(server.downlink_capacity),
|
||||
congestion = (server.congestion == "1") and true or false,
|
||||
readBufferSize = tonumber(server.read_buffer_size),
|
||||
writeBufferSize = tonumber(server.write_buffer_size),
|
||||
header = {
|
||||
type = server.kcp_guise
|
||||
},
|
||||
seed = server.seed or nil
|
||||
} or nil,
|
||||
wsSettings = (server.transport == "ws") and (server.ws_path ~= nil or server.ws_host ~= nil) and {
|
||||
path = server.ws_path,
|
||||
headers = (server.ws_host ~= nil) and {
|
||||
Host = server.ws_host
|
||||
} or nil,
|
||||
} or nil,
|
||||
httpSettings = (server.transport == "h2") and {
|
||||
path = server.h2_path or "",
|
||||
host = {server.h2_host} or nil
|
||||
} or nil,
|
||||
quicSettings = (server.transport == "quic") and {
|
||||
security = server.quic_security,
|
||||
key = server.quic_key,
|
||||
header = {
|
||||
type = server.quic_guise
|
||||
}
|
||||
} or nil
|
||||
},
|
||||
mux = (server.xtls ~= "1") and {
|
||||
enabled = (server.mux == "1") and true or false,
|
||||
concurrency = tonumber(server.concurrency)
|
||||
} or nil
|
||||
} or nil
|
||||
}
|
||||
print(json.stringify(Xray,1))
|
||||
@ -1,61 +1,47 @@
|
||||
#!/bin/sh
|
||||
NAME=shadowsocksr
|
||||
switch_server=$1
|
||||
uci_get_by_type() {
|
||||
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
. $IPKG_INSTROOT/etc/init.d/shadowsocksr
|
||||
netflix() {
|
||||
if [ -f "$TMP_DNSMASQ_PATH/gfw_list.conf" ]; then
|
||||
for line in $(cat /etc/ssrplus/netflix.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/gfw_list.conf; done
|
||||
for line in $(cat /etc/ssrplus/netflix.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/gfw_base.conf; done
|
||||
fi
|
||||
cat /etc/ssrplus/netflix.list | sed '/^$/d' | sed '/#/d' | sed "/.*/s/.*/server=\/&\/127.0.0.1#$1\nipset=\/&\/netflix/" >$TMP_DNSMASQ_PATH/netflix_forward.conf
|
||||
}
|
||||
if [ -z "$switch_server" ]; then
|
||||
GLOBAL_SERVER=$(uci_get_by_type global global_server nil)
|
||||
else
|
||||
GLOBAL_SERVER=$switch_server
|
||||
fi
|
||||
|
||||
mkdir -p /tmp/dnsmasq.ssr
|
||||
mkdir -p $TMP_DNSMASQ_PATH
|
||||
if [ "$(uci_get_by_type global run_mode router)" == "oversea" ]; then
|
||||
cp -rf /etc/ssr/oversea_list.conf /tmp/dnsmasq.ssr/
|
||||
cp -rf /etc/ssrplus/oversea_list.conf $TMP_DNSMASQ_PATH/
|
||||
else
|
||||
cp -rf /etc/ssr/gfw_list.conf /tmp/dnsmasq.ssr/
|
||||
cp -rf /etc/ssr/gfw_base.conf /tmp/dnsmasq.ssr/
|
||||
cp -rf /etc/ssrplus/gfw_list.conf $TMP_DNSMASQ_PATH/
|
||||
cp -rf /etc/ssrplus/gfw_base.conf $TMP_DNSMASQ_PATH/
|
||||
fi
|
||||
|
||||
NETFLIX_SERVER=$(uci_get_by_type global netflix_server nil)
|
||||
[ "$NETFLIX_SERVER" == "same" ] && NETFLIX_SERVER=$GLOBAL_SERVER
|
||||
if [ "$NETFLIX_SERVER" != "nil" ]; then
|
||||
netflix() {
|
||||
if [ -f "/tmp/dnsmasq.ssr/gfw_list.conf" ]; then
|
||||
for line in $(cat /etc/ssr/netflix.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf; done
|
||||
for line in $(cat /etc/ssr/netflix.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_base.conf; done
|
||||
fi
|
||||
awk '!/^$/&&!/^#/{printf("ipset=/%s/'"netflix"'\n",$0)}' /etc/ssr/netflix.list >/tmp/dnsmasq.ssr/netflix_forward.conf
|
||||
awk '!/^$/&&!/^#/{printf("server=/%s/'"127.0.0.1#$1"'\n",$0)}' /etc/ssr/netflix.list >>/tmp/dnsmasq.ssr/netflix_forward.conf
|
||||
}
|
||||
if [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then
|
||||
netflix 5555
|
||||
else
|
||||
netflix 5335
|
||||
fi
|
||||
else
|
||||
rm -f /tmp/dnsmasq.ssr/netflix_forward.conf
|
||||
fi
|
||||
for line in $(cat /etc/ssr/black.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf; done
|
||||
for line in $(cat /etc/ssr/black.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_base.conf; done
|
||||
for line in $(cat /etc/ssr/white.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf; done
|
||||
for line in $(cat /etc/ssr/white.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_base.conf; done
|
||||
for line in $(cat /etc/ssr/deny.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf; done
|
||||
for line in $(cat /etc/ssr/deny.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_base.conf; done
|
||||
awk '!/^$/&&!/^#/{printf("ipset=/%s/'"blacklist"'\n",$0)}' /etc/ssr/black.list >/tmp/dnsmasq.ssr/blacklist_forward.conf
|
||||
awk '!/^$/&&!/^#/{printf("server=/%s/'"127.0.0.1#5335"'\n",$0)}' /etc/ssr/black.list >>/tmp/dnsmasq.ssr/blacklist_forward.conf
|
||||
awk '!/^$/&&!/^#/{printf("ipset=/%s/'"whitelist"'\n",$0)}' /etc/ssr/white.list >/tmp/dnsmasq.ssr/whitelist_forward.conf
|
||||
awk '!/^$/&&!/^#/{printf("address=/%s/''\n",$0)}' /etc/ssr/deny.list >/tmp/dnsmasq.ssr/denylist.conf
|
||||
case "$(uci_get_by_type global netflix_server nil)" in
|
||||
nil)
|
||||
rm -f $TMP_DNSMASQ_PATH/netflix_forward.conf
|
||||
;;
|
||||
same)
|
||||
netflix 5335
|
||||
;;
|
||||
*)
|
||||
netflix $tmp_shunt_dns_port
|
||||
;;
|
||||
esac
|
||||
for line in $(cat /etc/ssrplus/black.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/gfw_list.conf; done
|
||||
for line in $(cat /etc/ssrplus/black.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/gfw_base.conf; done
|
||||
for line in $(cat /etc/ssrplus/white.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/gfw_list.conf; done
|
||||
for line in $(cat /etc/ssrplus/white.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/gfw_base.conf; done
|
||||
for line in $(cat /etc/ssrplus/deny.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/gfw_list.conf; done
|
||||
for line in $(cat /etc/ssrplus/deny.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/gfw_base.conf; done
|
||||
cat /etc/ssrplus/black.list | sed '/^$/d' | sed '/#/d' | sed "/.*/s/.*/server=\/&\/127.0.0.1#5335\nipset=\/&\/blacklist/" >$TMP_DNSMASQ_PATH/blacklist_forward.conf
|
||||
cat /etc/ssrplus/white.list | sed '/^$/d' | sed '/#/d' | sed "/.*/s/.*/server=\/&\/127.0.0.1\nipset=\/&\/whitelist/" >$TMP_DNSMASQ_PATH/whitelist_forward.conf
|
||||
cat /etc/ssrplus/deny.list | sed '/^$/d' | sed '/#/d' | sed "/.*/s/.*/address=\/&\//" >$TMP_DNSMASQ_PATH/denylist.conf
|
||||
if [ "$(uci_get_by_type global adblock 0)" == "1" ]; then
|
||||
[ -z "$switch_server" ] && cp -f /etc/ssr/ad.conf /tmp/dnsmasq.ssr/
|
||||
if [ -f "/tmp/dnsmasq.ssr/ad.conf" ]; then
|
||||
for line in $(cat /etc/ssr/black.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/ad.conf; done
|
||||
for line in $(cat /etc/ssr/white.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/ad.conf; done
|
||||
for line in $(cat /etc/ssr/deny.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/ad.conf; done
|
||||
for line in $(cat /etc/ssr/netflix.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/ad.conf; done
|
||||
cp -f /etc/ssrplus/ad.conf $TMP_DNSMASQ_PATH/
|
||||
if [ -f "$TMP_DNSMASQ_PATH/ad.conf" ]; then
|
||||
for line in $(cat /etc/ssrplus/black.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/ad.conf; done
|
||||
for line in $(cat /etc/ssrplus/white.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/ad.conf; done
|
||||
for line in $(cat /etc/ssrplus/deny.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/ad.conf; done
|
||||
for line in $(cat /etc/ssrplus/netflix.list); do sed -i "/$line/d" $TMP_DNSMASQ_PATH/ad.conf; done
|
||||
fi
|
||||
else
|
||||
rm -f /tmp/dnsmasq.ssr/ad.conf
|
||||
rm -f $TMP_DNSMASQ_PATH/ad.conf
|
||||
fi
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
/usr/bin/lua /usr/share/shadowsocksr/update.lua
|
||||
sleep 2s
|
||||
/usr/share/shadowsocksr/chinaipset.sh /tmp/etc/china_ssr.txt
|
||||
/usr/share/shadowsocksr/chinaipset.sh /var/etc/ssrplus/china_ssr.txt
|
||||
sleep 2s
|
||||
/usr/bin/lua /usr/share/shadowsocksr/subscribe.lua
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user