Add frpc,frps Luci app

This commit is contained in:
WindyMadman 2023-11-26 14:35:30 +08:00
parent 4043133a58
commit b1c5ec0593
19 changed files with 1910 additions and 0 deletions

View File

@ -0,0 +1,19 @@
#
# Copyright (C) 2008-2014 The LuCI Team <luci@lists.subsignal.org>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI for Frp Client
LUCI_DEPENDS:=+wget +frpc
LUCI_PKGARCH:=all
PKG_NAME:=luci-app-frpclient
PKG_VERSION:=1.4
PKG_RELEASE:=2
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,18 @@
module("luci.controller.frp", package.seeall)
function index()
if not nixio.fs.access("/etc/config/frp") then
return
end
entry({"admin", "services", "frp"}, cbi("frp/basic"), _("Frp Client"), 100).dependent = true
entry({"admin", "services", "frp", "config"}, cbi("frp/config")).leaf = true
entry({"admin", "services", "frp", "status"}, call("act_status")).leaf = true
end
function act_status()
local e = {}
e.running = luci.sys.call("pidof frpc > /dev/null") == 0
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end

View File

@ -0,0 +1,261 @@
local o = require "luci.dispatcher"
local e = require ("luci.model.ipkg")
local s = require "nixio.fs"
local e = luci.model.uci.cursor()
local i = "frp"
local a, t, e
local n = {}
a = Map("frp")
a.title = translate("Frp Client")
a.description = translate("Frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.")
a:section(SimpleSection).template = "frp/frp_status"
t = a:section(NamedSection, "common", "frp")
t.anonymous = true
t.addremove = false
t:tab("base", translate("Basic Settings"))
t:tab("other", translate("Other Settings"))
t:tab("log", translate("Client Log"))
e = t:taboption("base", Flag, "enabled", translate("Enabled"))
e.rmempty = false
e = t:taboption("base", Value, "server_addr", translate("Server"))
e.optional = false
e.rmempty = false
e = t:taboption("base", Value, "server_port", translate("Port"))
e.datatype = "port"
e.optional = false
e.rmempty = false
e = t:taboption("base", Value, "token", translate("Token"))
e.description = translate("Time duration between server of frpc and frps mustn't exceed 15 minutes.")
e.optional = false
e.password = true
e.rmempty = false
e = t:taboption("base", Value, "user", translate("User"))
e.description = translate("Commonly used to distinguish you with other clients.")
e.optional = true
e.default = ""
e.rmempty = false
e = t:taboption("base", Value, "vhost_http_port", translate("Vhost HTTP Port"))
e.datatype = "port"
e.rmempty = false
e = t:taboption("base", Value, "vhost_https_port", translate("Vhost HTTPS Port"))
e.datatype = "port"
e.rmempty = false
e = t:taboption("base", Value, "time", translate("Service registration interval"))
e.description = translate("0 means disable this feature, unit: min")
e.datatype = "range(0,59)"
e.default = 30
e.rmempty = false
e = t:taboption("other", Flag, "login_fail_exit", translate("Exit program when first login failed"))
e.description = translate("decide if exit program when first login failed, otherwise continuous relogin to frps.")
e.default = "1"
e.rmempty = false
e = t:taboption("other", Flag, "tcp_mux", translate("TCP Stream Multiplexing"))
e.description = translate("Default is Ture. This feature in frps.ini and frpc.ini must be same.")
e.default = "1"
e.rmempty = false
e = t:taboption("other", Flag, "tls_enable", translate("Use TLS Connection"))
e.description = translate("if tls_enable is true, frpc will connect frps by tls.")
e.default = "0"
e.rmempty = false
e = t:taboption("other", Flag, "enable_custom_certificate", translate("Custom TLS Protocol Encryption"))
e.description = translate("Frp supports traffic encryption between frpc and frps through the TLS protocol, and supports client or server unidirectional and bidirectional authentication.")
e.default = "0"
e.rmempty = false
e:depends("tls_enable", 1)
e = t:taboption("other", Value, "tls_cert_file", translate("Client Certificate File"))
e.description = translate("Frps one-way verifies the identity of frpc.")
e.placeholder = "/var/etc/frp/client.crt"
e.optional = false
e:depends("enable_custom_certificate", 1)
e = t:taboption("other", Value, "tls_key_file", translate("Client Key File"))
e.description = translate("Frps one-way verifies the identity of frpc.")
e.placeholder = "/var/etc/frp/client.key"
e.optional = false
e:depends("enable_custom_certificate", 1)
e = t:taboption("other", Value, "tls_trusted_ca_file", translate("CA Certificate File"))
e.description = translate("Frpc one-way verifies the identity of frps.")
e.placeholder = "/var/etc/frp/ca.crt"
e.optional = false
e:depends("enable_custom_certificate", 1)
e = t:taboption("other", ListValue, "protocol", translate("Protocol Type"))
e.description = translate("Frp support kcp protocol since v0.12.0")
e.default = "tcp"
e:value("tcp", translate("TCP Protocol"))
e:value("kcp", translate("KCP Protocol"))
e = t:taboption("other", Flag, "enable_http_proxy", translate("Connect frps by HTTP PROXY"))
e.description = translate("frpc can connect frps using HTTP PROXY")
e.default = "0"
e.rmempty = false
e:depends("protocol", "tcp")
e = t:taboption("other", Value, "http_proxy", translate("HTTP PROXY"))
e.placeholder = "http://user:pwd@192.168.1.128:8080"
e:depends("enable_http_proxy", 1)
e.optional = false
e = t:taboption("other", Flag, "enable_cpool", translate("Enable Connection Pool"))
e.description = translate("This feature is fit for a large number of short connections.")
e.rmempty = false
e = t:taboption("other", Value, "pool_count", translate("Connection Pool"))
e.description = translate("Connections will be established in advance.")
e.datatype = "uinteger"
e.default = "1"
e:depends("enable_cpool", 1)
e.optional = false
e = t:taboption("other", ListValue, "log_level", translate("Log Level"))
e.default = "warn"
e:value("trace", translate("Trace"))
e:value("debug", translate("Debug"))
e:value("info", translate("Info"))
e:value("warn", translate("Warning"))
e:value("error", translate("Error"))
e = t:taboption("other", Value, "log_max_days", translate("Log Keepd Max Days"))
e.datatype = "uinteger"
e.default = "3"
e.rmempty = false
e.optional = false
e = t:taboption("other", Flag, "admin_enable", translate("Enable Web API"))
e.description = translate("set admin address for control frpc's action by http api such as reload.")
e.default = "0"
e.rmempty = false
e = t:taboption("other", Value, "admin_port", translate("Admin Web Port"))
e.datatype = "port"
e.default = 7400
e:depends("admin_enable", 1)
e = t:taboption("other", Value, "admin_user", translate("Admin Web UserName"))
e.optional = false
e.default = "admin"
e:depends("admin_enable", 1)
e = t:taboption("other", Value, "admin_pwd", translate("Admin Web PassWord"))
e.optional = false
e.default = "admin"
e.password = true
e:depends("admin_enable", 1)
e = t:taboption("log", TextValue, "log")
e.rows = 26
e.wrap = "off"
e.readonly = true
e.cfgvalue = function(t,t)
return s.readfile("/var/etc/frp/frpc.log")or""
end
e.write = function(e,e,e)
end
t = a:section(TypedSection, "proxy", translate("Services List"))
t.anonymous = true
t.addremove = true
t.template = "cbi/tblsection"
t.extedit = o.build_url("admin", "services", "frp", "config", "%s")
function t.create(e,t)
new = TypedSection.create(e,t)
luci.http.redirect(e.extedit:format(new))
end
function t.remove(e,t)
e.map.proceed = true
e.map:del(t)
luci.http.redirect(o.build_url("admin","services","frp"))
end
local o = ""
e = t:option(DummyValue, "remark", translate("Service Remark Name"))
e.width = "10%"
e = t:option(DummyValue, "type", translate("Frp Protocol Type"))
e.width = "10%"
e = t:option(DummyValue, "custom_domains", translate("Domain/Subdomain"))
e.width = "20%"
e.cfgvalue = function(t,n)
local t = a.uci:get(i,n,"domain_type")or""
local m = a.uci:get(i,n,"type")or""
if t=="custom_domains" then
local b = a.uci:get(i,n,"custom_domains")or"" return b end
if t=="subdomain" then
local b = a.uci:get(i,n,"subdomain")or"" return b end
if t=="both_dtype" then
local b = a.uci:get(i,n,"custom_domains")or""
local c = a.uci:get(i,n,"subdomain")or""
b="%s/%s"%{b,c} return b end
if m=="tcp" or m=="udp" then
local b = a.uci:get(i,"common","server_addr")or"" return b end
end
e = t:option(DummyValue, "remote_port", translate("Remote Port"))
e.width = "10%"
e.cfgvalue = function(t,b)
local t = a.uci:get(i,b,"type")or""
if t==""or b==""then return""end
if t=="http" then
local b = a.uci:get(i,"common","vhost_http_port")or"" return b end
if t=="https" then
local b = a.uci:get(i,"common","vhost_https_port")or"" return b end
if t=="tcp" or t=="udp" then
local b = a.uci:get(i,b,"remote_port")or"" return b end
end
e = t:option(DummyValue, "local_ip", translate("Local Host Address"))
e.width = "15%"
e = t:option(DummyValue, "local_port", translate("Local Host Port"))
e.width = "10%"
e = t:option(DummyValue, "use_encryption", translate("Use Encryption"))
e.width = "15%"
e.cfgvalue = function(t,n)
local t = a.uci:get(i,n,"use_encryption")or""
local b
if t==""or b==""then return""end
if t=="1" then b="ON"
else b="OFF" end
return b
end
e = t:option(DummyValue, "use_compression", translate("Use Compression"))
e.width = "15%"
e.cfgvalue = function(t,n)
local t = a.uci:get(i,n,"use_compression")or""
local b
if t==""or b==""then return""end
if t=="1" then b="ON"
else b="OFF" end
return b
end
e = t:option(Flag, "enable", translate("Enable State"))
e.width = "10%"
e.rmempty = false
return a

