mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-19 03:43:29 +00:00
luci-app-v2ray-server: bump to 13-1 version (#5894)
This commit is contained in:
parent
a5217b2901
commit
c06f6662d4
@ -1,18 +1,17 @@
|
||||
# Copyright (C) 2018-2019 Lienol
|
||||
# Copyright (C) 2018-2020 Lienol <lawlienol@gmail.com>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-v2ray-server
|
||||
LUCI_TITLE:=LuCI support for V2ray Server
|
||||
LUCI_DEPENDS:=+v2ray
|
||||
LUCI_DEPENDS:=+unzip
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_VERSION:=1.1
|
||||
PKG_RELEASE:=5
|
||||
PKG_VERSION:=13
|
||||
PKG_RELEASE:=1
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
|
||||
|
@ -1,25 +1,17 @@
|
||||
-- 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
|
||||
entry({"admin", "services", "v2ray_server"}, cbi("v2ray_server/index"), _("V2ray Server"), 3).dependent = true
|
||||
entry({"admin", "services", "v2ray_server", "config"}, cbi("v2ray_server/user")).leaf = true
|
||||
entry({"admin", "services", "v2ray_server", "users_status"}, call("users_status")).leaf = true
|
||||
entry({"admin", "services", "v2ray_server", "check"}, call("v2ray_check")).leaf = true
|
||||
entry({"admin", "services", "v2ray_server", "update"}, call("v2ray_update")).leaf = true
|
||||
entry({"admin", "services", "v2ray_server", "get_log"}, call("get_log")).leaf = true
|
||||
entry({"admin", "services", "v2ray_server", "clear_log"}, call("clear_log")).leaf = true
|
||||
end
|
||||
|
||||
local function http_write_json(content)
|
||||
@ -27,12 +19,18 @@ local function http_write_json(content)
|
||||
http.write_json(content or {code = 1})
|
||||
end
|
||||
|
||||
function v2ray_users_status()
|
||||
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
|
||||
|
||||
function 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
|
||||
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
|
||||
|
||||
@ -56,10 +54,3 @@ function v2ray_update()
|
||||
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
|
||||
|
||||
|
109
package/lean/luci-app-v2ray-server/luasrc/model/cbi/v2ray_server/api/app.lua
Executable file
109
package/lean/luci-app-v2ray-server/luasrc/model/cbi/v2ray_server/api/app.lua
Executable file
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local action = arg[1]
|
||||
local sys = require 'luci.sys'
|
||||
local jsonc = require "luci.jsonc"
|
||||
local ucic = require"luci.model.uci".cursor()
|
||||
|
||||
local CONFIG = "v2ray_server"
|
||||
local CONFIG_PATH = "/var/etc/" .. CONFIG
|
||||
local LOG_PATH = "/var/log/" .. CONFIG
|
||||
local LOG_APP_FILE = LOG_PATH .. "/app.log"
|
||||
local BIN_PATH = "/var/bin/"
|
||||
local BIN_PATH_FILE = BIN_PATH .. CONFIG
|
||||
|
||||
local function log(...)
|
||||
local f, err = io.open(LOG_APP_FILE, "a")
|
||||
if f and err == nil then
|
||||
local str = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ")
|
||||
f:write(str .. "\n")
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
local function cmd(cmd)
|
||||
sys.call(cmd)
|
||||
end
|
||||
|
||||
local function gen_include()
|
||||
cmd(string.format("echo '#!/bin/sh' > /var/etc/%s.include", CONFIG))
|
||||
local function extract_rules(a)
|
||||
local result = "*" .. a
|
||||
result = result .. "\n" .. sys.exec('iptables-save -t ' .. a .. ' | grep "V2RAY-SERVER" | sed -e "s/^-A \\(INPUT\\)/-I \\1 1/"')
|
||||
result = result .. "COMMIT"
|
||||
return result
|
||||
end
|
||||
local f, err = io.open("/var/etc/" .. CONFIG .. ".include", "a")
|
||||
if f and err == nil then
|
||||
f:write('iptables-save -c | grep -v "V2RAY-SERVER" | iptables-restore -c' .. "\n")
|
||||
f:write('iptables-restore -n <<-EOT' .. "\n")
|
||||
f:write(extract_rules("filter") .. "\n")
|
||||
f:write("EOT" .. "\n")
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
local function start()
|
||||
local enabled = tonumber(ucic:get(CONFIG, "@global[0]", "enable") or 0)
|
||||
if enabled == nil or enabled == 0 then
|
||||
return
|
||||
end
|
||||
cmd(string.format("mkdir -p %s %s", CONFIG_PATH, LOG_PATH))
|
||||
cmd(string.format("touch %s", LOG_APP_FILE))
|
||||
cmd("iptables -N V2RAY-SERVER")
|
||||
cmd("iptables -I INPUT -j V2RAY-SERVER")
|
||||
ucic:foreach(CONFIG, "user", function(user)
|
||||
local id = user[".name"]
|
||||
local enable = user.enable
|
||||
if enable and tonumber(enable) == 1 then
|
||||
local remarks = user.remarks
|
||||
local port = tonumber(user.port)
|
||||
if nixio.fs.access("/usr/bin/xray") and not nixio.fs.access(BIN_PATH_FILE) then
|
||||
cmd(string.format("mkdir -p %s", BIN_PATH))
|
||||
cmd(string.format("cp -a /usr/bin/xray %s", BIN_PATH_FILE))
|
||||
end
|
||||
local bin = BIN_PATH_FILE
|
||||
local config = {}
|
||||
local config_file = CONFIG_PATH .. "/" .. id .. ".json"
|
||||
|
||||
config = require("luci.model.cbi.v2ray_server.api.gen_config").gen_config(user)
|
||||
bin = bin .. " -config " .. config_file
|
||||
|
||||
if next(config) then
|
||||
local f, err = io.open(config_file, "w")
|
||||
if f and err == nil then
|
||||
f:write(jsonc.stringify(config, 1))
|
||||
f:close()
|
||||
end
|
||||
log(string.format("%s %s 生成配置文件并运行 - %s", remarks, port, config_file))
|
||||
end
|
||||
|
||||
if bin then
|
||||
cmd(bin .. ">/dev/null 2>&1 &")
|
||||
end
|
||||
|
||||
local bind_local = user.bind_local or 0
|
||||
if bind_local and tonumber(bind_local) ~= 1 then
|
||||
cmd(string.format('iptables -A V2RAY-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
|
||||
cmd(string.format('iptables -A V2RAY-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
|
||||
end
|
||||
end
|
||||
end)
|
||||
gen_include()
|
||||
end
|
||||
|
||||
local function stop()
|
||||
cmd(string.format("ps -w | grep -v 'grep' | grep '%s/' | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &", CONFIG_PATH))
|
||||
cmd("iptables -D INPUT -j V2RAY-SERVER 2>/dev/null")
|
||||
cmd("iptables -F V2RAY-SERVER 2>/dev/null")
|
||||
cmd("iptables -X V2RAY-SERVER 2>/dev/null")
|
||||
cmd(string.format("rm -rf %s %s /var/etc/%s.include", CONFIG_PATH, LOG_APP_FILE, CONFIG))
|
||||
end
|
||||
|
||||
if action then
|
||||
if action == "start" then
|
||||
start()
|
||||
elseif action == "stop" then
|
||||
stop()
|
||||
end
|
||||
end
|
@ -0,0 +1,184 @@
|
||||
module("luci.model.cbi.v2ray_server.api.gen_config", package.seeall)
|
||||
|
||||
function gen_config(user)
|
||||
local settings = nil
|
||||
local routing = nil
|
||||
local outbounds = {
|
||||
{protocol = "freedom", tag = "direct"}, {protocol = "blackhole", tag = "blocked"}
|
||||
}
|
||||
|
||||
if user.protocol == "vmess" or user.protocol == "vless" then
|
||||
if user.uuid then
|
||||
local clients = {}
|
||||
for i = 1, #user.uuid do
|
||||
clients[i] = {
|
||||
id = user.uuid[i],
|
||||
flow = (user.xtls and user.xtls == "1") and user.flow or nil,
|
||||
level = tonumber(user.level),
|
||||
alterId = tonumber(user.alter_id)
|
||||
}
|
||||
end
|
||||
settings = {
|
||||
clients = clients,
|
||||
decryption = user.decryption or "none"
|
||||
}
|
||||
end
|
||||
elseif user.protocol == "socks" then
|
||||
settings = {
|
||||
auth = (user.auth and user.auth == "1") and "password" or "noauth",
|
||||
accounts = (user.auth and user.auth == "1") and {
|
||||
{
|
||||
user = user.username,
|
||||
pass = user.password
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif user.protocol == "http" then
|
||||
settings = {
|
||||
allowTransparent = false,
|
||||
accounts = (user.auth and user.auth == "1") and {
|
||||
{
|
||||
user = user.username,
|
||||
pass = user.password
|
||||
}
|
||||
}
|
||||
}
|
||||
user.transport = "tcp"
|
||||
user.tcp_guise = "none"
|
||||
elseif user.protocol == "shadowsocks" then
|
||||
settings = {
|
||||
method = user.method,
|
||||
password = user.password,
|
||||
level = tonumber(user.level) or 1,
|
||||
network = user.ss_network or "TCP,UDP"
|
||||
}
|
||||
elseif user.protocol == "trojan" then
|
||||
if user.uuid then
|
||||
local clients = {}
|
||||
for i = 1, #user.uuid do
|
||||
clients[i] = {
|
||||
password = user.uuid[i],
|
||||
level = tonumber(user.level)
|
||||
}
|
||||
end
|
||||
settings = {
|
||||
clients = clients
|
||||
}
|
||||
end
|
||||
elseif user.protocol == "mtproto" then
|
||||
settings = {
|
||||
users = {
|
||||
{
|
||||
level = tonumber(user.level) or 1,
|
||||
secret = (user.password == nil) and "" or user.password
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
routing = {
|
||||
domainStrategy = "IPOnDemand",
|
||||
rules = {
|
||||
{
|
||||
type = "field",
|
||||
ip = {"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"},
|
||||
outboundTag = (user.accept_lan == nil or user.accept_lan == "0") and "blocked" or "direct"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local config = {
|
||||
log = {
|
||||
-- error = "/var/etc/v2ray_server/log/" .. user[".name"] .. ".log",
|
||||
loglevel = "warning"
|
||||
},
|
||||
-- 传入连接
|
||||
inbounds = {
|
||||
{
|
||||
listen = (user.bind_local == "1") and "127.0.0.1" or nil,
|
||||
port = tonumber(user.port),
|
||||
protocol = user.protocol,
|
||||
settings = settings,
|
||||
streamSettings = {
|
||||
network = user.transport,
|
||||
security = "none",
|
||||
xtlsSettings = (user.tls and user.tls == "1" and user.xtls and user.xtls == "1") and {
|
||||
--alpn = {"http/1.1"},
|
||||
disableSystemRoot = false,
|
||||
certificates = {
|
||||
{
|
||||
certificateFile = user.tls_certificateFile,
|
||||
keyFile = user.tls_keyFile
|
||||
}
|
||||
}
|
||||
} or nil,
|
||||
tlsSettings = (user.tls and user.tls == "1") and {
|
||||
disableSystemRoot = false,
|
||||
certificates = {
|
||||
{
|
||||
certificateFile = user.tls_certificateFile,
|
||||
keyFile = user.tls_keyFile
|
||||
}
|
||||
}
|
||||
} or nil,
|
||||
tcpSettings = (user.transport == "tcp") and {
|
||||
header = {
|
||||
type = user.tcp_guise,
|
||||
request = (user.tcp_guise == "http") and {
|
||||
path = {user.tcp_guise_http_path} or {"/"},
|
||||
headers = {
|
||||
Host = {user.tcp_guise_http_host} or {}
|
||||
}
|
||||
} or nil
|
||||
}
|
||||
} or nil,
|
||||
kcpSettings = (user.transport == "mkcp") and {
|
||||
mtu = tonumber(user.mkcp_mtu),
|
||||
tti = tonumber(user.mkcp_tti),
|
||||
uplinkCapacity = tonumber(user.mkcp_uplinkCapacity),
|
||||
downlinkCapacity = tonumber(user.mkcp_downlinkCapacity),
|
||||
congestion = (user.mkcp_congestion == "1") and true or false,
|
||||
readBufferSize = tonumber(user.mkcp_readBufferSize),
|
||||
writeBufferSize = tonumber(user.mkcp_writeBufferSize),
|
||||
seed = (user.mkcp_seed and user.mkcp_seed ~= "") and user.mkcp_seed or nil,
|
||||
header = {type = user.mkcp_guise}
|
||||
} or nil,
|
||||
wsSettings = (user.transport == "ws") and {
|
||||
acceptProxyProtocol = false,
|
||||
headers = (user.ws_host) and {Host = user.ws_host} or nil,
|
||||
path = user.ws_path
|
||||
} or nil,
|
||||
httpSettings = (user.transport == "h2") and {
|
||||
path = user.h2_path, host = user.h2_host
|
||||
} or nil,
|
||||
dsSettings = (user.transport == "ds") and {
|
||||
path = user.ds_path
|
||||
} or nil,
|
||||
quicSettings = (user.transport == "quic") and {
|
||||
security = user.quic_security,
|
||||
key = user.quic_key,
|
||||
header = {type = user.quic_guise}
|
||||
} or nil
|
||||
}
|
||||
}
|
||||
},
|
||||
-- 传出连接
|
||||
outbounds = outbounds,
|
||||
routing = routing
|
||||
}
|
||||
|
||||
if user.tls and user.tls == "1" then
|
||||
config.inbounds[1].streamSettings.security = "tls"
|
||||
if user.xtls and user.xtls == "1" then
|
||||
config.inbounds[1].streamSettings.security = "xtls"
|
||||
config.inbounds[1].streamSettings.tlsSettings = nil
|
||||
end
|
||||
end
|
||||
|
||||
if user.transport == "mkcp" or user.transport == "quic" then
|
||||
config.inbounds[1].streamSettings.security = "none"
|
||||
config.inbounds[1].streamSettings.tlsSettings = nil
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
@ -1,135 +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
|
||||
local routing = 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 = (server.socks_username == nil and server.socks_password == nil) and
|
||||
"noauth" or "password",
|
||||
accounts = {
|
||||
{
|
||||
user = (server.socks_username == nil) and "" or
|
||||
server.socks_username,
|
||||
pass = (server.socks_password == nil) and "" or
|
||||
server.socks_password
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif server.protocol == "http" then
|
||||
settings = {
|
||||
allowTransparent = false,
|
||||
accounts = {
|
||||
{
|
||||
user = (server.http_username == nil) and "" or
|
||||
server.http_username,
|
||||
pass = (server.http_password == nil) and "" or
|
||||
server.http_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
|
||||
|
||||
if server.accept_lan == nil or server.accept_lan == "0" then
|
||||
routing = {
|
||||
domainStrategy = "IPOnDemand",
|
||||
rules = {
|
||||
{
|
||||
type = "field",
|
||||
ip = {"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"},
|
||||
outboundTag = "blocked"
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
tcpSettings = (server.transport == "tcp") and {
|
||||
header = {
|
||||
type = server.tcp_guise,
|
||||
request = {
|
||||
path = server.tcp_guise_http_path,
|
||||
headers = {
|
||||
Host = server.tcp_guise_http_host
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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"}},
|
||||
routing = routing
|
||||
}
|
||||
print(json.stringify(v2ray, 1))
|
58
package/lean/luci-app-v2ray-server/luasrc/model/cbi/v2ray_server/api/v2ray.lua
Normal file → Executable file
58
package/lean/luci-app-v2ray-server/luasrc/model/cbi/v2ray_server/api/v2ray.lua
Normal file → Executable file
@ -7,12 +7,9 @@ local i18n = require "luci.i18n"
|
||||
local ipkg = require "luci.model.ipkg"
|
||||
|
||||
local appname = "v2ray_server"
|
||||
local v2ray_api =
|
||||
"https://api.github.com/repos/v2fly/v2ray-core/releases/latest"
|
||||
local v2ray_api ="https://api.github.com/repos/XTLS/Xray-core/releases/latest"
|
||||
local wget = "/usr/bin/wget"
|
||||
local wget_args = {
|
||||
"--no-check-certificate", "--quiet", "--timeout=100", "--tries=3"
|
||||
}
|
||||
local wget_args = {"--no-check-certificate", "--quiet", "--timeout=100", "--tries=3"}
|
||||
local command_timeout = 300
|
||||
|
||||
local LEDE_BOARD = nil
|
||||
@ -95,12 +92,10 @@ 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}'`")
|
||||
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}'`")
|
||||
DISTRIB_TARGET = sys.exec("echo -n `grep 'DISTRIB_TARGET' /etc/openwrt_release | awk -F '[\\042\\047]' '{print $2}'`")
|
||||
end
|
||||
|
||||
if arch == "mips" then
|
||||
@ -108,15 +103,13 @@ local function auto_get_arch()
|
||||
if string.match(LEDE_BOARD, "ramips") == "ramips" then
|
||||
arch = "ramips"
|
||||
else
|
||||
arch = sys.exec("echo '" .. LEDE_BOARD ..
|
||||
"' | grep -oE 'ramips|ar71xx'")
|
||||
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'")
|
||||
arch = sys.exec("echo '" .. DISTRIB_TARGET .. "' | grep -oE 'ramips|ar71xx'")
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -162,23 +155,19 @@ local function get_api_json(url)
|
||||
-- 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)
|
||||
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_file_path() return "/usr/bin" 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" ..
|
||||
"`")
|
||||
if fs.access(get_v2ray_file_path() .. "/xray") then
|
||||
return luci.sys.exec("echo -n `" .. get_v2ray_file_path() .. "/xray -version | awk '{print $2}' | sed -n 1P" .. "`")
|
||||
end
|
||||
end
|
||||
return ""
|
||||
@ -192,8 +181,7 @@ function to_check(arch)
|
||||
if file_tree == "" then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate(
|
||||
"Can't determine ARCH, or ARCH not supported.")
|
||||
error = i18n.translate("Can't determine ARCH, or ARCH not supported.")
|
||||
}
|
||||
end
|
||||
|
||||
@ -207,8 +195,7 @@ function to_check(arch)
|
||||
end
|
||||
|
||||
local remote_version = json.tag_name:match("[^v]+")
|
||||
local needs_update = compare_versions(get_v2ray_version(), "<",
|
||||
remote_version)
|
||||
local needs_update = compare_versions(get_v2ray_version(), "<",remote_version)
|
||||
local html_url, download_url
|
||||
|
||||
if needs_update then
|
||||
@ -227,8 +214,7 @@ function to_check(arch)
|
||||
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.")
|
||||
error = i18n.translate("New version found, but failed to get new version download url.")
|
||||
}
|
||||
end
|
||||
|
||||
@ -250,8 +236,7 @@ function to_download(url)
|
||||
|
||||
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
|
||||
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})
|
||||
@ -302,25 +287,16 @@ function to_move(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
|
||||
result = exec("/bin/mv", {"-f", file .. "/xray", 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)
|
||||
error = i18n.translatef("Can't move new file to path: %s", client_file)
|
||||
}
|
||||
end
|
||||
|
||||
exec("/bin/chmod", {"-R", "755", client_file})
|
||||
exec("/bin/chmod", {"-R", "755", client_file .. "/xray"})
|
||||
|
||||
sys.call("/bin/rm -rf /tmp/v2ray_extract.*")
|
||||
|
||||
|
@ -1,238 +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("http",translate("Http"))
|
||||
protocol:value("shadowsocks", translate("Shadowsocks"))
|
||||
|
||||
socks_username = t:option(Value, "socks_username", translate("User name"))
|
||||
socks_username.rmempty = true
|
||||
socks_username:depends("protocol", "socks")
|
||||
|
||||
socks_password = t:option(Value, "socks_password", translate("Password"))
|
||||
socks_password.rmempty = true
|
||||
socks_password.password = true
|
||||
socks_password:depends("protocol", "socks")
|
||||
|
||||
http_username = t:option(Value, "http_username", translate("User name"))
|
||||
http_username.rmempty = true
|
||||
http_username:depends("protocol", "http")
|
||||
|
||||
http_password = t:option(Value, "http_password", translate("Password"))
|
||||
http_password.rmempty = true
|
||||
http_password.password = true
|
||||
http_password:depends("protocol", "http")
|
||||
|
||||
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)
|
||||
|
||||
accept_lan = t:option(Flag, "accept_lan", translate("Accept LAN Access"),
|
||||
translate(
|
||||
"When selected, it can accessed lan , this will not be safe!"))
|
||||
accept_lan.default = "0"
|
||||
accept_lan.rmempty = false
|
||||
|
||||
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,7 +1,4 @@
|
||||
local i = require "luci.dispatcher"
|
||||
local e = require "nixio.fs"
|
||||
local e = require "luci.sys"
|
||||
local e = luci.model.uci.cursor()
|
||||
local ds = require "luci.dispatcher"
|
||||
local o = "v2ray_server"
|
||||
|
||||
m = Map(o, translate("V2ray Server"))
|
||||
@ -17,88 +14,41 @@ 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")
|
||||
t.extedit = ds.build_url("admin", "services", 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))
|
||||
local uuid = luci.sys.exec("echo -n $(cat /proc/sys/kernel/random/uuid)") or ""
|
||||
uuid = string.gsub(uuid, "-", "")
|
||||
local e = TypedSection.create(t, uuid)
|
||||
luci.http.redirect(ds.build_url("admin", "services", o, "config", uuid))
|
||||
end
|
||||
function t.remove(t, a)
|
||||
t.map.proceed = true
|
||||
t.map:del(a)
|
||||
luci.http.redirect(i.build_url("admin", "vpn", o))
|
||||
luci.http.redirect(ds.build_url("admin", "services", 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.rawhtml = true
|
||||
e.cfgvalue = function(t, n)
|
||||
return string.format('<font class="users_status" hint="%s">%s</font>', n, translate("Collecting data..."))
|
||||
end
|
||||
|
||||
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"
|
||||
elseif protocol == "http" then
|
||||
e = "http_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"))
|
||||
|
||||
|
@ -0,0 +1,315 @@
|
||||
local d = require "luci.dispatcher"
|
||||
local appname = "v2ray_server"
|
||||
|
||||
local v_ss_encrypt_method_list = {
|
||||
"aes-128-cfb", "aes-256-cfb", "aes-128-gcm", "aes-256-gcm", "chacha20", "chacha20-ietf", "chacha20-poly1305", "chacha20-ietf-poly1305"
|
||||
}
|
||||
|
||||
local header_type_list = {
|
||||
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard"
|
||||
}
|
||||
|
||||
m = Map(appname, translate("Server Config"))
|
||||
m.redirect = d.build_url("admin", "services", appname)
|
||||
|
||||
s = m:section(NamedSection, arg[1], "user", "")
|
||||
s.addremove = false
|
||||
s.dynamic = false
|
||||
|
||||
enable = s:option(Flag, "enable", translate("Enable"))
|
||||
enable.default = "1"
|
||||
enable.rmempty = false
|
||||
|
||||
remarks = s:option(Value, "remarks", translate("Remarks"))
|
||||
remarks.default = translate("Remarks")
|
||||
remarks.rmempty = false
|
||||
|
||||
protocol = s:option(ListValue, "protocol", translate("Protocol"))
|
||||
protocol:value("vmess", "Vmess")
|
||||
protocol:value("vless", "VLESS")
|
||||
protocol:value("http", "HTTP")
|
||||
protocol:value("socks", "Socks")
|
||||
protocol:value("shadowsocks", "Shadowsocks")
|
||||
protocol:value("trojan", "Trojan")
|
||||
protocol:value("mtproto", "MTProto")
|
||||
|
||||
port = s:option(Value, "port", translate("Port"))
|
||||
port.datatype = "port"
|
||||
port.rmempty = false
|
||||
|
||||
auth = s:option(Flag, "auth", translate("Auth"))
|
||||
auth.validate = function(self, value, t)
|
||||
if value and value == "1" then
|
||||
local user_v = username:formvalue(t) or ""
|
||||
local pass_v = password:formvalue(t) or ""
|
||||
if user_v == "" or pass_v == "" then
|
||||
return nil, translate("Username and Password must be used together!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
auth:depends({ protocol = "socks" })
|
||||
auth:depends({ protocol = "http" })
|
||||
|
||||
username = s:option(Value, "username", translate("Username"))
|
||||
username:depends("auth", "1")
|
||||
|
||||
password = s:option(Value, "password", translate("Password"))
|
||||
password.password = true
|
||||
password:depends("auth", "1")
|
||||
password:depends({ protocol = "shadowsocks" })
|
||||
|
||||
mtproto_password = s:option(Value, "mtproto_password", translate("Password"), translate("The MTProto protocol must be 32 characters and can only contain characters from 0 to 9 and a to f."))
|
||||
mtproto_password:depends({ protocol = "mtproto" })
|
||||
mtproto_password.default = arg[1]
|
||||
function mtproto_password.cfgvalue(self, section)
|
||||
return m:get(section, "password")
|
||||
end
|
||||
function mtproto_password.write(self, section, value)
|
||||
m:set(section, "password", value)
|
||||
end
|
||||
|
||||
decryption = s:option(Value, "decryption", translate("Encrypt Method"))
|
||||
decryption.default = "none"
|
||||
decryption:depends({ protocol = "vless" })
|
||||
|
||||
v_ss_encrypt_method = s:option(ListValue, "v_ss_encrypt_method", translate("Encrypt Method"))
|
||||
for a, t in ipairs(v_ss_encrypt_method_list) do v_ss_encrypt_method:value(t) end
|
||||
v_ss_encrypt_method:depends({ protocol = "shadowsocks" })
|
||||
function v_ss_encrypt_method.cfgvalue(self, section)
|
||||
return m:get(section, "method")
|
||||
end
|
||||
function v_ss_encrypt_method.write(self, section, value)
|
||||
m:set(section, "method", value)
|
||||
end
|
||||
|
||||
ss_network = s: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" })
|
||||
|
||||
uuid = s:option(DynamicList, "uuid", translate("ID") .. "/" .. translate("Password"))
|
||||
for i = 1, 3 do
|
||||
uuid:value(luci.sys.exec("echo -n $(cat /proc/sys/kernel/random/uuid)"))
|
||||
end
|
||||
uuid:depends({ protocol = "vmess" })
|
||||
uuid:depends({ protocol = "vless" })
|
||||
uuid:depends({ protocol = "trojan" })
|
||||
|
||||
alter_id = s:option(Value, "alter_id", translate("Alter ID"))
|
||||
alter_id.default = 16
|
||||
alter_id:depends({ protocol = "vmess" })
|
||||
|
||||
level = s:option(Value, "level", translate("User Level"))
|
||||
level.default = 1
|
||||
level:depends({ protocol = "vmess" })
|
||||
level:depends({ protocol = "vless" })
|
||||
level:depends({ protocol = "shadowsocks" })
|
||||
level:depends({ protocol = "trojan" })
|
||||
level:depends({ protocol = "mtproto" })
|
||||
|
||||
tls = s:option(Flag, "tls", translate("TLS"))
|
||||
tls.default = 0
|
||||
tls.validate = function(self, value, t)
|
||||
if value then
|
||||
if value == "1" then
|
||||
local ca = tls_certificateFile:formvalue(t) or ""
|
||||
local key = tls_keyFile:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Public key and Private key path can not be empty!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
end
|
||||
tls:depends({ protocol = "vmess" })
|
||||
tls:depends({ protocol = "vless" })
|
||||
tls:depends({ protocol = "socks" })
|
||||
tls:depends({ protocol = "shadowsocks" })
|
||||
|
||||
xtls = s:option(Flag, "xtls", translate("XTLS"))
|
||||
xtls.default = 0
|
||||
xtls:depends({ protocol = "vless", tls = "1" })
|
||||
|
||||
flow = s:option(Value, "flow", translate("flow"))
|
||||
flow.default = "xtls-rprx-direct"
|
||||
flow:value("xtls-rprx-origin")
|
||||
flow:value("xtls-rprx-origin-udp443")
|
||||
flow:value("xtls-rprx-direct")
|
||||
flow:value("xtls-rprx-direct-udp443")
|
||||
flow:value("xtls-rprx-splice")
|
||||
flow:value("xtls-rprx-splice-udp443")
|
||||
flow:depends("xtls", "1")
|
||||
|
||||
-- [[ TLS部分 ]] --
|
||||
|
||||
tls_serverName = s:option(Value, "tls_serverName", translate("Domain"))
|
||||
tls_serverName:depends("tls", "1")
|
||||
|
||||
tls_certificateFile = s:option(Value, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
tls_certificateFile.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
tls_certificateFile:depends("tls", "1")
|
||||
|
||||
tls_keyFile = s:option(Value, "tls_keyFile", translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
|
||||
tls_keyFile.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not nixio.fs.access(value) then
|
||||
return nil, translate("Can't find this file!")
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
tls_keyFile:depends("tls", "1")
|
||||
|
||||
transport = s:option(ListValue, "transport", translate("Transport"))
|
||||
transport:value("tcp", "TCP")
|
||||
transport:value("mkcp", "mKCP")
|
||||
transport:value("ws", "WebSocket")
|
||||
transport:value("h2", "HTTP/2")
|
||||
transport:value("ds", "DomainSocket")
|
||||
transport:value("quic", "QUIC")
|
||||
transport:depends({ protocol = "vmess" })
|
||||
transport:depends({ protocol = "vless" })
|
||||
transport:depends({ protocol = "socks" })
|
||||
transport:depends({ protocol = "shadowsocks" })
|
||||
transport:depends({ protocol = "trojan" })
|
||||
|
||||
-- [[ WebSocket部分 ]]--
|
||||
|
||||
ws_host = s:option(Value, "ws_host", translate("WebSocket Host"))
|
||||
ws_host:depends("transport", "ws")
|
||||
ws_host:depends("ss_transport", "ws")
|
||||
ws_host:depends("trojan_transport", "h2+ws")
|
||||
ws_host:depends("trojan_transport", "ws")
|
||||
|
||||
ws_path = s:option(Value, "ws_path", translate("WebSocket Path"))
|
||||
ws_path:depends("transport", "ws")
|
||||
ws_path:depends("ss_transport", "ws")
|
||||
ws_path:depends("trojan_transport", "h2+ws")
|
||||
ws_path:depends("trojan_transport", "ws")
|
||||
|
||||
-- [[ HTTP/2部分 ]]--
|
||||
|
||||
h2_host = s:option(Value, "h2_host", translate("HTTP/2 Host"))
|
||||
h2_host:depends("transport", "h2")
|
||||
h2_host:depends("ss_transport", "h2")
|
||||
h2_host:depends("trojan_transport", "h2+ws")
|
||||
h2_host:depends("trojan_transport", "h2")
|
||||
|
||||
h2_path = s:option(Value, "h2_path", translate("HTTP/2 Path"))
|
||||
h2_path:depends("transport", "h2")
|
||||
h2_path:depends("ss_transport", "h2")
|
||||
h2_path:depends("trojan_transport", "h2+ws")
|
||||
h2_path:depends("trojan_transport", "h2")
|
||||
|
||||
-- [[ TCP部分 ]]--
|
||||
|
||||
-- TCP伪装
|
||||
tcp_guise = s:option(ListValue, "tcp_guise", translate("Camouflage Type"))
|
||||
tcp_guise:value("none", "none")
|
||||
tcp_guise:value("http", "http")
|
||||
tcp_guise:depends("transport", "tcp")
|
||||
|
||||
-- HTTP域名
|
||||
tcp_guise_http_host = s:option(DynamicList, "tcp_guise_http_host", translate("HTTP Host"))
|
||||
tcp_guise_http_host:depends("tcp_guise", "http")
|
||||
|
||||
-- HTTP路径
|
||||
tcp_guise_http_path = s:option(DynamicList, "tcp_guise_http_path", translate("HTTP Path"))
|
||||
tcp_guise_http_path:depends("tcp_guise", "http")
|
||||
|
||||
-- [[ mKCP部分 ]]--
|
||||
|
||||
mkcp_guise = s: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_list) do mkcp_guise:value(t) end
|
||||
mkcp_guise:depends("transport", "mkcp")
|
||||
|
||||
mkcp_mtu = s:option(Value, "mkcp_mtu", translate("KCP MTU"))
|
||||
mkcp_mtu.default = "1350"
|
||||
mkcp_mtu:depends("transport", "mkcp")
|
||||
|
||||
mkcp_tti = s:option(Value, "mkcp_tti", translate("KCP TTI"))
|
||||
mkcp_tti.default = "20"
|
||||
mkcp_tti:depends("transport", "mkcp")
|
||||
|
||||
mkcp_uplinkCapacity = s:option(Value, "mkcp_uplinkCapacity", translate("KCP uplinkCapacity"))
|
||||
mkcp_uplinkCapacity.default = "5"
|
||||
mkcp_uplinkCapacity:depends("transport", "mkcp")
|
||||
|
||||
mkcp_downlinkCapacity = s:option(Value, "mkcp_downlinkCapacity", translate("KCP downlinkCapacity"))
|
||||
mkcp_downlinkCapacity.default = "20"
|
||||
mkcp_downlinkCapacity:depends("transport", "mkcp")
|
||||
|
||||
mkcp_congestion = s:option(Flag, "mkcp_congestion", translate("KCP Congestion"))
|
||||
mkcp_congestion:depends("transport", "mkcp")
|
||||
|
||||
mkcp_readBufferSize = s:option(Value, "mkcp_readBufferSize", translate("KCP readBufferSize"))
|
||||
mkcp_readBufferSize.default = "1"
|
||||
mkcp_readBufferSize:depends("transport", "mkcp")
|
||||
|
||||
mkcp_writeBufferSize = s:option(Value, "mkcp_writeBufferSize", translate("KCP writeBufferSize"))
|
||||
mkcp_writeBufferSize.default = "1"
|
||||
mkcp_writeBufferSize:depends("transport", "mkcp")
|
||||
|
||||
mkcp_seed = s:option(Value, "mkcp_seed", translate("KCP Seed"))
|
||||
mkcp_seed:depends("transport", "mkcp")
|
||||
|
||||
-- [[ DomainSocket部分 ]]--
|
||||
|
||||
ds_path = s:option(Value, "ds_path", "Path", translate("A legal file path. This file must not exist before running V2Ray."))
|
||||
ds_path:depends("transport", "ds")
|
||||
|
||||
-- [[ QUIC部分 ]]--
|
||||
quic_security = s: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 = s:option(Value, "quic_key", translate("Encrypt Method") .. translate("Key"))
|
||||
quic_key:depends("transport", "quic")
|
||||
|
||||
quic_guise = s:option(ListValue, "quic_guise", translate("Camouflage Type"))
|
||||
for a, t in ipairs(header_type_list) do quic_guise:value(t) end
|
||||
quic_guise:depends("transport", "quic")
|
||||
|
||||
-- [[ VLESS Fallback部分 ]]--
|
||||
--[[
|
||||
fallback = s:option(Flag, "fallback", translate("Fallback"))
|
||||
fallback:depends({ protocol = "vless", transport = "tcp", tls = "1" })
|
||||
|
||||
fallback_alpn = s:option(Value, "fallback_alpn", "Fallback alpn")
|
||||
fallback_alpn:depends("fallback", "1")
|
||||
|
||||
fallback_path = s:option(Value, "fallback_path", "Fallback path")
|
||||
fallback_path:depends("fallback", "1")
|
||||
|
||||
fallback_dest = s:option(Value, "fallback_dest", "Fallback dest")
|
||||
fallback_dest:depends("fallback", "1")
|
||||
|
||||
fallback_xver = s:option(Value, "fallback_xver", "Fallback xver")
|
||||
fallback_xver.default = 0
|
||||
fallback_xver:depends("fallback", "1")
|
||||
]]--
|
||||
|
||||
bind_local = s: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"
|
||||
|
||||
accept_lan = s:option(Flag, "accept_lan", translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
|
||||
accept_lan.default = "0"
|
||||
accept_lan.rmempty = false
|
||||
|
||||
return m
|
@ -1,7 +1,7 @@
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
function clear_log(btn) {
|
||||
XHR.get('<%=url([[admin]], [[vpn]], [[v2ray_server]], [[clear_log]])%>', null,
|
||||
XHR.get('<%=url([[admin]], [[services]], [[v2ray_server]], [[clear_log]])%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
var log_textarea = document.getElementById('log_textarea');
|
||||
@ -11,7 +11,7 @@
|
||||
}
|
||||
);
|
||||
}
|
||||
XHR.poll(3, '<%=url([[admin]], [[vpn]], [[v2ray_server]], [[get_log]])%>', null,
|
||||
XHR.poll(3, '<%=url([[admin]], [[services]], [[v2ray_server]], [[get_log]])%>', null,
|
||||
function(x, data) {
|
||||
if(x && x.status == 200) {
|
||||
var log_textarea = document.getElementById('log_textarea');
|
||||
|
@ -1,21 +1,17 @@
|
||||
<%
|
||||
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;
|
||||
var users_status = document.getElementsByClassName('users_status');
|
||||
for(var i = 0; i < users_status.length; i++) {
|
||||
var id = 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")%>', {
|
||||
XHR.poll(1, '<%=url([[admin]], [[services]], [[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');
|
||||
users_status[result.index].setAttribute("style","font-weight:bold;");
|
||||
users_status[result.index].setAttribute("color",result.status ? "green":"red");
|
||||
users_status[result.index].innerHTML = (result.status ? '✓' : 'X');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
<%+cbi/valueheader%>
|
||||
<font class="v2ray_users_status" hint="<%=self:cfgvalue(section)%>">--</font>
|
||||
<%+cbi/valuefooter%>
|
@ -1,18 +1,20 @@
|
||||
<%
|
||||
local v2ray_version=luci.sys.exec("[ -f '/usr/bin/v2ray/v2ray' ] && /usr/bin/v2ray/v2ray -version | awk '{print $2}' | sed -n 1P")
|
||||
local dsp = require "luci.dispatcher"
|
||||
local v2ray_version=luci.sys.exec("/usr/bin/xray -version | awk '{print $2}' | sed -n 1P")
|
||||
-%>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var v2rayInfo;
|
||||
var tokenStr = '<%=token%>';
|
||||
var noUpdateText = '<%:已是最新版本%>';
|
||||
var updateSuccessText = '<%:更新成功.%>';
|
||||
var clickToUpdateText = '<%:点击更新%>';
|
||||
var inProgressText = '<%:正在更新...%>';
|
||||
var unexpectedErrorText = '<%:意外错误.%>';
|
||||
var updateInProgressNotice = '<%:正在更新,你确认要关闭吗?%>';
|
||||
var noUpdateText = '<%:It is the latest version%>';
|
||||
var updateSuccessText = '<%:Update successful%>';
|
||||
var clickToUpdateText = '<%:Click to update%>';
|
||||
var inProgressText = '<%:Updating...%>';
|
||||
var unexpectedErrorText = '<%:Unexpected error%>';
|
||||
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
|
||||
var downloadingText = '<%:Downloading...%>';
|
||||
var decompressioningText = '<%:Unpacking...%>';
|
||||
var movingText = '<%:Moving...%>';
|
||||
|
||||
window.onload = function() {
|
||||
var v2rayCheckBtn = document.getElementById('_v2ray-check_btn');
|
||||
@ -82,7 +84,7 @@ local dsp = require "luci.dispatcher"
|
||||
|
||||
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
||||
|
||||
doAjaxGet('<%=dsp.build_url("admin/vpn/v2ray_server/check")%>', {
|
||||
doAjaxGet('<%=url([[admin]], [[services]], [[v2ray_server]], [[check]])%>', {
|
||||
token: tokenStr,
|
||||
arch: ''
|
||||
}, function(json) {
|
||||
@ -118,11 +120,11 @@ local dsp = require "luci.dispatcher"
|
||||
|
||||
function doUpdate_v2ray(btn) {
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:下载中...%>';
|
||||
btn.value = downloadingText;
|
||||
|
||||
addPageNotice_v2ray();
|
||||
|
||||
var v2rayUpdateUrl = '<%=dsp.build_url("admin/vpn/v2ray_server/update")%>';
|
||||
var v2rayUpdateUrl = '<%=url([[admin]], [[services]], [[v2ray_server]], [[update]])%>';
|
||||
// Download file
|
||||
doAjaxGet(v2rayUpdateUrl, {
|
||||
token: tokenStr,
|
||||
@ -132,7 +134,7 @@ local dsp = require "luci.dispatcher"
|
||||
removePageNotice_v2ray();
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
btn.value = '<%:解压中...%>';
|
||||
btn.value = decompressioningText;
|
||||
|
||||
// Extract file
|
||||
doAjaxGet(v2rayUpdateUrl, {
|
||||
@ -145,7 +147,7 @@ local dsp = require "luci.dispatcher"
|
||||
removePageNotice_v2ray();
|
||||
onRequestError_v2ray(btn, json.error);
|
||||
} else {
|
||||
btn.value = '<%:移动中...%>';
|
||||
btn.value = movingText;
|
||||
|
||||
// Move file to target dir
|
||||
doAjaxGet(v2rayUpdateUrl, {
|
||||
|
@ -4,6 +4,12 @@ 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 "服务器配置"
|
||||
|
||||
@ -52,6 +58,12 @@ 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 "请不要冲突"
|
||||
|
||||
@ -61,6 +73,9 @@ msgstr "使用HTTPS"
|
||||
msgid "TLS Settings"
|
||||
msgstr "TLS配置"
|
||||
|
||||
msgid "Nginx does not support HTTP/2 reverse proxies"
|
||||
msgstr "Nginx 不支持HTTP/2反向代理"
|
||||
|
||||
msgid "as:"
|
||||
msgstr "如:"
|
||||
|
||||
@ -73,6 +88,12 @@ 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 "transit node"
|
||||
msgstr "中转到此节点"
|
||||
|
||||
msgid "This is the node inside passwall, which you can't use if you don't have it installed."
|
||||
msgstr "这里显示的是passwall里的节点,如果没有安装,将无法使用此功能。"
|
||||
|
||||
msgid "Accept LAN Access"
|
||||
msgstr "接受局域网访问"
|
||||
|
||||
@ -85,6 +106,66 @@ 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 "Update..."
|
||||
msgstr "更新中"
|
||||
|
||||
msgid "It is the latest version"
|
||||
msgstr "已是最新版本"
|
||||
|
||||
msgid "Update successful"
|
||||
msgstr "更新成功"
|
||||
|
||||
msgid "Click to update"
|
||||
msgstr "点击更新"
|
||||
|
||||
msgid "Updating..."
|
||||
msgstr "更新中"
|
||||
|
||||
msgid "Unexpected error"
|
||||
msgstr "意外错误"
|
||||
|
||||
msgid "Updating, are you sure to close?"
|
||||
msgstr "正在更新,你确认要关闭吗?"
|
||||
|
||||
msgid "Downloading..."
|
||||
msgstr "下载中"
|
||||
|
||||
msgid "Unpacking..."
|
||||
msgstr "解压中"
|
||||
|
||||
msgid "Moving..."
|
||||
msgstr "移动中"
|
||||
|
||||
msgid "Enabled"
|
||||
msgstr "启用"
|
||||
|
||||
|
@ -2,28 +2,3 @@
|
||||
config global
|
||||
option enable '0'
|
||||
|
||||
config user
|
||||
option enable '1'
|
||||
option remarks 'tcp'
|
||||
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 'ws'
|
||||
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 '0'
|
||||
option port '30010'
|
||||
|
@ -1,64 +1,16 @@
|
||||
#!/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"
|
||||
if [ ! -f /var/v2server ]; then
|
||||
local ret="/usr/bin/xray"
|
||||
[ ! -f "$ret" ] && ret="/usr/bin/v2ray/v2ray"
|
||||
[ ! -f "$ret" ] && ret="/usr/bin/v2ray"
|
||||
cp -a $ret /var/v2server
|
||||
fi
|
||||
/var/v2server -config $CONFIG_PATH/$1.json >/dev/null 2>&1 &
|
||||
}
|
||||
|
||||
start_v2ray_server() {
|
||||
mkdir -p $CONFIG_PATH $LOG_PATH
|
||||
touch $LOG_APP_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
|
||||
/usr/lib/lua/luci/model/cbi/v2ray_server/api/app.lua start
|
||||
}
|
||||
|
||||
stop() {
|
||||
stop_v2ray_server
|
||||
/usr/lib/lua/luci/model/cbi/v2ray_server/api/app.lua stop
|
||||
}
|
||||
|
||||
restart() {
|
||||
stop
|
||||
sleep 1
|
||||
start
|
||||
}
|
||||
|
@ -4,8 +4,9 @@ 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.path=/var/etc/v2ray_server.include
|
||||
set firewall.v2ray_server.reload=1
|
||||
commit firewall
|
||||
EOF
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
@ -15,7 +16,5 @@ uci -q batch <<-EOF >/dev/null
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
chmod a+x /usr/share/v2ray_server/* >/dev/null 2>&1
|
||||
|
||||
rm -rf /tmp/luci-*
|
||||
rm -rf /tmp/luci-*cache
|
||||
exit 0
|
||||
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-v2ray-server": {
|
||||
"description": "Grant UCI access for luci-app-v2ray-server",
|
||||
"read": {
|
||||
"uci": [ "v2ray_server" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "v2ray_server" ]
|
||||
}
|
||||
}
|
||||
}
|
@ -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