From 6c9d45915956d06a81d35a10c6f867ecf9dc2e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=A0=E7=81=AB?= <35611650+leaplu@users.noreply.github.com> Date: Sun, 8 Mar 2020 12:50:24 +0800 Subject: [PATCH] Add frps and luci-app-frps (#3572) --- package/lean/frps/Makefile | 70 +++++++ package/lean/luci-app-frps/Makefile | 39 ++++ .../luci-app-frps/luasrc/controller/frps.lua | 43 ++++ .../luasrc/model/cbi/frps/common.lua | 110 ++++++++++ .../luasrc/model/cbi/frps/server.lua | 43 ++++ .../luasrc/view/frps/status_header.htm | 29 +++ .../lean/luci-app-frps/root/etc/config/frps | 6 + .../lean/luci-app-frps/root/etc/init.d/frps | 189 ++++++++++++++++++ .../root/etc/uci-defaults/40_luci-frps | 25 +++ 9 files changed, 554 insertions(+) create mode 100644 package/lean/frps/Makefile create mode 100644 package/lean/luci-app-frps/Makefile create mode 100644 package/lean/luci-app-frps/luasrc/controller/frps.lua create mode 100644 package/lean/luci-app-frps/luasrc/model/cbi/frps/common.lua create mode 100644 package/lean/luci-app-frps/luasrc/model/cbi/frps/server.lua create mode 100644 package/lean/luci-app-frps/luasrc/view/frps/status_header.htm create mode 100644 package/lean/luci-app-frps/root/etc/config/frps create mode 100644 package/lean/luci-app-frps/root/etc/init.d/frps create mode 100644 package/lean/luci-app-frps/root/etc/uci-defaults/40_luci-frps diff --git a/package/lean/frps/Makefile b/package/lean/frps/Makefile new file mode 100644 index 000000000..ea9829162 --- /dev/null +++ b/package/lean/frps/Makefile @@ -0,0 +1,70 @@ +# +# Copyright (C) 2015-2016 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v3. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=frps +PKG_VERSION:=0.31.2 +PKG_RELEASE:=1 + +ifeq ($(ARCH),mipsel) + FRPC_ARCH:=mipsle +endif +ifeq ($(ARCH),mips) + FRPC_ARCH:=mips +endif +ifeq ($(ARCH),i386) + FRPC_ARCH:=386 +endif +ifeq ($(ARCH),x86_64) + FRPC_ARCH:=amd64 +endif +ifeq ($(ARCH),arm) + FRPC_ARCH:=arm +endif +ifeq ($(ARCH),aarch64) + FRPC_ARCH:=arm64 +endif + +PKG_LICENSE:=Apache-2.0 + +PKG_SOURCE_URL:=https://github.com/fatedier/frp/releases/download/v$(PKG_VERSION) +PKG_SOURCE:=frp_$(PKG_VERSION)_linux_$(FRPC_ARCH).tar.gz +PKG_BUILD_DIR:=$(BUILD_DIR)/frp_$(PKG_VERSION)_linux_$(FRPC_ARCH) +PKG_HASH:=skip + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + TITLE:=FRPC Client + DEPENDS:= + URL:=https://github.com/fatedier/frp/releases +endef + + + +define Package/$(PKG_NAME)/description +frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet +endef + +define Build/Prepare + $(PKG_UNPACK) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/frps $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/package/lean/luci-app-frps/Makefile b/package/lean/luci-app-frps/Makefile new file mode 100644 index 000000000..3637e79ee --- /dev/null +++ b/package/lean/luci-app-frps/Makefile @@ -0,0 +1,39 @@ +# +# Copyright 2020 Weizheng Li +# Licensed to the public under the MIT License. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-frps +PKG_VERSION:=0.0.1 +PKG_RELEASE:=1 + +PKG_LICENSE:=MIT +PKG_LICENSE_FILES:=LICENSE + +PKG_MAINTAINER:=Weizheng Li + +LUCI_TITLE:=LuCI support for Frps +LUCI_DEPENDS:=+wget +frps +LUCI_PKGARCH:=all + +define Package/$(PKG_NAME)/conffiles +/etc/config/frps +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +define Package/$(PKG_NAME)/postinst +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + ( . /etc/uci-defaults/40_luci-frps ) && rm -f /etc/uci-defaults/40_luci-frps +fi + +chmod 755 "$${IPKG_INSTROOT}/etc/init.d/frps" >/dev/null 2>&1 +ln -sf "../init.d/frps" \ + "$${IPKG_INSTROOT}/etc/rc.d/S99frps" >/dev/null 2>&1 +exit 0 +endef + +# call BuildPackage - OpenWrt buildroot signature diff --git a/package/lean/luci-app-frps/luasrc/controller/frps.lua b/package/lean/luci-app-frps/luasrc/controller/frps.lua new file mode 100644 index 000000000..94916c0bd --- /dev/null +++ b/package/lean/luci-app-frps/luasrc/controller/frps.lua @@ -0,0 +1,43 @@ +-- Copyright 2020 Weizheng Li +-- Licensed to the public under the MIT License. + +local http = require "luci.http" +local uci = require "luci.model.uci".cursor() +local sys = require "luci.sys" + +module("luci.controller.frps", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/frps") then + return + end + + entry({"admin", "services", "frps"}, + firstchild(), _("Frps")).dependent = false + + entry({"admin", "services", "frps", "common"}, + cbi("frps/common"), _("Settings"), 1) + + entry({"admin", "services", "frps", "server"}, + cbi("frps/server"), _("Server"), 2).leaf = true + + entry({"admin", "services", "frps", "status"}, call("action_status")) +end + + +function action_status() + local running = false + + local client = uci:get("frps", "main", "client_file") + if client and client ~= "" then + local file_name = client:match(".*/([^/]+)$") or "" + if file_name ~= "" then + running = sys.call("pidof %s >/dev/null" % file_name) == 0 + end + end + + http.prepare_content("application/json") + http.write_json({ + running = running + }) +end diff --git a/package/lean/luci-app-frps/luasrc/model/cbi/frps/common.lua b/package/lean/luci-app-frps/luasrc/model/cbi/frps/common.lua new file mode 100644 index 000000000..ba42f3da6 --- /dev/null +++ b/package/lean/luci-app-frps/luasrc/model/cbi/frps/common.lua @@ -0,0 +1,110 @@ +-- Copyright 2020 Weizheng Li +-- Licensed to the public under the MIT License. + +local uci = require "luci.model.uci".cursor() +local util = require "luci.util" +local fs = require "nixio.fs" +local sys = require "luci.sys" + +local m, s, o +local server_table = { } + +local function frps_version() + local file = uci:get("frps", "main", "client_file") + + if not file or file == "" or not fs.stat(file) then + return "%s" % translate("Invalid client file") + end + + if not fs.access(file, "rwx", "rx", "rx") then + fs.chmod(file, 755) + end + + local version = util.trim(sys.exec("%s -v 2>/dev/null" % file)) + if version == "" then + return "%s" % translate("Can't get client version") + end + return translatef("Version: %s", version) +end + +m = Map("frps", "%s - %s" % { translate("Frps"), translate("Common Settings") }, +"

%s

%s

" % { + translate("Frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet."), + translatef("For more information, please visit: %s", + "https://github.com/fatedier/frp") +}) + +m:append(Template("frps/status_header")) + +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"), frps_version()) +o.datatype = "file" +o.rmempty = false + +o = s:taboption("general", ListValue, "run_user", translate("Run daemon as user")) +o:value("", translate("-- default --")) +local user +for user in 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.placeholder = "/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("Warn")) +o:value("error", translate("Error")) +o.default = "warn" + +o = s:taboption("general", Value, "log_max_days", translate("Log max days")) +o:depends("enable_logging", "1") +o.datatype = "uinteger" +o.placeholder = '3' + +o = s:taboption("general", Value, "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"), + 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"), + 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"), + 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"), translatef("dashboard addr's default value is same with bind_addr")) +o.datatype = "host" + +o = s:taboption("dashboard", Value, "dashboard_port", translate("Dashboard port"), translatef("dashboard is available only if dashboard_port is set")) +o.datatype = "port" + +o = s:taboption("dashboard", Value, "dashboard_user", translate("Dashboard user"), 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 diff --git a/package/lean/luci-app-frps/luasrc/model/cbi/frps/server.lua b/package/lean/luci-app-frps/luasrc/model/cbi/frps/server.lua new file mode 100644 index 000000000..44d4b38ca --- /dev/null +++ b/package/lean/luci-app-frps/luasrc/model/cbi/frps/server.lua @@ -0,0 +1,43 @@ +-- Copyright 2020 Weizheng Li +-- Licensed to the public under the MIT License. + +local dsp = require "luci.dispatcher" + +local m, s, o + +m = Map("frps", "%s - %s" % { translate("Frps"), translate("FRPS Server setting") }) + +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(Value, "bind_udp_port", translate("UDP bind port"), + 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"), + 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, "vhost_http_port", translate("vhost http port"), + 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"), + translatef("Optional: Note: http port and https port can be same with bind_port")) +o.datatype = "port" + +return m \ No newline at end of file diff --git a/package/lean/luci-app-frps/luasrc/view/frps/status_header.htm b/package/lean/luci-app-frps/luasrc/view/frps/status_header.htm new file mode 100644 index 000000000..7df8bf9e6 --- /dev/null +++ b/package/lean/luci-app-frps/luasrc/view/frps/status_header.htm @@ -0,0 +1,29 @@ +<%# + Copyright 2020 Weizheng Li + Licensed to the public under the MIT License. +-%> + +<% +local dsp = require "luci.dispatcher" +-%> + +
+

+ <%:Collecting data...%> +

+
+ + diff --git a/package/lean/luci-app-frps/root/etc/config/frps b/package/lean/luci-app-frps/root/etc/config/frps new file mode 100644 index 000000000..ab15b3385 --- /dev/null +++ b/package/lean/luci-app-frps/root/etc/config/frps @@ -0,0 +1,6 @@ +config frps 'main' + option enabled '0' + option server 'frps' + option client_file '/usr/bin/frps' + option bind_port '7000' + option tcp_mux 'true' \ No newline at end of file diff --git a/package/lean/luci-app-frps/root/etc/init.d/frps b/package/lean/luci-app-frps/root/etc/init.d/frps new file mode 100644 index 000000000..b524c5e0b --- /dev/null +++ b/package/lean/luci-app-frps/root/etc/init.d/frps @@ -0,0 +1,189 @@ +#!/bin/sh /etc/rc.common +# +# Copyright 2020 Weizheng Li +# 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' \ + 'bind_udp_port:port' \ + 'kcp_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" "bind_udp_port" "kcp_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" + + 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" +} diff --git a/package/lean/luci-app-frps/root/etc/uci-defaults/40_luci-frps b/package/lean/luci-app-frps/root/etc/uci-defaults/40_luci-frps new file mode 100644 index 000000000..b0f9d5783 --- /dev/null +++ b/package/lean/luci-app-frps/root/etc/uci-defaults/40_luci-frps @@ -0,0 +1,25 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@frps[-1] + add ucitrack frps + set ucitrack.@frps[-1].init=frps + commit ucitrack +EOF + +frps=$(uci -q get frps.@frps[-1]) + +if [ -z "$frps" ]; then + uci -q add frps frps +fi + +if [ "x$frps" != "xmain" ]; then + uci -q batch <<-EOF >/dev/null + rename frps.@frps[-1]="main" + set frps.main.enabled="0" + commit frps + EOF +fi + +rm -rf /tmp/luci-indexcache /tmp/luci-modulecache +exit 0