View File

@ -0,0 +1,239 @@
local n = "frp"
local i = require "luci.dispatcher"
local o = require "luci.model.network".init()
local m = require "nixio.fs"
local a, t, e
arg[1] = arg[1]or""
a = Map("frp")
a.title = translate("Frp Domain Config")
a.redirect = i.build_url("admin", "services", "frp")
t = a:section(NamedSection, arg[1], "frp")
t.title = translate("Config Frp Protocol")
t.addremove = false
t.dynamic = false
t:tab("base", translate("Basic Settings"))
t:tab("other", translate("Other Settings"))
e = t:taboption("base", ListValue, "enable", translate("Enable State"))
e.default = "1"
e.rmempty = false
e:value("1", translate("Enable"))
e:value("0", translate("Disable"))
e = t:taboption("base", ListValue, "type", translate("Frp Protocol Type"))
e:value("http", translate("HTTP"))
e:value("https", translate("HTTPS"))
e:value("tcp", translate("TCP"))
e:value("udp", translate("UDP"))
e:value("stcp", translate("STCP"))
e:value("sudp", translate("SUDP"))
e:value("xtcp", translate("XTCP"))
e = t:taboption("base", ListValue, "domain_type", translate("Domain Type"))
e.default = "custom_domains"
e:value("custom_domains", translate("Custom Domains"))
e:value("subdomain", translate("SubDomain"))
e:value("both_dtype", translate("Both the above two Domain types"))
e:depends("type", "http")
e:depends("type", "https")
e = t:taboption("base", Value, "custom_domains", translate("Custom Domains"))
e.description = translate("If SubDomain is used, Custom Domains couldn't be subdomain or wildcard domain of the maindomain(subdomain_host).")
e:depends("domain_type", "custom_domains")
e:depends("domain_type", "both_dtype")
e = t:taboption("base", Value, "subdomain", translate("SubDomain"))
e.description = translate("subdomain_host must be configured in server: frps in advance.")
e:depends("domain_type", "subdomain")
e:depends("domain_type", "both_dtype")
e = t:taboption("base", ListValue, "stcp_role", translate("STCP Role"))
e.default = "server"
e:value("server", translate("STCP Server"))
e:value("visitor", translate("STCP Vistor"))
e:depends("type", "stcp")
e = t:taboption("base", ListValue, "sudp_role", translate("SUDP Role"))
e.default = "server"
e:value("server", translate("SUDP Server"))
e:value("visitor", translate("SUDP Vistor"))
e:depends("type", "sudp")
e = t:taboption("base", ListValue, "xtcp_role", translate("XTCP Role"))
e.default = "server"
e:value("server", translate("XTCP Server"))
e:value("visitor", translate("XTCP Vistor"))
e:depends("type", "xtcp")
e = t:taboption("base", Value, "remote_port", translate("Remote Port"))
e.datatype = "port"
e:depends("type", "tcp")
e:depends("type", "udp")
e = t:taboption("other", Flag, "enable_plugin", translate("Use Plugin"))
e.description = translate("If plugin is defined, local_ip and local_port is useless, plugin will handle connections got from frps.")
e.default = "0"
e:depends("type", "tcp")
e = t:taboption("base", Value, "local_ip", translate("Local Host Address"))
luci.sys.net.ipv4_hints(function(x,d)
e:value(x,"%s (%s)"%{x,d})
end)
luci.sys.net.ipv6_hints(function(x,d)
e:value(x,"%s (%s)"%{x,d})
end)
e:depends("type", "udp")
e:depends("type", "http")
e:depends("type", "https")
e:depends("enable_plugin", 0)
e = t:taboption("base", Value, "local_port", translate("Local Host Port"))
e.datatype = "port"
e:depends("type", "udp")
e:depends("type", "http")
e:depends("type", "https")
e:depends("enable_plugin", 0)
e = t:taboption("base", Value, "stcp_secretkey", translate("STCP Screct Key"))
e.default = "abcdefg"
e:depends("type", "stcp")
e = t:taboption("base", Value, "stcp_servername", translate("STCP Server Name"))
e.description = translate("STCP Server Name is Service Remark Name of STCP Server")
e.default = "secret_tcp"
e:depends("stcp_role", "visitor")
e = t:taboption("base", Value, "sudp_secretkey", translate("SUDP Screct Key"))
e.default = "abcdefg"
e:depends("type", "sudp")
e = t:taboption("base", Value, "sudp_servername", translate("SUDP Server Name"))
e.description = translate("SUDP Server Name is Service Remark Name of SUDP Server")
e.default = "secret_tcp"
e:depends("sudp_role", "visitor")
e = t:taboption("base", Value, "xtcp_secretkey", translate("XTCP Screct Key"))
e.default = "abcdefg"
e:depends("type", "xtcp")
e = t:taboption("base", Value, "xtcp_servername", translate("XTCP Server Name"))
e.description = translate("XTCP Server Name is Service Remark Name of XTCP Server")
e.default = "p2p_tcp"
e:depends("xtcp_role", "visitor")
e = t:taboption("other", Flag, "enable_locations", translate("Enable URL routing"))
e.description = translate("Frp support forward http requests to different backward web services by url routing.")
e:depends("type", "http")
e = t:taboption("other", Value, "locations", translate("URL routing"))
e.description = translate("Http requests with url prefix /news will be forwarded to this service.")
e.default = "locations=/"
e:depends("enable_locations", 1)
e = t:taboption("other", ListValue, "plugin", translate("Choose Plugin"))
e:value("http_proxy", translate("http_proxy"))
e:value("socks5", translate("socks5"))
e:value("unix_domain_socket", translate("unix_domain_socket"))
e:depends("enable_plugin", 1)
e = t:taboption("other", Flag, "enable_plugin_httpuserpw", translate("Proxy Authentication"))
e.description = translate("Other PCs could access the Internet through frpc's network by using http_proxy plugin.")
e.default = "0"
e:depends("plugin", "http_proxy")
e = t:taboption("other", Value, "plugin_http_user", translate("HTTP Proxy UserName"))
e.default = "abc"
e:depends("enable_plugin_httpuserpw", 1)
e = t:taboption("other", Value, "plugin_http_passwd", translate("HTTP Proxy Password"))
e.default = "abc"
e:depends("enable_plugin_httpuserpw", 1)
e = t:taboption("other", Value, "plugin_unix_path", translate("Plugin Unix Sock Path"))
e.default = "/var/run/docker.sock"
e:depends("plugin", "unix_domain_socket")
e = t:taboption("other", Flag, "enable_http_auth", translate("Password protecting your web service"))
e.description = translate("Http username and password are safety certification for http protocol.")
e.default = "0"
e:depends("type", "http")
e = t:taboption("other", Value, "http_user", translate("HTTP UserName"))
e.default = "frp"
e:depends("enable_http_auth", 1)
e = t:taboption("other", Value, "http_pwd", translate("HTTP PassWord"))
e.default = "frp"
e:depends("enable_http_auth", 1)
e = t:taboption("other", Flag, "enable_host_header_rewrite", translate("Rewriting the Host Header"))
e.description = translate("Frp can rewrite http requests with a modified Host header.")
e.default = "0"
e:depends("type", "http")
e = t:taboption("other", Value, "host_header_rewrite", translate("Host Header"))
e.description = translate("The Host header will be rewritten to match the hostname portion of the forwarding address.")
e.default = "dev.yourdomain.com"
e:depends("enable_host_header_rewrite", 1)
e = t:taboption("other", Flag, "enable_https_plugin", translate("Use Plugin"))
e.default = "0"
e:depends("type", "https")
e = t:taboption("other", ListValue, "https_plugin", translate("Choose Plugin"))
e.description = translate("If plugin is defined, local_ip and local_port is useless, plugin will handle connections got from frps.")
e:value("https2http", translate("https2http"))
e:depends("enable_https_plugin", 1)
e = t:taboption("other", Value, "plugin_local_addr", translate("Plugin_Local_Addr"))
e.default = "127.0.0.1:80"
e:depends("https_plugin", "https2http")
e = t:taboption("other", Value, "plugin_crt_path", translate("plugin_crt_path"))
e.default = "./server.crt"
e:depends("https_plugin", "https2http")
e = t:taboption("other", Value, "plugin_key_path", translate("plugin_key_path"))
e.default = "./server.key"
e:depends("https_plugin", "https2http")
e = t:taboption("other", Value, "plugin_host_header_rewrite", translate("plugin_host_header_rewrite"))
e.default = "127.0.0.1"
e:depends("https_plugin", "https2http")
e = t:taboption("other", Value, "plugin_header_X_From_Where", translate("plugin_header_X-From-Where"))
e.default = "frp"
e:depends("https_plugin", "https2http")
e = t:taboption("base", ListValue, "proxy_protocol_version", translate("Proxy-Protocol Version"))
e.description = translate("Proxy Protocol to send user's real IP to local services.")
e.default = "disable"
e:value("disable", translate("Disable"))
e:value("v1", translate("V1"))
e:value("v2", translate("V2"))
e:depends("type", "tcp")
e:depends("type", "stcp")
e:depends("type", "sudp")
e:depends("type", "xtcp")
e:depends("type", "http")
e:depends("type", "https")
e = t:taboption("base", Flag, "use_encryption", translate("Use Encryption"))
e.description = translate("Encrypted the communication between frpc and frps, will effectively prevent the traffic intercepted (If Custom TLS Protocol Encryption is enabled, except that the protocol of xtcp is configured as kcp, you can no longer set Use Encryption to repeat encryption).")
e.default = "1"
e.rmempty = false
e = t:taboption("base", Flag, "use_compression", translate("Use Compression"))
e.description = translate("The contents will be compressed to speed up the traffic forwarding speed, but this will consume some additional cpu resources.")
e.default = "1"
e.rmempty = false
e = t:taboption("base", Value, "remark", translate("Service Remark Name"))
e.description = translate("<font color=\"red\">Please ensure the remark name is unique.</font>")
e.rmempty = false
return a

