/src/osquery/plugins/logger/tls_logger.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * Copyright (c) 2014-present, The osquery authors |
3 | | * |
4 | | * This source code is licensed as defined by the LICENSE file found in the |
5 | | * root directory of this source tree. |
6 | | * |
7 | | * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) |
8 | | */ |
9 | | |
10 | | // clang-format off |
11 | | // Keep it on top of all other includes to fix double include WinSock.h header file |
12 | | // which is windows specific boost build problem |
13 | | #include <osquery/remote/utility.h> |
14 | | // clang-format on |
15 | | |
16 | | #include "tls_logger.h" |
17 | | |
18 | | #include <boost/property_tree/ptree.hpp> |
19 | | |
20 | | #include <osquery/remote/enroll/enroll.h> |
21 | | #include <osquery/core/flags.h> |
22 | | #include <osquery/core/flagalias.h> |
23 | | #include <osquery/registry/registry.h> |
24 | | |
25 | | #include <osquery/remote/serializers/json.h> |
26 | | |
27 | | #include <plugins/config/parsers/decorators.h> |
28 | | #include <osquery/utils/json/json.h> |
29 | | |
30 | | namespace osquery { |
31 | | |
32 | | FLAG(uint64, |
33 | | logger_tls_max_lines, |
34 | | 1024, |
35 | | "Max number of logs to send per period"); |
36 | | |
37 | | FLAG(string, logger_tls_endpoint, "", "TLS/HTTPS endpoint for results logging"); |
38 | | |
39 | | FLAG(uint64, |
40 | | logger_tls_period, |
41 | | 4, |
42 | | "Seconds between flushing logs over TLS/HTTPS"); |
43 | | |
44 | | FLAG(uint64, |
45 | | logger_tls_backoff_max, |
46 | | 60 * 60, |
47 | | "Maximum seconds to wait before flushing logs over TLS/HTTPS. Backoff " |
48 | | "kicks in when regular flush fails. Should be a multiple of " |
49 | | "logger_tls_period. 0 disables backoff"); |
50 | | |
51 | | FLAG(uint64, |
52 | | logger_tls_max_linesize, |
53 | | 1 * 1024 * 1024, |
54 | | "Max size in bytes allowed per log line"); |
55 | | |
56 | | FLAG(bool, tls_disable_status_log, false, "Disable sending status logs"); |
57 | | |
58 | | // The flag name logger_tls_max is deprecated. |
59 | | FLAG_ALIAS(google::uint64, logger_tls_max, logger_tls_max_linesize); |
60 | | |
61 | | FLAG(bool, logger_tls_compress, false, "GZip compress TLS/HTTPS request body"); |
62 | | |
63 | | REGISTER(TLSLoggerPlugin, "logger", "tls"); |
64 | | |
65 | | TLSLogForwarder::TLSLogForwarder() |
66 | 0 | : BufferedLogForwarder("TLSLogForwarder", |
67 | 0 | "tls", |
68 | 0 | std::chrono::seconds(FLAGS_logger_tls_period), |
69 | 0 | FLAGS_logger_tls_max_lines, |
70 | 0 | std::chrono::seconds(FLAGS_logger_tls_backoff_max)) { |
71 | 0 | uri_ = TLSRequestHelper::makeURI(FLAGS_logger_tls_endpoint); |
72 | 0 | } |
73 | | |
74 | 0 | Status TLSLoggerPlugin::logString(const std::string& s) { |
75 | 0 | return forwarder_->logString(s); |
76 | 0 | } |
77 | | |
78 | 0 | Status TLSLoggerPlugin::logStatus(const std::vector<StatusLogLine>& log) { |
79 | 0 | return forwarder_->logStatus(log); |
80 | 0 | } |
81 | | |
82 | 0 | Status TLSLoggerPlugin::setUp() { |
83 | | // Start the log forwarding/flushing thread. |
84 | 0 | forwarder_ = std::make_shared<TLSLogForwarder>(); |
85 | 0 | Status s = forwarder_->setUp(); |
86 | 0 | if (!s.ok()) { |
87 | 0 | LOG(ERROR) << "Error initializing TLS logger: " << s.getMessage(); |
88 | 0 | return s; |
89 | 0 | } |
90 | | |
91 | 0 | auto node_key = getNodeKey("tls"); |
92 | 0 | if (!FLAGS_disable_enrollment && node_key.size() == 0) { |
93 | | // Could not generate a node key, continue logging to stderr. |
94 | 0 | return Status(1, "No node key, TLS logging disabled."); |
95 | 0 | } |
96 | | |
97 | 0 | Dispatcher::addService(forwarder_); |
98 | |
|
99 | 0 | return Status(0); |
100 | 0 | } |
101 | | |
102 | | void TLSLoggerPlugin::init(const std::string& name, |
103 | 0 | const std::vector<StatusLogLine>& log) { |
104 | 0 | logStatus(log); |
105 | 0 | } |
106 | | |
107 | 0 | void TLSLoggerPlugin::configure() { |
108 | 0 | if (forwarder_ != nullptr) { |
109 | 0 | std::unique_lock<decltype(forwarder_->configuration_mutex)> lock( |
110 | 0 | forwarder_->configuration_mutex); |
111 | 0 | forwarder_->configuration_updated = true; |
112 | 0 | forwarder_->updated_uri = |
113 | 0 | TLSRequestHelper::makeURI(FLAGS_logger_tls_endpoint); |
114 | 0 | forwarder_->updated_log_period = |
115 | 0 | std::chrono::seconds(FLAGS_logger_tls_period); |
116 | 0 | forwarder_->updated_max_log_lines = FLAGS_logger_tls_max_lines; |
117 | 0 | forwarder_->updated_max_backoff_period = |
118 | 0 | std::chrono::seconds(FLAGS_logger_tls_backoff_max); |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | | Status TLSLogForwarder::send(std::vector<std::string>& log_data, |
123 | 0 | const std::string& log_type) { |
124 | | // Skip sending status logs to remote server if disabled |
125 | 0 | if (FLAGS_tls_disable_status_log && log_type == "status") { |
126 | 0 | return Status::success(); |
127 | 0 | } |
128 | | |
129 | 0 | JSON params; |
130 | 0 | params.add("node_key", getNodeKey("tls")); |
131 | 0 | params.add("log_type", log_type); |
132 | |
|
133 | 0 | { |
134 | | // Read each logged line into JSON and populate a list of lines. |
135 | | // The result list will use the 'data' key. |
136 | 0 | auto children = params.newArray(); |
137 | 0 | iterate(log_data, ([¶ms, &children](std::string& item) { |
138 | | // Enforce a max log line size for TLS logging. |
139 | 0 | if (item.size() > FLAGS_logger_tls_max_linesize) { |
140 | 0 | LOG(WARNING) |
141 | 0 | << "Linesize exceeds TLS logger maximum: " << item.size(); |
142 | 0 | return; |
143 | 0 | } |
144 | | |
145 | 0 | JSON child; |
146 | 0 | Status s = child.fromString(item); |
147 | 0 | if (!s.ok()) { |
148 | | // The log line entered was not valid JSON, skip it. |
149 | 0 | return; |
150 | 0 | } |
151 | 0 | std::string().swap(item); |
152 | 0 | params.push(child.doc(), children.doc()); |
153 | 0 | })); |
154 | 0 | params.add("data", children.doc()); |
155 | 0 | } |
156 | | |
157 | | // The response body is ignored (status is set appropriately by |
158 | | // TLSRequestHelper::go()) |
159 | 0 | std::string response; |
160 | 0 | if (FLAGS_logger_tls_compress) { |
161 | 0 | params.add("_compress", true); |
162 | 0 | } |
163 | 0 | return TLSRequestHelper::go<JSONSerializer>(uri_, params, response); |
164 | 0 | } |
165 | | |
166 | 0 | void TLSLogForwarder::applyNewConfiguration() { |
167 | 0 | std::unique_lock<decltype(configuration_mutex)> lock(configuration_mutex); |
168 | 0 | if (configuration_updated) { |
169 | 0 | uri_ = updated_uri; |
170 | 0 | log_period_ = updated_log_period; |
171 | 0 | max_log_lines_ = updated_max_log_lines; |
172 | 0 | max_backoff_period_ = updated_max_backoff_period; |
173 | 0 | } |
174 | 0 | configuration_updated = false; |
175 | 0 | } |
176 | | |
177 | | } // namespace osquery |