mirror of
https://github.com/SunBK201/UA3F.git
synced 2025-12-16 08:44:29 +00:00
feat: port user group management
This commit is contained in:
parent
bdd13b0b86
commit
a7a9f45145
@ -6,71 +6,6 @@ START=99
|
|||||||
|
|
||||||
NAME="ua3f"
|
NAME="ua3f"
|
||||||
PROG="/usr/bin/$NAME"
|
PROG="/usr/bin/$NAME"
|
||||||
SERVER_MODE=""
|
|
||||||
UA3F_GROUP="nogroup"
|
|
||||||
LOG_FILE="/var/log/ua3f/ua3f.log"
|
|
||||||
|
|
||||||
LOG() {
|
|
||||||
if [ -n "${1}" ]; then
|
|
||||||
printf '[%s] %s\n' "$(date "+%Y-%m-%d %H:%M:%S")" "$1" >>"$LOG_FILE"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
opkg_available() { command -v opkg >/dev/null 2>&1; }
|
|
||||||
|
|
||||||
openclash_exists() {
|
|
||||||
if opkg_available; then
|
|
||||||
if opkg list-installed luci-app-openclash | grep -q 'luci-app-openclash'; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
openclash_running() {
|
|
||||||
if pgrep -f "openclash" >/dev/null 2>&1; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
shellclash_exists() {
|
|
||||||
if id -u shellclash >/dev/null 2>&1; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if id -u shellcrash >/dev/null 2>&1; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
shellclash_running() {
|
|
||||||
if pgrep -f "ShellCrash" >/dev/null 2>&1; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
set_ua3f_group() {
|
|
||||||
if [ "$SERVER_MODE" = "REDIRECT" ]; then
|
|
||||||
UA3F_GROUP="root"
|
|
||||||
return
|
|
||||||
elif [ "$SERVER_MODE" = "NFQUEUE" ]; then
|
|
||||||
UA3F_GROUP="root"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
if openclash_running; then
|
|
||||||
UA3F_GROUP="nogroup"
|
|
||||||
elif shellclash_running; then
|
|
||||||
UA3F_GROUP="shellcrash"
|
|
||||||
elif openclash_exists; then
|
|
||||||
UA3F_GROUP="nogroup"
|
|
||||||
elif shellclash_exists; then
|
|
||||||
UA3F_GROUP="shellcrash"
|
|
||||||
else
|
|
||||||
UA3F_GROUP="nogroup"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
start_service() {
|
start_service() {
|
||||||
config_load "$NAME"
|
config_load "$NAME"
|
||||||
@ -83,10 +18,10 @@ start_service() {
|
|||||||
config_get_bool enabled "enabled" "enabled" "0"
|
config_get_bool enabled "enabled" "enabled" "0"
|
||||||
[ "$enabled" -eq "1" ] || return 0
|
[ "$enabled" -eq "1" ] || return 0
|
||||||
|
|
||||||
local port bind ua log_level ua_regex partial_replace
|
local server_mode port bind ua log_level ua_regex partial_replace
|
||||||
local rewrite_mode rewrite_rules
|
local rewrite_mode rewrite_rules
|
||||||
local set_ttl set_ipid del_tcpts
|
local set_ttl set_ipid del_tcpts
|
||||||
config_get SERVER_MODE "main" "server_mode" "TPROXY"
|
config_get server_mode "main" "server_mode" "TPROXY"
|
||||||
config_get port "main" "port" "1080"
|
config_get port "main" "port" "1080"
|
||||||
config_get bind "main" "bind" "127.0.0.1"
|
config_get bind "main" "bind" "127.0.0.1"
|
||||||
config_get ua "main" "ua" "FFF"
|
config_get ua "main" "ua" "FFF"
|
||||||
@ -99,21 +34,16 @@ start_service() {
|
|||||||
config_get_bool set_ipid "main" "set_ipid" 0
|
config_get_bool set_ipid "main" "set_ipid" 0
|
||||||
config_get_bool del_tcpts "main" "del_tcpts" 0
|
config_get_bool del_tcpts "main" "del_tcpts" 0
|
||||||
|
|
||||||
# compose set_ttl set_ipid del_tcpts with others ",ttl,ipid,tcpts,"
|
|
||||||
local others=","
|
local others=","
|
||||||
[ "$set_ipid" -eq "1" ] && others="${others}ipid,"
|
[ "$set_ipid" -eq "1" ] && others="${others}ipid,"
|
||||||
[ "$del_tcpts" -eq "1" ] && others="${others}tcpts,"
|
[ "$del_tcpts" -eq "1" ] && others="${others}tcpts,"
|
||||||
[ "$set_ttl" -eq "1" ] && others="${others}ttl,"
|
[ "$set_ttl" -eq "1" ] && others="${others}ttl,"
|
||||||
|
|
||||||
SERVER_MODE="$(echo "$SERVER_MODE" | tr '[:lower:]' '[:upper:]')"
|
|
||||||
|
|
||||||
set_ua3f_group
|
set_ua3f_group
|
||||||
LOG "Server Mode: $SERVER_MODE"
|
|
||||||
LOG "Group: $UA3F_GROUP"
|
|
||||||
|
|
||||||
procd_open_instance "$NAME"
|
procd_open_instance "$NAME"
|
||||||
procd_set_param command "$PROG"
|
procd_set_param command "$PROG"
|
||||||
procd_append_param command -m "$SERVER_MODE"
|
procd_append_param command -m "$server_mode"
|
||||||
procd_append_param command -p "$port"
|
procd_append_param command -p "$port"
|
||||||
procd_append_param command -b "$bind"
|
procd_append_param command -b "$bind"
|
||||||
procd_append_param command -f "$ua"
|
procd_append_param command -f "$ua"
|
||||||
@ -128,11 +58,8 @@ start_service() {
|
|||||||
procd_set_param stdout 1
|
procd_set_param stdout 1
|
||||||
procd_set_param stderr 1
|
procd_set_param stderr 1
|
||||||
procd_set_param limits nproc="unlimited" as="unlimited" memlock="unlimited" nofile="65535 65535"
|
procd_set_param limits nproc="unlimited" as="unlimited" memlock="unlimited" nofile="65535 65535"
|
||||||
procd_set_param group $UA3F_GROUP
|
|
||||||
|
|
||||||
procd_close_instance
|
procd_close_instance
|
||||||
|
|
||||||
LOG "$NAME service started"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
service_triggers() {
|
service_triggers() {
|
||||||
|
|||||||
11
src/internal/usergroup/usergroup_others.go
Normal file
11
src/internal/usergroup/usergroup_others.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
package usergroup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sunbk201/ua3f/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetUserGroup(cfg *config.Config) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
138
src/internal/usergroup/usergroup_unix.go
Normal file
138
src/internal/usergroup/usergroup_unix.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package usergroup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/sunbk201/ua3f/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetUserGroup(cfg *config.Config) error {
|
||||||
|
groupName := determineGroup(cfg.ServerMode)
|
||||||
|
if groupName == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gid, err := getGroupID(groupName)
|
||||||
|
if err != nil {
|
||||||
|
slog.Warn("getGroupID", slog.String("group", groupName), slog.Any("error", err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := syscall.Setgid(gid); err != nil {
|
||||||
|
if err == syscall.EPERM {
|
||||||
|
slog.Warn("syscall.Setgid", slog.String("group", groupName), slog.Int("gid", gid), slog.Any("error", err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("syscall.Setgid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Info("Setup user group", slog.String("group", groupName), slog.Int("gid", gid))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func determineGroup(serverMode config.ServerMode) string {
|
||||||
|
if serverMode == config.ServerModeRedirect || serverMode == config.ServerModeNFQueue {
|
||||||
|
return "root"
|
||||||
|
}
|
||||||
|
|
||||||
|
if processRunning("openclash") {
|
||||||
|
return "nogroup"
|
||||||
|
}
|
||||||
|
|
||||||
|
if processRunning("ShellCrash") {
|
||||||
|
return "shellcrash"
|
||||||
|
}
|
||||||
|
|
||||||
|
if openClashExists() {
|
||||||
|
return "nogroup"
|
||||||
|
}
|
||||||
|
|
||||||
|
if shellClashExists() {
|
||||||
|
return "shellcrash"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "nogroup"
|
||||||
|
}
|
||||||
|
|
||||||
|
func openClashExists() bool {
|
||||||
|
if !opkgAvailable() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("opkg", "list-installed", "luci-app-openclash")
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Contains(string(output), "luci-app-openclash")
|
||||||
|
}
|
||||||
|
|
||||||
|
func shellClashExists() bool {
|
||||||
|
if userExists("shellclash") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if userExists("shellcrash") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func opkgAvailable() bool {
|
||||||
|
_, err := exec.LookPath("opkg")
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processRunning(name string) bool {
|
||||||
|
cmd := exec.Command("pgrep", "-f", name)
|
||||||
|
err := cmd.Run()
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func userExists(username string) bool {
|
||||||
|
cmd := exec.Command("id", "-u", username)
|
||||||
|
err := cmd.Run()
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGroupID(groupName string) (int, error) {
|
||||||
|
if groupName == "root" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open("/etc/group")
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to open /etc/group: %w", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = file.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
parts := strings.Split(line, ":")
|
||||||
|
if len(parts) >= 3 && parts[0] == groupName {
|
||||||
|
gid, err := strconv.Atoi(parts[2])
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to parse GID for group %s: %w", groupName, err)
|
||||||
|
}
|
||||||
|
return gid, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return 0, fmt.Errorf("error reading /etc/group: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf("group %s not found", groupName)
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/sunbk201/ua3f/internal/server"
|
"github.com/sunbk201/ua3f/internal/server"
|
||||||
"github.com/sunbk201/ua3f/internal/server/netlink"
|
"github.com/sunbk201/ua3f/internal/server/netlink"
|
||||||
"github.com/sunbk201/ua3f/internal/statistics"
|
"github.com/sunbk201/ua3f/internal/statistics"
|
||||||
|
"github.com/sunbk201/ua3f/internal/usergroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
var appVersion = "Development"
|
var appVersion = "Development"
|
||||||
@ -30,6 +31,11 @@ func main() {
|
|||||||
|
|
||||||
log.LogHeader(appVersion, cfg)
|
log.LogHeader(appVersion, cfg)
|
||||||
|
|
||||||
|
if err := usergroup.SetUserGroup(cfg); err != nil {
|
||||||
|
slog.Error("usergroup.SetUserGroup", slog.Any("error", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
rw, err := rewrite.New(cfg)
|
rw, err := rewrite.New(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("rewrite.New", slog.Any("error", err))
|
slog.Error("rewrite.New", slog.Any("error", err))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user