View File

@ -0,0 +1,22 @@
<script type="text/javascript">//<![CDATA[
XHR.poll(3, '<%=url([[admin]], [[services]], [[frp]], [[status]])%>', null,
function(x, data) {
var tb = document.getElementById('frp_status');
if (data && tb) {
if (data.running) {
var links = '<em><b><font color=green>Frp <%:RUNNING%></font></b></em>';
tb.innerHTML = links;
} else {
tb.innerHTML = '<em><b><font color=red>Frp <%:NOT RUNNING%></font></b></em>';
}
}
}
);
//]]>
</script>
<style>.mar-10 {margin-left: 50px; margin-right: 10px;}</style>
<fieldset class="cbi-section">
<p id="frp_status">
<em><%:Collecting data...%></em>
</p>
</fieldset>

View File

@ -0,0 +1,335 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Frp Client"
msgstr "Frp 客户端"
msgid "NOT RUNNING"
msgstr "未运行"
msgid "RUNNING"
msgstr "运行中"
msgid "Frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet."
msgstr "Frp 是一个可用于内网穿透的高性能的反向代理应用。"
msgid "Basic Settings"
msgstr "基本设置"
msgid "Other Settings"
msgstr "其他设置"
msgid "Client Log"
msgstr "日志"
msgid "Enabled"
msgstr "启用"
msgid "Server"
msgstr "服务器"
msgid "Port"
msgstr "端口"
msgid "Token"
msgstr "令牌"
msgid "User"
msgstr "用户名"
msgid "Commonly used to distinguish you with other clients."
msgstr "通常用于区分你与其他客户端"
msgid "Time duration between server of frpc and frps mustn't exceed 15 minutes."
msgstr "frpc服务器与frps之间的时间间隔不得超过15分钟"
msgid "Vhost HTTP Port"
msgstr "HTTP 穿透服务端口"
msgid "Vhost HTTPS Port"
msgstr "HTTPS 穿透服务端口"
msgid "Exit program when first login failed"
msgstr "初始登录失败即退出程序"
msgid "TCP Stream Multiplexing"
msgstr "TCP 端口复用"
msgid "decide if exit program when first login failed, otherwise continuous relogin to frps."
msgstr "第一次登录失败就退出程序,否则将持续尝试登陆 Frp 服务器。"
msgid "Default is Ture. This feature in frps.ini and frpc.ini must be same."
msgstr "该功能默认启用,该配置项在服务端和客户端必须保持一致。"
msgid "Use TLS Connection"
msgstr "TLS 连接"
msgid "if tls_enable is true, frpc will connect frps by tls."
msgstr "使用 TLS 协议与服务器连接(若连接服务器异常可以尝试开启)"
msgid "Custom TLS Protocol Encryption"
msgstr "自定义TLS协议加密"
msgid "Frp supports traffic encryption between frpc and frps through the TLS protocol, and supports client or server unidirectional and bidirectional authentication."
msgstr "frp 支持 frpc 和 frps 之间的流量通过 TLS 协议加密,并且支持客户端或服务端单向验证,双向验证等功能。"
msgid "Frps one-way verifies the identity of frpc."
msgstr "frps 单向验证 frpc 身份。"
msgid "Client Certificate File"
msgstr "TLS 客户端证书文件路径"
msgid "Client Key File"
msgstr "TLS 客户端密钥文件路径"
msgid "Frpc one-way verifies the identity of frps."
msgstr "frpc 单向验证 frps 身份。"
msgid "CA Certificate File"
msgstr "TLS CA 证书路径"
msgid "Protocol Type"
msgstr "协议类型"
msgid "Frp support kcp protocol since v0.12.0"
msgstr "从 v0.12.0 版本开始,底层通信协议支持选择 kcp 协议加速。"
msgid "TCP Protocol"
msgstr "TCP 协议"
msgid "KCP Protocol"
msgstr "KCP 协议"
msgid "Connect frps by HTTP PROXY"
msgstr "通过代理连接 frps"
msgid "frpc can connect frps using HTTP PROXY"
msgstr "frpc 支持通过 HTTP PROXY 和 frps 进行通信"
msgid "HTTP PROXY"
msgstr "HTTP 代理"
msgid "Enable Connection Pool"
msgstr "启用连接池功能"
msgid "This feature is fit for a large number of short connections."
msgstr "适合有大量短连接请求时开启"
msgid "Connection Pool"
msgstr "指定预创建连接的数量"
msgid "Connections will be established in advance."
msgstr "frpc 会预先和服务端建立起指定数量的连接。"
msgid "Service registration interval"
msgstr "服务注册间隔"
msgid "0 means disable this feature, unit: min"
msgstr "0表示禁用定时注册功能单位分钟"
msgid "Log Level"
msgstr "日志记录等级"
msgid "Trace"
msgstr "追踪"
msgid "Debug"
msgstr "调试"
msgid "Info"
msgstr "信息"
msgid "Warning"
msgstr "警告"
msgid "Error"
msgstr "错误"
msgid "Log Keepd Max Days"
msgstr "日志记录天数"
msgid "Enable Web API"
msgstr "开启网页管理"
msgid "set admin address for control frpc's action by http api such as reload."
msgstr "可通过http查看客户端状态以及通过API控制"
msgid "Admin Web Port"
msgstr "管理员端口号"
msgid "Admin Web UserName"
msgstr "管理员用户名"
msgid "Admin Web PassWord"
msgstr "管理员密码"
msgid "Services List"
msgstr "服务列表"
msgid "Service Remark Name"
msgstr "服务备注名"
msgid "Domain/Subdomain"
msgstr "域名/子域名"
msgid "Remote Port"
msgstr "远程主机端口"
msgid "Local Host Address"
msgstr "内网主机地址"
msgid "Local Host Port"
msgstr "内网主机端口"
msgid "Use Encryption"
msgstr "开启数据加密"
msgid "Use Compression"
msgstr "使用压缩"
msgid "Enable State"
msgstr "开启状态"
msgid "Frp Domain Config"
msgstr "Frp 域名配置"
msgid "Config Frp Protocol"
msgstr "配置 Frp 协议参数"
msgid "Disable"
msgstr "关闭"
msgid "Frp Protocol Type"
msgstr "Frp 协议类型"
msgid "Domain Type"
msgstr "域名类型"
msgid "Custom Domains"
msgstr "自定义域名"
msgid "SubDomain"
msgstr "子域名"
msgid "Both the above two Domain types"
msgstr "同时使用2种域名"
msgid "If SubDomain is used, Custom Domains couldn't be subdomain or wildcard domain of the maindomain(subdomain_host)."
msgstr "如果服务端配置了主域名(subdomain_host),则自定义域名不能是属于主域名(subdomain_host) 的子域名或者泛域名。"
msgid "subdomain_host must be configured in server: frps in advance."
msgstr "使用子域名时,必须预先在服务端配置主域名(subdomain_host)参数。"
msgid "STCP Role"
msgstr "STCP 服务类型"
msgid "SUDP Role"
msgstr "SUDP 服务类型"
msgid "XTCP Role"
msgstr "XTCP 服务类型"
msgid "Use Plugin"
msgstr "使用插件"
msgid "If plugin is defined, local_ip and local_port is useless, plugin will handle connections got from frps."
msgstr "使用插件使用插件模式时,本地 IP 地址和端口无需配置,插件将会处理来自服务端的链接请求。"
msgid "STCP Screct Key"
msgstr "STCP 密钥"
msgid "STCP Server Name"
msgstr "STCP 服务名称"
msgid "SUDP Screct Key"
msgstr "SUDP 密钥"
msgid "SUDP Server Name"
msgstr "SUDP 服务名称"
msgid "XTCP Screct Key"
msgstr "XTCP 密钥"
msgid "XTCP Server Name"
msgstr "XTCP 服务名称"
msgid "Enable URL routing"
msgstr "启用 URL 路由"
msgid "Frp support forward http requests to different backward web services by url routing."
msgstr "Frp 支持通过url路由将http请求转发到不同的反向web服务。"
msgid "Choose Plugin"
msgstr "选择插件"
msgid "Proxy Authentication"
msgstr "代理认证"
msgid "Other PCs could access the Internet through frpc's network by using http_proxy plugin."
msgstr "http proxy 插件,可以使其他机器通过 frpc 的网络访问互联网;开启身份验证之后需要用户名、密码才能连接到 HTTP 代理。"
msgid "HTTP Proxy UserName"
msgstr "HTTP 代理用户名"
msgid "HTTP Proxy Password"
msgstr "HTTP 代理密码"
msgid "Plugin Unix Sock Path"
msgstr "Unix Sock 插件路径"
msgid "Password protecting your web service"
msgstr "密码保护您的web服务"
msgid "HTTP UserName"
msgstr "HTTP 用户名"
msgid "HTTP PassWord"
msgstr "HTTP 密码"
msgid "Rewriting the Host Header"
msgstr "修改 Host Header"
msgid "Frp can rewrite http requests with a modified Host header."
msgstr "Frp可以用修改后的主机头重写http请求。"
msgid "Proxy-Protocol Version"
msgstr "Proxy-Protocol 版本"
msgid "Encrypted the communication between frpc and frps, will effectively prevent the traffic intercepted (If Custom TLS Protocol Encryption is enabled, except that the protocol of xtcp is configured as kcp, you can no longer set Use Encryption to repeat encryption)."
msgstr "将 frpc 与 frps 之间的通信内容加密传输将会有效防止流量被拦截启用自定义TLS协议加密后除 xtcp 的 protocol 配置为 kcp 外,可不再设置此项重复加密)。"
msgid "The contents will be compressed to speed up the traffic forwarding speed, but this will consume some additional cpu resources."
msgstr "对传输内容进行压缩,加快流量转发速度,但是会额外消耗一些 cpu 资源。"
msgid "Http username and password are safety certification for http protocol."
msgstr "Http用户名和密码是Http协议的安全认证。"
msgid "Proxy Protocol to send user's real IP to local services."
msgstr "将用户的真实IP发送到本地服务的代理协议。"
msgid "STCP Server Name is Service Remark Name of STCP Server"
msgstr "STCP服务器别名"
msgid "SUDP Server Name is Service Remark Name of SUDP Server"
msgstr "SUDP服务器别名"
msgid "XTCP Server Name is Service Remark Name of XTCP Server"
msgstr "XTCP服务器别名"
msgid "<font color=\"red\">Please ensure the remark name is unique.</font>"
msgstr "<font color=\"red\">确保备注名唯一</font>"
msgid "Plugin_Local_Addr"
msgstr "插件本地地址(格式 IP:Port"
msgid "plugin_crt_path"
msgstr "插件证书路径"
msgid "plugin_key_path"
msgstr "插件私钥路径"
msgid "plugin_host_header_rewrite"
msgstr "插件 Host Header 重写"
msgid "plugin_header_X-From-Where"
msgstr "插件X-From-Where请求头"

