osquery-1/osquery/distributed/distributed.h
Zachary Wasserman 79034111a5 POC for client side of distributed queries.
This introduces the notion of a DistributedQueryHandler that uses a "provider" to read/write requests and results to and from the master. The full flow is exercised via integration tests, and unit tests for each component.

It is intended to foster discussion around this client side interface, as well as provide a base to build from.
2015-02-13 13:01:02 -08:00

155 lines
4.7 KiB
C++

/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#pragma once
#include <set>
#include <vector>
#include <boost/property_tree/ptree.hpp>
#include <osquery/database/results.h>
#include <osquery/sql.h>
namespace osquery {
/**
* @brief This is an interface for distributed query "providers"
*
* Providers implement the communication between the distributed query master
* and the individual host. A provider may utilize any communications strategy
* that supports reading and writing JSON (i.e. HTTPS requests, reading from a
* file, querying a message queue, etc.)
*/
class IDistributedProvider {
public:
virtual ~IDistributedProvider() {}
/*
* @brief Get the JSON string containing the queries to be executed
*
* @param query_json A string to fill with the retrieved JSON
*
* @return osquery::Status indicating success or failure of the operation
*/
virtual Status getQueriesJSON(std::string& query_json) = 0;
/*
* @brief Write the results JSON back to the master
*
* @param results A string containing the results JSON
*
* @return osquery::Status indicating success or failure of the operation
*/
virtual Status writeResultsJSON(const std::string& results) = 0;
};
/**
* @brief A mocked implementation of IDistributedProvider
*
* This implementation is useful for writing unit tests of the
* DistributedQueryHandler functionality.
*/
class MockDistributedProvider : public IDistributedProvider {
public:
// These methods just read/write the corresponding public members
Status getQueriesJSON(std::string& query_json) override;
Status writeResultsJSON(const std::string& results) override;
std::string queriesJSON_;
std::string resultsJSON_;
};
/**
* @brief Small struct containing the query and ID information for a
* distributed query
*/
struct DistributedQueryRequest {
public:
explicit DistributedQueryRequest() {}
explicit DistributedQueryRequest(const std::string& q, const std::string& i)
: query(q), id(i) {}
std::string query;
std::string id;
};
/**
* @brief The main handler class for distributed queries
*
* This class is responsible for implementing the core functionality of
* distributed queries. It manages state, uses the provider to read/write from
* the master, and executes queries.
*/
class DistributedQueryHandler {
public:
/**
* @brief Construct a new handler with the given provider
*
* @param provider The provider used retrieving queries and writing results
*/
explicit DistributedQueryHandler(
std::unique_ptr<IDistributedProvider> provider)
: provider_(std::move(provider)) {}
/**
* @brief Retrieve queries, run them, and write results
*
* This is the core method of DistributedQueryHandler, tying together all the
* other components to read the requests from the provider, execute the
* queries, and write the results back to the provider.
*
* @return osquery::Status indicating success or failure of the operation
*/
Status doQueries();
/**
* @brief Run and annotate an individual query
*
* @param query_string A string containing the query to be executed
*
* @return A SQL object containing the (annotated) query results
*/
static SQL handleQuery(const std::string& query_string);
/**
* @brief Serialize the results of all requests into a ptree
*
* @param results The vector of requests and results
* @param tree The tree to serialize results into
*
* @return osquery::Status indicating success or failure of the operation
*/
static Status serializeResults(
const std::vector<std::pair<DistributedQueryRequest, SQL> >& results,
boost::property_tree::ptree& tree);
/**
* @brief Parse the query JSON into the individual query objects
*
* @param query_json The JSON string containing the queries
* @param requests A vector to fill with the query objects
*
* @return osquery::Status indicating success or failure of the parsing
*/
static Status parseQueriesJSON(const std::string& query_json,
std::vector<DistributedQueryRequest>& requests);
private:
// The provider used to read and write queries and results
std::unique_ptr<IDistributedProvider> provider_;
// Used to store already executed queries to avoid duplication. (Some master
// configurations may asynchronously process the results of requests, so a
// request might be seen by the host after it has already been executed.)
std::set<std::string> executedRequestIds_;
};
} // namespace osquery