feat: add local mariadb port and remote ip access controls

This commit is contained in:
Sora39831 2026-04-22 11:20:55 +08:00
parent cc66b073a4
commit df20cc7e0b
4 changed files with 733 additions and 3 deletions

View file

@ -0,0 +1,56 @@
Task Record
Date: 2026-04-22
Related Module: install.sh, x-ui.sh, MariaDB runtime configuration
Change Type: Fix
Background
The existing MariaDB setup flow only supported local-only business accounts and default port handling. It did not provide a script path to change the local MariaDB server port or to explicitly authorize selected remote VPS IPs for worker-style access after installation.
Changes
Added reusable shell helpers in `install.sh` and `x-ui.sh` to manage local MariaDB server network settings through an override config file, including `port` and `bind-address`.
Updated the local MariaDB install/switch flow to prompt for `本地 MariaDB port [3306]`, validate the input, apply the port to the local MariaDB server, and keep default local-only binding (`127.0.0.1`).
Extended the `x-ui.sh` database management menu with local MariaDB runtime actions:
- set local MariaDB port
- view MariaDB remote access status
- enable MariaDB remote access
- disable MariaDB remote access
- view allowed remote IPs
- add allowed remote IP
- remove allowed remote IP
Remote access management now uses MariaDB per-host grants for the current business user and current business database. Enabling remote access switches MariaDB bind address to `0.0.0.0` and requires at least one authorized remote IP. Disabling remote access restores `127.0.0.1` and removes non-local grants for the current business user.
Impact
Affected files:
- `install.sh`
- `x-ui.sh`
- `tests/mariadb_install_switch_test.sh`
- `docs/Tasktracking/2026-04-22-add-mariadb-remote-ip-access.md`
This changes shell installer behavior, runtime shell menu behavior, and local MariaDB server configuration on hosts that use the new flow.
No Go API, database schema, or frontend behavior was changed.
Worker-side remote database host and port configuration continues to use the existing `dbHost` and `dbPort` settings flow.
Verification
Commands:
- `bash tests/mariadb_install_switch_test.sh`
- `bash -n install.sh`
- `bash -n x-ui.sh`
Result:
- All commands completed successfully.
Not verified:
- No live MariaDB install/runtime session was executed in this environment.
- No end-to-end validation against an actual remote worker VPS IP was executed in this session.
Risks And Follow-Up
The MariaDB config override path is selected from common distro include directories. On an uncommon MariaDB packaging layout, manual adjustment may still be required.
This implementation restricts remote access by MariaDB host grants, not by firewall source filtering. Unauthorised source IPs should be rejected by MariaDB authentication, but the database service still listens on the configured port while remote access is enabled.
If stricter network-layer isolation is required later, a follow-up can add optional per-IP firewall rules on top of the current MariaDB host-grant model.

View file