View File

@ -0,0 +1,17 @@
config frp 'common'
option log_max_days '3'
option login_fail_exit '0'
option enable_cpool '0'
option time '40'
option tcp_mux '1'
option enabled '0'
option vhost_http_port '80'
option vhost_https_port '443'
option server_addr 'yourdomain.com'
option server_port '7000'
option token '1234567'
option log_level 'info'
option enable_http_proxy '0'
option protocol 'tcp'
option user ''

View File

@ -0,0 +1,268 @@
#!/bin/sh /etc/rc.common
#Author: monokoo <realstones2012@gmail.com>
#Thanks to FW867's help
START=99
SERVICE_WRITE_PID=1
SERVICE_DAEMONIZE=1
LOGFILE="/var/etc/frp/frpc.log"
echo_date(){
local log=$1
echo $(date +%Y/%m/%d\ %X): "$log" >> $LOGFILE
}
Reduce_Log(){
local log=$1
[ ! -f "$log" ] && return
local sc=200
[ -n "$2" ] && sc=$2
local count=$(grep -c "" $log)
if [ $count -gt $sc ];then
let count=count-$sc
sed -i "1,$count d" $log
fi
}
conf_proxy_add() {
local cfg="$1"
local tmpconf="$2"
local enable type domain_type custom_domains remote_port local_ip local_port enable_http_auth enable_host_header_rewrite host_header_rewrite
local subdomain proxy_protocol_version use_encryption use_compression http_user http_pwd remark locations
local enable_plugin plugin plugin_http_user plugin_http_passwd plugin_unix_path stcp_role stcp_secretkey stcp_servername xtcp_role xtcp_secretkey xtcp_servername
local enable_https_plugin https_plugin plugin_local_addr plugin_crt_path plugin_key_path plugin_host_header_rewrite plugin_header_X_From_Where
config_get_bool enable "$cfg" enable 1
[ "$enable" -gt 0 ] || return 1
config_get type "$cfg" type
config_get custom_domains "$cfg" custom_domains
config_get subdomain "$cfg" subdomain
config_get remote_port "$cfg" remote_port
config_get local_ip "$cfg" local_ip
config_get local_port "$cfg" local_port
config_get locations "$cfg" locations
config_get host_header_rewrite "$cfg" host_header_rewrite
config_get http_user "$cfg" http_user
config_get http_pwd "$cfg" http_pwd
config_get remark "$cfg" remark
config_get plugin "$cfg" plugin
config_get plugin_http_user "$cfg" plugin_http_user
config_get plugin_http_passwd "$cfg" plugin_http_passwd
config_get plugin_unix_path "$cfg" plugin_unix_path
config_get stcp_role "$cfg" stcp_role
config_get stcp_secretkey "$cfg" stcp_secretkey
config_get stcp_servername "$cfg" stcp_servername
config_get xtcp_role "$cfg" xtcp_role
config_get xtcp_secretkey "$cfg" xtcp_secretkey
config_get xtcp_servername "$cfg" xtcp_servername
config_get proxy_protocol_version "$cfg" proxy_protocol_version
config_get https_plugin "$cfg" https_plugin
config_get plugin_local_addr "$cfg" plugin_local_addr
config_get plugin_crt_path "$cfg" plugin_crt_path
config_get plugin_key_path "$cfg" plugin_key_path
config_get plugin_host_header_rewrite "$cfg" plugin_host_header_rewrite
config_get plugin_header_X_From_Where "$cfg" plugin_header_X_From_Where
[ -n "$remark" ] && [ -n "$type" ] || return 1
echo "" >>$tmpconf
echo "[$remark]" >>$tmpconf
echo "type=$type" >>$tmpconf
[ -n "$custom_domains" ] && echo "custom_domains=$custom_domains" >>$tmpconf
[ -n "$subdomain" ] && echo "subdomain=$subdomain" >>$tmpconf
[ -n "$remote_port" ] && echo "remote_port=$remote_port" >>$tmpconf
[ -z "$stcp_role" ] && [ -z "$xtcp_role" ] && [ -n "$local_ip" ] && echo "local_ip=$local_ip" >>$tmpconf
[ -z "$stcp_role" ] && [ -z "$xtcp_role" ] && [ -n "$local_port" ] && echo "local_port=$local_port" >>$tmpconf
[ -n "$locations" ] && echo "locations=$locations" >>$tmpconf
[ -n "$http_user" -a -n "$http_pwd" ] && {
echo "http_user=$http_user" >>$tmpconf
echo "http_pwd=$http_pwd" >>$tmpconf
}
[ -n "$host_header_rewrite" ] && echo "host_header_rewrite=$host_header_rewrite" >>$tmpconf
[ -n "$plugin" ] && echo "plugin=$plugin" >>$tmpconf
[ -n "$plugin_http_user" -a -n "$plugin_http_passwd" ] && {
echo "plugin_http_user=$plugin_http_user" >>$tmpconf
echo "plugin_http_passwd=$plugin_http_passwd" >>$tmpconf
}
[ -n "$plugin_unix_path" ] && echo "plugin_unix_path=$plugin_unix_path" >>$tmpconf
[ -n "$stcp_role" ] && {
if [ "$stcp_role" == "visitor" ]; then
echo "role=$stcp_role" >>$tmpconf
[ -n "$local_ip" ] && echo "bind_addr=$local_ip" >>$tmpconf
[ -n "$local_port" ] && echo "bind_port=$local_port" >>$tmpconf
[ -n "$stcp_servername" ] && echo "server_name=$stcp_servername" >>$tmpconf || return 1
else
[ -n "$local_ip" ] && echo "local_ip=$local_ip" >>$tmpconf
[ -n "$local_port" ] && echo "local_port=$local_port" >>$tmpconf
fi
[ -n "$stcp_secretkey" ] && echo "sk=$stcp_secretkey" >>$tmpconf || return 1
}
[ -n "$xtcp_role" ] && {
if [ "$xtcp_role" == "visitor" ]; then
echo "role=$xtcp_role" >>$tmpconf
[ -n "$local_ip" ] && echo "bind_addr=$local_ip" >>$tmpconf
[ -n "$local_port" ] && echo "bind_port=$local_port" >>$tmpconf
[ -n "$xtcp_servername" ] && echo "server_name=$xtcp_servername" >>$tmpconf || return 1
else
[ -n "$local_ip" ] && echo "local_ip=$local_ip" >>$tmpconf
[ -n "$local_port" ] && echo "local_port=$local_port" >>$tmpconf
fi
[ -n "$xtcp_secretkey" ] && echo "sk=$xtcp_secretkey" >>$tmpconf || return 1
}
[ -n "$proxy_protocol_version" ] && {
if [ "$proxy_protocol_version" != "disable" ]; then
echo "proxy_protocol_version=$proxy_protocol_version" >>$tmpconf
fi
}
[ -n "$https_plugin" ] && echo "plugin=$https_plugin" >>$tmpconf
[ -n "$plugin_local_addr" ] && echo "plugin_local_addr=$plugin_local_addr" >>$tmpconf
[ -n "$plugin_crt_path" -a -n "$plugin_key_path" ] && {
echo "plugin_crt_path=$plugin_crt_path" >>$tmpconf
echo "plugin_key_path=$plugin_key_path" >>$tmpconf
}
[ -n "$plugin_host_header_rewrite" ] && echo "plugin_host_header_rewrite=$plugin_host_header_rewrite" >>$tmpconf
[ -n "$plugin_header_X_From_Where" ] && echo "plugin_header_X_From_Where=$plugin_header_X_From_Where" >>$tmpconf
frp_write_bool use_encryption $cfg 1
frp_write_bool use_compression $cfg 1
}
frp_write_bool() {
local opt="$1"
local config="$2"
local def="$3"
local val
config_get_bool val $config "$opt" "$def"
if [ "$val" -eq 0 ]; then
echo "${opt}=false" >> $tmpconf
else
echo "${opt}=true" >> $tmpconf
fi
}
frp_add_cru(){
time=$1
if [ ! -f "/etc/crontabs/root" ] || [ -z "$(cat /etc/crontabs/root | grep frp)" ]; then
sed -i '/frp/d' /etc/crontabs/root >/dev/null 2>&1
echo "*/$time * * * * /etc/init.d/frp restart" >> /etc/crontabs/root
fi
}
frp_del_cru(){
if [ ! -f "/etc/crontabs/root" ] || [ -n "$(cat /etc/crontabs/root | grep frp)" ]; then
sed -i '/frp/d' /etc/crontabs/root >/dev/null 2>&1
fi
}
download_binary(){
echo_date "开始下载frpc二进制文件..."
/usr/bin/wget --no-check-certificate --timeout=10 --tries=1 -o $LOGFILE https://github.com/fatedier/frp/releases/download/v0.13.0/frp_0.13.0_linux_arm.tar.gz -O /tmp/frp_0.13.0_linux_arm.tar.gz
[ ! -s "/tmp/frp_0.13.0_linux_arm.tar.gz" ] && /usr/bin/wget -q --no-check-certificate --timeout=10 --tries=1 https://any.mokoo.xyz/app/frp_0.13.0_linux_arm.tar.gz -O /tmp/frp_0.13.0_linux_arm.tar.gz
[ -f "/tmp/frp_0.13.0_linux_arm.tar.gz" ] && tar -xf /tmp/frp_0.13.0_linux_arm.tar.gz -C /tmp && \
mv /tmp/frp_0.13.0_linux_arm/frpc /usr/bin/frpc
rm -rf /tmp/frp_0.13.0_linux_arm*
if [ -f "/usr/bin/frpc" ]; then
chmod +x /usr/bin/frpc && echo_date "成功下载frpc二进制文件"
else
echo_date "下载frpc二进制文件失败请重试"
fi
}
boot() {
sleep 10s
start
}
start() {
config_load "frp"
local enabled server_addr server_port time privilege_token user tcp_mux enable_cpool tls_enable
local pool_count log_level log_max_days login_fail_exit http_proxy protocol admin_port admin_user admin_pwd
local tls_cert_file tls_key_file tls_trusted_ca_file
config_get_bool enabled common enabled 1
[ "$enabled" -gt 0 ] || return 1
config_get server_addr common server_addr
config_get server_port common server_port
config_get token common token
config_get user common user
config_get enable_cpool common enable_cpool
config_get pool_count common pool_count
config_get log_level common log_level
config_get log_max_days common log_max_days
config_get http_proxy common http_proxy
config_get protocol common protocol
config_get time common time
config_get admin_port common admin_port
config_get admin_user common admin_user
config_get admin_pwd common admin_pwd
config_get tls_cert_file common tls_cert_file
config_get tls_key_file common tls_key_file
config_get tls_trusted_ca_file common tls_trusted_ca_file
mkdir -p /var/etc/frp
[ ! -f "$LOGFILE" ] && touch $LOGFILE
[ ! -f "/usr/bin/frpc" ] && download_binary
[ ! -f "/usr/bin/frpc" ] && logger -t Frp 'Download frpc failed, please retry.' && exit 0
local tmpconf="/var/etc/frp/frpc.conf"
echo "[common]" >$tmpconf
echo "server_addr=${server_addr}" >>$tmpconf
echo "server_port=${server_port}" >>$tmpconf
echo "token=${token}" >>$tmpconf
[ -n "$user" ] && echo "user=$user" >>$tmpconf
echo "log_level=${log_level}" >>$tmpconf
echo "log_max_days=${log_max_days}" >>$tmpconf
echo "protocol=${protocol}" >>$tmpconf
echo "log_file=$LOGFILE" >>$tmpconf
[ -n "$http_proxy" ] && echo "http_proxy=$http_proxy" >>$tmpconf
[ -n "$pool_count" ] && echo "pool_count=$pool_count" >>$tmpconf
[ -n "$admin_port" ] && echo "admin_addr=0.0.0.0" >>$tmpconf && echo "admin_port=$admin_port" >>$tmpconf
[ -n "$admin_user" ] && echo "admin_user=$admin_user" >>$tmpconf
[ -n "$admin_pwd" ] && echo "admin_pwd=$admin_pwd" >>$tmpconf
[[ -n "$tls_cert_file" && -n "$tls_key_file" ]] && echo "tls_cert_file=$tls_cert_file" >>$tmpconf && echo "tls_key_file=$tls_key_file" >>$tmpconf
[ -n "$tls_trusted_ca_file" ] && echo "tls_trusted_ca_file=$tls_trusted_ca_file" >>$tmpconf
config_load "frp"
frp_write_bool tcp_mux common 1
frp_write_bool tls_enable common 0
frp_write_bool login_fail_exit common 1
config_foreach conf_proxy_add proxy "$tmpconf"
[ "$(cat "$tmpconf" | grep -c "type=")" -gt 0 ] || (echo_date "frp服务启动失败请首先添加服务列表" && exit 0)
logger -t FRPC 'Starting frp service'
SERVICE_DAEMONIZE=1 \
service_start /usr/bin/frpc -c $tmpconf
[ "$time" -gt 0 ] && frp_add_cru $time
[ -z "$(pgrep /usr/bin/frpc)" ] && echo_date "frp服务启动失败请检查服务端 “TCP多路复用(tcp_mux)”设置,确保与客户端完全一致!"
return 0
}
stop() {
frp_del_cru
if [ -n "`pidof frpc`" ]; then
logger -t FRPC 'Shutting down frp service'
service_stop /usr/bin/frpc
Reduce_Log $LOGFILE
fi
return 0
}

