luci: add v2ray server luci

This commit is contained in:
coolsnowwolf 2019-05-12 23:36:11 +08:00
parent facb9642b3
commit 015810919d
14 changed files with 999 additions and 0 deletions

View File

@ -0,0 +1,18 @@
# Copyright (C) 2018-2019 Lienol
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for V2ray Server
LUCI_DEPENDS:=+libsodium +luci-lib-jsonc +v2ray
LUCI_PKGARCH:=all
PKG_VERSION:=1.0
PKG_RELEASE:=1
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,47 @@
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
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

View File

@ -0,0 +1,65 @@
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 v2ray = {
log = {
--error = "/var/log/v2ray.log",
loglevel = "warning"
},
-- 传入连接
inbound = {
port = tonumber(server.port),
protocol = server.protocol,
settings = {
clients = {
{
id = server.VMess_id,
alterId = tonumber(server.VMess_alterId),
level = tonumber(server.VMess_level)
}
}
},
-- 底层传输配置
streamSettings = {
network = server.transport,
security = (server.tls == '1') and "tls" or "none",
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,
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
}
},
-- 传出连接
outbound = {
protocol = "freedom"
},
-- 额外传出连接
outboundDetour = {
{
protocol = "blackhole",
tag = "blocked"
}
}
}
print(json.stringify(v2ray,1))

View File

@ -0,0 +1,321 @@
-- Copyright 2018 Lienol <lienol@qq.com>
-- Licensed to the public under the Apache License 2.0.
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"
module("luci.model.cbi.v2ray_server.api.v2ray", package.seeall)
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=10", "--tries=2" }
local curl = "/usr/bin/curl"
local command_timeout = 40
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 arch == "mips" then
if fs.access("/usr/lib/os-release") then
arch = sys.exec("grep 'LEDE_BOARD' /usr/lib/os-release | grep -oE 'ramips|ar71xx'")
elseif fs.access("/etc/openwrt_release") then
arch = sys.exec("grep 'DISTRIB_TARGET' /etc/openwrt_release | grep -oE 'ramips|ar71xx'")
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 == "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]")
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(curl.." -sL "..url)
if json_content == "" then
return { }
end
return jsonc.parse(json_content) or { }
end
function get_config_option(option, default)
return uci:get("v2ray", "general", option) or default
end
function get_current_log_file(type)
local log_folder = get_config_option("log_folder", "/var/log/v2ray")
return "%s/%s.%s.log" % { log_folder, type, "general" }
end
function is_running(client)
if client and client ~= "" then
local file_name = client:match(".*/([^/]+)$") or ""
if file_name ~= "" then
return sys.call("pidof %s >/dev/null" % file_name) == 0
end
end
return false
end
function get_v2ray_version()
return luci.sys.exec("/usr/bin/v2ray/v2ray -version | awk '{print $2}' | sed -n 1P")
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. Please select manually.")
}
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,
version = remote_version,
html_url = html_url,
type = file_tree .. sub_version,
error = i18n.translate("New version found, but failed to get new version download url.")
}
end
return {
code = 0,
update = needs_update,
version = remote_version,
url = {
html = html_url,
download = download_url
},
type = file_tree .. sub_version
}
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=sys.call("opkg list-installed | grep unzip > /dev/null")==0
if not isinstall_unzip then
sys.call("opkg update && opkg install unzip > /dev/null")
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 = "/usr/bin/v2ray"
sys.call("mkdir -p "..client_file)
local result = exec("/bin/mv", { "-f", file.."/v2ray", file.."/v2ctl", client_file }, nil, command_timeout) == 0
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

View File

@ -0,0 +1,110 @@
local i = "v2ray_server"
local d = require "luci.dispatcher"
local a,t,e
local header_type={
"none",
"srtp",
"utp",
"wechat-video",
"dtls",
"wireguard",
}
a=Map(i,"V2ray "..translate("Server Config"))
a.redirect=d.build_url("admin","vpn","v2ray_server")
t=a:section(NamedSection,arg[1],"user","")
t.addremove=false
t.dynamic=false
e=t:option(Flag, "enable", translate("Enable"))
e.default = "1"
e.rmempty = false
e=t:option(Value,"remarks",translate("Remarks"))
e.default=translate("Remarks")
e.rmempty=false
e=t:option(Value,"port",translate("Port"))
e.datatype="port"
e.rmempty=false
e=t:option(ListValue,"protocol",translate("Protocol"))
e:value("vmess",translate("Vmess"))
e=t:option(Value,"VMess_id",translate("ID"))
e.default = luci.sys.exec("cat /proc/sys/kernel/random/uuid")
e.rmempty=false
e:depends("protocol","vmess")
e=t:option(Value,"VMess_alterId",translate("Alter ID"))
e.default=16
e.rmempty=false
e:depends("protocol","vmess")
e=t:option(Value,"VMess_level",translate("User Level"))
e.default=1
e=t:option(ListValue,"transport",translate("Transport"))
e:value("tcp","TCP")
e:value("mkcp", "mKCP")
e:value("quic", "QUIC")
-- [[ TCP部分 ]]--
-- TCP伪装
e = t:option(ListValue, "tcp_guise", translate("Camouflage Type"))
e:depends("transport", "tcp")
e:value("none", "none")
e:value("http", "http")
-- HTTP域名
e = t:option(DynamicList, "tcp_guise_http_host", translate("HTTP Host"))
e:depends("tcp_guise", "http")
-- HTTP路径
e = t:option(DynamicList, "tcp_guise_http_path", translate("HTTP Path"))
e:depends("tcp_guise", "http")
-- [[ mKCP部分 ]]--
e=t:option(ListValue,"mkcp_guise",translate("Camouflage Type"))
for a,t in ipairs(header_type)do e:value(t)end
e:depends("transport","mkcp")
e=t:option(Value,"mkcp_mtu",translate("KCP MTU"))
e:depends("transport","mkcp")
e=t:option(Value,"mkcp_tti",translate("KCP TTI"))
e:depends("transport","mkcp")
e=t:option(Value,"mkcp_uplinkCapacity",translate("KCP uplinkCapacity"))
e:depends("transport","mkcp")
e=t:option(Value,"mkcp_downlinkCapacity",translate("KCP downlinkCapacity"))
e:depends("transport","mkcp")
e=t:option(Flag,"mkcp_congestion",translate("KCP Congestion"))
e:depends("transport","mkcp")
e=t:option(Value,"mkcp_readBufferSize",translate("KCP readBufferSize"))
e:depends("transport","mkcp")
e=t:option(Value,"mkcp_writeBufferSize",translate("KCP writeBufferSize"))
e:depends("transport","mkcp")
-- [[ QUIC部分 ]]--
e=t:option(ListValue,"quic_security",translate("Encrypt Method"))
e:value("none")
e:value("aes-128-gcm")
e:value("chacha20-poly1305")
e:depends("transport","quic")
e=t:option(Value,"quic_key",translate("Encrypt Method")..translate("Key"))
e:depends("transport","quic")
e=t:option(ListValue,"quic_guise",translate("Camouflage Type"))
for a,t in ipairs(header_type)do e:value(t)end
e:depends("transport","quic")
return a

