mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-01 06:03:56 +08:00
This commit is contained in:
1 parent
442d463b24
commit
516a4a541c
13 files changed
+2302
-73
No files matched your search
@@ -0,0 +1,80 @@
|
|||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=frp
|
||||||
|
PKG_VERSION:=0.70.1
|
||||||
|
PKG_RELEASE:=5
|
||||||
|
|
||||||
|
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||||
|
PKG_SOURCE_URL:=https://codeload.github.com/fatedier/frp/tar.gz/v$(PKG_VERSION)?
|
||||||
|
PKG_HASH:=skip
|
||||||
|
|
||||||
|
PKG_MAINTAINER:=Alexandru Ardelean <ardeleanalex@gmail.com>
|
||||||
|
PKG_LICENSE:=Apache-2.0
|
||||||
|
PKG_LICENSE_FILES:=LICENSE
|
||||||
|
|
||||||
|
PKG_BUILD_DEPENDS:=golang/host node/host
|
||||||
|
PKG_BUILD_PARALLEL:=1
|
||||||
|
PKG_BUILD_FLAGS:=no-mips16
|
||||||
|
|
||||||
|
GO_PKG:=github.com/fatedier/frp
|
||||||
|
GO_PKG_BUILD_PKG:=github.com/fatedier/frp/cmd/...
|
||||||
|
GO_PKG_LDFLAGS:=-s -w
|
||||||
|
GO_PKG_LDFLAGS_X:=github.com/fatedier/frp/pkg/util/version.version=$(PKG_VERSION)
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
|
||||||
|
|
||||||
|
define Build/Compile
|
||||||
|
( \
|
||||||
|
$(MAKE) -C $(PKG_BUILD_DIR)/web/frpc install ; \
|
||||||
|
$(MAKE) -C $(PKG_BUILD_DIR)/web/frps install ; \
|
||||||
|
$(MAKE) -C $(PKG_BUILD_DIR) web ; \
|
||||||
|
$(call GoPackage/Build/Compile) ; \
|
||||||
|
)
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/frp/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/bin/
|
||||||
|
$(INSTALL_DIR) $(1)/etc/config/
|
||||||
|
$(INSTALL_DIR) $(1)/etc/frp/$(2).d/
|
||||||
|
$(INSTALL_DIR) $(1)/etc/init.d/
|
||||||
|
|
||||||
|
$(INSTALL_BIN) $(GO_PKG_BUILD_BIN_DIR)/$(2) $(1)/usr/bin/
|
||||||
|
$(INSTALL_CONF) ./files/$(2).config $(1)/etc/config/$(2)
|
||||||
|
$(INSTALL_BIN) ./files/$(2).init $(1)/etc/init.d/$(2)
|
||||||
|
|
||||||
|
if [ -r ./files/$(2).uci-defaults ]; then \
|
||||||
|
$(INSTALL_DIR) $(1)/etc/uci-defaults; \
|
||||||
|
$(INSTALL_DATA) ./files/$(2).uci-defaults $(1)/etc/uci-defaults/$(2); \
|
||||||
|
fi
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/frp/template
|
||||||
|
define Package/$(1)
|
||||||
|
SECTION:=net
|
||||||
|
CATEGORY:=Network
|
||||||
|
SUBMENU:=Web Servers/Proxies
|
||||||
|
TITLE:=$(1) - fast reverse proxy $(2)
|
||||||
|
URL:=https://github.com/fatedier/frp
|
||||||
|
DEPENDS:=$(GO_ARCH_DEPENDS)
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/$(1)/description
|
||||||
|
$(1) is a fast reverse proxy $(2) that helps you expose a local server
|
||||||
|
behind a NAT or firewall to the internet.
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/$(1)/conffiles
|
||||||
|
/etc/config/$(1)
|
||||||
|
/etc/frp/$(1).d/
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/$(1)/install
|
||||||
|
$(call Package/frp/install,$$(1),$(1))
|
||||||
|
endef
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call Package/frp/template,frpc,client))
|
||||||
|
$(eval $(call Package/frp/template,frps,server))
|
||||||
|
$(eval $(call BuildPackage,frpc))
|
||||||
|
$(eval $(call BuildPackage,frps))
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
config init
|
||||||
|
option stdout '1'
|
||||||
|
option stderr '1'
|
||||||
|
# Uncomment to run frpc as an existing user/group. Keep disabled by
|
||||||
|
# default to avoid permission issues with certificate, log and included
|
||||||
|
# config files.
|
||||||
|
# option user 'nobody'
|
||||||
|
# option group 'nogroup'
|
||||||
|
option respawn '1'
|
||||||
|
# For full configuration options, see:
|
||||||
|
# https://github.com/fatedier/frp/blob/master/conf/frpc_full_example.toml
|
||||||
|
#
|
||||||
|
# Additional config files should be readable root-level TOML fragments.
|
||||||
|
# The service will refuse to start if a listed fragment is missing or outside /etc/frp/frpc.d/.
|
||||||
|
# Use frp's own includes option or per-proxy raw settings for proxy/visitor tables.
|
||||||
|
# list conf_inc '/etc/frp/frpc.d/frpc_extra.toml'
|
||||||
|
|
||||||
|
config conf 'common'
|
||||||
|
option server_addr '127.0.0.1'
|
||||||
|
option server_port '7000'
|
||||||
|
option authentication_method 'token'
|
||||||
|
# option token 'your_token'
|
||||||
|
# Alternatively, load a token from a file or command. Exec token sources
|
||||||
|
# require frpc to run with --allow-unsafe=TokenSourceExec; the init script
|
||||||
|
# adds that flag automatically when token_source_type is exec.
|
||||||
|
# option token_source_type 'file'
|
||||||
|
# option token_source_file_path '/etc/frp/client_token'
|
||||||
|
# option token_source_type 'exec'
|
||||||
|
# option token_source_exec_command '/usr/bin/get-frpc-token'
|
||||||
|
# list token_source_exec_args '--format'
|
||||||
|
# list token_source_exec_args 'raw'
|
||||||
|
# list token_source_exec_env 'TOKEN_SERVICE=production'
|
||||||
|
option login_fail_exit 'true'
|
||||||
|
option protocol 'tcp'
|
||||||
|
option wire_protocol 'v1'
|
||||||
|
option tcp_mux 'true'
|
||||||
|
option tls_enable 'true'
|
||||||
|
option disable_custom_tls_first_byte 'true'
|
||||||
|
# Web server is disabled when admin_port is empty or 0.
|
||||||
|
# option admin_addr '127.0.0.1'
|
||||||
|
# option admin_port '7400'
|
||||||
|
# option admin_user 'admin'
|
||||||
|
# option admin_pwd 'admin'
|
||||||
|
option admin_tls_enable 'false'
|
||||||
|
option pprof_enable 'false'
|
||||||
|
# option admin_tls_cert_file '/etc/ssl/acme/example.com.fullchain.crt'
|
||||||
|
# option admin_tls_key_file '/etc/ssl/acme/example.com.key'
|
||||||
|
option log_file 'console'
|
||||||
|
option log_level 'info'
|
||||||
|
option log_max_days '3'
|
||||||
|
# Uncomment to enable runtime proxy/visitor persistence via frpc web UI or API.
|
||||||
|
# option store_path '/etc/frp/frpc_store.json'
|
||||||
|
# List options with name "_" will be directly appended as raw TOML lines.
|
||||||
|
# Use this only for options not covered by UCI options above.
|
||||||
|
# Do not duplicate keys generated by UCI options above.
|
||||||
|
# list _ 'uncovered.option = "value"'
|
||||||
|
|
||||||
|
config conf 'ssh'
|
||||||
|
option name 'ssh'
|
||||||
|
option type 'tcp'
|
||||||
|
option local_ip '127.0.0.1'
|
||||||
|
option local_port '22'
|
||||||
|
option remote_port '6000'
|
||||||
|
option enabled 'true'
|
||||||
+1003
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,109 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
. /lib/functions.sh
|
||||||
|
|
||||||
|
changed=0
|
||||||
|
init_section=
|
||||||
|
package=frpc
|
||||||
|
|
||||||
|
find_init_section() {
|
||||||
|
[ -z "$init_section" ] && init_section="$1"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
set_if_empty() {
|
||||||
|
local section="$1"
|
||||||
|
local option="$2"
|
||||||
|
local value="$3"
|
||||||
|
local cur
|
||||||
|
|
||||||
|
config_get cur "$section" "$option"
|
||||||
|
|
||||||
|
if [ -z "$cur" ]; then
|
||||||
|
uci_set "$package" "$section" "$option" "$value"
|
||||||
|
changed=1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_if_empty() {
|
||||||
|
local section="$1"
|
||||||
|
local old_option="$2"
|
||||||
|
local new_option="$3"
|
||||||
|
local value
|
||||||
|
|
||||||
|
config_get value "$section" "$old_option"
|
||||||
|
[ -n "$value" ] || return 0
|
||||||
|
|
||||||
|
set_if_empty "$section" "$new_option" "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
upgrade_common() {
|
||||||
|
local section="$1"
|
||||||
|
local dashboard_tls_mode
|
||||||
|
|
||||||
|
[ "$section" = "common" ] || return 0
|
||||||
|
|
||||||
|
set_if_empty "$section" server_addr 127.0.0.1
|
||||||
|
set_if_empty "$section" server_port 7000
|
||||||
|
set_if_empty "$section" authentication_method token
|
||||||
|
set_if_empty "$section" login_fail_exit true
|
||||||
|
set_if_empty "$section" protocol tcp
|
||||||
|
set_if_empty "$section" wire_protocol v1
|
||||||
|
set_if_empty "$section" tcp_mux true
|
||||||
|
set_if_empty "$section" tls_enable true
|
||||||
|
set_if_empty "$section" disable_custom_tls_first_byte true
|
||||||
|
|
||||||
|
config_get dashboard_tls_mode "$section" dashboard_tls_mode
|
||||||
|
if [ -n "$dashboard_tls_mode" ]; then
|
||||||
|
set_if_empty "$section" admin_tls_enable "$dashboard_tls_mode"
|
||||||
|
else
|
||||||
|
set_if_empty "$section" admin_tls_enable false
|
||||||
|
fi
|
||||||
|
|
||||||
|
copy_if_empty "$section" dashboard_addr admin_addr
|
||||||
|
copy_if_empty "$section" dashboard_port admin_port
|
||||||
|
copy_if_empty "$section" dashboard_user admin_user
|
||||||
|
copy_if_empty "$section" dashboard_pwd admin_pwd
|
||||||
|
copy_if_empty "$section" dashboard_tls_cert_file admin_tls_cert_file
|
||||||
|
copy_if_empty "$section" dashboard_tls_key_file admin_tls_key_file
|
||||||
|
|
||||||
|
set_if_empty "$section" pprof_enable false
|
||||||
|
set_if_empty "$section" log_file console
|
||||||
|
set_if_empty "$section" log_level info
|
||||||
|
set_if_empty "$section" log_max_days 3
|
||||||
|
}
|
||||||
|
|
||||||
|
upgrade_init() {
|
||||||
|
if [ -z "$init_section" ]; then
|
||||||
|
init_section="$(uci add "$package" init)" || return 0
|
||||||
|
changed=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set_if_empty "$init_section" stdout 1
|
||||||
|
set_if_empty "$init_section" stderr 1
|
||||||
|
set_if_empty "$init_section" respawn 1
|
||||||
|
}
|
||||||
|
|
||||||
|
upgrade_proxy_name() {
|
||||||
|
local section="$1"
|
||||||
|
local name
|
||||||
|
|
||||||
|
[ "$section" != "common" ] || return 0
|
||||||
|
|
||||||
|
config_get name "$section" name
|
||||||
|
|
||||||
|
if [ -z "$name" ]; then
|
||||||
|
uci_set "$package" "$section" name "$section"
|
||||||
|
changed=1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
config_load "$package"
|
||||||
|
config_foreach find_init_section init
|
||||||
|
upgrade_init
|
||||||
|
config_foreach upgrade_common conf
|
||||||
|
config_foreach upgrade_proxy_name conf
|
||||||
|
|
||||||
|
[ "$changed" -eq 1 ] && uci_commit "$package"
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
config init
|
||||||
|
option stdout '1'
|
||||||
|
option stderr '1'
|
||||||
|
# Uncomment to run frps as an existing user/group. Keep disabled by
|
||||||
|
# default to avoid permission issues with certificate, log and included
|
||||||
|
# config files.
|
||||||
|
# option user 'nobody'
|
||||||
|
# option group 'nogroup'
|
||||||
|
option respawn '1'
|
||||||
|
# For full configuration options, see:
|
||||||
|
# https://github.com/fatedier/frp/blob/master/conf/frps_full_example.toml
|
||||||
|
#
|
||||||
|
# Additional config files should be readable root-level TOML fragments.
|
||||||
|
# The service will refuse to start if a listed fragment is missing or outside /etc/frp/frps.d/.
|
||||||
|
# Use raw settings below for table-specific extra options such as HTTP plugins.
|
||||||
|
# list conf_inc '/etc/frp/frps.d/frps_extra.toml'
|
||||||
|
|
||||||
|
config conf 'common'
|
||||||
|
option bind_addr '0.0.0.0'
|
||||||
|
option bind_port '7000'
|
||||||
|
|
||||||
|
option authentication_method 'token'
|
||||||
|
# option token 'your_token'
|
||||||
|
# Alternatively, load a token from a file or command. Exec token sources
|
||||||
|
# require frps to run with --allow-unsafe=TokenSourceExec; the init script
|
||||||
|
# adds that flag automatically when token_source_type is exec.
|
||||||
|
# option token_source_type 'file'
|
||||||
|
# option token_source_file_path '/etc/frp/server_token'
|
||||||
|
# option token_source_type 'exec'
|
||||||
|
# option token_source_exec_command '/usr/bin/get-frps-token'
|
||||||
|
# list token_source_exec_args '--format'
|
||||||
|
# list token_source_exec_args 'raw'
|
||||||
|
# list token_source_exec_env 'TOKEN_SERVICE=production'
|
||||||
|
|
||||||
|
option max_pool_count '5'
|
||||||
|
option tcp_mux 'true'
|
||||||
|
option tls_force 'false'
|
||||||
|
option detailed_errors_to_client 'true'
|
||||||
|
|
||||||
|
# Web server is disabled when admin_port is empty or 0.
|
||||||
|
# option admin_addr '127.0.0.1'
|
||||||
|
# option admin_port '7500'
|
||||||
|
# option admin_user 'admin'
|
||||||
|
# option admin_pwd 'admin'
|
||||||
|
option admin_tls_enable 'false'
|
||||||
|
option pprof_enable 'false'
|
||||||
|
option enable_prometheus 'false'
|
||||||
|
# option admin_tls_cert_file '/etc/ssl/acme/example.com.fullchain.crt'
|
||||||
|
# option admin_tls_key_file '/etc/ssl/acme/example.com.key'
|
||||||
|
|
||||||
|
# Allow ports can be single ports or ranges.
|
||||||
|
# list allow_ports '2000-3000'
|
||||||
|
# list allow_ports '3001'
|
||||||
|
|
||||||
|
option log_file 'console'
|
||||||
|
option log_level 'info'
|
||||||
|
option log_max_days '3'
|
||||||
|
|
||||||
|
# List options with name "_" will be directly appended as raw TOML lines.
|
||||||
|
# Use this only for options not covered by UCI options above.
|
||||||
|
# Do not duplicate keys generated by UCI options above.
|
||||||
|
# list _ 'uncovered.option = "value"'
|
||||||
|
|
||||||
|
# HTTP plugin hooks for frps. This emits [[httpPlugins]] TOML tables.
|
||||||
|
#config http_plugin 'user_manager'
|
||||||
|
# option name 'user-manager'
|
||||||
|
# option addr '127.0.0.1:9000'
|
||||||
|
# option path '/handler'
|
||||||
|
# list ops 'Login'
|
||||||
|
# option tls_verify 'false'
|
||||||
|
|
||||||
|
#config http_plugin 'port_manager'
|
||||||
|
# option name 'port-manager'
|
||||||
|
# option addr '127.0.0.1:9001'
|
||||||
|
# option path '/handler'
|
||||||
|
# list ops 'NewProxy'
|
||||||
|
# option tls_verify 'false'
|
||||||
@@ -0,0 +1,780 @@
|
|||||||
|
#!/bin/sh /etc/rc.common
|
||||||
|
|
||||||
|
START=99
|
||||||
|
USE_PROCD=1
|
||||||
|
|
||||||
|
NAME=frps
|
||||||
|
PROG=/usr/bin/$NAME
|
||||||
|
CONF_FILE=/var/etc/$NAME.toml
|
||||||
|
|
||||||
|
_err() {
|
||||||
|
echo "$*" >&2
|
||||||
|
logger -p daemon.err -t "$NAME" "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
_trim() {
|
||||||
|
printf '%s' "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
_toml_escape() {
|
||||||
|
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
|
||||||
|
}
|
||||||
|
|
||||||
|
_toml_quote() {
|
||||||
|
printf '"%s"' "$(_toml_escape "$1")"
|
||||||
|
}
|
||||||
|
|
||||||
|
_toml_key_quote() {
|
||||||
|
_toml_quote "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_toml_bool() {
|
||||||
|
local v
|
||||||
|
v="$(printf '%s' "$1" | tr 'A-Z' 'a-z')"
|
||||||
|
|
||||||
|
case "$v" in
|
||||||
|
1|true|yes|on|enabled)
|
||||||
|
printf 'true'
|
||||||
|
;;
|
||||||
|
0|false|no|off|disabled)
|
||||||
|
printf 'false'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf 'false'
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_TOML_ERR=0
|
||||||
|
_ALLOW_UNSAFE_TOKEN_SOURCE_EXEC=0
|
||||||
|
|
||||||
|
_is_uinteger() {
|
||||||
|
case "$1" in
|
||||||
|
''|*[!0-9]*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_integer() {
|
||||||
|
local value="$1"
|
||||||
|
|
||||||
|
case "$value" in
|
||||||
|
+*|-*)
|
||||||
|
value="${value#?}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_is_uinteger "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_port_value() {
|
||||||
|
_is_uinteger "$1" || return 1
|
||||||
|
[ "$1" -ge 1 ] 2>/dev/null && [ "$1" -le 65535 ] 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_port_or_zero_value() {
|
||||||
|
_is_uinteger "$1" || return 1
|
||||||
|
[ "$1" -ge 0 ] 2>/dev/null && [ "$1" -le 65535 ] 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_toml_line() {
|
||||||
|
local key="$1"
|
||||||
|
local value="$2"
|
||||||
|
local type="$3"
|
||||||
|
|
||||||
|
[ -z "$value" ] && return 0
|
||||||
|
|
||||||
|
case "$type" in
|
||||||
|
bool)
|
||||||
|
printf '%s = %s\n' "$key" "$(_toml_bool "$value")"
|
||||||
|
;;
|
||||||
|
int|integer|number)
|
||||||
|
if ! _is_integer "$value"; then
|
||||||
|
_err "invalid integer for $key: $value"
|
||||||
|
_TOML_ERR=1
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s = %s\n' "$key" "$value"
|
||||||
|
;;
|
||||||
|
port)
|
||||||
|
if ! _is_port_value "$value"; then
|
||||||
|
_err "invalid port for $key: $value"
|
||||||
|
_TOML_ERR=1
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s = %s\n' "$key" "$value"
|
||||||
|
;;
|
||||||
|
port0)
|
||||||
|
if ! _is_port_or_zero_value "$value"; then
|
||||||
|
_err "invalid port for $key: $value"
|
||||||
|
_TOML_ERR=1
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s = %s\n' "$key" "$value"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf '%s = %s\n' "$key" "$(_toml_quote "$value")"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_opt() {
|
||||||
|
local section="$1"
|
||||||
|
local option="$2"
|
||||||
|
local toml_key="$3"
|
||||||
|
local type="$4"
|
||||||
|
local value
|
||||||
|
|
||||||
|
config_get value "$section" "$option"
|
||||||
|
_toml_line "$toml_key" "$value" "$type"
|
||||||
|
}
|
||||||
|
|
||||||
|
_TOML_ARRAY=
|
||||||
|
_TOML_HAS_LIST=0
|
||||||
|
|
||||||
|
_toml_array_add() {
|
||||||
|
local item="$1"
|
||||||
|
|
||||||
|
item="$(_trim "$item")"
|
||||||
|
[ -z "$item" ] && return 0
|
||||||
|
|
||||||
|
if [ -n "$_TOML_ARRAY" ]; then
|
||||||
|
_TOML_ARRAY="${_TOML_ARRAY}, "
|
||||||
|
fi
|
||||||
|
|
||||||
|
_TOML_ARRAY="${_TOML_ARRAY}$(_toml_quote "$item")"
|
||||||
|
}
|
||||||
|
|
||||||
|
_collect_array_item() {
|
||||||
|
_TOML_HAS_LIST=1
|
||||||
|
_toml_array_add "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_collect_array_option() {
|
||||||
|
local section="$1"
|
||||||
|
local option="$2"
|
||||||
|
local scalar item
|
||||||
|
|
||||||
|
_TOML_ARRAY=
|
||||||
|
_TOML_HAS_LIST=0
|
||||||
|
|
||||||
|
config_list_foreach "$section" "$option" _collect_array_item
|
||||||
|
|
||||||
|
if [ "$_TOML_HAS_LIST" = "0" ]; then
|
||||||
|
config_get scalar "$section" "$option"
|
||||||
|
|
||||||
|
while [ -n "$scalar" ]; do
|
||||||
|
case "$scalar" in
|
||||||
|
*,*)
|
||||||
|
item="${scalar%%,*}"
|
||||||
|
scalar="${scalar#*,}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
item="$scalar"
|
||||||
|
scalar=
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_toml_array_add "$item"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_array_opt() {
|
||||||
|
local section="$1"
|
||||||
|
local option="$2"
|
||||||
|
local toml_key="$3"
|
||||||
|
|
||||||
|
_collect_array_option "$section" "$option"
|
||||||
|
|
||||||
|
[ -n "$_TOML_ARRAY" ] || return 0
|
||||||
|
printf '%s = [%s]\n' "$toml_key" "$_TOML_ARRAY"
|
||||||
|
}
|
||||||
|
|
||||||
|
_NAME_VALUE_ARRAY=
|
||||||
|
_NAME_VALUE_HAS_LIST=0
|
||||||
|
|
||||||
|
_name_value_array_add() {
|
||||||
|
local line="$1"
|
||||||
|
local key value item
|
||||||
|
|
||||||
|
case "$line" in
|
||||||
|
*=*)
|
||||||
|
key="${line%%=*}"
|
||||||
|
value="${line#*=}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
key="$(_trim "$key")"
|
||||||
|
value="$(_trim "$value")"
|
||||||
|
|
||||||
|
[ -n "$key" ] || return 0
|
||||||
|
|
||||||
|
item="{ name = $(_toml_quote "$key"), value = $(_toml_quote "$value") }"
|
||||||
|
|
||||||
|
if [ -n "$_NAME_VALUE_ARRAY" ]; then
|
||||||
|
_NAME_VALUE_ARRAY="${_NAME_VALUE_ARRAY}, "
|
||||||
|
fi
|
||||||
|
|
||||||
|
_NAME_VALUE_ARRAY="${_NAME_VALUE_ARRAY}${item}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_collect_name_value_item() {
|
||||||
|
_NAME_VALUE_HAS_LIST=1
|
||||||
|
_name_value_array_add "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_name_value_array_opt() {
|
||||||
|
local section="$1"
|
||||||
|
local option="$2"
|
||||||
|
local toml_key="$3"
|
||||||
|
local scalar
|
||||||
|
|
||||||
|
_NAME_VALUE_ARRAY=
|
||||||
|
_NAME_VALUE_HAS_LIST=0
|
||||||
|
|
||||||
|
config_list_foreach "$section" "$option" _collect_name_value_item
|
||||||
|
|
||||||
|
if [ "$_NAME_VALUE_HAS_LIST" = "0" ]; then
|
||||||
|
config_get scalar "$section" "$option"
|
||||||
|
[ -n "$scalar" ] && _name_value_array_add "$scalar"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -n "$_NAME_VALUE_ARRAY" ] || return 0
|
||||||
|
printf '%s = [%s]\n' "$toml_key" "$_NAME_VALUE_ARRAY"
|
||||||
|
}
|
||||||
|
|
||||||
|
_RAW_HAS_LIST=0
|
||||||
|
|
||||||
|
_emit_raw_item() {
|
||||||
|
_RAW_HAS_LIST=1
|
||||||
|
[ -n "$1" ] || return 0
|
||||||
|
printf '%s\n' "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_raw_opt() {
|
||||||
|
local section="$1"
|
||||||
|
local option="$2"
|
||||||
|
local scalar
|
||||||
|
|
||||||
|
_RAW_HAS_LIST=0
|
||||||
|
config_list_foreach "$section" "$option" _emit_raw_item
|
||||||
|
|
||||||
|
if [ "$_RAW_HAS_LIST" = "0" ]; then
|
||||||
|
config_get scalar "$section" "$option"
|
||||||
|
[ -n "$scalar" ] || return 0
|
||||||
|
printf '%s\n' "$scalar"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_port() {
|
||||||
|
_is_port_value "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_ALLOW_PORTS_ARRAY=
|
||||||
|
_ALLOW_PORTS_HAS_LIST=0
|
||||||
|
_ALLOW_PORTS_ERR=0
|
||||||
|
|
||||||
|
_allow_ports_array_add() {
|
||||||
|
local item="$1"
|
||||||
|
local start end table
|
||||||
|
|
||||||
|
item="$(_trim "$item")"
|
||||||
|
[ -z "$item" ] && return 0
|
||||||
|
|
||||||
|
case "$item" in
|
||||||
|
\{*\})
|
||||||
|
table="$item"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*-*)
|
||||||
|
start="${item%%-*}"
|
||||||
|
end="${item#*-}"
|
||||||
|
|
||||||
|
start="$(_trim "$start")"
|
||||||
|
end="$(_trim "$end")"
|
||||||
|
|
||||||
|
if ! _is_port "$start" || ! _is_port "$end"; then
|
||||||
|
_err "invalid allow_ports range: $item"
|
||||||
|
_ALLOW_PORTS_ERR=1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$start" -gt "$end" ]; then
|
||||||
|
_err "invalid allow_ports range, start is greater than end: $item"
|
||||||
|
_ALLOW_PORTS_ERR=1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$start" = "$end" ]; then
|
||||||
|
table="{ single = $start }"
|
||||||
|
else
|
||||||
|
table="{ start = $start, end = $end }"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
if ! _is_port "$item"; then
|
||||||
|
_err "invalid allow_ports value: $item"
|
||||||
|
_ALLOW_PORTS_ERR=1
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
table="{ single = $item }"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n "$_ALLOW_PORTS_ARRAY" ]; then
|
||||||
|
_ALLOW_PORTS_ARRAY="${_ALLOW_PORTS_ARRAY}, "
|
||||||
|
fi
|
||||||
|
|
||||||
|
_ALLOW_PORTS_ARRAY="${_ALLOW_PORTS_ARRAY}${table}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_collect_allow_port_item() {
|
||||||
|
_ALLOW_PORTS_HAS_LIST=1
|
||||||
|
_allow_ports_array_add "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_allow_ports() {
|
||||||
|
local section="$1"
|
||||||
|
local option="$2"
|
||||||
|
local scalar item
|
||||||
|
|
||||||
|
_ALLOW_PORTS_ARRAY=
|
||||||
|
_ALLOW_PORTS_HAS_LIST=0
|
||||||
|
_ALLOW_PORTS_ERR=0
|
||||||
|
|
||||||
|
config_list_foreach "$section" "$option" _collect_allow_port_item
|
||||||
|
|
||||||
|
if [ "$_ALLOW_PORTS_HAS_LIST" = "0" ]; then
|
||||||
|
config_get scalar "$section" "$option"
|
||||||
|
|
||||||
|
while [ -n "$scalar" ]; do
|
||||||
|
case "$scalar" in
|
||||||
|
*,*)
|
||||||
|
item="${scalar%%,*}"
|
||||||
|
scalar="${scalar#*,}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
item="$scalar"
|
||||||
|
scalar=
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_allow_ports_array_add "$item"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$_ALLOW_PORTS_ERR" = "0" ] || return 1
|
||||||
|
[ -n "$_ALLOW_PORTS_ARRAY" ] || return 0
|
||||||
|
|
||||||
|
printf 'allowPorts = [%s]\n' "$_ALLOW_PORTS_ARRAY"
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_auth_scopes() {
|
||||||
|
local section="$1"
|
||||||
|
local hb nwc v
|
||||||
|
|
||||||
|
_collect_array_option "$section" auth_additional_scopes
|
||||||
|
|
||||||
|
if [ -z "$_TOML_ARRAY" ]; then
|
||||||
|
config_get hb "$section" authenticate_heartbeats
|
||||||
|
config_get nwc "$section" authenticate_new_work_conns
|
||||||
|
|
||||||
|
v="$(_toml_bool "$hb")"
|
||||||
|
[ "$v" = "true" ] && _toml_array_add "HeartBeats"
|
||||||
|
|
||||||
|
v="$(_toml_bool "$nwc")"
|
||||||
|
[ "$v" = "true" ] && _toml_array_add "NewWorkConns"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -n "$_TOML_ARRAY" ] || return 0
|
||||||
|
printf 'auth.additionalScopes = [%s]\n' "$_TOML_ARRAY"
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_admin_web_tls() {
|
||||||
|
local section="$1"
|
||||||
|
local enabled cert key
|
||||||
|
|
||||||
|
config_get enabled "$section" admin_tls_enable
|
||||||
|
|
||||||
|
[ "$(_toml_bool "$enabled")" = "true" ] || return 0
|
||||||
|
|
||||||
|
config_get cert "$section" admin_tls_cert_file
|
||||||
|
config_get key "$section" admin_tls_key_file
|
||||||
|
|
||||||
|
if [ -z "$cert" ] || [ -z "$key" ]; then
|
||||||
|
_err "admin_tls_cert_file and admin_tls_key_file are required when admin_tls_enable is enabled"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -r "$cert" ]; then
|
||||||
|
_err "admin TLS certificate file is not readable: $cert"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -r "$key" ]; then
|
||||||
|
_err "admin TLS private key file is not readable: $key"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_toml_line webServer.tls.certFile "$cert" string
|
||||||
|
_toml_line webServer.tls.keyFile "$key" string
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_admin_web() {
|
||||||
|
local section="$1"
|
||||||
|
local port addr
|
||||||
|
|
||||||
|
config_get port "$section" admin_port
|
||||||
|
|
||||||
|
# Empty or 0 means web server is disabled.
|
||||||
|
[ -n "$port" ] && [ "$port" != "0" ] || return 0
|
||||||
|
|
||||||
|
config_get addr "$section" admin_addr
|
||||||
|
_toml_line webServer.addr "${addr:-127.0.0.1}" string
|
||||||
|
_toml_line webServer.port "$port" port
|
||||||
|
_emit_opt "$section" admin_user webServer.user string
|
||||||
|
_emit_opt "$section" admin_pwd webServer.password string
|
||||||
|
_emit_admin_web_tls "$section" || return 1
|
||||||
|
_emit_opt "$section" assets_dir webServer.assetsDir string
|
||||||
|
_emit_opt "$section" pprof_enable webServer.pprofEnable bool
|
||||||
|
_emit_opt "$section" enable_prometheus enablePrometheus bool
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_common() {
|
||||||
|
local section="common"
|
||||||
|
local method token token_source_type token_source_file_path
|
||||||
|
|
||||||
|
# Root options
|
||||||
|
_emit_opt "$section" bind_addr bindAddr string
|
||||||
|
_emit_opt "$section" bind_port bindPort port
|
||||||
|
_emit_opt "$section" kcp_bind_port kcpBindPort port0
|
||||||
|
_emit_opt "$section" quic_bind_port quicBindPort port0
|
||||||
|
_emit_opt "$section" proxy_bind_addr proxyBindAddr string
|
||||||
|
_emit_opt "$section" vhost_http_port vhostHTTPPort port0
|
||||||
|
_emit_opt "$section" vhost_https_port vhostHTTPSPort port0
|
||||||
|
_emit_opt "$section" vhost_http_timeout vhostHTTPTimeout int
|
||||||
|
_emit_opt "$section" tcpmux_httpconnect_port tcpmuxHTTPConnectPort port0
|
||||||
|
_emit_opt "$section" tcpmux_passthrough tcpmuxPassthrough bool
|
||||||
|
_emit_opt "$section" subdomain_host subDomainHost string
|
||||||
|
_emit_opt "$section" custom_404_page custom404Page string
|
||||||
|
_emit_opt "$section" udp_packet_size udpPacketSize int
|
||||||
|
_emit_opt "$section" detailed_errors_to_client detailedErrorsToClient bool
|
||||||
|
_emit_opt "$section" user_conn_timeout userConnTimeout int
|
||||||
|
_emit_opt "$section" nathole_analysis_data_reserve_hours natholeAnalysisDataReserveHours int
|
||||||
|
|
||||||
|
# Auth
|
||||||
|
config_get method "$section" authentication_method
|
||||||
|
config_get token "$section" token
|
||||||
|
config_get token_source_type "$section" token_source_type
|
||||||
|
config_get token_source_file_path "$section" token_source_file_path
|
||||||
|
|
||||||
|
[ -z "$method" ] && { [ -n "$token" ] || [ -n "$token_source_type" ]; } && method="token"
|
||||||
|
|
||||||
|
_toml_line auth.method "$method" string
|
||||||
|
|
||||||
|
if [ "$method" = "token" ] || [ -z "$method" ]; then
|
||||||
|
if [ -n "$token_source_type" ]; then
|
||||||
|
if [ -n "$token" ]; then
|
||||||
|
_err "token and token_source_type are mutually exclusive"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$token_source_type" in
|
||||||
|
file)
|
||||||
|
if [ -z "$token_source_file_path" ]; then
|
||||||
|
_err "token_source_file_path is required when token_source_type=file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_toml_line auth.tokenSource.type "$token_source_type" string
|
||||||
|
_toml_line auth.tokenSource.file.path "$token_source_file_path" string
|
||||||
|
;;
|
||||||
|
|
||||||
|
exec)
|
||||||
|
local token_source_exec_command
|
||||||
|
|
||||||
|
config_get token_source_exec_command "$section" token_source_exec_command
|
||||||
|
if [ -z "$token_source_exec_command" ]; then
|
||||||
|
_err "token_source_exec_command is required when token_source_type=exec"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_ALLOW_UNSAFE_TOKEN_SOURCE_EXEC=1
|
||||||
|
_toml_line auth.tokenSource.type "$token_source_type" string
|
||||||
|
_toml_line auth.tokenSource.exec.command "$token_source_exec_command" string
|
||||||
|
_emit_array_opt "$section" token_source_exec_args auth.tokenSource.exec.args
|
||||||
|
_emit_name_value_array_opt "$section" token_source_exec_env auth.tokenSource.exec.env
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
_err "unsupported token_source_type: $token_source_type"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
_toml_line auth.token "$token" string
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_emit_auth_scopes "$section"
|
||||||
|
|
||||||
|
if [ "$method" = "oidc" ]; then
|
||||||
|
_emit_opt "$section" oidc_issuer auth.oidc.issuer string
|
||||||
|
_emit_opt "$section" oidc_audience auth.oidc.audience string
|
||||||
|
_emit_opt "$section" oidc_skip_expiry_check auth.oidc.skipExpiryCheck bool
|
||||||
|
_emit_opt "$section" oidc_skip_issuer_check auth.oidc.skipIssuerCheck bool
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Transport
|
||||||
|
_emit_opt "$section" max_pool_count transport.maxPoolCount int
|
||||||
|
_emit_opt "$section" tcp_mux transport.tcpMux bool
|
||||||
|
_emit_opt "$section" tcp_mux_keepalive_interval transport.tcpMuxKeepaliveInterval int
|
||||||
|
_emit_opt "$section" tcp_keepalive transport.tcpKeepalive int
|
||||||
|
_emit_opt "$section" heartbeat_timeout transport.heartbeatTimeout int
|
||||||
|
|
||||||
|
# QUIC
|
||||||
|
_emit_opt "$section" quic_keepalive_period transport.quic.keepalivePeriod int
|
||||||
|
_emit_opt "$section" quic_max_idle_timeout transport.quic.maxIdleTimeout int
|
||||||
|
_emit_opt "$section" quic_max_incoming_streams transport.quic.maxIncomingStreams int
|
||||||
|
|
||||||
|
# TLS
|
||||||
|
_emit_opt "$section" tls_force transport.tls.force bool
|
||||||
|
_emit_opt "$section" tls_cert_file transport.tls.certFile string
|
||||||
|
_emit_opt "$section" tls_key_file transport.tls.keyFile string
|
||||||
|
_emit_opt "$section" tls_trusted_ca_file transport.tls.trustedCaFile string
|
||||||
|
|
||||||
|
# Web dashboard server
|
||||||
|
_emit_admin_web "$section" || return 1
|
||||||
|
|
||||||
|
# Access control
|
||||||
|
_emit_allow_ports "$section" allow_ports || return 1
|
||||||
|
_emit_opt "$section" max_ports_per_client maxPortsPerClient int
|
||||||
|
|
||||||
|
# SSH tunnel gateway
|
||||||
|
_emit_opt "$section" ssh_tunnel_bind_port sshTunnelGateway.bindPort port0
|
||||||
|
_emit_opt "$section" ssh_tunnel_private_key_file sshTunnelGateway.privateKeyFile string
|
||||||
|
_emit_opt "$section" ssh_tunnel_auto_gen_private_key_path sshTunnelGateway.autoGenPrivateKeyPath string
|
||||||
|
_emit_opt "$section" ssh_tunnel_authorized_keys_file sshTunnelGateway.authorizedKeysFile string
|
||||||
|
|
||||||
|
# Log
|
||||||
|
_emit_opt "$section" log_file log.to string
|
||||||
|
_emit_opt "$section" log_level log.level string
|
||||||
|
_emit_opt "$section" log_max_days log.maxDays int
|
||||||
|
_emit_opt "$section" disable_log_color log.disablePrintColor bool
|
||||||
|
|
||||||
|
# Raw extra TOML lines kept for manual UCI usage; LuCI intentionally hides this.
|
||||||
|
_emit_raw_opt "$section" _
|
||||||
|
}
|
||||||
|
|
||||||
|
_emit_http_plugin() {
|
||||||
|
local section="$1"
|
||||||
|
local name addr path
|
||||||
|
|
||||||
|
config_get name "$section" name "$section"
|
||||||
|
config_get addr "$section" addr
|
||||||
|
config_get path "$section" path
|
||||||
|
|
||||||
|
if [ -z "$addr" ] || [ -z "$path" ]; then
|
||||||
|
_err "http plugin $name requires addr and path"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_collect_array_option "$section" ops
|
||||||
|
|
||||||
|
if [ -z "$_TOML_ARRAY" ]; then
|
||||||
|
_err "http plugin $name requires at least one operation"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '\n[[httpPlugins]]\n'
|
||||||
|
_toml_line name "$name" string
|
||||||
|
_toml_line addr "$addr" string
|
||||||
|
_toml_line path "$path" string
|
||||||
|
printf 'ops = [%s]\n' "$_TOML_ARRAY"
|
||||||
|
_emit_opt "$section" tls_verify tlsVerify bool
|
||||||
|
|
||||||
|
# Raw extra TOML lines for plugin options not covered by UCI options above.
|
||||||
|
_emit_raw_opt "$section" _
|
||||||
|
}
|
||||||
|
|
||||||
|
_find_init_section() {
|
||||||
|
[ -z "$init_cfg" ] && init_cfg="$1"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_append_conf_file() {
|
||||||
|
local file="$1"
|
||||||
|
local dir="/etc/frp/$NAME.d/"
|
||||||
|
local real_file
|
||||||
|
|
||||||
|
case "$file" in
|
||||||
|
"$dir"*.toml)
|
||||||
|
case "$file" in
|
||||||
|
*../*)
|
||||||
|
_err "additional config file outside $dir is not allowed: $file"
|
||||||
|
_TOML_ERR=1
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_err "additional config file must be under $dir and end with .toml: $file"
|
||||||
|
_TOML_ERR=1
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ -r "$file" ] || {
|
||||||
|
_err "additional config file not readable: $file"
|
||||||
|
_TOML_ERR=1
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
real_file="$(readlink -f "$file")" || {
|
||||||
|
_err "additional config file path cannot be resolved: $file"
|
||||||
|
_TOML_ERR=1
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$real_file" in
|
||||||
|
"$dir"*.toml)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_err "additional config file resolves outside $dir or is not .toml: $file"
|
||||||
|
_TOML_ERR=1
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
printf '\n' >> "$CONF_FILE"
|
||||||
|
cat "$real_file" >> "$CONF_FILE"
|
||||||
|
printf '\n' >> "$CONF_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
_watch_conf_file() {
|
||||||
|
local file="$1"
|
||||||
|
|
||||||
|
[ -r "$file" ] && procd_set_param file "$file"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_append_env() {
|
||||||
|
procd_append_param env "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
service_triggers() {
|
||||||
|
procd_add_reload_trigger "$NAME"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_service() {
|
||||||
|
local init_cfg=
|
||||||
|
local stdout=1
|
||||||
|
local stderr=1
|
||||||
|
local respawn=1
|
||||||
|
local run_user=
|
||||||
|
local run_group=
|
||||||
|
local old_umask
|
||||||
|
|
||||||
|
mkdir -p /var/etc
|
||||||
|
_TOML_ERR=0
|
||||||
|
_ALLOW_UNSAFE_TOKEN_SOURCE_EXEC=0
|
||||||
|
|
||||||
|
config_load "$NAME"
|
||||||
|
|
||||||
|
config_foreach _find_init_section init
|
||||||
|
|
||||||
|
old_umask="$(umask)"
|
||||||
|
umask 077
|
||||||
|
: > "$CONF_FILE" || {
|
||||||
|
umask "$old_umask"
|
||||||
|
_err "failed to create $CONF_FILE"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
umask "$old_umask"
|
||||||
|
chmod 600 "$CONF_FILE" || {
|
||||||
|
_err "failed to chmod $CONF_FILE"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
printf '# This file is automatically generated from /etc/config/%s.\n' "$NAME"
|
||||||
|
printf '# Do not edit this file directly.\n\n'
|
||||||
|
|
||||||
|
_emit_common
|
||||||
|
} >> "$CONF_FILE" || return 1
|
||||||
|
[ "$_TOML_ERR" = "0" ] || return 1
|
||||||
|
|
||||||
|
if [ -n "$init_cfg" ]; then
|
||||||
|
config_list_foreach "$init_cfg" conf_inc _append_conf_file
|
||||||
|
|
||||||
|
config_get_bool stdout "$init_cfg" stdout 1
|
||||||
|
config_get_bool stderr "$init_cfg" stderr 1
|
||||||
|
config_get_bool respawn "$init_cfg" respawn 1
|
||||||
|
config_get run_user "$init_cfg" user
|
||||||
|
config_get run_group "$init_cfg" group
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
config_foreach _emit_http_plugin http_plugin
|
||||||
|
} >> "$CONF_FILE" || return 1
|
||||||
|
[ "$_TOML_ERR" = "0" ] || return 1
|
||||||
|
|
||||||
|
if [ -n "$run_user" ]; then
|
||||||
|
chown "$run_user${run_group:+:$run_group}" "$CONF_FILE" 2>/dev/null || {
|
||||||
|
_err "failed to chown $CONF_FILE to $run_user${run_group:+:$run_group}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 600 "$CONF_FILE" || {
|
||||||
|
_err "failed to chmod $CONF_FILE"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
procd_open_instance
|
||||||
|
if [ "$_ALLOW_UNSAFE_TOKEN_SOURCE_EXEC" = "1" ]; then
|
||||||
|
procd_set_param command "$PROG" -c "$CONF_FILE" --allow-unsafe=TokenSourceExec
|
||||||
|
else
|
||||||
|
procd_set_param command "$PROG" -c "$CONF_FILE"
|
||||||
|
fi
|
||||||
|
procd_set_param file "$CONF_FILE"
|
||||||
|
procd_set_param file "/etc/config/$NAME"
|
||||||
|
|
||||||
|
if [ -n "$init_cfg" ]; then
|
||||||
|
config_list_foreach "$init_cfg" conf_inc _watch_conf_file
|
||||||
|
fi
|
||||||
|
|
||||||
|
procd_set_param stdout "$stdout"
|
||||||
|
procd_set_param stderr "$stderr"
|
||||||
|
|
||||||
|
[ -n "$run_user" ] && procd_set_param user "$run_user"
|
||||||
|
[ -n "$run_group" ] && procd_set_param group "$run_group"
|
||||||
|
[ "$respawn" -eq 1 ] && procd_set_param respawn
|
||||||
|
|
||||||
|
if [ -n "$init_cfg" ]; then
|
||||||
|
config_list_foreach "$init_cfg" env _append_env
|
||||||
|
fi
|
||||||
|
|
||||||
|
procd_close_instance
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
. /lib/functions.sh
|
||||||
|
|
||||||
|
changed=0
|
||||||
|
init_section=
|
||||||
|
package=frps
|
||||||
|
|
||||||
|
find_init_section() {
|
||||||
|
[ -z "$init_section" ] && init_section="$1"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
set_if_empty() {
|
||||||
|
local section="$1"
|
||||||
|
local option="$2"
|
||||||
|
local value="$3"
|
||||||
|
local cur
|
||||||
|
|
||||||
|
config_get cur "$section" "$option"
|
||||||
|
|
||||||
|
if [ -z "$cur" ]; then
|
||||||
|
uci_set "$package" "$section" "$option" "$value"
|
||||||
|
changed=1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_if_empty() {
|
||||||
|
local section="$1"
|
||||||
|
local old_option="$2"
|
||||||
|
local new_option="$3"
|
||||||
|
local value
|
||||||
|
|
||||||
|
config_get value "$section" "$old_option"
|
||||||
|
[ -n "$value" ] || return 0
|
||||||
|
|
||||||
|
set_if_empty "$section" "$new_option" "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
upgrade_common() {
|
||||||
|
local section="$1"
|
||||||
|
local dashboard_tls_mode
|
||||||
|
local tls_only
|
||||||
|
local nat_hole_hours
|
||||||
|
|
||||||
|
[ "$section" = "common" ] || return 0
|
||||||
|
|
||||||
|
set_if_empty "$section" bind_addr 0.0.0.0
|
||||||
|
set_if_empty "$section" bind_port 7000
|
||||||
|
set_if_empty "$section" authentication_method token
|
||||||
|
set_if_empty "$section" max_pool_count 5
|
||||||
|
set_if_empty "$section" tcp_mux true
|
||||||
|
set_if_empty "$section" detailed_errors_to_client true
|
||||||
|
set_if_empty "$section" pprof_enable false
|
||||||
|
set_if_empty "$section" enable_prometheus false
|
||||||
|
|
||||||
|
config_get tls_only "$section" tls_only
|
||||||
|
if [ -n "$tls_only" ]; then
|
||||||
|
set_if_empty "$section" tls_force "$tls_only"
|
||||||
|
else
|
||||||
|
set_if_empty "$section" tls_force false
|
||||||
|
fi
|
||||||
|
|
||||||
|
config_get dashboard_tls_mode "$section" dashboard_tls_mode
|
||||||
|
if [ -n "$dashboard_tls_mode" ]; then
|
||||||
|
set_if_empty "$section" admin_tls_enable "$dashboard_tls_mode"
|
||||||
|
else
|
||||||
|
set_if_empty "$section" admin_tls_enable false
|
||||||
|
fi
|
||||||
|
|
||||||
|
copy_if_empty "$section" dashboard_addr admin_addr
|
||||||
|
copy_if_empty "$section" dashboard_port admin_port
|
||||||
|
copy_if_empty "$section" dashboard_user admin_user
|
||||||
|
copy_if_empty "$section" dashboard_pwd admin_pwd
|
||||||
|
copy_if_empty "$section" dashboard_tls_cert_file admin_tls_cert_file
|
||||||
|
copy_if_empty "$section" dashboard_tls_key_file admin_tls_key_file
|
||||||
|
|
||||||
|
config_get nat_hole_hours "$section" nat_hole_analysis_data_reserve_hours
|
||||||
|
[ -n "$nat_hole_hours" ] && \
|
||||||
|
set_if_empty "$section" nathole_analysis_data_reserve_hours "$nat_hole_hours"
|
||||||
|
|
||||||
|
set_if_empty "$section" log_file console
|
||||||
|
set_if_empty "$section" log_level info
|
||||||
|
set_if_empty "$section" log_max_days 3
|
||||||
|
}
|
||||||
|
|
||||||
|
upgrade_init() {
|
||||||
|
if [ -z "$init_section" ]; then
|
||||||
|
init_section="$(uci add "$package" init)" || return 0
|
||||||
|
changed=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set_if_empty "$init_section" stdout 1
|
||||||
|
set_if_empty "$init_section" stderr 1
|
||||||
|
set_if_empty "$init_section" respawn 1
|
||||||
|
}
|
||||||
|
|
||||||
|
config_load "$package"
|
||||||
|
config_foreach find_init_section init
|
||||||
|
upgrade_init
|
||||||
|
config_foreach upgrade_common conf
|
||||||
|
|
||||||
|
[ "$changed" -eq 1 ] && uci_commit "$package"
|
||||||
|
|
||||||
|
exit 0
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# frpc/frps both accept "verify -c <file>" to validate a config without
|
||||||
|
# connecting, which exercises the TOML config loader end-to-end.
|
||||||
|
case "$1" in
|
||||||
|
frpc)
|
||||||
|
conf="/tmp/frpc.$$.toml"
|
||||||
|
printf 'serverAddr = "127.0.0.1"\nserverPort = 7000\n' > "$conf"
|
||||||
|
frpc verify -c "$conf" || { echo "FAIL: frpc rejected a valid config"; rm -f "$conf"; exit 1; }
|
||||||
|
rm -f "$conf"
|
||||||
|
;;
|
||||||
|
frps)
|
||||||
|
conf="/tmp/frps.$$.toml"
|
||||||
|
printf 'bindPort = 7000\n' > "$conf"
|
||||||
|
frps verify -c "$conf" || { echo "FAIL: frps rejected a valid config"; rm -f "$conf"; exit 1; }
|
||||||
|
rm -f "$conf"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-passwall
|
PKG_NAME:=luci-app-passwall
|
||||||
PKG_VERSION:=26.8.19
|
PKG_VERSION:=26.8.19
|
||||||
PKG_RELEASE:=241
|
PKG_RELEASE:=242
|
||||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||||
|
|
||||||
PKG_CONFIG_DEPENDS:= \
|
PKG_CONFIG_DEPENDS:= \
|
||||||
|
|||||||
@@ -33,15 +33,17 @@ for _, v in pairs(nodes_table) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
local socks_list = {}
|
local socks_list = {}
|
||||||
m:foreach("socks", function(s)
|
if has_singbox or has_xray then
|
||||||
if s.enabled == "1" and s.node then
|
m:foreach("socks", function(s)
|
||||||
socks_list[#socks_list + 1] = {
|
if s.enabled == "1" and s.node then
|
||||||
id = s[".name"],
|
socks_list[#socks_list + 1] = {
|
||||||
remark = translate("Socks Config") .. " " .. string.format("[%s %s]", s.port, translate("Port")),
|
id = s[".name"],
|
||||||
group = "Socks"
|
remark = translate("Socks Config") .. " " .. string.format("[%s %s]", s.port, translate("Port")),
|
||||||
}
|
group = "Socks"
|
||||||
end
|
}
|
||||||
end)
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
-- [[ ACLs Settings ]]--
|
-- [[ ACLs Settings ]]--
|
||||||
s = m:section(NamedSection, arg[1], translate("ACLs"), translate("ACLs"))
|
s = m:section(NamedSection, arg[1], translate("ACLs"), translate("ACLs"))
|
||||||
|
|||||||
@@ -62,11 +62,13 @@ m:foreach("socks", function(s)
|
|||||||
id = id,
|
id = id,
|
||||||
remark = id .. " - " .. (remark or translate("Misconfigured"))
|
remark = id .. " - " .. (remark or translate("Misconfigured"))
|
||||||
}
|
}
|
||||||
socks_list[#socks_list + 1] = {
|
if has_singbox or has_xray then
|
||||||
id = s[".name"],
|
socks_list[#socks_list + 1] = {
|
||||||
remark = translate("Socks Config") .. " " .. string.format("[%s %s]", s.port, translate("Port")),
|
id = s[".name"],
|
||||||
group = "Socks"
|
remark = translate("Socks Config") .. " " .. string.format("[%s %s]", s.port, translate("Port")),
|
||||||
}
|
group = "Socks"
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
@@ -325,20 +325,14 @@ run_socks() {
|
|||||||
log_file="/dev/null"
|
log_file="/dev/null"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local node2socks_port=0
|
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
|
||||||
local type remarks server_host server_port
|
local remarks=$(config_n_get $node remarks)
|
||||||
|
local server_host=$(config_n_get $node address)
|
||||||
|
local server_port=$(config_n_get $node port)
|
||||||
|
|
||||||
if [ "$(config_get_type $node)" = "socks" ]; then
|
if [ "$(config_get_type $node)" = "socks" ]; then
|
||||||
node2socks_port=$(config_n_get $node port 0)
|
|
||||||
fi
|
|
||||||
if [ "$node2socks_port" = "0" ]; then
|
|
||||||
type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
|
|
||||||
remarks=$(config_n_get $node remarks)
|
|
||||||
server_host=$(config_n_get $node address)
|
|
||||||
server_port=$(config_n_get $node port)
|
|
||||||
else
|
|
||||||
type="socks"
|
type="socks"
|
||||||
server_host="127.0.0.1"
|
server_host="127.0.0.1"
|
||||||
server_port=$node2socks_port
|
|
||||||
remarks="Socks 配置($server_port 端口)"
|
remarks="Socks 配置($server_port 端口)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -382,16 +376,8 @@ run_socks() {
|
|||||||
json_add_string "server_port" "${server_port}"
|
json_add_string "server_port" "${server_port}"
|
||||||
case "$type" in
|
case "$type" in
|
||||||
socks)
|
socks)
|
||||||
local _socks_address _socks_port _socks_username _socks_password
|
local socks_username=$(config_n_get $node username)
|
||||||
if [ "$node2socks_port" = "0" ]; then
|
local socks_password=$(config_n_get $node password)
|
||||||
_socks_address=$(config_n_get $node address)
|
|
||||||
_socks_port=$(config_n_get $node port)
|
|
||||||
_socks_username=$(config_n_get $node username)
|
|
||||||
_socks_password=$(config_n_get $node password)
|
|
||||||
else
|
|
||||||
_socks_address="127.0.0.1"
|
|
||||||
_socks_port=$node2socks_port
|
|
||||||
fi
|
|
||||||
[ "$http_port" != "0" ] && {
|
[ "$http_port" != "0" ] && {
|
||||||
http_flag=1
|
http_flag=1
|
||||||
config_file="${config_file%%.*}+http${config_file#${config_file%%.*}}"
|
config_file="${config_file%%.*}+http${config_file#${config_file%%.*}}"
|
||||||
@@ -403,10 +389,10 @@ run_socks() {
|
|||||||
json_add_string "local_socks_address" "$bind"
|
json_add_string "local_socks_address" "$bind"
|
||||||
json_add_string "local_socks_port" "$socks_port"
|
json_add_string "local_socks_port" "$socks_port"
|
||||||
json_add_string "server_proto" "socks"
|
json_add_string "server_proto" "socks"
|
||||||
json_add_string "server_address" "${_socks_address}"
|
json_add_string "server_address" "${server_host}"
|
||||||
json_add_string "server_port" "${_socks_port}"
|
json_add_string "server_port" "${server_port}"
|
||||||
json_add_string "server_username" "${_socks_username}"
|
json_add_string "server_username" "${socks_username}"
|
||||||
json_add_string "server_password" "${_socks_password}"
|
json_add_string "server_password" "${socks_password}"
|
||||||
if [ -n "${SINGBOX_BIN}" ]; then
|
if [ -n "${SINGBOX_BIN}" ]; then
|
||||||
type="sing-box"
|
type="sing-box"
|
||||||
local bin="${SINGBOX_BIN}"
|
local bin="${SINGBOX_BIN}"
|
||||||
@@ -519,32 +505,35 @@ run_socks() {
|
|||||||
|
|
||||||
start_global() {
|
start_global() {
|
||||||
[ -z "$NODE" ] && return 1
|
[ -z "$NODE" ] && return 1
|
||||||
|
|
||||||
local type=$(echo $(config_n_get $NODE type) | tr 'A-Z' 'a-z')
|
|
||||||
|
|
||||||
local config_file=${GLOBAL_ACL_PATH}/global.json
|
local config_file=${GLOBAL_ACL_PATH}/global.json
|
||||||
local log_file=${GLOBAL_ACL_PATH}/global.log
|
local log_file=${GLOBAL_ACL_PATH}/global.log
|
||||||
local node2socks_port=0
|
|
||||||
local remarks server_host port
|
local remarks=$(config_n_get $NODE remarks)
|
||||||
if [ "$(config_get_type $NODE)" = "socks" ]; then
|
local server_host=$(config_n_get $NODE address)
|
||||||
node2socks_port=$(config_n_get $NODE port 0)
|
local port=$(config_n_get $NODE port)
|
||||||
fi
|
local type=$(echo $(config_n_get $NODE type) | tr 'A-Z' 'a-z')
|
||||||
if [ "$node2socks_port" = "0" ]; then
|
|
||||||
remarks=$(config_n_get $NODE remarks)
|
local is_socks_cfg=0
|
||||||
server_host=$(config_n_get $NODE address)
|
[ "$(config_get_type $NODE)" = "socks" ] && is_socks_cfg=1
|
||||||
port=$(config_n_get $NODE port)
|
|
||||||
else
|
if [ "$type" = "socks" ] || [ "$is_socks_cfg" = "1" ] ; then
|
||||||
if [ "${DNS_MODE}" = "xray" ]; then
|
if [ "${DNS_MODE}" = "xray" ]; then
|
||||||
type="xray"
|
type="xray"
|
||||||
elif [ "${DNS_MODE}" = "sing-box" ]; then
|
elif [ "${DNS_MODE}" = "sing-box" ]; then
|
||||||
type="sing-box"
|
type="sing-box"
|
||||||
|
elif [ -n "${SINGBOX_BIN}" ]; then
|
||||||
|
type="sing-box"
|
||||||
|
elif [ -n "${XRAY_BIN}" ]; then
|
||||||
|
type="xray"
|
||||||
else
|
else
|
||||||
type="socks"
|
type="socks"
|
||||||
fi
|
fi
|
||||||
server_host="127.0.0.1"
|
if [ "$is_socks_cfg" = "1" ] ; then
|
||||||
port=$node2socks_port
|
server_host="127.0.0.1"
|
||||||
remarks="Socks 配置($port 端口)"
|
remarks="Socks 配置($port 端口)"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local enable_log=$(config_n_get @global[0] log_node 1)
|
local enable_log=$(config_n_get @global[0] log_node 1)
|
||||||
[ "$enable_log" != "1" ] && log_file="/dev/null"
|
[ "$enable_log" != "1" ] && log_file="/dev/null"
|
||||||
[ -n "$server_host" ] && [ -n "$port" ] && {
|
[ -n "$server_host" ] && [ -n "$port" ] && {
|
||||||
@@ -583,22 +572,15 @@ start_global() {
|
|||||||
case "$type" in
|
case "$type" in
|
||||||
socks)
|
socks)
|
||||||
_socks_flag=1
|
_socks_flag=1
|
||||||
if [ "$node2socks_port" = "0" ]; then
|
_socks_address=$server_host
|
||||||
_socks_address=$(config_n_get $NODE address)
|
_socks_port=$port
|
||||||
_socks_port=$(config_n_get $NODE port)
|
_socks_username=$(config_n_get $NODE username)
|
||||||
_socks_username=$(config_n_get $NODE username)
|
_socks_password=$(config_n_get $NODE password)
|
||||||
_socks_password=$(config_n_get $NODE password)
|
|
||||||
else
|
|
||||||
_socks_address="127.0.0.1"
|
|
||||||
_socks_port=$node2socks_port
|
|
||||||
fi
|
|
||||||
[ -z "$can_ipt" ] && {
|
[ -z "$can_ipt" ] && {
|
||||||
local _config_file=$config_file
|
local _config_file="global_${NODE}_socks.json"
|
||||||
_config_file="Global_SOCKS_${NODE}.json"
|
|
||||||
local _port=$(get_new_port 3001)
|
|
||||||
run_socks flag="global" node=$NODE bind=127.0.0.1 socks_port=${_port} config_file=${_config_file}
|
|
||||||
_socks_address="127.0.0.1"
|
_socks_address="127.0.0.1"
|
||||||
_socks_port=${_port}
|
_socks_port=$GLOBAL_SOCKS_port
|
||||||
|
run_socks flag="global" node=$NODE bind=${node_socks_bind} socks_port=${_socks_port} config_file=${_config_file}
|
||||||
unset _socks_username
|
unset _socks_username
|
||||||
unset _socks_password
|
unset _socks_password
|
||||||
}
|
}
|
||||||
@@ -1463,6 +1445,10 @@ acl_app() {
|
|||||||
type="xray"
|
type="xray"
|
||||||
elif [ "${dns_mode}" = "sing-box" ]; then
|
elif [ "${dns_mode}" = "sing-box" ]; then
|
||||||
type="sing-box"
|
type="sing-box"
|
||||||
|
elif [ -n "${SINGBOX_BIN}" ]; then
|
||||||
|
type="sing-box"
|
||||||
|
elif [ -n "${XRAY_BIN}" ]; then
|
||||||
|
type="xray"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
|
type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=luci-app-wwand
|
PKG_NAME:=luci-app-wwand
|
||||||
PKG_RELEASE:=3
|
PKG_RELEASE:=4
|
||||||
|
|
||||||
PKG_SOURCE_PROTO:=git
|
PKG_SOURCE_PROTO:=git
|
||||||
PKG_SOURCE_URL:=https://github.com/ddimension/luci-app-wwand.git
|
PKG_SOURCE_URL:=https://github.com/ddimension/luci-app-wwand.git
|
||||||
PKG_SOURCE_VERSION:=c9c2e1870b094cdc7bdd9013a7e4862e030b9500
|
PKG_SOURCE_VERSION:=7f0c58f56cc060bd3355fed7fd86a68ad7003e9e
|
||||||
PKG_SOURCE_DATE:=2026-08-23
|
PKG_SOURCE_DATE:=2026-08-24
|
||||||
PKG_MIRROR_HASH:=skip
|
PKG_MIRROR_HASH:=skip
|
||||||
|
|
||||||
PKG_LICENSE:=GPL-2.0-only
|
PKG_LICENSE:=GPL-2.0-only
|
||||||
|
|||||||
Reference in new issue
Block a user