View File

@ -0,0 +1,11 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@frp[-1]
add ucitrack frp
set ucitrack.@frp[-1].init=frp
commit ucitrack
EOF
rm -f /tmp/luci-indexcache
exit 0

View File

@ -0,0 +1,11 @@
{
"luci-app-frpc": {
"description": "Grant UCI access for luci-app-frpc",
"read": {
"uci": [ "frp" ]
},
"write": {
"uci": [ "frp" ]
}
}
}

View File

@ -0,0 +1,27 @@
#
# Copyright 2020 lwz322 <lwz322@qq.com>
# Licensed to the public under the MIT License.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-frpserver
PKG_VERSION:=0.0.2
PKG_RELEASE:=4
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=lwz322 <lwz322@qq.com>
LUCI_TITLE:=LuCI support for Frp Server
LUCI_DEPENDS:=+wget +frps
LUCI_PKGARCH:=all
define Package/$(PKG_NAME)/conffiles
/etc/config/frps
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,24 @@
-- Copyright 2020 lwz322 <lwz322@qq.com>
-- Licensed to the public under the MIT License.
module("luci.controller.frps", package.seeall)
function index()
if not nixio.fs.access("/etc/config/frps") then
return
end
entry({"admin", "services", "frps"}, alias("admin", "services", "frps", "common"), _("Frp Server"), 99).dependent = true
entry({"admin", "services", "frps", "common"}, cbi("frps/common"), _("Settings"), 1).leaf = true
entry({"admin", "services", "frps", "server"}, cbi("frps/server"), _("Server"), 2).leaf = true
entry({"admin", "services", "frps", "status"}, call("action_status")).leaf = true
end
function action_status()
local e = {}
e.running = luci.sys.call("pidof frps >/dev/null") == 0
e.bin_version = luci.sys.exec("frps -v")
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end

