mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-20 08:03:55 +08:00
feat: Optimize SSH session performance on Ubuntu 25. (#13152)
* feat: Optimize SSH session performance on Ubuntu 25. * feat: Optimize SSH session performance on Ubuntu 25. * feat: Optimize SSH session performance on Ubuntu 25. * feat: Optimize SSH session performance on Ubuntu 25.
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -250,8 +252,13 @@ func getSSHSessions(config SSHSessionConfig) (res []byte, err error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
if sessions, ok := loadLoginctlSSHSessions(ctx); ok && len(sessions) > 0 {
|
||||
res, err = json.Marshal(filterSSHSessions(sessions, config))
|
||||
return
|
||||
}
|
||||
|
||||
users, err = host.UsersWithContext(ctx)
|
||||
if err != nil {
|
||||
if err != nil || len(users) == 0 {
|
||||
res, err = json.Marshal(result)
|
||||
return
|
||||
}
|
||||
@@ -275,6 +282,22 @@ func getSSHSessions(config SSHSessionConfig) (res []byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
connections, err := net.ConnectionsMaxWithContext(ctx, "all", 32768)
|
||||
if err != nil {
|
||||
res, err = json.Marshal(result)
|
||||
return
|
||||
}
|
||||
pidConnections := make(map[int32][]net.ConnectionStat, 256)
|
||||
for _, conn := range connections {
|
||||
if conn.Pid == 0 || conn.Raddr.IP == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := usersByHost[conn.Raddr.IP]; !ok {
|
||||
continue
|
||||
}
|
||||
pidConnections[conn.Pid] = append(pidConnections[conn.Pid], conn)
|
||||
}
|
||||
|
||||
processes, err = process.ProcessesWithContext(ctx)
|
||||
if err != nil {
|
||||
res, err = json.Marshal(result)
|
||||
@@ -286,12 +309,12 @@ func getSSHSessions(config SSHSessionConfig) (res []byte, err error) {
|
||||
if name != "sshd" || proc.Pid == 0 {
|
||||
continue
|
||||
}
|
||||
connections, _ := proc.Connections()
|
||||
connections := pidConnections[proc.Pid]
|
||||
if len(connections) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
cmdline, cmdErr := proc.Cmdline()
|
||||
cmdline, cmdErr := proc.CmdlineWithContext(ctx)
|
||||
if cmdErr != nil {
|
||||
continue
|
||||
}
|
||||
@@ -320,6 +343,86 @@ func getSSHSessions(config SSHSessionConfig) (res []byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func loadLoginctlSSHSessions(ctx context.Context) ([]sshSession, bool) {
|
||||
if _, err := exec.LookPath("loginctl"); err != nil {
|
||||
return nil, false
|
||||
}
|
||||
output, err := exec.CommandContext(ctx, "loginctl", "list-sessions", "--no-legend", "--no-pager").Output()
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
var result []sshSession
|
||||
for _, line := range strings.Split(string(output), "\n") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
sessionOutput, err := exec.CommandContext(ctx, "loginctl", "show-session", fields[0], "--no-pager",
|
||||
"-p", "Name", "-p", "Remote", "-p", "RemoteHost", "-p", "TTY", "-p", "Timestamp", "-p", "Leader", "-p", "Service", "-p", "State").Output()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
session, ok := parseLoginctlSSHSession(string(sessionOutput))
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
result = append(result, session)
|
||||
}
|
||||
return result, true
|
||||
}
|
||||
|
||||
func filterSSHSessions(sessions []sshSession, config SSHSessionConfig) []sshSession {
|
||||
result := make([]sshSession, 0, len(sessions))
|
||||
for _, session := range sessions {
|
||||
if config.LoginUser != "" && !strings.Contains(session.Username, config.LoginUser) {
|
||||
continue
|
||||
}
|
||||
if config.LoginIP != "" && !strings.Contains(session.Host, config.LoginIP) {
|
||||
continue
|
||||
}
|
||||
result = append(result, session)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func parseLoginctlSSHSession(output string) (sshSession, bool) {
|
||||
props := map[string]string{}
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
key, value, ok := strings.Cut(line, "=")
|
||||
if ok {
|
||||
props[key] = strings.TrimSpace(value)
|
||||
}
|
||||
}
|
||||
service := props["Service"]
|
||||
if props["Remote"] != "yes" || props["Name"] == "" || props["RemoteHost"] == "" || props["State"] != "active" || (service != "sshd" && service != "ssh") {
|
||||
return sshSession{}, false
|
||||
}
|
||||
pid, _ := strconv.ParseInt(props["Leader"], 10, 32)
|
||||
return sshSession{
|
||||
Username: props["Name"],
|
||||
Host: props["RemoteHost"],
|
||||
Terminal: props["TTY"],
|
||||
PID: int32(pid),
|
||||
LoginTime: parseLoginctlTimestamp(props["Timestamp"]),
|
||||
}, true
|
||||
}
|
||||
|
||||
func parseLoginctlTimestamp(value string) string {
|
||||
fields := strings.Fields(value)
|
||||
for i := 0; i < len(fields)-1; i++ {
|
||||
if strings.Count(fields[i], "-") != 2 || strings.Count(fields[i+1], ":") != 2 {
|
||||
continue
|
||||
}
|
||||
candidate := fields[i] + " " + fields[i+1]
|
||||
t, err := time.ParseInLocation("2006-01-02 15:04:05", candidate, time.Local)
|
||||
if err != nil {
|
||||
return candidate
|
||||
}
|
||||
return t.Format("2006-1-2 15:04:05")
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func getNetConnections(config NetConfig) (res []byte, err error) {
|
||||
result := make([]ProcessConnect, 0, 1024)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
|
||||
@@ -134,6 +134,8 @@ const stop = async (PID: number) => {
|
||||
.then(async () => {
|
||||
try {
|
||||
await stopProcess({ PID: PID });
|
||||
data.value = data.value.filter((item: any) => item.PID !== PID);
|
||||
search();
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
} catch (error) {
|
||||
MsgError(error);
|
||||
|
||||
Reference in New Issue
Block a user