View File

@ -0,0 +1,57 @@
local o = require "luci.dispatcher"
local fs = require "nixio.fs"
local sys = require "luci.sys"
local cursor = luci.model.uci.cursor()
local appname = "v2ray_server"
local a,t,e
a=Map(appname, translate("V2ray Server"))
t=a: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=a:section(TypedSection,"user",translate("Users Manager"))
t.anonymous=true
t.addremove=true
t.template="cbi/tblsection"
t.extedit=o.build_url("admin","vpn",appname,"config","%s")
function t.create(e,t)
local e=TypedSection.create(e,t)
luci.http.redirect(o.build_url("admin","vpn",appname,"config",e))
end
function t.remove(t,a)
t.map.proceed=true
t.map:del(a)
luci.http.redirect(o.build_url("admin","vpn",appname))
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=t:option(DummyValue,"VMess_id",translate("ID"))
e.width="35%"
a:append(Template("v2ray_server/users_list_status"))
return a

View File

@ -0,0 +1,28 @@
<%#
Copyright 2018 Lienol
Licensed to the public under the Apache License 2.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>

View File

@ -0,0 +1,3 @@
<%+cbi/valueheader%>
<font class="v2ray_users_status" hint="<%=self:cfgvalue(section)%>">--</font>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,188 @@
<%#
Copyright 2018 <lienol@qq.com>
Licensed to the public under the Apache License 2.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">
<img src="/luci-static/resources/cbi/help.gif">
<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>

View File

@ -0,0 +1,53 @@
msgid "V2ray Server"
msgstr "V2ray 服务器"
msgid "Global Settings"
msgstr "全局设置"
msgid "Server Config"
msgstr "服务器配置"
msgid "Users Manager"
msgstr "用户管理"
msgid "Remarks"
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 "Transport"
msgstr "传输方式"
msgid "Camouflage Type"
msgstr "伪装类型"
msgid "Enabled"
msgstr "启用"
msgid "Status"
msgstr "状态"
msgid "Current Condition"
msgstr "当前状态"
msgid "NOT RUNNING"
msgstr "未运行"
msgid "RUNNING"
msgstr "运行中"

View File

@ -0,0 +1,15 @@
config global
option enable '0'
config user
option enable '1'
option remarks '备注222'
option protocol 'vmess'
option 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'

View File

@ -0,0 +1,48 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2018-2019 Lienol <lawlienol@gmail.com>
START=99
CONFIG=v2ray_server
CONFIG_PATH=/var/etc/$CONFIG
gen_v2ray_config_file() {
config_get enable $1 enable
[ "$enable" = "0" ] && return 0
config_get remarks $1 remarks
config_get port $1 port
lua /usr/lib/lua/luci/model/cbi/v2ray_server/api/genv2rayconfig.lua $1 > $CONFIG_PATH/$1.json
/usr/bin/v2ray/v2ray -config $CONFIG_PATH/$1.json >/dev/null 2>&1 &
}
start_v2ray_server() {
config_foreach gen_v2ray_config_file "user"
fw3 reload
}
stop_v2ray_server() {
fw3 reload
ps -w | grep "$CONFIG_PATH/" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
}
start() {
config_load $CONFIG
enable=$(uci get $CONFIG.@global[0].enable)
if [ "$enable" = "0" ];then
stop_v2ray_server
else
mkdir -p $CONFIG_PATH
start_v2ray_server
fi
}
stop() {
stop_v2ray_server
rm -rf $CONFIG_PATH
}
restart() {
stop
sleep 1
start
}

View File

@ -0,0 +1,21 @@
#!/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

View File

@ -0,0 +1,25 @@
#!/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 port $1 port
iptables -A V2RAY-SERVER -p tcp --dport $port -m comment --comment "$remarks" -j ACCEPT
iptables -A V2RAY-SERVER -p udp --dport $port -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