// sendSshKeepAlive is a helper which sends a [email protected] request // on the specified SSH connections and returns true of the request succeeds // within a specified timeout. If the request fails, the associated conn is // closed, which will terminate the associated tunnel. func sendSshKeepAlive( sshClient *ssh.Client, conn net.Conn, timeout time.Duration) error { errChannel := make(chan error, 2) if timeout > 0 { time.AfterFunc(timeout, func() { errChannel <- TimeoutError{} }) } go func() { // Random padding to frustrate fingerprinting randomPadding, err := common.MakeSecureRandomPadding(0, TUNNEL_SSH_KEEP_ALIVE_PAYLOAD_MAX_BYTES) if err != nil { NoticeAlert("MakeSecureRandomPadding failed: %s", err) // Proceed without random padding randomPadding = make([]byte, 0) } // Note: reading a reply is important for last-received-time tunnel // duration calculation. _, _, err = sshClient.SendRequest("*****@*****.**", true, randomPadding) errChannel <- err }() err := <-errChannel if err != nil { sshClient.Close() conn.Close() } return common.ContextError(err) }
func (serverContext *ServerContext) getStatusParams(isTunneled bool) requestJSONObject { params := serverContext.getBaseParams() // Add a random amount of padding to help prevent stats updates from being // a predictable size (which often happens when the connection is quiet). // TODO: base64 encoding of padding means the padding size is not exactly // [0, PADDING_MAX_BYTES]. randomPadding, err := common.MakeSecureRandomPadding(0, PSIPHON_API_STATUS_REQUEST_PADDING_MAX_BYTES) if err != nil { NoticeAlert("MakeSecureRandomPadding failed: %s", err) // Proceed without random padding randomPadding = make([]byte, 0) } params["padding"] = base64.StdEncoding.EncodeToString(randomPadding) // Legacy clients set "connected" to "0" when disconnecting, and this value // is used to calculate session duration estimates. This is now superseded // by explicit tunnel stats duration reporting. // The legacy method of reconstructing session durations is not compatible // with this client's connected request retries and asynchronous final // status request attempts. So we simply set this "connected" flag to reflect // whether the request is sent tunneled or not. connected := "1" if !isTunneled { connected = "0" } params["connected"] = connected return params }