Merge Mainline
This commit is contained in:
commit
6151d81905
@ -1,8 +1,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-vssr
|
||||
PKG_VERSION:=1.18
|
||||
PKG_RELEASE:=20201204
|
||||
PKG_VERSION:=1.19
|
||||
PKG_RELEASE:=20201205
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
@ -46,7 +46,7 @@ define Package/luci-app-vssr
|
||||
SUBMENU:=3. Applications
|
||||
TITLE:=A New SS/SSR/V2Ray/Trojan LuCI interface
|
||||
PKGARCH:=all
|
||||
DEPENDS:=+shadowsocksr-libev-alt +ipset +ip-full +iptables-mod-tproxy +dnsmasq-full +coreutils +coreutils-base64 +bash +pdnsd-alt +wget +luasocket +coreutils-nohup +lua-maxminddb \
|
||||
DEPENDS:=+shadowsocksr-libev-alt +ipset +ip-full +iptables-mod-tproxy +dnsmasq-full +coreutils +coreutils-base64 +bash +pdnsd-alt +wget +luasocket +lua-maxminddb \
|
||||
+shadowsocks-libev-ss-local +shadowsocksr-libev-ssr-local +shadowsocks-libev-ss-redir +simple-obfs \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_plugin:v2ray-plugin \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray \
|
||||
|
||||
@ -28,7 +28,7 @@ function index()
|
||||
end
|
||||
|
||||
entry({'admin', 'services', 'vssr', 'log'}, cbi('vssr/log'), _('Log'), 30).leaf = true
|
||||
entry({'admin', 'services', 'vssr', 'licence'}, template('vssr/licence'), _('Licence'), 40).leaf = true
|
||||
--entry({'admin', 'services', 'vssr', 'licence'}, template('vssr/licence'), _('Licence'), 40).leaf = true
|
||||
|
||||
entry({'admin', 'services', 'vssr', 'refresh'}, call('refresh_data')) -- 更新白名单和GFWLIST
|
||||
entry({'admin', 'services', 'vssr', 'checkport'}, call('check_port')) -- 检测单个端口并返回Ping
|
||||
@ -60,7 +60,7 @@ function get_subscribe()
|
||||
uci:set(name, '@server_subscribe[0]', 'filter_words', filter_words)
|
||||
uci:set_list(name, '@server_subscribe[0]', 'subscribe_url', cjson.parse(subscribe_url))
|
||||
uci:commit(name)
|
||||
luci.sys.exec('nohup /usr/bin/lua /usr/share/vssr/subscribe.lua >/www/check_update.htm 2>/dev/null &')
|
||||
luci.sys.exec('/usr/bin/lua /usr/share/vssr/subscribe.lua >/www/check_update.htm 2>/dev/null &')
|
||||
e.error = 0
|
||||
else
|
||||
e.error = 1
|
||||
@ -215,6 +215,7 @@ function get_flag()
|
||||
end
|
||||
|
||||
-- 刷新检测文件
|
||||
|
||||
function refresh_data()
|
||||
local set = luci.http.formvalue('set')
|
||||
local icount = 0
|
||||
@ -245,8 +246,7 @@ function refresh_data()
|
||||
retstring = '-1'
|
||||
end
|
||||
elseif set == 'ip_data' then
|
||||
refresh_cmd =
|
||||
"wget -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' 2>/dev/null| awk -F\\| '/CN\\|ipv4/ { printf(\"%s/%d\\n\", $4, 32-log($5)/log(2)) }' > /tmp/china_ssr.txt"
|
||||
refresh_cmd = "wget -O- 'https://ispip.clang.cn/all_cn.txt' > /tmp/china_ssr.txt"
|
||||
sret = luci.sys.call(refresh_cmd)
|
||||
icount = luci.sys.exec('cat /tmp/china_ssr.txt | wc -l')
|
||||
if sret == 0 and tonumber(icount) > 1000 then
|
||||
|
||||
@ -5,7 +5,8 @@ local m, s, sec, o, kcp_enable
|
||||
local vssr = 'vssr'
|
||||
local gfwmode = 0
|
||||
|
||||
if nixio.fs.access('/etc/vssr/gfw_list.conf') then
|
||||
|
||||
if nixio.fs.access('/etc/dnsmasq.ssr/gfw_list.conf') then
|
||||
gfwmode = 1
|
||||
end
|
||||
|
||||
@ -18,70 +19,26 @@ m:section(SimpleSection).template = 'vssr/status_top'
|
||||
local server_table = {}
|
||||
local tw_table = {}
|
||||
local tvb_table = {}
|
||||
|
||||
|
||||
local server_table = {}
|
||||
uci:foreach(
|
||||
vssr,
|
||||
'vssr',
|
||||
'servers',
|
||||
function(s)
|
||||
if s.alias then
|
||||
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
|
||||
}
|
||||
end
|
||||
|
||||
if s.flag == 'tw' then
|
||||
if s.alias then
|
||||
tw_table[s['.name']] = '[%s]:%s' % {string.upper(s.type), s.alias}
|
||||
elseif s.server and s.server_port then
|
||||
tw_table[s['.name']] =
|
||||
'[%s]:%s:%s' %
|
||||
{
|
||||
string.upper(s.type),
|
||||
s.server,
|
||||
s.server_port
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if s.flag == 'hk' then
|
||||
if s.alias then
|
||||
tvb_table[s['.name']] = '[%s]:%s' % {string.upper(s.type), s.alias}
|
||||
elseif s.server and s.server_port then
|
||||
tvb_table[s['.name']] =
|
||||
'[%s]:%s:%s' %
|
||||
{
|
||||
string.upper(s.type),
|
||||
s.server,
|
||||
s.server_port
|
||||
}
|
||||
end
|
||||
end
|
||||
s['name'] = s['.name']
|
||||
s['gname'] = '[%s]:%s' % {string.upper(s.type), s.alias}
|
||||
table.insert(server_table, s)
|
||||
end
|
||||
)
|
||||
|
||||
local key_table = {}
|
||||
for key, _ in pairs(server_table) do
|
||||
table.insert(key_table, key)
|
||||
function my_sort(a,b)
|
||||
if(a.alias ~= nil and b.alias ~= nil) then
|
||||
return a.alias < b.alias
|
||||
end
|
||||
end
|
||||
table.sort(server_table, my_sort)
|
||||
|
||||
local key_table_tw = {}
|
||||
for key, _ in pairs(tw_table) do
|
||||
table.insert(key_table_tw, key)
|
||||
end
|
||||
|
||||
local key_table_tvb = {}
|
||||
for key, _ in pairs(tvb_table) do
|
||||
table.insert(key_table_tvb, key)
|
||||
end
|
||||
|
||||
table.sort(key_table)
|
||||
table.sort(key_table_tw)
|
||||
table.sort(key_table_tvb)
|
||||
local route_name = {
|
||||
'youtube_server',
|
||||
'tw_video_server',
|
||||
@ -107,8 +64,8 @@ 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])
|
||||
for _, key in pairs(server_table) do
|
||||
o:value(key.name, key.gname)
|
||||
end
|
||||
o.default = 'nil'
|
||||
o.rmempty = false
|
||||
@ -116,12 +73,14 @@ 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 Main Server'))
|
||||
for _, key in pairs(key_table) do
|
||||
o:value(key, server_table[key])
|
||||
for _, key in pairs(server_table) do
|
||||
o:value(key.name, key.gname)
|
||||
end
|
||||
if nixio.fs.access('/usr/bin/xray') or nixio.fs.access('/usr/bin/xray/xray') then
|
||||
o = s:option(Flag, 'use_xray', translate('Use Xray instead of V2ray'))
|
||||
o.rmempty = false
|
||||
end
|
||||
|
||||
o = s:option(Flag, 'use_xray', translate('Use Xray instead of V2ray'))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, 'v2ray_flow', translate('Open v2ray route'))
|
||||
o.rmempty = false
|
||||
@ -130,17 +89,15 @@ o.description = translate('When open v2ray routed,Apply may take more time.')
|
||||
for i, v in pairs(route_name) do
|
||||
o = s:option(ListValue, v, translate(route_label[i]))
|
||||
o:value('nil', translate('Same as Main Server'))
|
||||
if (v == 'tw_video_server') then
|
||||
for _, key in pairs(key_table_tw) do
|
||||
o:value(key, tw_table[key])
|
||||
for _, key in pairs(server_table) do
|
||||
if(v == 'tw_video_server' and key.flag == "tw") then
|
||||
o:value(key.name, key.gname)
|
||||
end
|
||||
elseif (v == 'tvb_server') then
|
||||
for _, key in pairs(key_table_tvb) do
|
||||
o:value(key, tvb_table[key])
|
||||
if(v == 'tvb_server' and key.flag == "hk") then
|
||||
o:value(key.name, key.gname)
|
||||
end
|
||||
else
|
||||
for _, key in pairs(key_table) do
|
||||
o:value(key, server_table[key])
|
||||
if(v ~= 'tvb_server' and v ~= 'tw_video_server') then
|
||||
o:value(key.name, key.gname)
|
||||
end
|
||||
end
|
||||
o:depends('v2ray_flow', '1')
|
||||
@ -162,6 +119,7 @@ o:value('router', translate('IP Route Mode'))
|
||||
o:value('all', translate('Global Mode'))
|
||||
o:value('oversea', translate('Oversea Mode'))
|
||||
o.default = 'router'
|
||||
|
||||
o = s:option(ListValue, 'dports', translate('Proxy Ports'))
|
||||
o:value('1', translate('All Ports'))
|
||||
o:value('2', translate('Only Common Ports'))
|
||||
|
||||
@ -24,7 +24,12 @@ uci:foreach(
|
||||
name = s['.name']
|
||||
end
|
||||
)
|
||||
|
||||
function my_sort(a,b)
|
||||
if(a.alias ~= nil and b.alias ~= nil) then
|
||||
return a.alias < b.alias
|
||||
end
|
||||
end
|
||||
table.sort(server_table, my_sort)
|
||||
m = Map(vssr)
|
||||
|
||||
m:section(SimpleSection).template = 'vssr/status_top'
|
||||
@ -37,6 +42,7 @@ s.sortable = false
|
||||
|
||||
s.des = server_count
|
||||
s.current = uci:get('vssr', name, 'global_server')
|
||||
s.serverTable = server_table
|
||||
s.servers = json.stringify(server_table)
|
||||
s.template = 'vssr/tblsection'
|
||||
s.extedit = luci.dispatcher.build_url('admin/services/vssr/servers/%s')
|
||||
|
||||
@ -11,34 +11,37 @@
|
||||
<div class="cbi-section-table pure-g p-in5">
|
||||
|
||||
<%- local isempty = true
|
||||
for i, k in ipairs(self:cfgsections()) do
|
||||
for i, k in ipairs(self.serverTable) do
|
||||
section = k
|
||||
isempty = false
|
||||
local fc = (section.name == self.current) and "fast" or ""
|
||||
local flag_icon = (section.flag ~= nil) and "flag-icon-" .. section.flag or "flag-icon-un"
|
||||
local switch_enable = (section.switch_enable == "1") and "" or "hidden"
|
||||
scope = { valueheader = "cbi/cell_valueheader", valuefooter = "cbi/cell_valuefooter" }
|
||||
-%>
|
||||
|
||||
<div class="pure-u-1-5">
|
||||
<div class="cbi-section-table-row " id="cbi-<%=self.config%>-<%=section%>" data-flag="<%=self.flag%>">
|
||||
<div class="cbi-section-table-row <%=fc %> " id="cbi-<%=self.config%>-<%=section.name%>" data-flag="<%=section.flag%>" server="<%=section.server%>" server_port="<%=section.server_port%>">
|
||||
<div class="loadings hide"></div>
|
||||
<div class="incon type flag-icon <%=self.flag%>" data-setction="<%=section%>">
|
||||
<img class="pure-imgw hidden" src="/luci-static/vssr/img/switch.png">
|
||||
<div class="tp"></div>
|
||||
<div class="incon type flag-icon <%=flag_icon %>" data-setction="<%=section.name%>">
|
||||
<img class="pure-imgw <%=switch_enable %>" src="/luci-static/vssr/img/switch.png">
|
||||
<div class="tp"><%=section.type%></div>
|
||||
</div>
|
||||
<div class="incon alias"></div>
|
||||
<div class="incon alias"><%=section.alias%></div>
|
||||
<%- if self.extedit or self.addremove then -%>
|
||||
<div class="cbi-section-table-cell">
|
||||
<div class="host_con"></div>
|
||||
<a class="cbi-button ssr-button" type="button" value="" onclick="apply_node('<%=section%>')"
|
||||
alt="<%:Apply%>" title="<%:Apply%>"><span class="icon-ok"></span> <%:Apply%></a>
|
||||
<a class="cbi-button ssr-button" type="button" value="" onclick="apply_node('<%=section.name%>')"
|
||||
alt="<%:Apply%>" title="<%:Apply%>"><span class="icon-use"></span> <%:Apply%></a>
|
||||
<%- if self.extedit then -%>
|
||||
<a class="cbi-button ssr-button " type="button" value="" <%- if type(self.extedit) == "string" then
|
||||
%> onclick="location.href='<%=self.extedit:format(section)%>'" <%- elseif type(self.extedit) == "function" then
|
||||
%> onclick="location.href='<%=self:extedit(section)%>'" <%- end
|
||||
%> onclick="location.href='<%=self.extedit:format(section.name)%>'" <%- elseif type(self.extedit) == "function" then
|
||||
%> onclick="location.href='<%=self:extedit(section.name)%>'" <%- end
|
||||
%> alt="<%:Edit%>" title="<%:Edit%>"><span class="icon-edit"></span> <%:Edit%></a>
|
||||
<%- end; if self.addremove then %>
|
||||
<button class="cbi-button ssr-button" type="submit" value=""
|
||||
onclick="this.form.cbi_state = 'del-section'; return true"
|
||||
name="cbi.rts.<%=self.config%>.<%=k%>" alt="<%:Delete%>" title="<%:Delete%>" /><span
|
||||
name="cbi.rts.<%=self.config%>.<%=section.name%>" alt="<%:Delete%>" title="<%:Delete%>" /><span
|
||||
class="icon-delete"></span> <%:Delete%></button>
|
||||
<%- end -%>
|
||||
</div>
|
||||
@ -93,32 +96,10 @@
|
||||
const CHECK_PING_URL = '<%=luci.dispatcher.build_url("admin", "services", "vssr","checkport")%>';
|
||||
const SWITCH_NODE_URL = '<%=luci.dispatcher.build_url("admin", "services", "vssr","switch")%>';
|
||||
|
||||
var servers = JSON.parse('<%= self.servers%>'.replace(/\t/g, ""));
|
||||
var iploaded = false;
|
||||
var ajaxArray = new Array();
|
||||
var currentCheckCount = 0;
|
||||
|
||||
|
||||
//渲染节点列表
|
||||
$.each(servers, function (i, val) {
|
||||
var id = '#cbi-' + CONFIG + '-' + val.name;
|
||||
if (val.name == CURRENT) {
|
||||
$(id).addClass("fast");
|
||||
}
|
||||
val.flag = (val.flag == undefined) ? "un" : val.flag;
|
||||
$(id).attr("data-flag", val.flag);
|
||||
$(id).find(".type .tp").text(val.type);
|
||||
$(id).find(".type").addClass("flag-icon-" + val.flag);
|
||||
$(id).find(".alias").text(val.alias);
|
||||
$(id).attr("server", val.server);
|
||||
$(id).attr("server_port", val.server_port);
|
||||
if (val.switch_enable == "1") {
|
||||
$(id).find(".pure-imgw").removeClass("hidden");
|
||||
} else {
|
||||
$(id).find(".pure-imgw").addClass("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
//转换节点名称的Emoji显示
|
||||
$(".alias").emoji();
|
||||
//适配方框的大小
|
||||
|
||||
@ -555,7 +555,12 @@ start() {
|
||||
if rules; then
|
||||
start_redir
|
||||
|
||||
mkdir -p /tmp/dnsmasq.d && cp -a /etc/vssr/ad.conf gfw_base.conf gfw_list.conf /tmp/ && cp -a /etc/vssr/oversea_list.conf /tmp/
|
||||
mkdir -p /tmp/dnsmasq.d \
|
||||
&& cp -a /etc/vssr/gfw_list.conf /tmp/dnsmasq.ssr \
|
||||
&& cp -a /etc/vssr/gfw_base.conf /tmp/dnsmasq.ssr \
|
||||
&& cp -a /etc/vssr/ad.conf /tmp/dnsmasq.ssr \
|
||||
&& cp -a /etc/vssr/oversea_list.conf /tmp/dnsmasq.oversea
|
||||
|
||||
if ! [ "$run_mode" = "oversea" ]; then
|
||||
cat >/tmp/dnsmasq.d/dnsmasq-ssr.conf <<EOF
|
||||
conf-dir=/tmp/dnsmasq.ssr
|
||||
|
||||
@ -380,6 +380,8 @@ server=/.aliengu.com/127.0.0.1#5335
|
||||
ipset=/.aliengu.com/gfwlist
|
||||
server=/.alkasir.com/127.0.0.1#5335
|
||||
ipset=/.alkasir.com/gfwlist
|
||||
server=/.all4mom.org/127.0.0.1#5335
|
||||
ipset=/.all4mom.org/gfwlist
|
||||
server=/.allcoin.com/127.0.0.1#5335
|
||||
ipset=/.allcoin.com/gfwlist
|
||||
server=/.allconnected.co/127.0.0.1#5335
|
||||
@ -510,6 +512,8 @@ server=/.anyporn.com/127.0.0.1#5335
|
||||
ipset=/.anyporn.com/gfwlist
|
||||
server=/.anysex.com/127.0.0.1#5335
|
||||
ipset=/.anysex.com/gfwlist
|
||||
server=/.ao3.org/127.0.0.1#5335
|
||||
ipset=/.ao3.org/gfwlist
|
||||
server=/.aobo.com.au/127.0.0.1#5335
|
||||
ipset=/.aobo.com.au/gfwlist
|
||||
server=/.aofriend.com/127.0.0.1#5335
|
||||
@ -550,6 +554,8 @@ server=/.apigee.com/127.0.0.1#5335
|
||||
ipset=/.apigee.com/gfwlist
|
||||
server=/.apk-dl.com/127.0.0.1#5335
|
||||
ipset=/.apk-dl.com/gfwlist
|
||||
server=/.apkcombo.com/127.0.0.1#5335
|
||||
ipset=/.apkcombo.com/gfwlist
|
||||
server=/.apkmirror.com/127.0.0.1#5335
|
||||
ipset=/.apkmirror.com/gfwlist
|
||||
server=/.apkplz.com/127.0.0.1#5335
|
||||
@ -588,8 +594,14 @@ server=/.archive.li/127.0.0.1#5335
|
||||
ipset=/.archive.li/gfwlist
|
||||
server=/.archive.org/127.0.0.1#5335
|
||||
ipset=/.archive.org/gfwlist
|
||||
server=/.archive.ph/127.0.0.1#5335
|
||||
ipset=/.archive.ph/gfwlist
|
||||
server=/.archive.today/127.0.0.1#5335
|
||||
ipset=/.archive.today/gfwlist
|
||||
server=/.archiveofourown.com/127.0.0.1#5335
|
||||
ipset=/.archiveofourown.com/gfwlist
|
||||
server=/.archiveofourown.org/127.0.0.1#5335
|
||||
ipset=/.archiveofourown.org/gfwlist
|
||||
server=/.archives.gov/127.0.0.1#5335
|
||||
ipset=/.archives.gov/gfwlist
|
||||
server=/.arctosia.com/127.0.0.1#5335
|
||||
@ -1286,6 +1298,8 @@ server=/.cafepress.com/127.0.0.1#5335
|
||||
ipset=/.cafepress.com/gfwlist
|
||||
server=/.cahr.org.tw/127.0.0.1#5335
|
||||
ipset=/.cahr.org.tw/gfwlist
|
||||
server=/.caijinglengyan.com/127.0.0.1#5335
|
||||
ipset=/.caijinglengyan.com/gfwlist
|
||||
server=/.calebelston.com/127.0.0.1#5335
|
||||
ipset=/.calebelston.com/gfwlist
|
||||
server=/.calgarychinese.ca/127.0.0.1#5335
|
||||
@ -1302,6 +1316,8 @@ server=/.cam4.sg/127.0.0.1#5335
|
||||
ipset=/.cam4.sg/gfwlist
|
||||
server=/.camfrog.com/127.0.0.1#5335
|
||||
ipset=/.camfrog.com/gfwlist
|
||||
server=/.campaignforuyghurs.org/127.0.0.1#5335
|
||||
ipset=/.campaignforuyghurs.org/gfwlist
|
||||
server=/.cams.com/127.0.0.1#5335
|
||||
ipset=/.cams.com/gfwlist
|
||||
server=/.cams.org.sg/127.0.0.1#5335
|
||||
@ -1754,8 +1770,6 @@ server=/.clipfish.de/127.0.0.1#5335
|
||||
ipset=/.clipfish.de/gfwlist
|
||||
server=/.cloakpoint.com/127.0.0.1#5335
|
||||
ipset=/.cloakpoint.com/gfwlist
|
||||
server=/.cloud.feedly.com/127.0.0.1#5335
|
||||
ipset=/.cloud.feedly.com/gfwlist
|
||||
server=/.cloud.mail.ru/127.0.0.1#5335
|
||||
ipset=/.cloud.mail.ru/gfwlist
|
||||
server=/.club1069.com/127.0.0.1#5335
|
||||
@ -2232,6 +2246,10 @@ server=/.discoins.com/127.0.0.1#5335
|
||||
ipset=/.discoins.com/gfwlist
|
||||
server=/.disconnect.me/127.0.0.1#5335
|
||||
ipset=/.disconnect.me/gfwlist
|
||||
server=/.discord.com/127.0.0.1#5335
|
||||
ipset=/.discord.com/gfwlist
|
||||
server=/.discord.gg/127.0.0.1#5335
|
||||
ipset=/.discord.gg/gfwlist
|
||||
server=/.discordapp.com/127.0.0.1#5335
|
||||
ipset=/.discordapp.com/gfwlist
|
||||
server=/.discordapp.net/127.0.0.1#5335
|
||||
@ -2402,6 +2420,8 @@ server=/.dtwang.org/127.0.0.1#5335
|
||||
ipset=/.dtwang.org/gfwlist
|
||||
server=/.duanzhihu.com/127.0.0.1#5335
|
||||
ipset=/.duanzhihu.com/gfwlist
|
||||
server=/.dubox.com/127.0.0.1#5335
|
||||
ipset=/.dubox.com/gfwlist
|
||||
server=/.duck.com/127.0.0.1#5335
|
||||
ipset=/.duck.com/gfwlist
|
||||
server=/.duckdns.org/127.0.0.1#5335
|
||||
@ -2948,6 +2968,8 @@ server=/.fdc89.jp/127.0.0.1#5335
|
||||
ipset=/.fdc89.jp/gfwlist
|
||||
server=/.feedburner.com/127.0.0.1#5335
|
||||
ipset=/.feedburner.com/gfwlist
|
||||
server=/.feedly.com/127.0.0.1#5335
|
||||
ipset=/.feedly.com/gfwlist
|
||||
server=/.feeds.fileforum.com/127.0.0.1#5335
|
||||
ipset=/.feeds.fileforum.com/gfwlist
|
||||
server=/.feedx.net/127.0.0.1#5335
|
||||
@ -3182,6 +3204,8 @@ server=/.freehongkong.org/127.0.0.1#5335
|
||||
ipset=/.freehongkong.org/gfwlist
|
||||
server=/.freeilhamtohti.org/127.0.0.1#5335
|
||||
ipset=/.freeilhamtohti.org/gfwlist
|
||||
server=/.freekazakhs.org/127.0.0.1#5335
|
||||
ipset=/.freekazakhs.org/gfwlist
|
||||
server=/.freekwonpyong.org/127.0.0.1#5335
|
||||
ipset=/.freekwonpyong.org/gfwlist
|
||||
server=/.freelotto.com/127.0.0.1#5335
|
||||
@ -3336,6 +3360,8 @@ server=/.gaeproxy.com/127.0.0.1#5335
|
||||
ipset=/.gaeproxy.com/gfwlist
|
||||
server=/.gaforum.org/127.0.0.1#5335
|
||||
ipset=/.gaforum.org/gfwlist
|
||||
server=/.gagaoolala.com/127.0.0.1#5335
|
||||
ipset=/.gagaoolala.com/gfwlist
|
||||
server=/.galaxymacau.com/127.0.0.1#5335
|
||||
ipset=/.galaxymacau.com/gfwlist
|
||||
server=/.galenwu.com/127.0.0.1#5335
|
||||
@ -3500,6 +3526,12 @@ server=/.gist.github.com/127.0.0.1#5335
|
||||
ipset=/.gist.github.com/gfwlist
|
||||
server=/.git.io/127.0.0.1#5335
|
||||
ipset=/.git.io/gfwlist
|
||||
server=/.github.io/127.0.0.1#5335
|
||||
ipset=/.github.io/gfwlist
|
||||
server=/.githubassets.com/127.0.0.1#5335
|
||||
ipset=/.githubassets.com/gfwlist
|
||||
server=/.githubusercontent.com/127.0.0.1#5335
|
||||
ipset=/.githubusercontent.com/gfwlist
|
||||
server=/.gizlen.net/127.0.0.1#5335
|
||||
ipset=/.gizlen.net/gfwlist
|
||||
server=/.gjczz.com/127.0.0.1#5335
|
||||
@ -3546,6 +3578,8 @@ server=/.gmozomg.izihost.org/127.0.0.1#5335
|
||||
ipset=/.gmozomg.izihost.org/gfwlist
|
||||
server=/.gnci.org.hk/127.0.0.1#5335
|
||||
ipset=/.gnci.org.hk/gfwlist
|
||||
server=/.gnews.org/127.0.0.1#5335
|
||||
ipset=/.gnews.org/gfwlist
|
||||
server=/.go-pki.com/127.0.0.1#5335
|
||||
ipset=/.go-pki.com/gfwlist
|
||||
server=/.go.nesnode.com/127.0.0.1#5335
|
||||
@ -3874,6 +3908,8 @@ server=/.gtricks.com/127.0.0.1#5335
|
||||
ipset=/.gtricks.com/gfwlist
|
||||
server=/.gts-vpn.com/127.0.0.1#5335
|
||||
ipset=/.gts-vpn.com/gfwlist
|
||||
server=/.gtv.org/127.0.0.1#5335
|
||||
ipset=/.gtv.org/gfwlist
|
||||
server=/.gu-chu-sum.org/127.0.0.1#5335
|
||||
ipset=/.gu-chu-sum.org/gfwlist
|
||||
server=/.guaguass.com/127.0.0.1#5335
|
||||
@ -3952,8 +3988,6 @@ server=/.hacker.org/127.0.0.1#5335
|
||||
ipset=/.hacker.org/gfwlist
|
||||
server=/.hackthatphone.net/127.0.0.1#5335
|
||||
ipset=/.hackthatphone.net/gfwlist
|
||||
server=/.hahaxixi.github.io/127.0.0.1#5335
|
||||
ipset=/.hahaxixi.github.io/gfwlist
|
||||
server=/.hahlo.com/127.0.0.1#5335
|
||||
ipset=/.hahlo.com/gfwlist
|
||||
server=/.hakkatv.org.tw/127.0.0.1#5335
|
||||
@ -3964,8 +3998,6 @@ server=/.hanime.tv/127.0.0.1#5335
|
||||
ipset=/.hanime.tv/gfwlist
|
||||
server=/.hanunyi.com/127.0.0.1#5335
|
||||
ipset=/.hanunyi.com/gfwlist
|
||||
server=/.haoel.github.io/127.0.0.1#5335
|
||||
ipset=/.haoel.github.io/gfwlist
|
||||
server=/.happy-vpn.com/127.0.0.1#5335
|
||||
ipset=/.happy-vpn.com/gfwlist
|
||||
server=/.haproxy.org/127.0.0.1#5335
|
||||
@ -4024,6 +4056,8 @@ server=/.helplinfen.com/127.0.0.1#5335
|
||||
ipset=/.helplinfen.com/gfwlist
|
||||
server=/.helpster.de/127.0.0.1#5335
|
||||
ipset=/.helpster.de/gfwlist
|
||||
server=/.helpuyghursnow.org/127.0.0.1#5335
|
||||
ipset=/.helpuyghursnow.org/gfwlist
|
||||
server=/.helpzhuling.org/127.0.0.1#5335
|
||||
ipset=/.helpzhuling.org/gfwlist
|
||||
server=/.hentai.to/127.0.0.1#5335
|
||||
@ -4158,6 +4192,8 @@ server=/.hkcoc.com/127.0.0.1#5335
|
||||
ipset=/.hkcoc.com/gfwlist
|
||||
server=/.hkcoc.weather.com.hk/127.0.0.1#5335
|
||||
ipset=/.hkcoc.weather.com.hk/gfwlist
|
||||
server=/.hkctu.org.hk/127.0.0.1#5335
|
||||
ipset=/.hkctu.org.hk/gfwlist
|
||||
server=/.hkday.net/127.0.0.1#5335
|
||||
ipset=/.hkday.net/gfwlist
|
||||
server=/.hkdf.org/127.0.0.1#5335
|
||||
@ -4354,6 +4390,8 @@ server=/.huhaitai.com/127.0.0.1#5335
|
||||
ipset=/.huhaitai.com/gfwlist
|
||||
server=/.huhamhire.com/127.0.0.1#5335
|
||||
ipset=/.huhamhire.com/gfwlist
|
||||
server=/.huhangfei.com/127.0.0.1#5335
|
||||
ipset=/.huhangfei.com/gfwlist
|
||||
server=/.huiyi.in/127.0.0.1#5335
|
||||
ipset=/.huiyi.in/gfwlist
|
||||
server=/.hulkshare.com/127.0.0.1#5335
|
||||
@ -4512,6 +4550,8 @@ server=/.ikstar.com/127.0.0.1#5335
|
||||
ipset=/.ikstar.com/gfwlist
|
||||
server=/.ikwb.com/127.0.0.1#5335
|
||||
ipset=/.ikwb.com/gfwlist
|
||||
server=/.ilhamtohtiinstitute.org/127.0.0.1#5335
|
||||
ipset=/.ilhamtohtiinstitute.org/gfwlist
|
||||
server=/.illusionfactory.com/127.0.0.1#5335
|
||||
ipset=/.illusionfactory.com/gfwlist
|
||||
server=/.ilove80.be/127.0.0.1#5335
|
||||
@ -4930,6 +4970,8 @@ server=/.k-doujin.net/127.0.0.1#5335
|
||||
ipset=/.k-doujin.net/gfwlist
|
||||
server=/.ka-wai.com/127.0.0.1#5335
|
||||
ipset=/.ka-wai.com/gfwlist
|
||||
server=/.kadokawa.co.jp/127.0.0.1#5335
|
||||
ipset=/.kadokawa.co.jp/gfwlist
|
||||
server=/.kagyu.org/127.0.0.1#5335
|
||||
ipset=/.kagyu.org/gfwlist
|
||||
server=/.kagyumonlam.org/127.0.0.1#5335
|
||||
@ -5610,6 +5652,8 @@ server=/.mimivv.com/127.0.0.1#5335
|
||||
ipset=/.mimivv.com/gfwlist
|
||||
server=/.mindrolling.org/127.0.0.1#5335
|
||||
ipset=/.mindrolling.org/gfwlist
|
||||
server=/.mingdemedia.org/127.0.0.1#5335
|
||||
ipset=/.mingdemedia.org/gfwlist
|
||||
server=/.minghui-a.org/127.0.0.1#5335
|
||||
ipset=/.minghui-a.org/gfwlist
|
||||
server=/.minghui-b.org/127.0.0.1#5335
|
||||
@ -5798,6 +5842,8 @@ server=/.mthruf.com/127.0.0.1#5335
|
||||
ipset=/.mthruf.com/gfwlist
|
||||
server=/.mtw.tl/127.0.0.1#5335
|
||||
ipset=/.mtw.tl/gfwlist
|
||||
server=/.mubi.com/127.0.0.1#5335
|
||||
ipset=/.mubi.com/gfwlist
|
||||
server=/.muchosucko.com/127.0.0.1#5335
|
||||
ipset=/.muchosucko.com/gfwlist
|
||||
server=/.mullvad.net/127.0.0.1#5335
|
||||
@ -5966,6 +6012,8 @@ server=/.nat.moe/127.0.0.1#5335
|
||||
ipset=/.nat.moe/gfwlist
|
||||
server=/.national-lottery.co.uk/127.0.0.1#5335
|
||||
ipset=/.national-lottery.co.uk/gfwlist
|
||||
server=/.nationalawakening.org/127.0.0.1#5335
|
||||
ipset=/.nationalawakening.org/gfwlist
|
||||
server=/.nationwide.com/127.0.0.1#5335
|
||||
ipset=/.nationwide.com/gfwlist
|
||||
server=/.naughtyamerica.com/127.0.0.1#5335
|
||||
@ -6142,6 +6190,8 @@ server=/.nintendium.com/127.0.0.1#5335
|
||||
ipset=/.nintendium.com/gfwlist
|
||||
server=/.ninth.biz/127.0.0.1#5335
|
||||
ipset=/.ninth.biz/gfwlist
|
||||
server=/.nitter.net/127.0.0.1#5335
|
||||
ipset=/.nitter.net/gfwlist
|
||||
server=/.niu.moe/127.0.0.1#5335
|
||||
ipset=/.niu.moe/gfwlist
|
||||
server=/.niusnews.com/127.0.0.1#5335
|
||||
@ -6430,6 +6480,8 @@ server=/.openid.net/127.0.0.1#5335
|
||||
ipset=/.openid.net/gfwlist
|
||||
server=/.openleaks.org/127.0.0.1#5335
|
||||
ipset=/.openleaks.org/gfwlist
|
||||
server=/.opensource.google/127.0.0.1#5335
|
||||
ipset=/.opensource.google/gfwlist
|
||||
server=/.openvpn.net/127.0.0.1#5335
|
||||
ipset=/.openvpn.net/gfwlist
|
||||
server=/.openvpn.org/127.0.0.1#5335
|
||||
@ -6550,6 +6602,10 @@ server=/.paradisepoker.com/127.0.0.1#5335
|
||||
ipset=/.paradisepoker.com/gfwlist
|
||||
server=/.parkansky.com/127.0.0.1#5335
|
||||
ipset=/.parkansky.com/gfwlist
|
||||
server=/.parler.com/127.0.0.1#5335
|
||||
ipset=/.parler.com/gfwlist
|
||||
server=/.parsevideo.com/127.0.0.1#5335
|
||||
ipset=/.parsevideo.com/gfwlist
|
||||
server=/.partycasino.com/127.0.0.1#5335
|
||||
ipset=/.partycasino.com/gfwlist
|
||||
server=/.partypoker.com/127.0.0.1#5335
|
||||
@ -6920,6 +6976,8 @@ server=/.psblog.name/127.0.0.1#5335
|
||||
ipset=/.psblog.name/gfwlist
|
||||
server=/.pscp.tv/127.0.0.1#5335
|
||||
ipset=/.pscp.tv/gfwlist
|
||||
server=/.pshvpn.com/127.0.0.1#5335
|
||||
ipset=/.pshvpn.com/gfwlist
|
||||
server=/.psiphon.ca/127.0.0.1#5335
|
||||
ipset=/.psiphon.ca/gfwlist
|
||||
server=/.psiphon.civisec.org/127.0.0.1#5335
|
||||
@ -7042,6 +7100,8 @@ server=/.radicalparty.org/127.0.0.1#5335
|
||||
ipset=/.radicalparty.org/gfwlist
|
||||
server=/.radiko.jp/127.0.0.1#5335
|
||||
ipset=/.radiko.jp/gfwlist
|
||||
server=/.radio.garden/127.0.0.1#5335
|
||||
ipset=/.radio.garden/gfwlist
|
||||
server=/.radioaustralia.net.au/127.0.0.1#5335
|
||||
ipset=/.radioaustralia.net.au/gfwlist
|
||||
server=/.radiohilight.net/127.0.0.1#5335
|
||||
@ -7084,8 +7144,6 @@ server=/.raremovie.cc/127.0.0.1#5335
|
||||
ipset=/.raremovie.cc/gfwlist
|
||||
server=/.raremovie.net/127.0.0.1#5335
|
||||
ipset=/.raremovie.net/gfwlist
|
||||
server=/.raw.githubusercontent.com/127.0.0.1#5335
|
||||
ipset=/.raw.githubusercontent.com/gfwlist
|
||||
server=/.rawgit.com/127.0.0.1#5335
|
||||
ipset=/.rawgit.com/gfwlist
|
||||
server=/.rawgithub.com/127.0.0.1#5335
|
||||
@ -7122,6 +7180,8 @@ server=/.realraptalk.com/127.0.0.1#5335
|
||||
ipset=/.realraptalk.com/gfwlist
|
||||
server=/.realsexpass.com/127.0.0.1#5335
|
||||
ipset=/.realsexpass.com/gfwlist
|
||||
server=/.reason.com/127.0.0.1#5335
|
||||
ipset=/.reason.com/gfwlist
|
||||
server=/.rebatesrule.net/127.0.0.1#5335
|
||||
ipset=/.rebatesrule.net/gfwlist
|
||||
server=/.recordhistory.org/127.0.0.1#5335
|
||||
@ -7172,6 +7232,8 @@ server=/.renyurenquan.org/127.0.0.1#5335
|
||||
ipset=/.renyurenquan.org/gfwlist
|
||||
server=/.resilio.com/127.0.0.1#5335
|
||||
ipset=/.resilio.com/gfwlist
|
||||
server=/.resistchina.org/127.0.0.1#5335
|
||||
ipset=/.resistchina.org/gfwlist
|
||||
server=/.retweeteffect.com/127.0.0.1#5335
|
||||
ipset=/.retweeteffect.com/gfwlist
|
||||
server=/.retweetist.com/127.0.0.1#5335
|
||||
@ -7200,8 +7262,6 @@ server=/.rferl.org/127.0.0.1#5335
|
||||
ipset=/.rferl.org/gfwlist
|
||||
server=/.rfi.fr/127.0.0.1#5335
|
||||
ipset=/.rfi.fr/gfwlist
|
||||
server=/.rg3.github.io/127.0.0.1#5335
|
||||
ipset=/.rg3.github.io/gfwlist
|
||||
server=/.rightbtc.com/127.0.0.1#5335
|
||||
ipset=/.rightbtc.com/gfwlist
|
||||
server=/.rigpa.org/127.0.0.1#5335
|
||||
@ -7374,6 +7434,8 @@ server=/.scmpchinese.com/127.0.0.1#5335
|
||||
ipset=/.scmpchinese.com/gfwlist
|
||||
server=/.scramble.io/127.0.0.1#5335
|
||||
ipset=/.scramble.io/gfwlist
|
||||
server=/.scratch.mit.edu/127.0.0.1#5335
|
||||
ipset=/.scratch.mit.edu/gfwlist
|
||||
server=/.scribd.com/127.0.0.1#5335
|
||||
ipset=/.scribd.com/gfwlist
|
||||
server=/.scriptspot.com/127.0.0.1#5335
|
||||
@ -7556,6 +7618,8 @@ server=/.shooshtime.com/127.0.0.1#5335
|
||||
ipset=/.shooshtime.com/gfwlist
|
||||
server=/.shop2000.com.tw/127.0.0.1#5335
|
||||
ipset=/.shop2000.com.tw/gfwlist
|
||||
server=/.shopee.tw/127.0.0.1#5335
|
||||
ipset=/.shopee.tw/gfwlist
|
||||
server=/.shopping.com/127.0.0.1#5335
|
||||
ipset=/.shopping.com/gfwlist
|
||||
server=/.showbiz.omy.sg/127.0.0.1#5335
|
||||
@ -7582,8 +7646,6 @@ server=/.sijihuisuo.club/127.0.0.1#5335
|
||||
ipset=/.sijihuisuo.club/gfwlist
|
||||
server=/.sijihuisuo.com/127.0.0.1#5335
|
||||
ipset=/.sijihuisuo.com/gfwlist
|
||||
server=/.sikaozhe1997.github.io/127.0.0.1#5335
|
||||
ipset=/.sikaozhe1997.github.io/gfwlist
|
||||
server=/.silkbook.com/127.0.0.1#5335
|
||||
ipset=/.silkbook.com/gfwlist
|
||||
server=/.simbolostwitter.com/127.0.0.1#5335
|
||||
@ -7716,8 +7778,6 @@ server=/.socrec.org/127.0.0.1#5335
|
||||
ipset=/.socrec.org/gfwlist
|
||||
server=/.sod.co.jp/127.0.0.1#5335
|
||||
ipset=/.sod.co.jp/gfwlist
|
||||
server=/.sodatea.github.io/127.0.0.1#5335
|
||||
ipset=/.sodatea.github.io/gfwlist
|
||||
server=/.softether-download.com/127.0.0.1#5335
|
||||
ipset=/.softether-download.com/gfwlist
|
||||
server=/.softether.co.jp/127.0.0.1#5335
|
||||
@ -7886,6 +7946,8 @@ server=/.stage64.hk/127.0.0.1#5335
|
||||
ipset=/.stage64.hk/gfwlist
|
||||
server=/.standupfortibet.org/127.0.0.1#5335
|
||||
ipset=/.standupfortibet.org/gfwlist
|
||||
server=/.standwithhk.org/127.0.0.1#5335
|
||||
ipset=/.standwithhk.org/gfwlist
|
||||
server=/.starfishfx.com/127.0.0.1#5335
|
||||
ipset=/.starfishfx.com/gfwlist
|
||||
server=/.starp2p.com/127.0.0.1#5335
|
||||
@ -8232,6 +8294,8 @@ server=/.teensinasia.com/127.0.0.1#5335
|
||||
ipset=/.teensinasia.com/gfwlist
|
||||
server=/.telecomspace.com/127.0.0.1#5335
|
||||
ipset=/.telecomspace.com/gfwlist
|
||||
server=/.telegra.ph/127.0.0.1#5335
|
||||
ipset=/.telegra.ph/gfwlist
|
||||
server=/.telegram.dog/127.0.0.1#5335
|
||||
ipset=/.telegram.dog/gfwlist
|
||||
server=/.telegram.me/127.0.0.1#5335
|
||||
@ -8252,8 +8316,6 @@ server=/.tensorflow.org/127.0.0.1#5335
|
||||
ipset=/.tensorflow.org/gfwlist
|
||||
server=/.tenzinpalmo.com/127.0.0.1#5335
|
||||
ipset=/.tenzinpalmo.com/gfwlist
|
||||
server=/.terminus2049.github.io/127.0.0.1#5335
|
||||
ipset=/.terminus2049.github.io/gfwlist
|
||||
server=/.tew.org/127.0.0.1#5335
|
||||
ipset=/.tew.org/gfwlist
|
||||
server=/.textnow.me/127.0.0.1#5335
|
||||
@ -8380,8 +8442,6 @@ server=/.tibet-foundation.org/127.0.0.1#5335
|
||||
ipset=/.tibet-foundation.org/gfwlist
|
||||
server=/.tibet-house-trust.co.uk/127.0.0.1#5335
|
||||
ipset=/.tibet-house-trust.co.uk/gfwlist
|
||||
server=/.tibet-info.net/127.0.0.1#5335
|
||||
ipset=/.tibet-info.net/gfwlist
|
||||
server=/.tibet-initiative.de/127.0.0.1#5335
|
||||
ipset=/.tibet-initiative.de/gfwlist
|
||||
server=/.tibet-munich.de/127.0.0.1#5335
|
||||
@ -8660,8 +8720,6 @@ server=/.totalvpn.com/127.0.0.1#5335
|
||||
ipset=/.totalvpn.com/gfwlist
|
||||
server=/.toutiaoabc.com/127.0.0.1#5335
|
||||
ipset=/.toutiaoabc.com/gfwlist
|
||||
server=/.toutyrater.github.io/127.0.0.1#5335
|
||||
ipset=/.toutyrater.github.io/gfwlist
|
||||
server=/.towngain.com/127.0.0.1#5335
|
||||
ipset=/.towngain.com/gfwlist
|
||||
server=/.toypark.in/127.0.0.1#5335
|
||||
@ -8802,6 +8860,8 @@ server=/.turbohide.com/127.0.0.1#5335
|
||||
ipset=/.turbohide.com/gfwlist
|
||||
server=/.turbotwitter.com/127.0.0.1#5335
|
||||
ipset=/.turbotwitter.com/gfwlist
|
||||
server=/.turkistantimes.com/127.0.0.1#5335
|
||||
ipset=/.turkistantimes.com/gfwlist
|
||||
server=/.turntable.fm/127.0.0.1#5335
|
||||
ipset=/.turntable.fm/gfwlist
|
||||
server=/.tushycash.com/127.0.0.1#5335
|
||||
@ -9162,6 +9222,8 @@ server=/.upornia.com/127.0.0.1#5335
|
||||
ipset=/.upornia.com/gfwlist
|
||||
server=/.uproxy.org/127.0.0.1#5335
|
||||
ipset=/.uproxy.org/gfwlist
|
||||
server=/.uptodown.com/127.0.0.1#5335
|
||||
ipset=/.uptodown.com/gfwlist
|
||||
server=/.upwill.org/127.0.0.1#5335
|
||||
ipset=/.upwill.org/gfwlist
|
||||
server=/.ur7s.com/127.0.0.1#5335
|
||||
@ -9744,6 +9806,8 @@ server=/.winning11.com/127.0.0.1#5335
|
||||
ipset=/.winning11.com/gfwlist
|
||||
server=/.winwhispers.info/127.0.0.1#5335
|
||||
ipset=/.winwhispers.info/gfwlist
|
||||
server=/.wionews.com/127.0.0.1#5335
|
||||
ipset=/.wionews.com/gfwlist
|
||||
server=/.wire.com/127.0.0.1#5335
|
||||
ipset=/.wire.com/gfwlist
|
||||
server=/.wiredbytes.com/127.0.0.1#5335
|
||||
@ -9838,8 +9902,6 @@ server=/.wretch.cc/127.0.0.1#5335
|
||||
ipset=/.wretch.cc/gfwlist
|
||||
server=/.writer.zoho.com/127.0.0.1#5335
|
||||
ipset=/.writer.zoho.com/gfwlist
|
||||
server=/.wsgzao.github.io/127.0.0.1#5335
|
||||
ipset=/.wsgzao.github.io/gfwlist
|
||||
server=/.wsj.com/127.0.0.1#5335
|
||||
ipset=/.wsj.com/gfwlist
|
||||
server=/.wsj.net/127.0.0.1#5335
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
-- @author Jerryk <jerrykuku@qq.com>
|
||||
------------------------------------------------
|
||||
local _M = {}
|
||||
|
||||
local icount = 0
|
||||
-- Get country iso code with remark or host
|
||||
-- Return String:iso_code
|
||||
function _M.get_flag(remark, host)
|
||||
@ -158,5 +158,6 @@ function _M.wget(url)
|
||||
return _M.trim(stdout)
|
||||
end
|
||||
|
||||
|
||||
return _M
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ else
|
||||
end
|
||||
|
||||
log('正在更新【国内IP段】数据库')
|
||||
refresh_cmd = "wget -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' 2>/dev/null| awk -F\\| '/CN\\|ipv4/ { printf(\"%s/%d\\n\", $4, 32-log($5)/log(2)) }' > /tmp/china_ssr.txt"
|
||||
refresh_cmd ="wget -O- 'https://ispip.clang.cn/all_cn.txt' > /tmp/china_ssr.txt 2>/dev/null"
|
||||
sret = luci.sys.call(refresh_cmd)
|
||||
icount = luci.sys.exec('cat /tmp/china_ssr.txt | wc -l')
|
||||
if sret == 0 then
|
||||
|
||||
@ -648,6 +648,7 @@ footer.mobile-hide {
|
||||
padding: 0 !important;
|
||||
background-color: transparent !important;
|
||||
color: #fff !important;
|
||||
margin-bottom: 0.5em !important;
|
||||
}
|
||||
|
||||
.modals h3 {
|
||||
@ -668,6 +669,7 @@ footer.mobile-hide {
|
||||
background: transparent;
|
||||
color: #FFFFFF;
|
||||
outline: none;
|
||||
margin-top: 10px;
|
||||
padding-left: 3px;
|
||||
padding-right: 22px;
|
||||
overflow: hidden
|
||||
|
||||
@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=Edge Theme
|
||||
LUCI_DEPENDS:=
|
||||
PKG_VERSION:=2.2
|
||||
PKG_RELEASE:=20201029
|
||||
PKG_VERSION:=2.4
|
||||
PKG_RELEASE:=20201128
|
||||
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
@ -364,46 +364,6 @@ a {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.col-1 {
|
||||
flex: 1 1 30px !important;
|
||||
}
|
||||
|
||||
.col-2 {
|
||||
flex: 2 2 60px !important;
|
||||
}
|
||||
|
||||
.col-3 {
|
||||
flex: 3 3 90px !important;
|
||||
}
|
||||
|
||||
.col-4 {
|
||||
flex: 4 4 120px !important;
|
||||
}
|
||||
|
||||
.col-5 {
|
||||
flex: 5 5 150px !important;
|
||||
}
|
||||
|
||||
.col-6 {
|
||||
flex: 6 6 180px !important;
|
||||
}
|
||||
|
||||
.col-7 {
|
||||
flex: 7 7 210px !important;
|
||||
}
|
||||
|
||||
.col-8 {
|
||||
flex: 8 8 240px !important;
|
||||
}
|
||||
|
||||
.col-9 {
|
||||
flex: 9 9 270px !important;
|
||||
}
|
||||
|
||||
.col-10 {
|
||||
flex: 10 10 300px !important;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
@ -480,7 +440,7 @@ input:not([type]), input[type=text]:not(.browser-default), input[type=password]:
|
||||
border-radius: 0;
|
||||
outline: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding: 0 0.5rem;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-sizing: content-box;
|
||||
@ -900,7 +860,7 @@ header .fill .status * {
|
||||
|
||||
.main .main-left .nav>li>a {
|
||||
display: block;
|
||||
font-size: 0.9rem !important;
|
||||
font-size: 0.93rem !important;
|
||||
margin: 0.4rem 0.5rem !important;
|
||||
padding: 0.5rem 0 0.5rem 2.5rem !important;
|
||||
transition: box-shadow .25s, -webkit-box-shadow .25s;
|
||||
@ -1113,7 +1073,15 @@ body[class*="node-"] > .main > .main-left > .nav > .slide > .menu.active::before
|
||||
}
|
||||
|
||||
#maincontent > .container {
|
||||
margin: 1rem 0 1rem 0;
|
||||
margin: 0 2%;
|
||||
}
|
||||
|
||||
.Overview.node-admin-status #maincontent > .container {
|
||||
padding:0;
|
||||
}
|
||||
|
||||
.Overview.node-admin-status #maincontent > .container h2{
|
||||
padding-left:2rem;
|
||||
}
|
||||
|
||||
ul {
|
||||
@ -1143,7 +1111,7 @@ h3 {
|
||||
|
||||
h4 {
|
||||
font-size: 1.2rem;
|
||||
margin: 2rem 0 0 0;
|
||||
margin: 1.2rem 0 0 0;
|
||||
padding: 0rem 2rem 0.75rem 2rem;
|
||||
}
|
||||
|
||||
@ -1153,25 +1121,9 @@ h5 {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.cbi-section,
|
||||
.cbi-section-error,
|
||||
#iptables,
|
||||
.Firewall form,
|
||||
#cbi-network > .cbi-section-node,
|
||||
#cbi-wireless > .cbi-section-node,
|
||||
#cbi-wireless > #wifi_assoclist_table,
|
||||
[data-tab-title],
|
||||
[data-page^="admin-system-admin"]:not(.node-main-login) .cbi-map:not(#cbi-dropbear),
|
||||
[data-page="admin-system-opkg"] #maincontent > .container {
|
||||
font-family: inherit;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
line-height: normal;
|
||||
min-width: inherit;
|
||||
margin: 1rem 0;
|
||||
padding: 0rem;
|
||||
border: 0;
|
||||
background-color: #fff;
|
||||
.container .cbi-section{
|
||||
margin-bottom:1rem;
|
||||
|
||||
}
|
||||
|
||||
.cbi-modal .cbi-section,
|
||||
@ -1188,7 +1140,7 @@ h5 {
|
||||
.cbi-section-descr {
|
||||
font-size: small;
|
||||
line-height: 2rem;
|
||||
padding: 0 0 0.5rem 2rem;
|
||||
padding: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.cbi-section-node {
|
||||
@ -1212,6 +1164,10 @@ h5 {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
fieldset.cbi-section{
|
||||
border:none;
|
||||
}
|
||||
|
||||
.cbi-section > legend {
|
||||
display: none !important;
|
||||
}
|
||||
@ -1411,38 +1367,13 @@ td > table > tbody > tr > td,
|
||||
-webkit-appearance: none !important;
|
||||
}
|
||||
|
||||
.btn:hover,
|
||||
.btn:focus,
|
||||
.btn:active,
|
||||
.cbi-button:hover,
|
||||
.cbi-button:focus,
|
||||
.cbi-button:active,
|
||||
.item:hover::after,
|
||||
.item:focus::after,
|
||||
.item:active::after,
|
||||
.cbi-page-actions .cbi-button-apply + .cbi-button-save:hover,
|
||||
.cbi-page-actions .cbi-button-apply + .cbi-button-save:focus,
|
||||
.cbi-page-actions .cbi-button-apply + .cbi-button-save:active {
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
.waves-input-wrapper:hover,
|
||||
.btn:hover,
|
||||
.btn:focus,
|
||||
.cbi-button:hover,
|
||||
.cbi-button:focus,
|
||||
.item:hover::after,
|
||||
.item:focus::after {
|
||||
opacity: 0.7;
|
||||
top: 0.15rem;
|
||||
}
|
||||
|
||||
.btn:active,
|
||||
.cbi-button:active,
|
||||
.item:active::after {
|
||||
.item:hover::after {
|
||||
opacity: 0.7;
|
||||
top: 0.1rem;
|
||||
}
|
||||
|
||||
.cbi-button-up:hover,
|
||||
@ -1450,10 +1381,6 @@ button:hover,
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.cbi-button-up:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.btn:disabled,
|
||||
.cbi-button:disabled {
|
||||
cursor: not-allowed;
|
||||
@ -1598,7 +1525,7 @@ button:hover,
|
||||
}
|
||||
|
||||
ul.tabs,.tabmenu .tabs,#tabmenu .tabs,ul.cbi-tabmenu {
|
||||
padding-left: 2rem;
|
||||
padding-left: 2.5%;
|
||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12);
|
||||
transition: box-shadow .25s, -webkit-box-shadow .25s;
|
||||
border-radius: 2px;
|
||||
@ -1608,6 +1535,11 @@ ul.tabs,.tabmenu .tabs,#tabmenu .tabs,ul.cbi-tabmenu {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
#packages{
|
||||
margin-left: -2%;
|
||||
width: 105%;
|
||||
}
|
||||
|
||||
.cbi-tabmenu > li:hover {
|
||||
background-color: rgba(246,178,181,0.2);
|
||||
}
|
||||
@ -1873,7 +1805,7 @@ ul.tabs,.tabmenu .tabs,#tabmenu .tabs,ul.cbi-tabmenu {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.cbi-dropdown > ul.preview {
|
||||
#cbi-adblock-global-adb_sources .cbi-dropdown > ul.preview {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -1959,6 +1891,7 @@ ul.tabs,.tabmenu .tabs,#tabmenu .tabs,ul.cbi-tabmenu {
|
||||
.cbi-dropdown > ul > li > form > input[type="checkbox"] {
|
||||
height: auto;
|
||||
margin: 0;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.cbi-dropdown > ul > li input[type="text"] {
|
||||
@ -1972,7 +1905,7 @@ ul.tabs,.tabmenu .tabs,#tabmenu .tabs,ul.cbi-tabmenu {
|
||||
width: auto;
|
||||
min-width: 100%;
|
||||
max-width: none;
|
||||
max-height: 200px !important;
|
||||
max-height: 200px;
|
||||
border: thin solid #918e8c;
|
||||
background: #f6f6f6;
|
||||
box-shadow: 0 0 4px #918e8c;
|
||||
@ -2259,7 +2192,6 @@ body.modal-overlay-active #modal_overlay {
|
||||
.cbi-page-actions {
|
||||
padding-top: 1rem;
|
||||
text-align: right;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.node-main-login .cbi-page-actions {
|
||||
@ -2347,8 +2279,12 @@ textarea {
|
||||
transition: box-shadow .25s, -webkit-box-shadow .25s;
|
||||
border-radius: 2px;
|
||||
border: 0 !important;
|
||||
margin: 0 2rem;
|
||||
width: 95% !important;
|
||||
}
|
||||
|
||||
textarea:focus{
|
||||
outline: none;
|
||||
border: 1px solid #5A8DEE !important;
|
||||
box-shadow: 0 0px 5px 0 #5A8DEE;
|
||||
}
|
||||
|
||||
.cbi-section textarea {
|
||||
@ -2647,8 +2583,8 @@ span[data-tooltip] .label {
|
||||
background-color: #D2FFE8;
|
||||
}
|
||||
|
||||
label > input[type="checkbox"],
|
||||
label > input[type="radio"] {
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
position: relative;
|
||||
right: 0.2rem;
|
||||
margin: 0;
|
||||
@ -2758,7 +2694,7 @@ input[name="nslookup"] {
|
||||
transition: box-shadow .25s, -webkit-box-shadow .25s;
|
||||
border-radius: 2px;
|
||||
text-align: left;
|
||||
background: #faf5f3c2;
|
||||
background: rgba(255, 255, 255, 0.75);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@ -2975,15 +2911,9 @@ input[name="nslookup"] {
|
||||
color: #32325d;
|
||||
color: var(--gray-dark);
|
||||
}
|
||||
/* software */
|
||||
[data-page="admin-system-opkg"] h2 {
|
||||
margin-left: 1.5rem;
|
||||
color: #32325d;
|
||||
color: var(--gray-dark);
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin: 0.5em 2rem 1em 2rem !important;
|
||||
margin: 0.5em 0 1em 0 !important;
|
||||
}
|
||||
|
||||
.controls > * > .btn:not([aria-label$="page"]) {
|
||||
@ -3008,12 +2938,6 @@ input[name="nslookup"] {
|
||||
padding-top: 0.1rem;
|
||||
}
|
||||
|
||||
.td.version,
|
||||
.td.size {
|
||||
white-space: normal !important;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.cbi-tabmenu + .cbi-section {
|
||||
margin-top: 0;
|
||||
}
|
||||
@ -3223,11 +3147,8 @@ input[type="checkbox"] {
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
display:none;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked {
|
||||
border: 1px solid #5A8DEE;
|
||||
background-image: url('data:image/svg+xml,%3csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 8 8\'%3e%3cpath fill=\'%23fff\' d=\'M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z\'/%3e%3c/svg%3e') !important;
|
||||
@ -3236,19 +3157,17 @@ input[type="checkbox"]:checked {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
/* IE hacks */
|
||||
@media all and (-ms-high-contrast: none) {
|
||||
.main > .main-left > .nav > .slide > .menu::before {
|
||||
top: 30.25%;
|
||||
}
|
||||
.cbi-dropdown[open]>ul.dropdown>li label {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
.main > .main-left > .nav > li:last-child::before {
|
||||
top: 20%;
|
||||
}
|
||||
#cbi-adblock-global-adb_sources .cbi-dropdown-open .cbi-dropdown[open] > ul.dropdown{
|
||||
position:relative !important;
|
||||
bottom:0 !important;
|
||||
}
|
||||
|
||||
.showSide::before {
|
||||
top: -12px;
|
||||
}
|
||||
#cbi-adblock-global-adb_sources .cbi-dropdown-open .preview,#cbi-adblock-global-adb_sources .cbi-dropdown-open .more,.cbi-dropdown-open .open{
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1600px) {
|
||||
@ -3420,10 +3339,6 @@ input[type="checkbox"]:checked {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.table {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.Interfaces .table {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
@ -3447,6 +3362,12 @@ input[type="checkbox"]:checked {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.node-admin-status.Overview .tr {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.th,
|
||||
.td {
|
||||
display: inline-block;
|
||||
@ -3548,6 +3469,14 @@ input[type="checkbox"]:checked {
|
||||
width: 100% !important;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
#packages .tr {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
#packages .td {
|
||||
padding: 1em 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
@ -3611,21 +3540,9 @@ input[type="checkbox"]:checked {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.main > .main-left > .nav > .slide > .menu {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.main > .main-left > .nav > .slide > .slide-menu > li > a {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.cbi-section > div {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.cbi-map >.cbi-section {
|
||||
padding: 0 1rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
@ -3722,6 +3639,7 @@ input[type="checkbox"]:checked {
|
||||
margin: 0.5rem 0;
|
||||
background: none;
|
||||
padding: 0;
|
||||
border:none;
|
||||
}
|
||||
|
||||
.cbi-map style+fieldset.cbi-section:first-of-type p font {
|
||||
@ -4002,10 +3920,6 @@ code,.cbi-progressbar::after {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.cbi-map >.cbi-section {
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.cbi-map >.cbi-section .cbi-value {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
@ -4059,15 +3973,9 @@ i input {
|
||||
flex-basis: auto !important;
|
||||
}
|
||||
|
||||
h2,.cbi-map-descr {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1680px) and (min-width: 1280px) {
|
||||
.cbi-map >.cbi-section .cbi-section-table,.cbi-map >.cbi-section .cbi-tabmenu,.cbi-map >.cbi-section .table {
|
||||
margin-left: -1.95rem !important;
|
||||
width: 105.5% !important;
|
||||
}
|
||||
.cbi-map >.cbi-section .cbi-section-table,.container .cbi-tabmenu,.container #tabmenu,.cbi-map >.cbi-section .table {
|
||||
margin-left: -2%;
|
||||
width: 105%;
|
||||
}
|
||||
|
||||
.admin-status-overview h2.content {
|
||||
@ -4137,10 +4045,14 @@ cbi-button.cbi-button-neutral {
|
||||
}
|
||||
|
||||
input[type=password]+.cbi-button.cbi-button-neutral {
|
||||
padding: 0.1rem 0.4rem;
|
||||
padding: 0 0.4rem;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.cbi-input-password[type=text]+.cbi-button.cbi-button-neutral {
|
||||
padding: 0.2rem 0.5rem;
|
||||
}
|
||||
|
||||
.main-right>hr {
|
||||
height: 6px;
|
||||
background-color: rgba(255, 0, 27, 0.95);
|
||||
@ -4166,6 +4078,10 @@ div[id^="cbi-unblockmusic"] .cbi-button {
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.cbi-section-table .tr>.td:last-child,#packages .tr>.td:last-child{
|
||||
padding-right:3%;
|
||||
}
|
||||
|
||||
.chromeframe {
|
||||
padding: 2rem 3rem;
|
||||
margin: 0 auto;
|
||||
@ -4188,8 +4104,12 @@ div[id^="cbi-unblockmusic"] .cbi-button {
|
||||
color: orangered;
|
||||
}
|
||||
|
||||
.landscape {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
[data-page="admin-network-wifi"] tr > td .cbi-button{
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
[data-page="admin-network-wifi"] tr > td input[type="button"]{
|
||||
padding: 0.5rem 1rem !important;
|
||||
}
|
||||
table.interfaces .th{
|
||||
padding:1.1em 0.5rem !important;
|
||||
}
|
||||
@ -282,36 +282,10 @@
|
||||
|
||||
var getaudio = $('#player')[0];
|
||||
/* Get the audio from the player (using the player's ID), the [0] is necessary */
|
||||
var mouseovertimer;
|
||||
/* Global variable for a timer. When the mouse is hovered over the speaker it will start playing after hovering for 1 second, if less than 1 second it won't play (incase you accidentally hover over the speaker) */
|
||||
var audiostatus = 'off';
|
||||
/* Global variable for the audio's status (off or on). It's a bit crude but it works for determining the status. */
|
||||
|
||||
$(document).on('mouseenter', '.speaker', function() {
|
||||
/* Bonus feature, if the mouse hovers over the speaker image for more than 1 second the audio will start playing */
|
||||
if (!mouseovertimer) {
|
||||
mouseovertimer = window.setTimeout(function() {
|
||||
mouseovertimer = null;
|
||||
if (!$('.speaker').hasClass("speakerplay")) {
|
||||
getaudio.load();
|
||||
/* Loads the audio */
|
||||
getaudio.play();
|
||||
/* Play the audio (starting at the beginning of the track) */
|
||||
$('.speaker').addClass('speakerplay');
|
||||
return false;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('mouseleave', '.speaker', function() {
|
||||
/* If the mouse stops hovering on the image (leaves the image) clear the timer, reset back to 0 */
|
||||
if (mouseovertimer) {
|
||||
window.clearTimeout(mouseovertimer);
|
||||
mouseovertimer = null;
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click touchend', '.speaker', function() {
|
||||
/* Touchend is necessary for mobile devices, click alone won't work */
|
||||
if (!$('.speaker').hasClass("speakerplay")) {
|
||||
@ -319,7 +293,6 @@
|
||||
$('.speaker').addClass('speakerplay');
|
||||
getaudio.load();
|
||||
getaudio.play();
|
||||
window.clearTimeout(mouseovertimer);
|
||||
audiostatus = 'on';
|
||||
return false;
|
||||
} else if (audiostatus == 'on') {
|
||||
@ -329,7 +302,6 @@
|
||||
} else if ($('.speaker').hasClass("speakerplay")) {
|
||||
getaudio.pause();
|
||||
$('.speaker').removeClass('speakerplay');
|
||||
window.clearTimeout(mouseovertimer);
|
||||
audiostatus = 'on';
|
||||
}
|
||||
});
|
||||
@ -362,13 +334,13 @@ $(".waves-input-wrapper").filter(function () {
|
||||
}
|
||||
}).hide();
|
||||
|
||||
$("div>select:first-child,div>input[type='text']:first-child,div>input[type='email']:first-child,div>input[type='url']:first-child,div>input[type='date']:first-child,div>input[type='datetime']:first-child,div>input[type='tel']:first-child,div>input[type='number']:first-child,div>input[type='search']:first-child").filter(function () {
|
||||
return (!$(this).parents(".cbi-dynlist").length&&!$("body.Diagnostics").length)
|
||||
$("div>select:first-child,div>input[type='text']:first-child").filter(function () {
|
||||
return (!$(this).parents(".cbi-dynlist").length&&!$("body.Diagnostics").length&&!$(this).hasClass("cbi-input-password"))
|
||||
}).after("<span class='focus-input'></span>");
|
||||
|
||||
$("input[type='checkbox']").filter(function () {
|
||||
return (!$(this).next("label").length)
|
||||
}).css({"position":"relative","opacity":"1","pointer-events":"auto"});
|
||||
}).show();
|
||||
|
||||
$("select,input").filter(function () {
|
||||
return ($(this).next(".focus-input").length)
|
||||
@ -377,6 +349,6 @@ $("select,input").filter(function () {
|
||||
}).blur(function(){
|
||||
$(this).css("border-bottom","1px solid #9e9e9e");
|
||||
});
|
||||
}, 400);
|
||||
}, 0);
|
||||
$(".cbi-value").has("textarea").css("background","none");
|
||||
})(jQuery);
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -6,7 +6,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI support for V2ray Server
|
||||
LUCI_DEPENDS:=+v2ray
|
||||
LUCI_DEPENDS:=+xray
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_VERSION:=1.1
|
||||
PKG_RELEASE:=5
|
||||
@ -14,5 +14,3 @@ PKG_RELEASE:=5
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<%
|
||||
local v2ray_version=luci.sys.exec("[ -f '/usr/bin/v2ray/v2ray' ] && /usr/bin/v2ray/v2ray -version | awk '{print $2}' | sed -n 1P")
|
||||
local v2ray_version=luci.sys.exec("[ -f '/usr/bin/v2ray' ] && /usr/bin/v2ray -version | awk '{print $2}' | sed -n 1P")
|
||||
local dsp = require "luci.dispatcher"
|
||||
-%>
|
||||
|
||||
@ -179,4 +179,4 @@ local dsp = require "luci.dispatcher"
|
||||
<span id="_v2ray-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
# Copyright (C) 2018-2020 Lienol
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-v2ray-server
|
||||
LUCI_TITLE:=LuCI support for V2ray Server
|
||||
LUCI_DEPENDS:=+libsodium +luci-lib-jsonc +unzip +v2ray
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_VERSION:=1.1
|
||||
PKG_RELEASE:=1-20200101
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
|
||||
@ -1,66 +0,0 @@
|
||||
-- Copyright 2018-2019 Lienol <lawlienol@gmail.com>
|
||||
module("luci.controller.v2ray_server", package.seeall)
|
||||
local http = require "luci.http"
|
||||
local v2ray = require "luci.model.cbi.v2ray_server.api.v2ray"
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/v2ray_server") then return end
|
||||
entry({"admin", "vpn"}, firstchild(), "VPN", 45).dependent = false
|
||||
entry({"admin", "vpn", "v2ray_server"}, cbi("v2ray_server/index"),
|
||||
_("V2ray Server"), 3).dependent = true
|
||||
entry({"admin", "vpn", "v2ray_server", "config"}, cbi("v2ray_server/config")).leaf =
|
||||
true
|
||||
|
||||
entry({"admin", "vpn", "v2ray_server", "users_status"},
|
||||
call("v2ray_users_status")).leaf = true
|
||||
entry({"admin", "vpn", "v2ray_server", "check"}, call("v2ray_check")).leaf =
|
||||
true
|
||||
entry({"admin", "vpn", "v2ray_server", "update"}, call("v2ray_update")).leaf =
|
||||
true
|
||||
entry({"admin", "vpn", "v2ray_server", "get_log"}, call("get_log")).leaf =
|
||||
true
|
||||
entry({"admin", "vpn", "v2ray_server", "clear_log"}, call("clear_log")).leaf =
|
||||
true
|
||||
end
|
||||
|
||||
local function http_write_json(content)
|
||||
http.prepare_content("application/json")
|
||||
http.write_json(content or {code = 1})
|
||||
end
|
||||
|
||||
function v2ray_users_status()
|
||||
local e = {}
|
||||
e.index = luci.http.formvalue("index")
|
||||
e.status = luci.sys.call(
|
||||
"ps -w| grep -v grep | grep '/var/etc/v2ray_server/" ..
|
||||
luci.http.formvalue("id") .. "' >/dev/null") == 0
|
||||
http_write_json(e)
|
||||
end
|
||||
|
||||
function v2ray_check()
|
||||
local json = v2ray.to_check("")
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function v2ray_update()
|
||||
local json = nil
|
||||
local task = http.formvalue("task")
|
||||
if task == "extract" then
|
||||
json =
|
||||
v2ray.to_extract(http.formvalue("file"), http.formvalue("subfix"))
|
||||
elseif task == "move" then
|
||||
json = v2ray.to_move(http.formvalue("file"))
|
||||
else
|
||||
json = v2ray.to_download(http.formvalue("url"))
|
||||
end
|
||||
|
||||
http_write_json(json)
|
||||
end
|
||||
|
||||
function get_log()
|
||||
luci.http.write(luci.sys.exec(
|
||||
"[ -f '/var/log/v2ray_server/app.log' ] && cat /var/log/v2ray_server/app.log"))
|
||||
end
|
||||
|
||||
function clear_log() luci.sys.call("echo '' > /var/log/v2ray_server/app.log") end
|
||||
|
||||
@ -1,91 +0,0 @@
|
||||
local ucursor = require"luci.model.uci".cursor()
|
||||
local json = require "luci.jsonc"
|
||||
local server_section = arg[1]
|
||||
local server = ucursor:get_all("v2ray_server", server_section)
|
||||
|
||||
local settings = nil
|
||||
|
||||
if server.protocol == "vmess" then
|
||||
if server.VMess_id then
|
||||
local clients = {}
|
||||
for i = 1, #server.VMess_id do
|
||||
clients[i] = {
|
||||
id = server.VMess_id[i],
|
||||
level = tonumber(server.VMess_level),
|
||||
alterId = tonumber(server.VMess_alterId)
|
||||
}
|
||||
end
|
||||
settings = {clients = clients}
|
||||
end
|
||||
elseif server.protocol == "socks" then
|
||||
settings = {
|
||||
auth = "password",
|
||||
accounts = {
|
||||
{user = server.socks_username, pass = server.socks_password}
|
||||
}
|
||||
}
|
||||
elseif server.protocol == "shadowsocks" then
|
||||
settings = {
|
||||
method = server.ss_method,
|
||||
password = server.ss_password,
|
||||
level = tonumber(server.ss_level),
|
||||
network = server.ss_network,
|
||||
ota = (server.ss_ota == '1') and true or false
|
||||
}
|
||||
end
|
||||
|
||||
local v2ray = {
|
||||
log = {
|
||||
-- error = "/var/log/v2ray.log",
|
||||
loglevel = "warning"
|
||||
},
|
||||
-- 传入连接
|
||||
inbound = {
|
||||
listen = (server.bind_local == "1") and "127.0.0.1" or nil,
|
||||
port = tonumber(server.port),
|
||||
protocol = server.protocol,
|
||||
-- 底层传输配置
|
||||
settings = settings,
|
||||
streamSettings = (server.protocol == "vmess") and {
|
||||
network = server.transport,
|
||||
security = (server.tls_enable == '1') and "tls" or "none",
|
||||
tlsSettings = (server.tls_enable == '1') and {
|
||||
-- serverName = (server.tls_serverName),
|
||||
allowInsecure = false,
|
||||
disableSystemRoot = false,
|
||||
certificates = {
|
||||
{
|
||||
certificateFile = server.tls_certificateFile,
|
||||
keyFile = server.tls_keyFile
|
||||
}
|
||||
}
|
||||
} or nil,
|
||||
kcpSettings = (server.transport == "mkcp") and {
|
||||
mtu = tonumber(server.mkcp_mtu),
|
||||
tti = tonumber(server.mkcp_tti),
|
||||
uplinkCapacity = tonumber(server.mkcp_uplinkCapacity),
|
||||
downlinkCapacity = tonumber(server.mkcp_downlinkCapacity),
|
||||
congestion = (server.mkcp_congestion == "1") and true or false,
|
||||
readBufferSize = tonumber(server.mkcp_readBufferSize),
|
||||
writeBufferSize = tonumber(server.mkcp_writeBufferSize),
|
||||
header = {type = server.mkcp_guise}
|
||||
} or nil,
|
||||
wsSettings = (server.transport == "ws") and {
|
||||
headers = (server.ws_host) and {Host = server.ws_host} or nil,
|
||||
path = server.ws_path
|
||||
} or nil,
|
||||
httpSettings = (server.transport == "h2") and
|
||||
{path = server.h2_path, host = server.h2_host} or nil,
|
||||
quicSettings = (server.transport == "quic") and {
|
||||
security = server.quic_security,
|
||||
key = server.quic_key,
|
||||
header = {type = server.quic_guise}
|
||||
} or nil
|
||||
} or nil
|
||||
},
|
||||
-- 传出连接
|
||||
outbound = {protocol = "freedom"},
|
||||
-- 额外传出连接
|
||||
outboundDetour = {{protocol = "blackhole", tag = "blocked"}}
|
||||
}
|
||||
print(json.stringify(v2ray, 1))
|
||||
@ -1,328 +0,0 @@
|
||||
module("luci.model.cbi.v2ray_server.api.v2ray", package.seeall)
|
||||
local fs = require "nixio.fs"
|
||||
local sys = require "luci.sys"
|
||||
local uci = require"luci.model.uci".cursor()
|
||||
local util = require "luci.util"
|
||||
local i18n = require "luci.i18n"
|
||||
local ipkg = require "luci.model.ipkg"
|
||||
|
||||
local appname = "v2ray_server"
|
||||
local v2ray_api =
|
||||
"https://api.github.com/repos/v2ray/v2ray-core/releases/latest"
|
||||
local wget = "/usr/bin/wget"
|
||||
local wget_args = {
|
||||
"--no-check-certificate", "--quiet", "--timeout=100", "--tries=3"
|
||||
}
|
||||
local command_timeout = 300
|
||||
|
||||
local LEDE_BOARD = nil
|
||||
local DISTRIB_TARGET = nil
|
||||
local is_armv7 = false
|
||||
|
||||
local function _unpack(t, i)
|
||||
i = i or 1
|
||||
if t[i] ~= nil then return t[i], _unpack(t, i + 1) end
|
||||
end
|
||||
|
||||
local function exec(cmd, args, writer, timeout)
|
||||
local os = require "os"
|
||||
local nixio = require "nixio"
|
||||
|
||||
local fdi, fdo = nixio.pipe()
|
||||
local pid = nixio.fork()
|
||||
|
||||
if pid > 0 then
|
||||
fdo:close()
|
||||
|
||||
if writer or timeout then
|
||||
local starttime = os.time()
|
||||
while true do
|
||||
if timeout and os.difftime(os.time(), starttime) >= timeout then
|
||||
nixio.kill(pid, nixio.const.SIGTERM)
|
||||
return 1
|
||||
end
|
||||
|
||||
if writer then
|
||||
local buffer = fdi:read(2048)
|
||||
if buffer and #buffer > 0 then
|
||||
writer(buffer)
|
||||
end
|
||||
end
|
||||
|
||||
local wpid, stat, code = nixio.waitpid(pid, "nohang")
|
||||
|
||||
if wpid and stat == "exited" then return code end
|
||||
|
||||
if not writer and timeout then nixio.nanosleep(1) end
|
||||
end
|
||||
else
|
||||
local wpid, stat, code = nixio.waitpid(pid)
|
||||
return wpid and stat == "exited" and code
|
||||
end
|
||||
elseif pid == 0 then
|
||||
nixio.dup(fdo, nixio.stdout)
|
||||
fdi:close()
|
||||
fdo:close()
|
||||
nixio.exece(cmd, args, nil)
|
||||
nixio.stdout:close()
|
||||
os.exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
local function compare_versions(ver1, comp, ver2)
|
||||
local table = table
|
||||
|
||||
local av1 = util.split(ver1, "[%.%-]", nil, true)
|
||||
local av2 = util.split(ver2, "[%.%-]", nil, true)
|
||||
|
||||
local max = table.getn(av1)
|
||||
local n2 = table.getn(av2)
|
||||
if (max < n2) then max = n2 end
|
||||
|
||||
for i = 1, max, 1 do
|
||||
local s1 = av1[i] or ""
|
||||
local s2 = av2[i] or ""
|
||||
|
||||
if comp == "~=" and (s1 ~= s2) then return true end
|
||||
if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
|
||||
if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
|
||||
if (s1 ~= s2) then return false end
|
||||
end
|
||||
|
||||
return not (comp == "<" or comp == ">")
|
||||
end
|
||||
|
||||
local function auto_get_arch()
|
||||
local arch = nixio.uname().machine or ""
|
||||
if fs.access("/usr/lib/os-release") then
|
||||
LEDE_BOARD = sys.exec(
|
||||
"echo -n `grep 'LEDE_BOARD' /usr/lib/os-release | awk -F '[\\042\\047]' '{print $2}'`")
|
||||
end
|
||||
if fs.access("/etc/openwrt_release") then
|
||||
DISTRIB_TARGET = sys.exec(
|
||||
"echo -n `grep 'DISTRIB_TARGET' /etc/openwrt_release | awk -F '[\\042\\047]' '{print $2}'`")
|
||||
end
|
||||
|
||||
if arch == "mips" then
|
||||
if LEDE_BOARD and LEDE_BOARD ~= "" then
|
||||
if string.match(LEDE_BOARD, "ramips") == "ramips" then
|
||||
arch = "ramips"
|
||||
else
|
||||
arch = sys.exec("echo '" .. LEDE_BOARD ..
|
||||
"' | grep -oE 'ramips|ar71xx'")
|
||||
end
|
||||
elseif DISTRIB_TARGET and DISTRIB_TARGET ~= "" then
|
||||
if string.match(DISTRIB_TARGET, "ramips") == "ramips" then
|
||||
arch = "ramips"
|
||||
else
|
||||
arch = sys.exec("echo '" .. DISTRIB_TARGET ..
|
||||
"' | grep -oE 'ramips|ar71xx'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return util.trim(arch)
|
||||
end
|
||||
|
||||
local function get_file_info(arch)
|
||||
local file_tree = ""
|
||||
local sub_version = ""
|
||||
|
||||
if arch == "x86_64" then
|
||||
file_tree = "64"
|
||||
elseif arch == "aarch64" then
|
||||
file_tree = "arm64"
|
||||
elseif arch == "ramips" then
|
||||
file_tree = "mipsle"
|
||||
elseif arch == "ar71xx" then
|
||||
file_tree = "mips"
|
||||
elseif arch:match("^i[%d]86$") then
|
||||
file_tree = "32"
|
||||
elseif arch:match("^armv[5-8]") then
|
||||
file_tree = "arm"
|
||||
sub_version = arch:match("[5-8]")
|
||||
if LEDE_BOARD and string.match(LEDE_BOARD, "bcm53xx") == "bcm53xx" then
|
||||
sub_version = "5"
|
||||
elseif DISTRIB_TARGET and string.match(DISTRIB_TARGET, "bcm53xx") ==
|
||||
"bcm53xx" then
|
||||
sub_version = "5"
|
||||
end
|
||||
sub_version = "5"
|
||||
if sub_version == "7" then is_armv7 = true end
|
||||
end
|
||||
|
||||
return file_tree, sub_version
|
||||
end
|
||||
|
||||
local function get_api_json(url)
|
||||
local jsonc = require "luci.jsonc"
|
||||
|
||||
local output = {}
|
||||
-- exec(wget, { "-O-", url, _unpack(wget_args) },
|
||||
-- function(chunk) output[#output + 1] = chunk end)
|
||||
-- local json_content = util.trim(table.concat(output))
|
||||
|
||||
local json_content = luci.sys.exec(wget ..
|
||||
" --no-check-certificate --timeout=10 -t 1 -O- " ..
|
||||
url)
|
||||
|
||||
if json_content == "" then return {} end
|
||||
|
||||
return jsonc.parse(json_content) or {}
|
||||
end
|
||||
|
||||
function get_v2ray_file_path() return "/usr/bin/v2ray" end
|
||||
|
||||
function get_v2ray_version()
|
||||
if get_v2ray_file_path() and get_v2ray_file_path() ~= "" then
|
||||
if fs.access(get_v2ray_file_path() .. "/v2ray") then
|
||||
return luci.sys.exec("echo -n `" .. get_v2ray_file_path() ..
|
||||
"/v2ray -version | awk '{print $2}' | sed -n 1P" ..
|
||||
"`")
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
function to_check(arch)
|
||||
if not arch or arch == "" then arch = auto_get_arch() end
|
||||
|
||||
local file_tree, sub_version = get_file_info(arch)
|
||||
|
||||
if file_tree == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate(
|
||||
"Can't determine ARCH, or ARCH not supported.")
|
||||
}
|
||||
end
|
||||
|
||||
local json = get_api_json(v2ray_api)
|
||||
|
||||
if json.tag_name == nil then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Get remote version info failed.")
|
||||
}
|
||||
end
|
||||
|
||||
local remote_version = json.tag_name:match("[^v]+")
|
||||
local needs_update = compare_versions(get_v2ray_version(), "<",
|
||||
remote_version)
|
||||
local html_url, download_url
|
||||
|
||||
if needs_update then
|
||||
html_url = json.html_url
|
||||
for _, v in ipairs(json.assets) do
|
||||
if v.name and v.name:match("linux%-" .. file_tree) then
|
||||
download_url = v.browser_download_url
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if needs_update and not download_url then
|
||||
return {
|
||||
code = 1,
|
||||
now_version = get_v2ray_version(),
|
||||
version = remote_version,
|
||||
html_url = html_url,
|
||||
error = i18n.translate(
|
||||
"New version found, but failed to get new version download url.")
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
code = 0,
|
||||
update = needs_update,
|
||||
now_version = get_v2ray_version(),
|
||||
version = remote_version,
|
||||
url = {html = html_url, download = download_url}
|
||||
}
|
||||
end
|
||||
|
||||
function to_download(url)
|
||||
if not url or url == "" then
|
||||
return {code = 1, error = i18n.translate("Download url is required.")}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -f /tmp/v2ray_download.*")
|
||||
|
||||
local tmp_file = util.trim(util.exec("mktemp -u -t v2ray_download.XXXXXX"))
|
||||
|
||||
local result = exec(wget, {"-O", tmp_file, url, _unpack(wget_args)}, nil,
|
||||
command_timeout) == 0
|
||||
|
||||
if not result then
|
||||
exec("/bin/rm", {"-f", tmp_file})
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translatef("File download failed or timed out: %s", url)
|
||||
}
|
||||
end
|
||||
|
||||
return {code = 0, file = tmp_file}
|
||||
end
|
||||
|
||||
function to_extract(file, subfix)
|
||||
local isinstall_unzip = ipkg.installed("unzip")
|
||||
if isinstall_unzip == nil then
|
||||
ipkg.update()
|
||||
ipkg.install("unzip")
|
||||
end
|
||||
|
||||
if not file or file == "" or not fs.access(file) then
|
||||
return {code = 1, error = i18n.translate("File path required.")}
|
||||
end
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
|
||||
local tmp_dir = util.trim(util.exec("mktemp -d -t v2ray_extract.XXXXXX"))
|
||||
|
||||
local output = {}
|
||||
exec("/usr/bin/unzip", {"-o", file, "-d", tmp_dir},
|
||||
function(chunk) output[#output + 1] = chunk end)
|
||||
|
||||
local files = util.split(table.concat(output))
|
||||
|
||||
exec("/bin/rm", {"-f", file})
|
||||
|
||||
return {code = 0, file = tmp_dir}
|
||||
end
|
||||
|
||||
function to_move(file)
|
||||
if not file or file == "" then
|
||||
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
|
||||
return {code = 1, error = i18n.translate("Client file is required.")}
|
||||
end
|
||||
|
||||
local client_file = get_v2ray_file_path()
|
||||
|
||||
sys.call("mkdir -p " .. client_file)
|
||||
|
||||
if not arch or arch == "" then arch = auto_get_arch() end
|
||||
local file_tree, sub_version = get_file_info(arch)
|
||||
local result = nil
|
||||
if is_armv7 and is_armv7 == true then
|
||||
result = exec("/bin/mv", {
|
||||
"-f", file .. "/v2ray_armv7", file .. "/v2ctl_armv7", client_file
|
||||
}, nil, command_timeout) == 0
|
||||
else
|
||||
result = exec("/bin/mv",
|
||||
{"-f", file .. "/v2ray", file .. "/v2ctl", client_file},
|
||||
nil, command_timeout) == 0
|
||||
end
|
||||
if not result or not fs.access(client_file) then
|
||||
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translatef("Can't move new file to path: %s",
|
||||
client_file)
|
||||
}
|
||||
end
|
||||
|
||||
exec("/bin/chmod", {"-R", "755", client_file})
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
|
||||
|
||||
return {code = 0}
|
||||
end
|
||||
@ -1,220 +0,0 @@
|
||||
local app_name = "v2ray_server"
|
||||
local d = require "luci.dispatcher"
|
||||
|
||||
local header_type = {"none", "srtp", "utp", "wechat-video", "dtls", "wireguard"}
|
||||
|
||||
map = Map(app_name, "V2ray " .. translate("Server Config"))
|
||||
map.redirect = d.build_url("admin", "vpn", "v2ray_server")
|
||||
|
||||
t = map:section(NamedSection, arg[1], "user", "")
|
||||
t.addremove = false
|
||||
t.dynamic = false
|
||||
|
||||
enable = t:option(Flag, "enable", translate("Enable"))
|
||||
enable.default = "1"
|
||||
enable.rmempty = false
|
||||
|
||||
remarks = t:option(Value, "remarks", translate("Remarks"))
|
||||
remarks.default = translate("Remarks")
|
||||
remarks.rmempty = false
|
||||
|
||||
bind_local = t:option(Flag, "bind_local", translate("Bind Local"), translate(
|
||||
"When selected, it can only be accessed locally,It is recommended to turn on when using reverse proxies."))
|
||||
bind_local.default = "0"
|
||||
bind_local.rmempty = false
|
||||
|
||||
port = t:option(Value, "port", translate("Port"))
|
||||
port.datatype = "port"
|
||||
port.rmempty = false
|
||||
|
||||
protocol = t:option(ListValue, "protocol", translate("Protocol"))
|
||||
protocol:value("vmess", translate("Vmess"))
|
||||
protocol:value("socks", translate("Socks"))
|
||||
protocol:value("shadowsocks", translate("Shadowsocks"))
|
||||
|
||||
socks_username = t:option(Value, "socks_username", translate("User name"))
|
||||
socks_username:depends("protocol", "socks")
|
||||
|
||||
socks_password = t:option(Value, "socks_password", translate("Password"))
|
||||
socks_password.password = true
|
||||
socks_password:depends("protocol", "socks")
|
||||
|
||||
ss_method = t:option(ListValue, "ss_method", translate("Encrypt Method"))
|
||||
ss_method:value("aes-128-cfb")
|
||||
ss_method:value("aes-256-cfb")
|
||||
ss_method:value("aes-128-gcm")
|
||||
ss_method:value("aes-256-gcm")
|
||||
ss_method:value("chacha20")
|
||||
ss_method:value("chacha20-ietf")
|
||||
ss_method:value("chacha20-poly1305")
|
||||
ss_method:value("chacha20-ietf-poly1305")
|
||||
ss_method:depends("protocol", "shadowsocks")
|
||||
|
||||
ss_password = t:option(Value, "ss_password", translate("Password"))
|
||||
ss_password:depends("protocol", "shadowsocks")
|
||||
|
||||
ss_level = t:option(Value, "ss_level", translate("User Level"))
|
||||
ss_level.default = 1
|
||||
ss_level:depends("protocol", "shadowsocks")
|
||||
|
||||
ss_network = t:option(ListValue, "ss_network", translate("Transport"))
|
||||
ss_network.default = "tcp,udp"
|
||||
ss_network:value("tcp", "TCP")
|
||||
ss_network:value("udp", "UDP")
|
||||
ss_network:value("tcp,udp", "TCP,UDP")
|
||||
ss_network:depends("protocol", "shadowsocks")
|
||||
|
||||
ss_ota = t:option(Flag, "ss_ota", translate("OTA"), translate(
|
||||
"When OTA is enabled, V2Ray will reject connections that are not OTA enabled. This option is invalid when using AEAD encryption."))
|
||||
ss_ota.default = "0"
|
||||
ss_ota:depends("protocol", "shadowsocks")
|
||||
|
||||
VMess_id = t:option(DynamicList, "VMess_id", translate("ID"))
|
||||
for i = 1, 3 do
|
||||
local uuid = luci.sys.exec("cat /proc/sys/kernel/random/uuid")
|
||||
VMess_id:value(uuid)
|
||||
end
|
||||
VMess_id:depends("protocol", "vmess")
|
||||
|
||||
VMess_alterId = t:option(Value, "VMess_alterId", translate("Alter ID"))
|
||||
VMess_alterId.default = 16
|
||||
VMess_alterId:depends("protocol", "vmess")
|
||||
|
||||
VMess_level = t:option(Value, "VMess_level", translate("User Level"))
|
||||
VMess_level.default = 1
|
||||
VMess_level:depends("protocol", "vmess")
|
||||
|
||||
transport = t:option(ListValue, "transport", translate("Transport"))
|
||||
transport:value("tcp", "TCP")
|
||||
transport:value("mkcp", "mKCP")
|
||||
transport:value("ws", "WebSocket")
|
||||
transport:value("h2", "HTTP/2")
|
||||
transport:value("quic", "QUIC")
|
||||
transport:depends("protocol", "vmess")
|
||||
|
||||
-- [[ TCP部分 ]]--
|
||||
-- TCP伪装
|
||||
tcp_guise = t:option(ListValue, "tcp_guise", translate("Camouflage Type"))
|
||||
tcp_guise:depends("transport", "tcp")
|
||||
tcp_guise:value("none", "none")
|
||||
tcp_guise:value("http", "http")
|
||||
|
||||
-- HTTP域名
|
||||
tcp_guise_http_host = t:option(DynamicList, "tcp_guise_http_host",
|
||||
translate("HTTP Host"))
|
||||
tcp_guise_http_host:depends("tcp_guise", "http")
|
||||
|
||||
-- HTTP路径
|
||||
tcp_guise_http_path = t:option(DynamicList, "tcp_guise_http_path",
|
||||
translate("HTTP Path"))
|
||||
tcp_guise_http_path:depends("tcp_guise", "http")
|
||||
|
||||
-- [[ mKCP部分 ]]--
|
||||
mkcp_guise = t:option(ListValue, "mkcp_guise", translate("Camouflage Type"),
|
||||
translate(
|
||||
'<br>none: default, no masquerade, data sent is packets with no characteristics.<br>srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br>utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br>wechat-video: packets disguised as WeChat video calls.<br>dtls: disguised as DTLS 1.2 packet.<br>wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)'))
|
||||
for a, t in ipairs(header_type) do mkcp_guise:value(t) end
|
||||
mkcp_guise:depends("transport", "mkcp")
|
||||
|
||||
mkcp_mtu = t:option(Value, "mkcp_mtu", translate("KCP MTU"))
|
||||
mkcp_mtu:depends("transport", "mkcp")
|
||||
|
||||
mkcp_tti = t:option(Value, "mkcp_tti", translate("KCP TTI"))
|
||||
mkcp_tti:depends("transport", "mkcp")
|
||||
|
||||
mkcp_uplinkCapacity = t:option(Value, "mkcp_uplinkCapacity",
|
||||
translate("KCP uplinkCapacity"))
|
||||
mkcp_uplinkCapacity:depends("transport", "mkcp")
|
||||
|
||||
mkcp_downlinkCapacity = t:option(Value, "mkcp_downlinkCapacity",
|
||||
translate("KCP downlinkCapacity"))
|
||||
mkcp_downlinkCapacity:depends("transport", "mkcp")
|
||||
|
||||
mkcp_congestion = t:option(Flag, "mkcp_congestion", translate("KCP Congestion"))
|
||||
mkcp_congestion:depends("transport", "mkcp")
|
||||
|
||||
mkcp_readBufferSize = t:option(Value, "mkcp_readBufferSize",
|
||||
translate("KCP readBufferSize"))
|
||||
mkcp_readBufferSize:depends("transport", "mkcp")
|
||||
|
||||
mkcp_writeBufferSize = t:option(Value, "mkcp_writeBufferSize",
|
||||
translate("KCP writeBufferSize"))
|
||||
mkcp_writeBufferSize:depends("transport", "mkcp")
|
||||
|
||||
-- [[ WebSocket部分 ]]--
|
||||
ws_path = t:option(Value, "ws_path", translate("WebSocket Path"))
|
||||
ws_path:depends("transport", "ws")
|
||||
|
||||
ws_host = t:option(Value, "ws_host", translate("WebSocket Host"))
|
||||
ws_host:depends("transport", "ws")
|
||||
|
||||
-- [[ HTTP/2部分 ]]--
|
||||
h2_path = t:option(Value, "h2_path", translate("HTTP/2 Path"))
|
||||
h2_path:depends("transport", "h2")
|
||||
|
||||
h2_host = t:option(DynamicList, "h2_host", translate("HTTP/2 Host"),
|
||||
translate("Camouflage Domain,you can not fill in"))
|
||||
h2_host:depends("transport", "h2")
|
||||
|
||||
-- [[ QUIC部分 ]]--
|
||||
quic_security =
|
||||
t:option(ListValue, "quic_security", translate("Encrypt Method"))
|
||||
quic_security:value("none")
|
||||
quic_security:value("aes-128-gcm")
|
||||
quic_security:value("chacha20-poly1305")
|
||||
quic_security:depends("transport", "quic")
|
||||
|
||||
quic_key = t:option(Value, "quic_key",
|
||||
translate("Encrypt Method") .. translate("Key"))
|
||||
quic_key:depends("transport", "quic")
|
||||
|
||||
quic_guise = t:option(ListValue, "quic_guise", translate("Camouflage Type"))
|
||||
for a, t in ipairs(header_type) do quic_guise:value(t) end
|
||||
quic_guise:depends("transport", "quic")
|
||||
|
||||
-- [[ TLS部分 ]] --
|
||||
tls_enable = t:option(Flag, "tls_enable", translate("Use HTTPS"))
|
||||
tls_enable:depends("transport", "ws")
|
||||
tls_enable:depends("transport", "h2")
|
||||
tls_enable.default = "1"
|
||||
tls_enable.rmempty = false
|
||||
|
||||
-- tls_serverName = t:option(Value, "tls_serverName", translate("Domain"))
|
||||
-- tls_serverName:depends("transport", "ws")
|
||||
-- tls_serverName:depends("transport", "h2")
|
||||
|
||||
tls_certificateFile = t:option(Value, "tls_certificateFile",
|
||||
translate("Public key absolute path"),
|
||||
translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
tls_certificateFile:depends("tls_enable", 1)
|
||||
|
||||
tls_keyFile = t:option(Value, "tls_keyFile",
|
||||
translate("Private key absolute path"),
|
||||
translate("as:") .. "/etc/ssl/private.key")
|
||||
tls_keyFile:depends("tls_enable", 1)
|
||||
|
||||
function rmempty_restore()
|
||||
VMess_id.rmempty = true
|
||||
VMess_alterId.rmempty = true
|
||||
socks_username.rmempty = true
|
||||
socks_password.rmempty = true
|
||||
ss_password.rmempty = true
|
||||
ss_ota.rmempty = true
|
||||
end
|
||||
|
||||
protocol.validate = function(self, value)
|
||||
rmempty_restore()
|
||||
if value == "vmess" then
|
||||
VMess_id.rmempty = false
|
||||
VMess_alterId.rmempty = false
|
||||
elseif value == "socks" then
|
||||
socks_username.rmempty = true
|
||||
socks_password.rmempty = true
|
||||
elseif value == "shadowsocks" then
|
||||
ss_password.rmempty = false
|
||||
ss_ota.rmempty = false
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
return map
|
||||
@ -1,105 +0,0 @@
|
||||
local i = require "luci.dispatcher"
|
||||
local e = require "nixio.fs"
|
||||
local e = require "luci.sys"
|
||||
local e = luci.model.uci.cursor()
|
||||
local o = "v2ray_server"
|
||||
|
||||
m = Map(o, translate("V2ray Server"))
|
||||
|
||||
t = m:section(TypedSection, "global", translate("Global Settings"))
|
||||
t.anonymous = true
|
||||
t.addremove = false
|
||||
e = t:option(Flag, "enable", translate("Enable"))
|
||||
e.rmempty = false
|
||||
t:append(Template("v2ray_server/v2ray"))
|
||||
|
||||
t = m:section(TypedSection, "user", translate("Users Manager"))
|
||||
t.anonymous = true
|
||||
t.addremove = true
|
||||
t.template = "cbi/tblsection"
|
||||
t.extedit = i.build_url("admin", "vpn", o, "config", "%s")
|
||||
function t.create(t, e)
|
||||
local e = TypedSection.create(t, e)
|
||||
luci.http.redirect(i.build_url("admin", "vpn", o, "config", e))
|
||||
end
|
||||
function t.remove(t, a)
|
||||
t.map.proceed = true
|
||||
t.map:del(a)
|
||||
luci.http.redirect(i.build_url("admin", "vpn", o))
|
||||
end
|
||||
e = t:option(Flag, "enable", translate("Enable"))
|
||||
e.width = "5%"
|
||||
e.rmempty = false
|
||||
e = t:option(DummyValue, "status", translate("Status"))
|
||||
e.template = "v2ray_server/users_status"
|
||||
e.value = translate("Collecting data...")
|
||||
e = t:option(DummyValue, "remarks", translate("Remarks"))
|
||||
e.width = "15%"
|
||||
e = t:option(DummyValue, "port", translate("Port"))
|
||||
e.width = "10%"
|
||||
e = t:option(DummyValue, "protocol", translate("Protocol"))
|
||||
e.width = "15%"
|
||||
e.cfgvalue = function(self, section)
|
||||
local str = "未知"
|
||||
local protocol = m:get(section, "protocol") or ""
|
||||
if protocol ~= "" then str = (protocol:gsub("^%l", string.upper)) end
|
||||
return str
|
||||
end
|
||||
e = t:option(DummyValue, "transport", translate("Transport"))
|
||||
e.width = "10%"
|
||||
e.cfgvalue = function(self, section)
|
||||
local t = "未知"
|
||||
local b = ""
|
||||
local protocol = m:get(section, "protocol") or ""
|
||||
if protocol == "vmess" then
|
||||
b = "transport"
|
||||
elseif protocol == "shadowsocks" then
|
||||
b = "ss_network"
|
||||
end
|
||||
local a = m:get(section, b) or ""
|
||||
if a == "tcp" then
|
||||
t = "TCP"
|
||||
elseif a == "udp" then
|
||||
t = "UDP"
|
||||
elseif a == "tcp,udp" then
|
||||
t = "TCP,UDP"
|
||||
elseif a == "mkcp" then
|
||||
t = "mKCP"
|
||||
elseif a == "ws" then
|
||||
t = "WebSocket"
|
||||
elseif a == "h2" then
|
||||
t = "HTTP/2"
|
||||
elseif a == "quic" then
|
||||
t = "QUIC"
|
||||
else
|
||||
t = "TCP,UDP"
|
||||
end
|
||||
return t
|
||||
end
|
||||
e = t:option(DummyValue, "password", translate("Password"))
|
||||
e.width = "30%"
|
||||
e.cfgvalue = function(self, section)
|
||||
local e = ""
|
||||
local protocol = m:get(section, "protocol") or ""
|
||||
if protocol == "vmess" then
|
||||
e = "VMess_id"
|
||||
elseif protocol == "shadowsocks" then
|
||||
e = "ss_password"
|
||||
elseif protocol == "socks" then
|
||||
e = "socks_password"
|
||||
end
|
||||
local e = m:get(section, e) or ""
|
||||
local t = ""
|
||||
if type(e) == "table" then
|
||||
for a = 1, #e do t = t .. e[a] end
|
||||
else
|
||||
t = e
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
m:append(Template("v2ray_server/log"))
|
||||
|
||||
m:append(Template("v2ray_server/users_list_status"))
|
||||
return m
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function clear_log(btn) {
|
||||
XHR.get('<%=url([[admin]], [[vpn]], [[v2ray_server]], [[clear_log]])%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
var log_textarea = document.getElementById('log_textarea');
|
||||
log_textarea.innerHTML = "";
|
||||
log_textarea.scrollTop = log_textarea.scrollHeight;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
XHR.poll(3, '<%=url([[admin]], [[vpn]], [[v2ray_server]], [[get_log]])%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
var log_textarea = document.getElementById('log_textarea');
|
||||
log_textarea.innerHTML = x.responseText;
|
||||
log_textarea.scrollTop = log_textarea.scrollHeight;
|
||||
}
|
||||
}
|
||||
);
|
||||
//]]>
|
||||
</script>
|
||||
<fieldset class="cbi-section" id="_log_fieldset">
|
||||
<legend>
|
||||
<%:Logs%>
|
||||
</legend>
|
||||
<input class="cbi-button cbi-input-remove" type="button" onclick="clear_log()" value="<%:Clear logs%>">
|
||||
<textarea id="log_textarea" class="cbi-input-textarea" style="width: 100%;margin-top: 10px;" data-update="change" rows="20" wrap="off" readonly="readonly"></textarea>
|
||||
</fieldset>
|
||||
@ -1,23 +0,0 @@
|
||||
<%
|
||||
local dsp = require "luci.dispatcher"
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var v2ray_users_status = document.getElementsByClassName('v2ray_users_status');
|
||||
for(var i = 0; i < v2ray_users_status.length; i++) {
|
||||
var id = v2ray_users_status[i].parentElement.parentElement.parentElement.id;
|
||||
id = id.substr(id.lastIndexOf("-") + 1);
|
||||
XHR.poll(1,'<%=dsp.build_url("admin/vpn/v2ray_server/users_status")%>', {
|
||||
index: i,
|
||||
id: id
|
||||
},
|
||||
function(x, result) {
|
||||
v2ray_users_status[result.index].setAttribute("style","font-weight:bold;");
|
||||
v2ray_users_status[result.index].setAttribute("color",result.status ? "green":"red");
|
||||
v2ray_users_status[result.index].innerHTML = (result.status ? '✓' : 'X');
|
||||
}
|
||||
);
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
@ -1,3 +0,0 @@
|
||||
<%+cbi/valueheader%>
|
||||
<font class="v2ray_users_status" hint="<%=self:cfgvalue(section)%>">--</font>
|
||||
<%+cbi/valuefooter%>
|
||||
@ -1,182 +0,0 @@
|
||||
<%
|
||||
local v2ray_version=luci.sys.exec("/usr/bin/v2ray/v2ray -version | awk '{print $2}' | sed -n 1P")
|
||||
local dsp = require "luci.dispatcher"
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var v2rayInfo;
|
||||
var tokenStr = '<%=token%>';
|
||||
var noUpdateText = '<%:已是最新版本%>';
|
||||
var updateSuccessText = '<%:更新成功.%>';
|
||||
var clickToUpdateText = '<%:点击更新%>';
|
||||
var inProgressText = '<%:正在更新...%>';
|
||||
var unexpectedErrorText = '<%:意外错误.%>';
|
||||
var updateInProgressNotice = '<%:正在更新,你确认要关闭吗?%>';
|
||||
|
||||
window.onload = function() {
|
||||
var v2rayCheckBtn = document.getElementById('_v2ray-check_btn');
|
||||
var v2rayDetailElm = document.getElementById('_v2ray-check_btn-detail');
|
||||
};
|
||||
|
||||
function addPageNotice_v2ray() {
|
||||
window.onbeforeunload = function(e) {
|
||||
e.returnValue = updateInProgressNotice;
|
||||
return updateInProgressNotice;
|
||||
};
|
||||
}
|
||||
|
||||
function removePageNotice_v2ray() {
|
||||
window.onbeforeunload = undefined;
|
||||
}
|
||||
|
||||
function onUpdateSuccess_v2ray(btn) {
|
||||
alert(updateSuccessText);
|
||||
|
||||
if(btn) {
|
||||
btn.value = updateSuccessText;
|
||||
btn.placeholder = updateSuccessText;
|
||||
btn.disabled = true;
|
||||
}
|
||||
|
||||
window.setTimeout(function() {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function onRequestError_v2ray(btn, errorMessage) {
|
||||
btn.disabled = false;
|
||||
btn.value = btn.placeholder;
|
||||
|
||||
if(errorMessage) {
|
||||
alert(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
function doAjaxGet(url, data, onResult) {
|
||||
new XHR().get(url, data, function(_, json) {
|
||||
var resultJson = json || {
|
||||
'code': 1,
|
||||
'error': unexpectedErrorText
|
||||
};
|
||||
|
||||
if(typeof onResult === 'function') {
|
||||
onResult(resultJson);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onBtnClick_v2ray(btn) {
|
||||
if(v2rayInfo === undefined) {
|
||||
checkUpdate_v2ray(btn);
|
||||
} else {
|
||||
doUpdate_v2ray(btn);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpdate_v2ray(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = inProgressText;
|
||||
|
||||
addPageNotice_v2ray();
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
|
||||
doAjaxGet('<%=dsp.build_url("admin/vpn/v2ray_server/check")%>', {
|
||||
token: tokenStr,
|
||||
arch: ''
|
||||
}, function(json) {
|
||||
removePageNotice_v2ray();
|
||||
|
||||
if(json.code) {
|
||||
v2rayInfo = undefined;
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
if(json.update) {
|
||||
v2rayInfo = json;
|
||||
btn.disabled = false;
|
||||
btn.value = clickToUpdateText;
|
||||
btn.placeholder = clickToUpdateText;
|
||||
|
||||
if(ckeckDetailElm) {
|
||||
var urlNode = '';
|
||||
if(json.version) {
|
||||
urlNode = '<em style="color:red;">最新版本号:' + json.version + '</em>';
|
||||
if(json.url && json.url.html) {
|
||||
urlNode = '<a href="' + json.url.html + '" target="_blank">' + urlNode + '</a>';
|
||||
}
|
||||
}
|
||||
ckeckDetailElm.innerHTML = urlNode;
|
||||
}
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.value = noUpdateText;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function doUpdate_v2ray(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:下载中...%>';
|
||||
|
||||
addPageNotice_v2ray();
|
||||
|
||||
var v2rayUpdateUrl = '<%=dsp.build_url("admin/vpn/v2ray_server/update")%>';
|
||||
// Download file
|
||||
doAjaxGet(v2rayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
url: v2rayInfo ? v2rayInfo.url.download : ''
|
||||
}, function(json) {
|
||||
if(json.code) {
|
||||
removePageNotice_v2ray();
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
btn.value = '<%:解压中...%>';
|
||||
|
||||
// Extract file
|
||||
doAjaxGet(v2rayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'extract',
|
||||
file: json.file,
|
||||
subfix: v2rayInfo ? v2rayInfo.type : ''
|
||||
}, function(json) {
|
||||
if(json.code) {
|
||||
removePageNotice_v2ray();
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
btn.value = '<%:移动中...%>';
|
||||
|
||||
// Move file to target dir
|
||||
doAjaxGet(v2rayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
task: 'move',
|
||||
file: json.file
|
||||
}, function(json) {
|
||||
removePageNotice_v2ray();
|
||||
if(json.code) {
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
onUpdateSuccess_v2ray(btn);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title">V2ray
|
||||
<%:Version%>
|
||||
</label>
|
||||
<div class="cbi-value-field">
|
||||
<div class="cbi-value-description">
|
||||
<span>【 <%=v2ray_version%>】</span>
|
||||
<input class="cbi-button cbi-input-apply" type="submit" id="_v2ray-check_btn" onclick="onBtnClick_v2ray(this);" value="<%:Manually update%>">
|
||||
<span id="_v2ray-check_btn-detail"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,137 +0,0 @@
|
||||
msgid "V2ray Server"
|
||||
msgstr "V2ray 服务器"
|
||||
|
||||
msgid "Global Settings"
|
||||
msgstr "全局设置"
|
||||
|
||||
msgid "Caddy path"
|
||||
msgstr "Caddy 路径"
|
||||
|
||||
msgid "if you want to run from memory, change the path, such as /tmp/caddy, Then save the application and update it manually."
|
||||
msgstr "如果你希望从内存中运行,请更改路径,例如/tmp/caddy,然后保存应用后,再手动更新。"
|
||||
|
||||
msgid "Server Config"
|
||||
msgstr "服务器配置"
|
||||
|
||||
msgid "Users Manager"
|
||||
msgstr "用户管理"
|
||||
|
||||
msgid "Remarks"
|
||||
msgstr "备注"
|
||||
|
||||
msgid "Bind Local"
|
||||
msgstr "本机监听"
|
||||
|
||||
msgid "When selected, it can only be accessed locally,It is recommended to turn on when using reverse proxies."
|
||||
msgstr "当勾选时,只能由本机访问此端口,当开启反向代理时建议勾选此项。"
|
||||
|
||||
msgid "Port"
|
||||
msgstr "端口"
|
||||
|
||||
msgid "Password"
|
||||
msgstr "密码"
|
||||
|
||||
msgid "Protocol"
|
||||
msgstr "协议"
|
||||
|
||||
msgid "Null"
|
||||
msgstr "无"
|
||||
|
||||
msgid "Alter ID"
|
||||
msgstr "额外ID(AlterID)"
|
||||
|
||||
msgid "User Level"
|
||||
msgstr "用户等级(Level)"
|
||||
|
||||
msgid "When OTA is enabled, V2Ray will reject connections that are not OTA enabled. This option is invalid when using AEAD encryption."
|
||||
msgstr "开启 OTA 后,V2Ray 会拒绝未启用 OTA 的连接。当使用 AEAD 加密时,该选项无效。"
|
||||
|
||||
msgid "Transport"
|
||||
msgstr "传输方式"
|
||||
|
||||
msgid "Camouflage Type"
|
||||
msgstr "伪装类型"
|
||||
|
||||
msgid "Camouflage Domain,you can not fill in"
|
||||
msgstr "伪装域名,也可以不填写"
|
||||
|
||||
msgid "Reverse Proxy"
|
||||
msgstr "反向代理"
|
||||
|
||||
msgid "Reverse Proxy Type"
|
||||
msgstr "反向代理类型"
|
||||
|
||||
msgid "can not has conflict"
|
||||
msgstr "请不要冲突"
|
||||
|
||||
msgid "Use HTTPS"
|
||||
msgstr "使用HTTPS"
|
||||
|
||||
msgid "TLS Settings"
|
||||
msgstr "TLS配置"
|
||||
|
||||
msgid "Nginx does not support HTTP/2 reverse proxies"
|
||||
msgstr "Nginx 不支持HTTP/2反向代理"
|
||||
|
||||
msgid "as:"
|
||||
msgstr "如:"
|
||||
|
||||
msgid "Public key absolute path"
|
||||
msgstr "公钥文件绝对路径"
|
||||
|
||||
msgid "Private key absolute path"
|
||||
msgstr "私钥文件绝对路径"
|
||||
|
||||
msgid "<br>none: default, no masquerade, data sent is packets with no characteristics.<br>srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br>utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br>wechat-video: packets disguised as WeChat video calls.<br>dtls: disguised as DTLS 1.2 packet.<br>wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)"
|
||||
msgstr "<br>none:默认值,不进行伪装,发送的数据是没有特征的数据包。<br>srtp:伪装成 SRTP 数据包,会被识别为视频通话数据(如 FaceTime)。<br>utp:伪装成 uTP 数据包,会被识别为 BT 下载数据。<br>wechat-video:伪装成微信视频通话的数据包。<br>dtls:伪装成 DTLS 1.2 数据包。<br>wireguard:伪装成 WireGuard 数据包。(并不是真正的 WireGuard 协议)"
|
||||
|
||||
msgid "Logs"
|
||||
msgstr "日志"
|
||||
|
||||
msgid "Clear logs"
|
||||
msgstr "清空日志"
|
||||
|
||||
msgid "Can't determine ARCH, or ARCH not supported."
|
||||
msgstr "无法确认ARCH架构,或是不支持。"
|
||||
|
||||
msgid "Get remote version info failed."
|
||||
msgstr "获取远程版本信息失败。"
|
||||
|
||||
msgid "New version found, but failed to get new version download url."
|
||||
msgstr "发现新版本,但未能获得新版本的下载地址。"
|
||||
|
||||
msgid "Download url is required."
|
||||
msgstr "请指定下载地址。"
|
||||
|
||||
msgid "File download failed or timed out: %s"
|
||||
msgstr "文件下载失败或超时:%s"
|
||||
|
||||
msgid "File path required."
|
||||
msgstr "请指定文件路径。"
|
||||
|
||||
msgid "Can't find client in file: %s"
|
||||
msgstr "无法在文件中找到客户端:%s"
|
||||
|
||||
msgid "Client file is required."
|
||||
msgstr "请指定客户端文件。"
|
||||
|
||||
msgid "The client file is not suitable for current device."
|
||||
msgstr "客户端文件不适合当前设备。"
|
||||
|
||||
msgid "Can't move new file to path: %s"
|
||||
msgstr "无法移动新文件到:%s"
|
||||
|
||||
msgid "Enabled"
|
||||
msgstr "启用"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Current Condition"
|
||||
msgstr "当前状态"
|
||||
|
||||
msgid "NOT RUNNING"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "RUNNING"
|
||||
msgstr "运行中"
|
||||
@ -1,45 +0,0 @@
|
||||
|
||||
config global
|
||||
option enable '0'
|
||||
|
||||
config user
|
||||
option enable '1'
|
||||
option remarks '备注222'
|
||||
option bind_local '0'
|
||||
option protocol 'vmess'
|
||||
list VMess_id 'fd00927a-b0c2-4629-aef7-d9ff15a9d722'
|
||||
option VMess_alterId '16'
|
||||
option VMess_level '1'
|
||||
option transport 'tcp'
|
||||
option tcp_guise 'none'
|
||||
option port '12366'
|
||||
|
||||
config user
|
||||
option enable '1'
|
||||
option remarks 'WebsocketDemo'
|
||||
option bind_local '0'
|
||||
option protocol 'vmess'
|
||||
option VMess_alterId '16'
|
||||
option VMess_level '1'
|
||||
list VMess_id 'fd00927a-b0c2-4629-aef7-d9ff15a9d722'
|
||||
option transport 'ws'
|
||||
option ws_path '/websocket'
|
||||
option tls_enable '1'
|
||||
option tls_certificateFile '/etc/config/ssl/fullchain.pem'
|
||||
option tls_keyFile '/etc/config/ssl/private.key'
|
||||
option port '30010'
|
||||
|
||||
config user
|
||||
option enable '1'
|
||||
option remarks 'H2Demo'
|
||||
option bind_local '0'
|
||||
option protocol 'vmess'
|
||||
option VMess_alterId '16'
|
||||
option VMess_level '1'
|
||||
list VMess_id 'fd00927a-b0c2-4629-aef7-d9ff15a9d722'
|
||||
option tls_enable '1'
|
||||
option tls_certificateFile '/etc/config/ssl/fullchain.pem'
|
||||
option tls_keyFile '/etc/config/ssl/private.key'
|
||||
option transport 'h2'
|
||||
option h2_path '/h2'
|
||||
option port '30011'
|
||||
@ -1,59 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2018-2020 Lienol <lawlienol@gmail.com>
|
||||
|
||||
START=99
|
||||
|
||||
CONFIG=v2ray_server
|
||||
CONFIG_PATH=/var/etc/$CONFIG
|
||||
LOG_PATH=/var/log/$CONFIG
|
||||
LOG_APP_FILE=$LOG_PATH/app.log
|
||||
|
||||
echolog() {
|
||||
echo -e "$(date "+%Y-%m-%d %H:%M:%S"): $1" >> $LOG_APP_FILE
|
||||
}
|
||||
|
||||
gen_v2ray_config_file() {
|
||||
config_get enable $1 enable
|
||||
[ "$enable" = "0" ] && return 0
|
||||
config_get remarks $1 remarks
|
||||
config_get port $1 port
|
||||
config_get transport $1 transport
|
||||
lua /usr/lib/lua/luci/model/cbi/v2ray_server/api/genv2rayconfig.lua $1 > $CONFIG_PATH/$1.json
|
||||
echolog "$remarks $port 生成并运行 V2ray 配置文件 - $CONFIG_PATH/$1.json"
|
||||
/usr/bin/v2ray/v2ray -config $CONFIG_PATH/$1.json >/dev/null 2>&1 &
|
||||
}
|
||||
|
||||
start_v2ray_server() {
|
||||
mkdir -p $CONFIG_PATH $LOG_PATH
|
||||
touch $LOG_APP_FILE
|
||||
caddy_file=$(uci get $CONFIG.@global[0].caddy_file)
|
||||
config_foreach gen_v2ray_config_file "user"
|
||||
fw3 reload >/dev/null 2>&1 &
|
||||
}
|
||||
|
||||
stop_v2ray_server() {
|
||||
fw3 reload >/dev/null 2>&1 &
|
||||
ps -w | grep "$CONFIG_PATH/" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
|
||||
rm -rf $CONFIG_PATH
|
||||
rm -rf $LOG_PATH
|
||||
}
|
||||
|
||||
start() {
|
||||
config_load $CONFIG
|
||||
enable=$(uci get $CONFIG.@global[0].enable)
|
||||
if [ "$enable" = "0" ];then
|
||||
stop_v2ray_server
|
||||
else
|
||||
start_v2ray_server
|
||||
fi
|
||||
}
|
||||
|
||||
stop() {
|
||||
stop_v2ray_server
|
||||
}
|
||||
|
||||
restart() {
|
||||
stop
|
||||
sleep 1
|
||||
start
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete firewall.v2ray_server
|
||||
set firewall.v2ray_server=include
|
||||
set firewall.v2ray_server.type=script
|
||||
set firewall.v2ray_server.path=/usr/share/v2ray_server/firewall.include
|
||||
set firewall.v2ray_server.reload=1
|
||||
EOF
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@v2ray_server[-1]
|
||||
add ucitrack v2ray_server
|
||||
set ucitrack.@v2ray_server[-1].init=v2ray_server
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
chmod a+x /usr/share/v2ray_server/* >/dev/null 2>&1
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
@ -1,29 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
. $IPKG_INSTROOT/lib/functions.sh
|
||||
. $IPKG_INSTROOT/lib/functions/service.sh
|
||||
|
||||
gen_user_iptables() {
|
||||
config_get enable $1 enable
|
||||
[ "$enable" = "0" ] && return 0
|
||||
config_get remarks $1 remarks
|
||||
config_get bind_local $1 bind_local
|
||||
config_get port $1 port
|
||||
dport=$port
|
||||
[ "$bind_local" != "1" ] && {
|
||||
iptables -A V2RAY-SERVER -p tcp --dport $dport -m comment --comment "$remarks" -j ACCEPT
|
||||
iptables -A V2RAY-SERVER -p udp --dport $dport -m comment --comment "$remarks" -j ACCEPT
|
||||
}
|
||||
}
|
||||
|
||||
iptables -F V2RAY-SERVER 2>/dev/null
|
||||
iptables -D INPUT -j V2RAY-SERVER 2>/dev/null
|
||||
iptables -X V2RAY-SERVER 2>/dev/null
|
||||
|
||||
enable=$(uci get v2ray_server.@global[0].enable)
|
||||
if [ $enable -eq 1 ]; then
|
||||
iptables -N V2RAY-SERVER
|
||||
iptables -I INPUT -j V2RAY-SERVER
|
||||
config_load v2ray_server
|
||||
config_foreach gen_user_iptables "user"
|
||||
fi
|
||||
Loading…
Reference in New Issue
Block a user