@ -263,6 +263,168 @@ escape_sql_string() {
printf "%s" "$1" | sed "s/'/''/g" printf "%s" "$1" | sed "s/'/''/g"
} }
validate_tcp_port() {
local port="$1"
[[ "$port" =~ ^[0-9]+$ ]] && ((port >= 1 && port <= 65535))
}
mariadb_server_override_path() {
local dir=""
for dir in /etc/mysql/mariadb.conf.d /etc/mysql/conf.d /etc/my.cnf.d /etc/mariadb.conf.d; do
if [ -d "$dir" ]; then
echo "${dir}/60-x-ui.cnf"
return 0
fi
done
echo "/etc/my.cnf"
}
mariadb_server_config_candidates() {
local override_path
override_path=$(mariadb_server_override_path)
echo "$override_path"
local path=""
for path in \
/etc/mysql/mariadb.conf.d/50-server.cnf \
/etc/mysql/mariadb.cnf \
/etc/mysql/my.cnf \
/etc/mysql/conf.d/mysql.cnf \
/etc/my.cnf.d/mariadb-server.cnf \
/etc/my.cnf.d/server.cnf \
/etc/mariadb.conf.d/50-server.cnf \
/etc/my.cnf; do
if [ -f "$path" ] && [ "$path" != "$override_path" ]; then
echo "$path"
fi
done
}
ensure_mariadb_override_file() {
local path
path=$(mariadb_server_override_path)
mkdir -p "$(dirname "$path")"
if [ ! -f "$path" ]; then
printf "[mysqld]\n" >"$path"
elif ! grep -q '^\[mysqld\]' "$path" 2>/dev/null; then
printf "\n[mysqld]\n" >>"$path"
fi
echo "$path"
}
upsert_mariadb_mysqld_option() {
local file="$1"
local key="$2"
local value="$3"
local tmp_file
tmp_file=$(mktemp)
awk -v key="$key" -v value="$value" '
BEGIN {
in_section = 0
section_seen = 0
key_written = 0
}
/^\[.*\][[:space:]]*$/ {
if (in_section && !key_written) {
print key " = " value
key_written = 1
}
if ($0 == "[mysqld]") {
in_section = 1
section_seen = 1
} else {
in_section = 0
}
print
next
}
{
if (in_section && $0 ~ "^[[:space:]]*[#;]?[[:space:]]*" key "[[:space:]]*=") {
if (!key_written) {
print key " = " value
key_written = 1
}
next
}
print
}
END {
if (!section_seen) {
print "[mysqld]"
}
if (!key_written) {
print key " = " value
}
}' "$file" >"$tmp_file"
cat "$tmp_file" >"$file"
rm -f "$tmp_file"
}
disable_mariadb_skip_networking() {
local file=""
local tmp_file=""
while IFS= read -r file; do
[ -f "$file" ] || continue
tmp_file=$(mktemp)
awk '
{
if ($0 ~ /^[[:space:]]*skip-networking([[:space:]]*=[[:space:]]*.*)?[[:space:]]*$/) {
print "# x-ui disabled skip-networking to keep managed MariaDB networking available"
next
}
print
}' "$file" >"$tmp_file"
cat "$tmp_file" >"$file"
rm -f "$tmp_file"
done < <(mariadb_server_config_candidates)
}
restart_mariadb_service() {
local svc_name=""
if command -v systemctl >/dev/null 2>&1; then
if systemctl list-unit-files 2>/dev/null | grep -q "^mariadb.service"; then
svc_name="mariadb"
elif systemctl list-unit-files 2>/dev/null | grep -q "^mysql.service"; then
svc_name="mysql"
fi
fi
if [ -n "$svc_name" ]; then
systemctl restart "$svc_name" 2>/dev/null
return $?
fi
if [[ $release == "alpine" ]]; then
rc-service mariadb restart 2>/dev/null
return $?
fi
start_mariadb_service
}
configure_local_mariadb_server_network() {
local db_port="$1"
local bind_address="$2"
local override_file=""
if ! validate_tcp_port "$db_port"; then
echo -e "${red}MariaDB 端口无效,请输入 1-65535 之间的数字${plain}"
return 1
fi
override_file=$(ensure_mariadb_override_file) || return 1
upsert_mariadb_mysqld_option "$override_file" "port" "$db_port"
upsert_mariadb_mysqld_option "$override_file" "bind-address" "$bind_address"
disable_mariadb_skip_networking
if ! restart_mariadb_service; then
echo -e "${red}重启 MariaDB 失败,请检查配置文件${plain}"
return 1
fi
return 0
}
LOCAL_MARIADB_ADMIN_MODE="" LOCAL_MARIADB_ADMIN_MODE=""
LOCAL_MARIADB_ADMIN_USER="" LOCAL_MARIADB_ADMIN_USER=""
LOCAL_MARIADB_ADMIN_PASS="" LOCAL_MARIADB_ADMIN_PASS=""
@ -1197,13 +1359,18 @@ config_after_install() {
fi fi
else else
db_host="127.0.0.1" db_host="127.0.0.1"
db_port="3306" read -rp "本地 MariaDB port [3306]: " db_port
read -rp "业务数据库名 [3xui]: " db_name read -rp "业务数据库名 [3xui]: " db_name
read -rp "业务用户名: " db_user read -rp "业务用户名: " db_user
read -rsp "业务密码: " db_pass read -rsp "业务密码: " db_pass
echo echo
db_port="${db_port:-3306}"
db_name="${db_name:-3xui}" db_name="${db_name:-3xui}"
if ! validate_tcp_port "$db_port"; then
echo -e "${red}本地 MariaDB 端口无效,请输入 1-65535 之间的数字${plain}"
return 1
fi
if [[ -z "$db_user" || -z "$db_pass" ]]; then if [[ -z "$db_user" || -z "$db_pass" ]]; then
echo -e "${red}本地 MariaDB 的业务用户名和业务密码不能为空${plain}" echo -e "${red}本地 MariaDB 的业务用户名和业务密码不能为空${plain}"
return 1 return 1
@ -1213,6 +1380,7 @@ config_after_install() {
echo -e "${red}准备本地 MariaDB 失败${plain}" echo -e "${red}准备本地 MariaDB 失败${plain}"
return 1 return 1
} }
configure_local_mariadb_server_network "$db_port" "127.0.0.1" || return 1
ensure_local_mariadb_admin_access "$db_port" || return 1 ensure_local_mariadb_admin_access "$db_port" || return 1
ensure_mariadb_database_and_user "$db_name" "$db_user" "$db_pass" || { ensure_mariadb_database_and_user "$db_name" "$db_user" "$db_pass" || {
echo -e "${red}创建本地 MariaDB 业务库或业务账号失败${plain}" echo -e "${red}创建本地 MariaDB 业务库或业务账号失败${plain}"

View file

@ -13,14 +13,19 @@ assert_contains() {
assert_contains "install.sh" "本地 MariaDB" assert_contains "install.sh" "本地 MariaDB"
assert_contains "install.sh" "远程 MariaDB" assert_contains "install.sh" "远程 MariaDB"
assert_contains "install.sh" "业务数据库名" assert_contains "install.sh" "业务数据库名"
assert_contains "install.sh" "本地 MariaDB port [3306]"
assert_contains "install.sh" "ensure_local_mariadb_ready" assert_contains "install.sh" "ensure_local_mariadb_ready"
assert_contains "install.sh" "远程 MariaDB 端口无效,请输入 1-65535 之间的数字" assert_contains "install.sh" "远程 MariaDB 端口无效,请输入 1-65535 之间的数字"
assert_contains "x-ui.sh" "本地 MariaDB" assert_contains "x-ui.sh" "本地 MariaDB"
assert_contains "x-ui.sh" "远程 MariaDB" assert_contains "x-ui.sh" "远程 MariaDB"
assert_contains "x-ui.sh" "本地 MariaDB port [3306]"
assert_contains "x-ui.sh" "ensure_local_mariadb_ready" assert_contains "x-ui.sh" "ensure_local_mariadb_ready"
assert_contains "x-ui.sh" "ensure_mariadb_database_and_user" assert_contains "x-ui.sh" "ensure_mariadb_database_and_user"
assert_contains "x-ui.sh" "远程 MariaDB 端口无效,请输入 1-65535 之间的数字" assert_contains "x-ui.sh" "远程 MariaDB 端口无效,请输入 1-65535 之间的数字"
assert_contains "x-ui.sh" "开启 MariaDB 远程访问"
assert_contains "x-ui.sh" "添加 MariaDB 允许 IP"
assert_contains "x-ui.sh" "移除 MariaDB 允许 IP"
assert_contains "x-ui.sh" "是否删除数据库并卸载本机 MariaDB" assert_contains "x-ui.sh" "是否删除数据库并卸载本机 MariaDB"
assert_contains "x-ui.sh" "remove_local_mariadb_data" assert_contains "x-ui.sh" "remove_local_mariadb_data"
assert_contains "x-ui.sh" "uninstall_local_mariadb_packages" assert_contains "x-ui.sh" "uninstall_local_mariadb_packages"

505
x-ui.sh
View file

@ -2666,6 +2666,215 @@ set_remote_database_connection() {
fi fi
} }
validate_tcp_port() {
local port="$1"
[[ "$port" =~ ^[0-9]+$ ]] && ((port >= 1 && port <= 65535))
}
is_local_mariadb_host() {
case "$1" in
"" | "127.0.0.1" | "localhost" | "::1")
return 0
;;
*)
return 1
;;
esac
}
mariadb_server_override_path() {
local dir=""
for dir in /etc/mysql/mariadb.conf.d /etc/mysql/conf.d /etc/my.cnf.d /etc/mariadb.conf.d; do
if [ -d "$dir" ]; then
echo "${dir}/60-x-ui.cnf"
return 0
fi
done
echo "/etc/my.cnf"
}
mariadb_server_config_candidates() {
local override_path
override_path=$(mariadb_server_override_path)
echo "$override_path"
local path=""
for path in \
/etc/mysql/mariadb.conf.d/50-server.cnf \
/etc/mysql/mariadb.cnf \
/etc/mysql/my.cnf \
/etc/mysql/conf.d/mysql.cnf \
/etc/my.cnf.d/mariadb-server.cnf \
/etc/my.cnf.d/server.cnf \
/etc/mariadb.conf.d/50-server.cnf \
/etc/my.cnf; do
if [ -f "$path" ] && [ "$path" != "$override_path" ]; then
echo "$path"
fi
done
}
ensure_mariadb_override_file() {
local path
path=$(mariadb_server_override_path)
mkdir -p "$(dirname "$path")"
if [ ! -f "$path" ]; then
printf "[mysqld]\n" >"$path"
elif ! grep -q '^\[mysqld\]' "$path" 2>/dev/null; then
printf "\n[mysqld]\n" >>"$path"
fi
echo "$path"
}
upsert_mariadb_mysqld_option() {
local file="$1"
local key="$2"
local value="$3"
local tmp_file
tmp_file=$(mktemp)
awk -v key="$key" -v value="$value" '
BEGIN {
in_section = 0
section_seen = 0
key_written = 0
}
/^\[.*\][[:space:]]*$/ {
if (in_section && !key_written) {
print key " = " value
key_written = 1
}
if ($0 == "[mysqld]") {
in_section = 1
section_seen = 1
} else {
in_section = 0
}
print
next
}
{
if (in_section && $0 ~ "^[[:space:]]*[#;]?[[:space:]]*" key "[[:space:]]*=") {
if (!key_written) {
print key " = " value
key_written = 1
}
next
}
print
}
END {
if (!section_seen) {
print "[mysqld]"
}
if (!key_written) {
print key " = " value
}
}' "$file" >"$tmp_file"
cat "$tmp_file" >"$file"
rm -f "$tmp_file"
}
disable_mariadb_skip_networking() {
local file=""
local tmp_file=""
while IFS= read -r file; do
[ -f "$file" ] || continue
tmp_file=$(mktemp)
awk '
{
if ($0 ~ /^[[:space:]]*skip-networking([[:space:]]*=[[:space:]]*.*)?[[:space:]]*$/) {
print "# x-ui disabled skip-networking to allow managed remote access"
next
}
print
}' "$file" >"$tmp_file"
cat "$tmp_file" >"$file"
rm -f "$tmp_file"
done < <(mariadb_server_config_candidates)
}
read_mariadb_server_option() {
local key="$1"
local default_value="$2"
local file=""
local value=""
local result=""
while IFS= read -r file; do
[ -f "$file" ] || continue
value=$(awk -v key="$key" '
BEGIN {
in_section = 0
value = ""
}
/^\[.*\][[:space:]]*$/ {
in_section = ($0 == "[mysqld]")
next
}
{
if (in_section && $0 !~ /^[[:space:]]*[#;]/ && $0 ~ "^[[:space:]]*" key "[[:space:]]*=") {
sub(/^[[:space:]]*[^=]+=[[:space:]]*/, "", $0)
gsub(/[[:space:]]+$/, "", $0)
value = $0
}
}
END {
print value
}' "$file")
if [ -n "$value" ]; then
result="$value"
fi
done < <(mariadb_server_config_candidates)
echo "${result:-$default_value}"
}
restart_mariadb_service() {
local svc_name=""
if command -v systemctl >/dev/null 2>&1; then
if systemctl list-unit-files 2>/dev/null | grep -q "^mariadb.service"; then
svc_name="mariadb"
elif systemctl list-unit-files 2>/dev/null | grep -q "^mysql.service"; then
svc_name="mysql"
fi
fi
if [ -n "$svc_name" ]; then
systemctl restart "$svc_name" 2>/dev/null
return $?
fi
if [[ $release == "alpine" ]]; then
rc-service mariadb restart 2>/dev/null
return $?
fi
start_mariadb_service
}
configure_local_mariadb_server_network() {
local db_port="$1"
local bind_address="$2"
local override_file=""
if ! validate_tcp_port "$db_port"; then
echo -e "${red}MariaDB 端口无效,请输入 1-65535 之间的数字${plain}"
return 1
fi
override_file=$(ensure_mariadb_override_file) || return 1
upsert_mariadb_mysqld_option "$override_file" "port" "$db_port"
upsert_mariadb_mysqld_option "$override_file" "bind-address" "$bind_address"
disable_mariadb_skip_networking
if ! restart_mariadb_service; then
echo -e "${red}重启 MariaDB 失败,请检查配置文件${plain}"
return 1
fi
return 0
}
has_mariadb_cli() { has_mariadb_cli() {
command -v mariadb >/dev/null 2>&1 || command -v mysql >/dev/null 2>&1 command -v mariadb >/dev/null 2>&1 || command -v mysql >/dev/null 2>&1
} }
@ -2920,6 +3129,30 @@ run_local_mariadb_admin_sql() {
esac esac
} }
run_local_mariadb_admin_query() {
local sql="$1"
local bin
local -a cmd
bin=$(mariadb_cli_bin) || return 1
case "$LOCAL_MARIADB_ADMIN_MODE" in
socket)
"$bin" -N -B -e "$sql" 2>/dev/null || "$bin" -uroot -N -B -e "$sql" 2>/dev/null
;;
password)
cmd=("$bin" -h "127.0.0.1" -P "$LOCAL_MARIADB_ADMIN_PORT" -u "$LOCAL_MARIADB_ADMIN_USER")
if [[ -n "$LOCAL_MARIADB_ADMIN_PASS" ]]; then
cmd+=("-p$LOCAL_MARIADB_ADMIN_PASS")
fi
cmd+=(-N -B -e "$sql")
"${cmd[@]}" 2>/dev/null
;;
*)
return 1
;;
esac
}
ensure_mariadb_database_and_user() { ensure_mariadb_database_and_user() {
local dbname="$1" dbuser="$2" dbpass="$3" local dbname="$1" dbuser="$2" dbpass="$3"
local escaped_pass local escaped_pass
@ -2949,6 +3182,229 @@ ensure_mariadb_database_and_user() {
run_local_mariadb_admin_sql "$sql" run_local_mariadb_admin_sql "$sql"
} }
CURRENT_LOCAL_DB_PORT=""
CURRENT_LOCAL_DB_USER=""
CURRENT_LOCAL_DB_PASS=""
CURRENT_LOCAL_DB_NAME=""
load_local_mariadb_business_context() {
local db_type=""
local db_host=""
db_type=$(read_json_dbtype)
if [ "$db_type" != "mariadb" ]; then
echo -e "${red}当前数据库类型不是 MariaDB${plain}"
return 1
fi
db_host=$(get_database_setting '.dbHost' '127.0.0.1')
if ! is_local_mariadb_host "$db_host"; then
echo -e "${red}当前面板使用的是远程 MariaDB无法管理本机 MariaDB 远程访问${plain}"
return 1
fi
CURRENT_LOCAL_DB_PORT=$(get_database_setting '.dbPort' '3306')
CURRENT_LOCAL_DB_USER=$(get_database_setting '.dbUser' '')
CURRENT_LOCAL_DB_PASS=$(get_database_setting '.dbPassword' '')
CURRENT_LOCAL_DB_NAME=$(get_database_setting '.dbName' '3xui')
if ! validate_tcp_port "$CURRENT_LOCAL_DB_PORT"; then
echo -e "${red}当前配置中的本地 MariaDB 端口无效${plain}"
return 1
fi
if [ -z "$CURRENT_LOCAL_DB_USER" ]; then
echo -e "${red}当前配置缺少 MariaDB 业务用户名${plain}"
return 1
fi
if [ -z "$CURRENT_LOCAL_DB_NAME" ]; then
echo -e "${red}当前配置缺少 MariaDB 业务数据库名${plain}"
return 1
fi
if ! is_safe_mariadb_identifier "$CURRENT_LOCAL_DB_USER"; then
echo -e "${red}当前配置中的 MariaDB 业务用户名不支持自动远程授权${plain}"
return 1
fi
if ! is_safe_mariadb_identifier "$CURRENT_LOCAL_DB_NAME"; then
echo -e "${red}当前配置中的 MariaDB 业务数据库名不支持自动远程授权${plain}"
return 1
fi
ensure_local_mariadb_ready || return 1
ensure_local_mariadb_admin_access "$CURRENT_LOCAL_DB_PORT" || return 1
return 0
}
list_remote_mariadb_hosts() {
local escaped_user=""
escaped_user=$(escape_sql_string "$CURRENT_LOCAL_DB_USER")
run_local_mariadb_admin_query "SELECT Host FROM mysql.user WHERE User = '${escaped_user}' AND Host NOT IN ('localhost', '127.0.0.1', '::1') ORDER BY Host;"
}
show_mariadb_remote_access_status() {
local bind_address=""
local server_port=""
local hosts=""
load_local_mariadb_business_context || return 1
bind_address=$(read_mariadb_server_option "bind-address" "127.0.0.1")
server_port=$(read_mariadb_server_option "port" "$CURRENT_LOCAL_DB_PORT")
hosts=$(list_remote_mariadb_hosts | sed '/^$/d')
echo -e "${green}MariaDB 服务端口: ${server_port}${plain}"
echo -e "${green}MariaDB 监听地址: ${bind_address}${plain}"
if [ "$bind_address" = "127.0.0.1" ]; then
echo -e "${yellow}远程访问状态: 已关闭${plain}"
else
echo -e "${yellow}远程访问状态: 已开启${plain}"
fi
if [ -n "$hosts" ]; then
echo -e "${green}允许的远程 IP:${plain}"
printf '%s\n' "$hosts"
else
echo -e "${yellow}允许的远程 IP: <empty>${plain}"
fi
}
add_mariadb_remote_ip_grant() {
local remote_ip="$1"
local escaped_user=""
local escaped_pass=""
local escaped_ip=""
if ! is_ip "$remote_ip"; then
echo -e "${red}仅支持输入单个 IP 地址${plain}"
return 1
fi
load_local_mariadb_business_context || return 1
escaped_user=$(escape_sql_string "$CURRENT_LOCAL_DB_USER")
escaped_pass=$(escape_sql_string "$CURRENT_LOCAL_DB_PASS")
escaped_ip=$(escape_sql_string "$remote_ip")
run_local_mariadb_admin_sql "CREATE USER IF NOT EXISTS '${escaped_user}'@'${escaped_ip}' IDENTIFIED BY '${escaped_pass}'; ALTER USER '${escaped_user}'@'${escaped_ip}' IDENTIFIED BY '${escaped_pass}'; GRANT ALL PRIVILEGES ON \`${CURRENT_LOCAL_DB_NAME}\`.* TO '${escaped_user}'@'${escaped_ip}'; FLUSH PRIVILEGES;"
}
remove_mariadb_remote_ip_grant() {
local remote_ip="$1"
local escaped_user=""
local escaped_ip=""
if ! is_ip "$remote_ip"; then
echo -e "${red}仅支持输入单个 IP 地址${plain}"
return 1
fi
load_local_mariadb_business_context || return 1
escaped_user=$(escape_sql_string "$CURRENT_LOCAL_DB_USER")
escaped_ip=$(escape_sql_string "$remote_ip")
run_local_mariadb_admin_sql "DROP USER IF EXISTS '${escaped_user}'@'${escaped_ip}'; FLUSH PRIVILEGES;"
}
set_local_mariadb_port() {
local current_port=""
local current_bind=""
local new_port=""
load_local_mariadb_business_context || return 1
current_port=$(read_mariadb_server_option "port" "$CURRENT_LOCAL_DB_PORT")
current_bind=$(read_mariadb_server_option "bind-address" "127.0.0.1")
read -rp "本地 MariaDB port [${current_port:-3306}]: " new_port
new_port="${new_port// /}"
new_port="${new_port:-$current_port}"
if ! validate_tcp_port "$new_port"; then
echo -e "${red}本地 MariaDB 端口无效,请输入 1-65535 之间的数字${plain}"
return 1
fi
if ! configure_local_mariadb_server_network "$new_port" "$current_bind"; then
return 1
fi
if ! ${xui_folder}/x-ui setting -dbPort "$new_port" >/dev/null 2>&1; then
echo -e "${red}写入面板数据库端口配置失败${plain}"
return 1
fi
echo -e "${yellow}本地 MariaDB 端口已更新为 ${new_port},建议重启面板使其完全生效。${plain}"
}
enable_mariadb_remote_access() {
local hosts=""
load_local_mariadb_business_context || return 1
hosts=$(list_remote_mariadb_hosts | sed '/^$/d')
if [ -z "$hosts" ]; then
echo -e "${red}请先添加至少一个允许的远程 IP${plain}"
return 1
fi
if ! configure_local_mariadb_server_network "$CURRENT_LOCAL_DB_PORT" "0.0.0.0"; then
return 1
fi
echo -e "${yellow}MariaDB 远程访问已开启,仅已授权的远程 IP 可连接。${plain}"
}
disable_mariadb_remote_access() {
local hosts=""
local host=""
load_local_mariadb_business_context || return 1
hosts=$(list_remote_mariadb_hosts | sed '/^$/d')
if [ -n "$hosts" ]; then
while IFS= read -r host; do
[ -n "$host" ] || continue
remove_mariadb_remote_ip_grant "$host" >/dev/null 2>&1 || true
done <<<"$hosts"
fi
if ! configure_local_mariadb_server_network "$CURRENT_LOCAL_DB_PORT" "127.0.0.1"; then
return 1
fi
echo -e "${yellow}MariaDB 远程访问已关闭,并已清理远程 IP 授权。${plain}"
}
show_mariadb_remote_ips() {
local hosts=""
load_local_mariadb_business_context || return 1
hosts=$(list_remote_mariadb_hosts | sed '/^$/d')
if [ -z "$hosts" ]; then
echo -e "${yellow}当前没有已授权的远程 IP${plain}"
return 0
fi
echo -e "${green}当前已授权的远程 IP:${plain}"
printf '%s\n' "$hosts"
}
add_mariadb_remote_ip() {
local remote_ip=""
read -rp "输入允许连接 MariaDB 的远程 IP: " remote_ip
remote_ip="${remote_ip// /}"
if ! add_mariadb_remote_ip_grant "$remote_ip"; then
echo -e "${red}添加 MariaDB 允许 IP 失败${plain}"
return 1
fi
echo -e "${yellow}已添加 MariaDB 允许 IP: ${remote_ip}${plain}"
}
remove_mariadb_remote_ip() {
local remote_ip=""
read -rp "输入要移除的远程 IP: " remote_ip
remote_ip="${remote_ip// /}"
if ! remove_mariadb_remote_ip_grant "$remote_ip"; then
echo -e "${red}移除 MariaDB 允许 IP 失败${plain}"
return 1
fi
echo -e "${yellow}已移除 MariaDB 允许 IP: ${remote_ip}${plain}"
}
# Switch to MariaDB # Switch to MariaDB
db_switch_to_mariadb() { db_switch_to_mariadb() {
local current_type=$(read_json_dbtype) local current_type=$(read_json_dbtype)
@ -3008,13 +3464,19 @@ db_switch_to_mariadb() {
fi fi
else else
db_host="127.0.0.1" db_host="127.0.0.1"
db_port="3306" read -rp "本地 MariaDB port [3306]: " db_port
read -rp "业务数据库名 [3xui]: " db_name read -rp "业务数据库名 [3xui]: " db_name
read -rp "业务用户名: " db_user read -rp "业务用户名: " db_user
read -rsp "业务密码: " db_pass read -rsp "业务密码: " db_pass
echo echo
db_port=${db_port:-3306}
db_name=${db_name:-3xui} db_name=${db_name:-3xui}
if ! validate_tcp_port "$db_port"; then
echo -e "${red}本地 MariaDB 端口无效,请输入 1-65535 之间的数字${plain}"
db_menu
return
fi
if [[ -z "$db_user" || -z "$db_pass" ]]; then if [[ -z "$db_user" || -z "$db_pass" ]]; then
echo -e "${red}业务用户名和业务密码不能为空${plain}" echo -e "${red}业务用户名和业务密码不能为空${plain}"
db_menu db_menu
@ -3026,6 +3488,10 @@ db_switch_to_mariadb() {
db_menu db_menu
return return
} }
configure_local_mariadb_server_network "$db_port" "127.0.0.1" || {
db_menu
return
}
ensure_local_mariadb_admin_access "$db_port" || { ensure_local_mariadb_admin_access "$db_port" || {
db_menu db_menu
return return
@ -3099,9 +3565,16 @@ db_menu() {
${green}7.${plain} 设置同步间隔 │ ${green}7.${plain} 设置同步间隔 │
${green}8.${plain} 设置流量回刷间隔 │ ${green}8.${plain} 设置流量回刷间隔 │
${green}9.${plain} 设置远程数据库连接 │ ${green}9.${plain} 设置远程数据库连接 │
${green}10.${plain} 设置本地 MariaDB 端口 │
${green}11.${plain} 查看 MariaDB 远程访问状态 │
${green}12.${plain} 开启 MariaDB 远程访问 │
${green}13.${plain} 关闭 MariaDB 远程访问 │
${green}14.${plain} 查看 MariaDB 允许 IP │
${green}15.${plain} 添加 MariaDB 允许 IP │
${green}16.${plain} 移除 MariaDB 允许 IP │
╚════════════════════════════════════════════════╝ ╚════════════════════════════════════════════════╝
" "
read -rp "请输入选择 [0-9]" num read -rp "请输入选择 [0-16]" num
case "${num}" in case "${num}" in
0) 0)
show_menu show_menu
@ -3140,6 +3613,34 @@ db_menu() {
set_remote_database_connection set_remote_database_connection
db_menu db_menu
;; ;;
10)
set_local_mariadb_port
db_menu
;;
11)
show_mariadb_remote_access_status
db_menu
;;
12)
enable_mariadb_remote_access
db_menu
;;
13)
disable_mariadb_remote_access
db_menu
;;
14)
show_mariadb_remote_ips
db_menu
;;
15)
add_mariadb_remote_ip
db_menu
;;
16)
remove_mariadb_remote_ip
db_menu
;;
*) *)
echo -e "${red}无效选项,请选择有效数字。${plain}\n" echo -e "${red}无效选项,请选择有效数字。${plain}\n"
db_menu db_menu