From 60d641a1a4ac4ccf22d23e699ca910a51c4b82a8 Mon Sep 17 00:00:00 2001 From: Erik Brakkee Date: Tue, 30 Jul 2024 19:45:25 +0200 Subject: [PATCH] When a duplicate id is requested the server now allocates a new unique id so that the session can be handled anyway. --- cmd/agent/agent.go | 25 +++++++++++++++++++++--- pkg/comms/agentserver.go | 16 ++++++++++++++++ pkg/comms/events.go | 13 +++++++++++-- pkg/converge/admin.go | 41 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 88 insertions(+), 7 deletions(-) diff --git a/cmd/agent/agent.go b/cmd/agent/agent.go index 4a03149..eacdc88 100755 --- a/cmd/agent/agent.go +++ b/cmd/agent/agent.go @@ -268,10 +268,26 @@ func main() { serverInfo, err := comms.AgentInitialization(wsConn, comms.NewAgentInfo()) if err != nil { - log.Printf("ERROR: %+v", err) + log.Printf("ERROR: %v", err) os.Exit(1) } + registration, err := comms.ReceiveRegistrationMessage(wsConn) + if err != nil { + log.Printf("ERROR: %v", err) + os.Exit(1) + } + log.Println("Server responded with: ", registration.Message) + + if registration.Id != id { + log.Println("==============================================================================") + log.Println("Duplicate agent id detected: the server allocated a new id to be used instead.") + log.Println("") + log.Println(registration.Id) + log.Println("==============================================================================") + } + clientUrl := args[0] + "/client/" + registration.Id + commChannel, err := comms.NewCommChannel(comms.Agent, wsConn) if err != nil { panic(err) @@ -298,7 +314,6 @@ func main() { log.Println() log.Printf("Clients should use the following commands to connect to this agent:") log.Println() - clientUrl := strings.ReplaceAll(wsURL, "/agent/", "/client/") sshCommand := fmt.Sprintf("ssh -oServerAliveInterval=10 -oProxyCommand=\"wsproxy %s\" %s@localhost", clientUrl, serverInfo.UserPassword.Username) sftpCommand := fmt.Sprintf("sftp -oServerAliveInterval=10 -oProxyCommand=\"wsproxy %s\" %s@localhost", @@ -311,9 +326,13 @@ func main() { log.Println() urlObject, _ := url.Parse(wsURL) + extension := "" + if runtime.GOOS == "windows" { + extension = ".exe" + } log.Printf("wsproxy can be downloaded from %s", strings.ReplaceAll(urlObject.Scheme, "ws", "http")+ - "://"+urlObject.Host+"/docs/wsproxy") + "://"+urlObject.Host+"/static/wsproxy"+extension) log.Println() agent.ConfigureAgent(commChannel, advanceWarningTime, agentExpriryTime, tickerInterval) diff --git a/pkg/comms/agentserver.go b/pkg/comms/agentserver.go index 10bf612..95b38a4 100644 --- a/pkg/comms/agentserver.go +++ b/pkg/comms/agentserver.go @@ -236,3 +236,19 @@ func ReceiveClientInfo(conn io.ReadWriter) (ClientInfo, error) { } return clientInfo, nil } + +// message sent on the initial connection from server to agent to confirm the registration + +func SendRegistrationMessage(conn io.ReadWriter, registration AgentRegistration) error { + channel := NewGOBChannel(conn) + return SendWithTimeout(channel, registration) +} + +func ReceiveRegistrationMessage(conn io.ReadWriter) (AgentRegistration, error) { + channel := NewGOBChannel(conn) + registration, err := ReceiveWithTimeout[AgentRegistration](channel) + if err != nil { + return AgentRegistration{}, err + } + return registration, nil +} diff --git a/pkg/comms/events.go b/pkg/comms/events.go index c3d50ff..28877ef 100644 --- a/pkg/comms/events.go +++ b/pkg/comms/events.go @@ -42,8 +42,6 @@ type HeartBeat struct { // Empty } -// Message sent from converge server to agent - type ProtocolVersion struct { Version int } @@ -53,10 +51,21 @@ type UserPassword struct { Password string } +// initialization mesaage when agent connects to server + type ServerInfo struct { UserPassword UserPassword } +// confirmation message when agent connects +type AgentRegistration struct { + Ok bool + Message string + // final Id assigned by the server. Usually identical to the requested id + // but if there is a conflict, a new id is chosen. + Id string +} + // Generic wrapper message required to send messages of arbitrary type type ConvergeMessage struct { diff --git a/pkg/converge/admin.go b/pkg/converge/admin.go index faf1000..c798cbd 100644 --- a/pkg/converge/admin.go +++ b/pkg/converge/admin.go @@ -95,13 +95,50 @@ func (admin *Admin) logStatus() { log.Printf("\n") } +func (admin *Admin) getFreeId(publicId string) (string, error) { + usedIds := make(map[string]bool) + for _, agent := range admin.agents { + usedIds[agent.PublicId] = true + } + if !usedIds[publicId] { + return publicId, nil + } + if usedIds[publicId] { + for i := 0; i < 100; i++ { + candidate := publicId + "-" + strconv.Itoa(i) + if !usedIds[candidate] { + return candidate, nil + } + } + } + return "", fmt.Errorf("Could not allocate agent id based on requested public id '%s'", publicId) +} + func (admin *Admin) addAgent(publicId string, agentInfo comms.AgentInfo, conn io.ReadWriteCloser) (*AgentConnection, error) { admin.mutex.Lock() defer admin.mutex.Unlock() + newPublicId, err := admin.getFreeId(publicId) + if err == nil { + message := "Requested id is accepted" + if publicId != newPublicId { + message = "The server allocated a new id." + } + publicId = newPublicId + comms.SendRegistrationMessage(conn, comms.AgentRegistration{ + Ok: true, + Message: message, + Id: publicId, + }) + } else { + comms.SendRegistrationMessage(conn, comms.AgentRegistration{ + Ok: false, + Message: err.Error(), + }) + } agent := admin.agents[publicId] if agent != nil { - return nil, fmt.Errorf("A different agent with same PublicId '%s' already registered", publicId) + return nil, fmt.Errorf("SHOULD NEVER GET HERE!!!, A different agent with same PublicId '%s' already registered", publicId) } commChannel, err := comms.NewCommChannel(comms.ConvergeServer, conn) @@ -188,7 +225,6 @@ func (admin *Admin) RemoveClient(client *ClientConnection) error { func (admin *Admin) Register(publicId string, conn io.ReadWriteCloser, userPassword comms.UserPassword) error { - defer conn.Close() serverInfo := comms.ServerInfo{ UserPassword: userPassword, @@ -203,6 +239,7 @@ func (admin *Admin) Register(publicId string, conn io.ReadWriteCloser, if err != nil { return err } + publicId = agent.PublicId defer func() { admin.RemoveAgent(publicId) }()