View File

@ -0,0 +1,93 @@
-- Copyright 2020 lwz322 <lwz322@qq.com>
-- Licensed to the public under the MIT License.
local m, s, o
m = Map("frps")
m.title = translate("Frps - Common Settings")
m.description = translate("Frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.<br/><a href=\"https://github.com/fatedier/frp\" target=\"_blank\">Project GitHub URL</a>")
m:section(SimpleSection).template = "frps/frps_status"
s = m:section(NamedSection, "main", "frps")
s.addremove = false
s.anonymous = true
s:tab("general", translate("General Options"))
s:tab("advanced", translate("Advanced Options"))
s:tab("dashboard", translate("Dashboard Options"))
o = s:taboption("general", Flag, "enabled", translate("Enabled"))
o = s:taboption("general", Value, "client_file", translate("Client file"))
o.default = "/usr/bin/frps"
o.rmempty = false
o = s:taboption("general", ListValue, "run_user", translate("Run daemon as user"))
o:value("", translate("root"))
local user
for user in luci.util.execi("cat /etc/passwd | cut -d':' -f1") do
o:value(user)
end
o = s:taboption("general", Flag, "enable_logging", translate("Enable logging"))
o = s:taboption("general", Value, "log_file", translate("Log file"))
o:depends("enable_logging", "1")
o.default = "/var/log/frps.log"
o = s:taboption("general", ListValue, "log_level", translate("Log level"))
o:depends("enable_logging", "1")
o:value("trace", translate("Trace"))
o:value("debug", translate("Debug"))
o:value("info", translate("Info"))
o:value("warn", translate("Warning"))
o:value("error", translate("Error"))
o.default = "Warn"
o = s:taboption("general", ListValue, "log_max_days", translate("Log max days"))
o.description = translate("Maximum number of days to keep log files is 3 day.")
o:depends("enable_logging", "1")
o.datatype = "uinteger"
o:value("1", translate("1"))
o:value("2", translate("2"))
o:value("3", translate("3"))
o.default = "3"
o.optional = false
o = s:taboption("general", Flag, "disable_log_color", translate("Disable log color"))
o:depends("enable_logging", "1")
o.enabled = "true"
o.disabled = "false"
o = s:taboption("advanced", Value, "max_pool_count", translate("Max pool count"))
o.description = translate("pool_count in each proxy will change to max_pool_count if they exceed the maximum value")
o.datatype = "uinteger"
o = s:taboption("advanced", Value, "max_ports_per_client", translate("Max ports per-client"))
o.description = translate("max ports can be used for each client, default value is 0 means no limit")
o.datatype = "uinteger"
o.defalut = '0'
o.placeholder = '0'
o = s:taboption("advanced", Value, "subdomain_host", translate("Subdomain host"))
o.description = translatef("if subdomain_host is not empty, you can set subdomain when type is http or https in frpc's configure file; when subdomain is test, the host used by routing is test.frps.com")
o.datatype = "host"
o = s:taboption("dashboard", Value, "dashboard_addr", translate("Dashboard addr"))
o.description = translatef("dashboard addr's default value is same with bind_addr")
o.default = "0.0.0.0"
o.datatype = "host"
o = s:taboption("dashboard", Value, "dashboard_port", translate("Dashboard port"))
o.description = translatef("dashboard is available only if dashboard_port is set")
o.default = "7500"
o.datatype = "port"
o = s:taboption("dashboard", Value, "dashboard_user", translate("Dashboard user"))
o.description = translatef("dashboard user and passwd for basic auth protect, if not set, both default value is admin")
o = s:taboption("dashboard", Value, "dashboard_pwd", translate("Dashboard password"))
o.password = true
return m

View File

