fix: bound and complete console relay teardown, restore proxy_failed audit
- Arm the unclaimed-relay watchdog in NewSession rather than Serve, so an agent that never opens its ProxyStream is bounded to 10s and reports reason "agent_timeout", per the design spec's failure-mode table. - Session.Close now also closes the accepted net.Conn (stored via setConn), so ConsoleProxy.Close() is an unconditional kill of the whole relay chain instead of only closing an already-idle listener. - Emit console.proxy_failed and end the console session from a defer in consoleTunnel guarded on relay.Reason(), since guac's OnDisconnect never runs when the connect callback errors -- which is the path every relay failure this feature introduces takes. Update the two docsite troubleshooting rows to match what the audit event can now actually show.
This commit is contained in:
@@ -150,7 +150,22 @@ func consoleTunnel(c *gin.Context) {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "could not open relay"})
|
||||
return
|
||||
}
|
||||
defer relay.Close()
|
||||
// guac.WebsocketServer.ServeHTTP returns before installing its
|
||||
// OnDisconnect handler when the connect callback errors, which is exactly
|
||||
// the path every relay failure this proxy introduces takes (the agent
|
||||
// never claims it, dial_refused, guacd never dials, rejected). Emitting
|
||||
// console.proxy_failed and ending the session here, unconditionally on
|
||||
// teardown, is what makes those failures reach the audit log at all;
|
||||
// OnDisconnect below only sees the rarer case of a session that was fully
|
||||
// established and then failed.
|
||||
defer func() {
|
||||
relay.Close()
|
||||
if reason := relay.Reason(); reason != "" {
|
||||
services.LogEvent(instanceID, "console.proxy_failed", actorFromCtx(c), srv.ServerID, "",
|
||||
fmt.Sprintf("console relay failed: %s (proxy_id=%s, port=%d)", reason, relay.ProxyID, relay.Port))
|
||||
}
|
||||
_ = services.EndConsoleSession(instanceID, sessionID)
|
||||
}()
|
||||
|
||||
services.LogEvent(instanceID, "console.proxy_opened", actorFromCtx(c), srv.ServerID, "",
|
||||
fmt.Sprintf("console relay opened (proxy_id=%s, port=%d)", relay.ProxyID, relay.Port))
|
||||
@@ -192,14 +207,9 @@ func consoleTunnel(c *gin.Context) {
|
||||
return guac.NewSimpleTunnel(stream), nil
|
||||
}
|
||||
|
||||
// Teardown (proxy_failed audit + EndConsoleSession) lives in the deferred
|
||||
// func above, not here: this only fires once a tunnel was actually
|
||||
// established, and letting both paths log would double the audit event.
|
||||
wsServer := guac.NewWebsocketServer(connect)
|
||||
wsServer.OnDisconnect = func(id string, r *http.Request, t guac.Tunnel) {
|
||||
if reason := relay.Reason(); reason != "" {
|
||||
services.LogEvent(instanceID, "console.proxy_failed", actorFromCtx(c), srv.ServerID, "",
|
||||
fmt.Sprintf("console relay failed: %s (proxy_id=%s, port=%d)", reason, relay.ProxyID, relay.Port))
|
||||
}
|
||||
relay.Close()
|
||||
_ = services.EndConsoleSession(instanceID, sessionID)
|
||||
}
|
||||
wsServer.ServeHTTP(c.Writer, c.Request)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user