@ -0,0 +1,58 @@
-- Copyright 2020 lwz322 <lwz322@qq.com>
-- Licensed to the public under the MIT License.
local m, s, o
m = Map("frps")
m.title = translate("Frps - Server Settings")
m.description = translate("FRPS Server Settings")
s = m:section(NamedSection, "main", "frps")
s.anonymous = true
s.addremove = false
o = s:option(Value, "bind_port", translate("Bind port"))
o.datatype = "port"
o.rmempty = false
o = s:option(Value, "token", translate("Token"))
o.password = true
o = s:option(Flag, "tcp_mux", translate("TCP mux"))
o.enabled = "true"
o.disabled = "false"
o.defalut = o.enabled
o.rmempty = false
o = s:option(Flag, "tls_only", translate("Enforce frps only accept TLS connection"))
o.description = translatef("Requirements: frpc v0.25.0+, frps v0.32.0+")
o.enabled = "true"
o.disabled = "false"
o.default = o.disabled
o.rmempty = false
o = s:option(Value, "bind_udp_port", translate("UDP bind port"))
o.description = translatef("Optional: udp port to help make udp hole to penetrate nat")
o.datatype = "port"
o = s:option(Value, "kcp_bind_port", translate("KCP bind port"))
o.description = translatef("Optional: udp port used for kcp protocol, it can be same with 'bind port'; if not set, kcp is disabled in frps")
o.datatype = "port"
o = s:option(Value, "quic_bind_port", translate("Quic bind port"))
o.description = translatef("Optional: udp port used for quic protocol, it can be same with 'bind port'; if not set, quic is disabled in frps")
o.datatype = "port"
o = s:option(Value, "vhost_http_port", translate("vhost http port"))
o.description = translatef("Optional: if you want to support virtual host, you must set the http port for listening")
o.datatype = "port"
o = s:option(Value, "vhost_https_port", translate("vhost https port"))
o.description = translatef("Optional: Note: http port and https port can be same with bind_port")
o.datatype = "port"
o = s:option(DynamicList, "extra_setting", translate("Extra Settings"))
o.description = translatef("List of extra settings will be added to config file. Format: option=value, eg. <code>detailed_errors_to_client=false</code>.(NO SPACE!)")
o.placeholder = "option=value"
return m

View File

@ -0,0 +1,26 @@
<script type="text/javascript">//<![CDATA[
XHR.poll(3, '<%=url([[admin]], [[services]], [[frps]], [[status]])%>', null,
function(x, data) {
var tb = document.getElementById('frps_status');
if (data && tb) {
if (data.running) {
tb.innerHTML = '<em><b><font color=green> <%:Frps%>' + data.bin_version + '<%:RUNNING%></font></b></em><input class="btn cbi-button mar-10" type="button" value="<%:Open Frps page%>" onclick="openwebui();" />';
} else {
tb.innerHTML = '<em><b><font color=red> <%:Frps%>' + data.bin_version + '<%:NOT RUNNING%></font></b></em>';
}
}
}
);
function openwebui(){
var url = window.location.host+":<%=luci.sys.exec("uci -q get frps.main.dashboard_port"):gsub("^%s*(.-)%s*$", "%1")%>";
window.open('http://'+url,'target','');
}
//]]>
</script>
<style>.mar-10 {margin-left: 50px; margin-right: 10px;}</style>
<fieldset class="cbi-section">
<p id="frps_status">
<em><%:Collecting data...%></em>
</p>
</fieldset>

View File

@ -0,0 +1,264 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
#: luasrc/model/cbi/frps/common.lua:54
# msgid "-- default --"
# msgstr "-- 默认 --"
#: luasrc/model/cbi/frps/common.lua:44
msgid "Advanced Options"
msgstr "高级选项"
#: luasrc/model/cbi/frps/server.lua:14
msgid "Bind port"
msgstr "绑定端口"
#: luasrc/model/cbi/frps/common.lua:22
msgid "Client file"
msgstr "客户端文件"
#: luasrc/model/cbi/frps/common.lua:7
msgid "Frps - Common Settings"
msgstr "Frps - 通用设置"
msgid "Frp Server"
msgstr "Frp 服务器"
#: luasrc/model/cbi/frps/common.lua:18
msgid "Dashboard Options"
msgstr "面板选项"
#: luasrc/model/cbi/frps/common.lua:78
msgid "Dashboard addr"
msgstr "面板绑定地址"
#: luasrc/model/cbi/frps/common.lua:91
msgid "Dashboard password"
msgstr "面板登录密码"
#: luasrc/model/cbi/frps/common.lua:83
msgid "Dashboard port"
msgstr "面板绑定端口"
#: luasrc/model/cbi/frps/common.lua:88
msgid "Dashboard user"
msgstr "面板登录用户名"
#: luasrc/model/cbi/frps/common.lua:69
# msgid "Debug"
# msgstr "调试"
#: luasrc/model/cbi/frps/common.lua:80
msgid "Disable log color"
msgstr "禁用日志颜色"
#: luasrc/model/cbi/frps/common.lua:60
msgid "Enable logging"
msgstr "启用日志"
#: luasrc/model/cbi/frps/common.lua:47
msgid "Enabled"
msgstr "已启用"
#: luasrc/model/cbi/frps/common.lua:72
msgid "Error"
msgstr "错误"
#: luasrc/model/cbi/frps/server.lua:8
msgid "Frps - Server Settings"
msgstr "Frps - 服务器设定"
#: luasrc/model/cbi/frps/server.lua:8
msgid "FRPS Server Settings"
msgstr "Frps 服务器设定"
#: luasrc/model/cbi/frps/common.lua:32
msgid "Frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.<br/><a href=\"https://github.com/fatedier/frp\" target=\"_blank\">Project GitHub URL</a>"
msgstr "Frp 是一个可用于内网穿透的高性能的反向代理应用。<br/><a href=\"https://github.com/fatedier/frp\" target=\"_blank\">Github 项目地址</a>"
#: luasrc/model/cbi/frps/common.lua:43
msgid "General Options"
msgstr "常规选项"
#: luasrc/model/cbi/frps/common.lua:70
msgid "Info"
msgstr "信息"
#: luasrc/model/cbi/frps/server.lua:31
msgid "KCP bind port"
msgstr "KCP绑定端口"
#: luasrc/model/cbi/frps/server.lua:31
msgid "Quic bind port"
msgstr "QUIC绑定端口"
#: luasrc/model/cbi/frps/common.lua:62
msgid "Log file"
msgstr "日志文件"
#: luasrc/model/cbi/frps/common.lua:66
msgid "Log level"
msgstr "日志等级"
#: luasrc/model/cbi/frps/common.lua:48
msgid "Log max days"
msgstr "日志保存天数"
#: luasrc/model/cbi/frps/common.lua:49
msgid "Maximum number of days to keep log files is 3 day."
msgstr "保留日志文件的最大天数为 3 天。"
#: luasrc/model/cbi/frps/common.lua:85
msgid "Max pool count"
msgstr "最大连接数"
#: luasrc/model/cbi/frps/common.lua:89
msgid "Max ports per-client"
msgstr "单客户端最大端口映射数"
#: luasrc/view/frps/status_header.htm:26
msgid "Not Running"
msgstr "服务未运行"
#: luasrc/model/cbi/frps/server.lua:40
msgid "Optional: Note: http port and https port can be same with bind_port"
msgstr "可选提示http/https端口可以和绑定端口设定为一致"
#: luasrc/model/cbi/frps/server.lua:36
msgid ""
"Optional: if you want to support virtual host, you must set the http port "
"for listening"
msgstr "可选如果您希望支持虚拟主机则必须设定http端口"
#: luasrc/model/cbi/frps/server.lua:28
msgid "Optional: udp port to help make udp hole to penetrate nat"
msgstr "可选设定UDP端口以帮助UDP协议穿透NAT"
#: luasrc/model/cbi/frps/server.lua:32
msgid ""
"Optional: udp port used for kcp protocol, it can be same with 'bind port'; "
"if not set, kcp is disabled in frps"
msgstr "可选UDP端口用于KCP协议可与绑定端口设定为一致留空以禁用KCP"
#: luasrc/model/cbi/frps/server.lua:32
msgid ""
"Optional: udp port used for quic protocol, it can be same with 'bind port'; "
"if not set, quic is disabled in frps"
msgstr "可选UDP端口用于quic协议可与绑定端口设定为一致留空以禁用quic"
#: luasrc/model/cbi/frps/common.lua:53
msgid "Run daemon as user"
msgstr "以用户身份运行"
#: luasrc/controller/frps.lua:22
msgid "Server"
msgstr "服务端"
#: luasrc/controller/frps.lua:19
msgid "Settings"
msgstr "设置"
#: luasrc/model/cbi/frps/common.lua:95
msgid "Subdomain host"
msgstr "子域名"
#: luasrc/model/cbi/frps/server.lua:21
msgid "TCP mux"
msgstr "TCP 复用"
#: luasrc/model/cbi/frps/server.lua:27
msgid "Enforce frps only accept TLS connection"
msgstr "强制frps只接受TLS连接"
#: luasrc/model/cbi/frps/server.lua:28
msgid "Requirements: frpc v0.25.0+, frps v0.32.0+"
msgstr "要求frpc版本0.25.0+, frps版本0.32.0+"
#: luasrc/model/cbi/frps/server.lua:18
msgid "Token"
msgstr "令牌"
#: luasrc/model/cbi/frps/common.lua:68
msgid "Trace"
msgstr "追踪"
#: luasrc/model/cbi/frps/server.lua:27
msgid "UDP bind port"
msgstr "UDP绑定端口"
#: luasrc/model/cbi/frps/common.lua:71
msgid "Log level"
msgstr "日志等级"
#: luasrc/model/cbi/frps/common.lua:41
msgid "Trace"
msgstr "追踪"
#: luasrc/model/cbi/frps/common.lua:42
msgid "Debug"
msgstr "调试"
#: luasrc/model/cbi/frps/common.lua:43
msgid "Info"
msgstr "信息"
#: luasrc/model/cbi/frps/common.lua:44
msgid "Warning"
msgstr "警告"
#: luasrc/model/cbi/frps/common.lua:45
msgid "Error"
msgstr "错误"
#: luasrc/model/cbi/frps/common.lua:99
msgid "dashboard addr's default value is same with bind_addr"
msgstr "面板地址默认和绑定地址一致"
#: luasrc/model/cbi/frps/common.lua:102
msgid "dashboard is available only if dashboard_port is set"
msgstr "仅在设定面板绑定端口后才可使用面板功能"
#: luasrc/model/cbi/frps/common.lua:105
msgid ""
"dashboard user and passwd for basic auth protect, if not set, both default "
"value is admin"
msgstr "面板用户名/密码用于基本安全认证;若留空,则用户名/密码均为admin"
#: luasrc/model/cbi/frps/common.lua:96
msgid ""
"if subdomain_host is not empty, you can set subdomain when type is http or "
"https in frpc's configure file; when subdomain is test, the host used by "
"routing is test.frps.com"
msgstr "如果subdomain_host不为空可以在frpc配置文件中设置类型为http(s)的subdomainsubdomain为test路由将使用test.frps.com"
#: luasrc/model/cbi/frps/common.lua:90
msgid ""
"max ports can be used for each client, default value is 0 means no limit"
msgstr "每个客户端最多可映射端口数留空则默认为0不限制"
#: luasrc/model/cbi/frps/common.lua:86
msgid ""
"pool_count in each proxy will change to max_pool_count if they exceed the "
"maximum value"
msgstr "代理连接数(pool_count)超过最大值时将变更为最大连接数(max_pool_count)"
#: luasrc/model/cbi/frps/server.lua:35
msgid "vhost http port"
msgstr "虚拟主机http绑定端口"
#: luasrc/model/cbi/frps/server.lua:39
msgid "vhost https port"
msgstr "虚拟主机https绑定端口"
#: luasrc/model/cbi/frps/server.lua:50
msgid "Extra Settings"
msgstr "额外设置"
#: luasrc/model/cbi/frps/server.lua:51
msgid "List of extra settings will be added to config file. Format: option=value, eg. <code>detailed_errors_to_client=false</code>.(NO SPACE!)"
msgstr "额外设置列表将会被添加到config文件中。 格式option=value<code>detailed_errors_to_client=false</code>.(不含空格!)"
#: luasrc/view/frps/frps_status.htm:7
msgid "Open Frps page"
msgstr "打开 Frps 管理面板"

View File

@ -0,0 +1,8 @@
config frps 'main'
option enabled '0'
option server 'frps'
option dashboard_addr '0.0.0.0'
option client_file '/usr/bin/frps'
option bind_port '7000'
option dashboard_port '7500'
option tcp_mux 'true'

View File

@ -0,0 +1,198 @@
#!/bin/sh /etc/rc.common
#
# Copyright 2020 lwz322 <lwz322@qq.com>
# Licensed to the public under the MIT License.
#
START=99
USE_PROCD=1
NAME="frps"
CONFIG_FOLDER="/var/etc/$NAME"
_log() {
local level="$1" ; shift
local msg="$@"
logger -p "daemon.$level" -t "$NAME" "$msg"
echo "[$level] $msg" >&2
}
_info() {
_log "info" $@
}
_err() {
_log "err" $@
}
append_options() {
local file="$1" ; shift
local o v
for o in "$@" ; do
v="$(eval echo "\$$o")"
if [ -n "$v" ] ; then
# add brackets when ipv6 address
if ( echo "$o" | grep -qE 'addr|ip' ) &&
( echo "$v" | grep -q ':' ) ; then
v="[$v]"
fi
echo "${o} = $v" >>"$file"
fi
done
}
append_setting() {
local file="$1" ; shift
local s="$1"
if [ -n "$s" ] ; then
echo "$s" >>"$file"
fi
}
frps_scetion_validate() {
uci_validate_section "$NAME" "frps" "$1" \
'enabled:bool:0' \
'client_file:file:/usr/bin/frps' \
'run_user:string' \
'enable_logging:bool:0' \
'log_file:string:/var/log/frps.log' \
'log_level:or("trace", "debug", "info", "warn", "error"):warn' \
'log_max_days:uinteger:3' \
'disable_log_color:or("true", "false")' \
'max_pool_count:uinteger' \
'max_ports_per_client:uinteger:0' \
'subdomain_host:host' \
'dashboard_addr:host' \
'dashboard_port:port' \
'dashboard_user:string' \
'dashboard_pwd:string' \
'bind_port:port' \
'token:string' \
'tcp_mux:or("true", "false"):true' \
'tls_only:or("true", "false"):false' \
'bind_udp_port:port' \
'kcp_bind_port:port' \
'quic_bind_port:port' \
'vhost_http_port:port' \
'vhost_https_port:port'
}
client_file_validate() {
local file="$1"
test -f "$file" || return 1
test -x "$file" || chmod 755 "$file"
eval "$file" -h | grep -q "$NAME"
return $?
}
add_rule_extra_option() {
append_setting "$2" "$1"
}
create_config_file() {
local config_file="$1"
local tmp_file="$(mktemp /tmp/frps-XXXXXX)"
echo "[common]" > "$tmp_file"
append_options "$tmp_file" \
"bind_port" "token" "tcp_mux" "tls_only" "bind_udp_port" "kcp_bind_port" "quic_bind_port" "vhost_http_port" "vhost_https_port"
if [ "x$enable_logging" = "x1" ] ; then
if [ -z "$log_file" ]; then
log_file="/var/log/frps.log"
fi
append_options "$tmp_file" \
"log_file" "log_level" "log_max_days" "disable_log_color"
if [ -f "$log_file" ] ; then
echo > "$log_file"
else
local log_folder="$(dirname "$log_file")"
if [ ! -d "$log_folder" ] ; then
mkdir -p "$log_folder"
fi
fi
if [ -n "$run_user" ] && ( user_exists "$run_user" ) ; then
chmod 644 "$log_file"
chown "$run_user" "$log_file"
else
run_user=""
fi
fi
append_options "$tmp_file" \
"max_pool_count" "max_ports_per_client" "subdomain_host" "dashboard_addr" "dashboard_port" "dashboard_user" "dashboard_pwd"
extra_setting=$(uci get frps.main.extra_setting 2>/dev/null)
if [ -n "$extra_setting" ] ; then
for o in $extra_setting ;do
echo "$o" >> "$tmp_file"
done
fi
sed '/^$/d' "$tmp_file" >"$config_file"
if [ "$?" = "0" ] ; then
rm -f "$tmp_file"
fi
}
start_instance() {
local section="$1"
if ! frps_scetion_validate "$section" ; then
_err "Config validate failed."
return 1
fi
if [ "x$enabled" != "x1" ] ; then
_info "Instance \"$section\" disabled."
return 1
fi
if [ -z "$client_file" ] || ( ! client_file_validate "$client_file" ) ; then
_err "Client file not valid."
return 1
fi
test -d "$CONFIG_FOLDER" || mkdir -p "$CONFIG_FOLDER"
local config_file="$CONFIG_FOLDER/frps.$section.ini"
create_config_file "$config_file"
if [ ! -f "$config_file" ] ; then
_err "Could not create config file: \"$config_file\""
return 1
fi
procd_open_instance "$NAME.$section"
procd_set_param command "$client_file"
procd_append_param command -c "$config_file"
procd_set_param respawn
procd_set_param file "$config_file"
if [ -n "$run_user" ] ; then
procd_set_param user "$run_user"
fi
procd_close_instance
}
service_triggers() {
procd_add_reload_trigger "$NAME"
}
start_service() {
config_load "$NAME"
config_foreach start_instance "frps"
}

View File

@ -0,0 +1,11 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@frps[-1]
add ucitrack frps
set ucitrack.@frps[-1].init=frps
commit ucitrack
EOF
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
exit 0