Tor 0.4.9.0-alpha-dev
metrics.c
Go to the documentation of this file.
1/* Copyright (c) 2007-2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * @file metrics.c
6 * @brief Metrics subsystem.
7 **/
8
9#include "orconfig.h"
10
11#include "core/or/or.h"
12
14#include "lib/log/util_bug.h"
15#include "lib/malloc/malloc.h"
17#include "lib/net/resolve.h"
18#include "lib/string/printf.h"
19#include "lib/net/nettypes.h"
20#include "lib/net/address.h"
21
25#include "core/or/policies.h"
26#include "core/or/port_cfg_st.h"
28
31
32#include "app/config/config.h"
33#include "app/main/subsysmgr.h"
34
35/** Metrics format driver set by the MetricsPort option. */
37
38/** Return true iff the given peer address is allowed by our MetricsPortPolicy
39 * option that is is in that list. */
40static bool
42{
43 tor_assert(peer_addr);
44
45 return metrics_policy_permits_address(peer_addr);
46}
47
48/** Helper: For a metrics port connection, write the HTTP response header
49 * using the data length passed. */
50static void
51write_metrics_http_response(const size_t data_len, connection_t *conn)
52{
53 char date[RFC1123_TIME_LEN+1];
54 buf_t *buf = buf_new_with_capacity(128 + data_len);
55
57 buf_add_printf(buf, "HTTP/1.0 200 OK\r\nDate: %s\r\n", date);
58 buf_add_printf(buf, "Content-Type: text/plain; charset=utf-8\r\n");
59 buf_add_printf(buf, "Content-Length: %" TOR_PRIuSZ "\r\n", data_len);
60 buf_add_string(buf, "\r\n");
61
62 connection_buf_add_buf(conn, buf);
63 buf_free(buf);
64}
65
66/** Return newly allocated buffer containing the output of all subsystems
67 * having metrics.
68 *
69 * This is used to output the content on the MetricsPort. */
70buf_t *
72{
73 buf_t *data = buf_new();
74
75 /* Go over all subsystems that exposes a metrics store. */
76 for (unsigned i = 0; i < n_tor_subsystems; ++i) {
77 const smartlist_t *stores;
78 const subsys_fns_t *sys = tor_subsystems[i];
79
80 /* Skip unsupported subsystems. */
81 if (!sys->supported) {
82 continue;
83 }
84
85 if (sys->get_metrics && (stores = sys->get_metrics())) {
86 SMARTLIST_FOREACH_BEGIN(stores, const metrics_store_t *, store) {
87 metrics_store_get_output(fmt, store, data);
88 } SMARTLIST_FOREACH_END(store);
89 }
90 }
91
92 return data;
93}
94
95/** Process what is in the inbuf of this connection of type metrics.
96 *
97 * Return 0 on success else -1 on error for which the connection is marked for
98 * close. */
99int
101{
102 int ret = -1;
103 char *headers = NULL, *command = NULL, *url = NULL;
104 const char *errmsg = NULL;
105
106 tor_assert(conn);
108
109 if (!metrics_request_allowed(&conn->addr)) {
110 /* Close connection. Don't bother returning anything if you are not
111 * allowed by being on the policy list. */
112 errmsg = NULL;
113 goto err;
114 }
115
116 const int http_status =
117 connection_fetch_from_buf_http(conn, &headers, 1024, NULL, NULL, 1024, 0);
118 if (http_status < 0) {
119 errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n";
120 goto err;
121 } else if (http_status == 0) {
122 /* no HTTP request yet. */
123 ret = 0;
124 goto done;
125 }
126
127 const int cmd_status = parse_http_command(headers, &command, &url);
128 if (cmd_status < 0) {
129 errmsg = "HTTP/1.0 400 Bad Request\r\n\r\n";
130 goto err;
131 } else if (strcmpstart(command, "GET")) {
132 errmsg = "HTTP/1.0 405 Method Not Allowed\r\n\r\n";
133 goto err;
134 }
135 tor_assert(url);
136
137 /* Where we expect the query to come for. */
138#define EXPECTED_URL_PATH "/metrics"
139#define EXPECTED_URL_PATH_LEN (sizeof(EXPECTED_URL_PATH) - 1) /* No NUL */
140
141 if (!strcmpstart(url, EXPECTED_URL_PATH) &&
142 strlen(url) == EXPECTED_URL_PATH_LEN) {
143 buf_t *data = metrics_get_output(the_format);
144
146 connection_buf_add_buf(conn, data);
147 buf_free(data);
148 } else {
149 errmsg = "HTTP/1.0 404 Not Found\r\n\r\n";
150 goto err;
151 }
152
153 ret = 0;
154 goto done;
155
156 err:
157 if (errmsg) {
158 log_info(LD_EDGE, "HTTP metrics error: saying %s", escaped(errmsg));
159 connection_buf_add(errmsg, strlen(errmsg), conn);
160 }
161 connection_mark_and_flush(conn);
162
163 done:
164 tor_free(headers);
166 tor_free(url);
167
168 return ret;
169}
170
171/** Parse metrics ports from options. On success, add the port to the ports
172 * list and return 0. On failure, set err_msg_out to a newly allocated string
173 * describing the problem and return -1. */
174int
176 char **err_msg_out)
177{
178 int num_elems, ok = 0, ret = -1;
179 const char *addrport_str = NULL, *fmt_str = NULL;
180 smartlist_t *elems = NULL;
181 port_cfg_t *cfg = NULL;
182
183 tor_assert(options);
184 tor_assert(ports);
185
186 /* No metrics port to configure, just move on . */
187 if (!options->MetricsPort_lines) {
188 return 0;
189 }
190
191 elems = smartlist_new();
192
193 /* Split between the protocol and the address/port. */
194 num_elems = smartlist_split_string(elems,
195 options->MetricsPort_lines->value, " ",
196 SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 2);
197 if (num_elems < 1) {
198 *err_msg_out = tor_strdup("MetricsPort is missing port.");
199 goto end;
200 }
201
202 addrport_str = smartlist_get(elems, 0);
203 if (num_elems >= 2) {
204 /* Parse the format if any. */
205 fmt_str = smartlist_get(elems, 1);
206 if (!strcasecmp(fmt_str, "prometheus")) {
208 } else {
209 tor_asprintf(err_msg_out, "MetricsPort unknown format: %s", fmt_str);
210 goto end;
211 }
212 }
213
214 /* Port configuration with default address. */
215 cfg = port_cfg_new(0);
217
218 /* Parse the port first. Then an address if any can be found. */
219 cfg->port = (int) tor_parse_long(addrport_str, 10, 0, 65535, &ok, NULL);
220 if (ok) {
221 tor_addr_parse(&cfg->addr, "127.0.0.1");
222 } else {
223 /* We probably have a host:port situation */
224 if (tor_addr_port_lookup(addrport_str, &cfg->addr,
225 (uint16_t *) &cfg->port) < 0) {
226 *err_msg_out = tor_strdup("MetricsPort address/port failed to parse or "
227 "resolve.");
228 goto end;
229 }
230 }
231 /* Add it to the ports list. */
232 smartlist_add(ports, cfg);
233
234 /* It is set. MetricsPort doesn't support the NoListen options or such that
235 * would prevent from being a real listener port. */
236 options->MetricsPort_set = 1;
237
238 /* Success. */
239 ret = 0;
240
241 end:
242 if (ret != 0) {
243 port_cfg_free(cfg);
244 }
245 SMARTLIST_FOREACH(elems, char *, e, tor_free(e));
246 smartlist_free(elems);
247 return ret;
248}
249
250/** Called when conn has gotten its socket closed. */
251int
253{
254 tor_assert(conn);
255
256 log_info(LD_EDGE, "Metrics connection reached EOF. Closing.");
257 connection_mark_for_close(conn);
258 return 0;
259}
260
261/** Called when conn has no more bytes left on its outbuf. Return 0 indicating
262 * success. */
263int
265{
266 tor_assert(conn);
267 return 0;
268}
269
270/** Initialize the subsystem. */
271void
273{
274}
275
276/** Cleanup and free any global memory of this subsystem. */
277void
279{
280}
int tor_addr_parse(tor_addr_t *addr, const char *src)
Definition: address.c:1349
Headers for address.h.
time_t approx_time(void)
Definition: approx_time.c:32
void buf_add_printf(buf_t *buf, const char *format,...)
Definition: buffers.c:568
buf_t * buf_new(void)
Definition: buffers.c:365
size_t buf_datalen(const buf_t *buf)
Definition: buffers.c:394
buf_t * buf_new_with_capacity(size_t size)
Definition: buffers.c:356
void buf_add_string(buf_t *buf, const char *string)
Definition: buffers.c:561
port_cfg_t * port_cfg_new(size_t namelen)
Definition: config.c:5870
tor_cmdline_mode_t command
Definition: config.c:2468
Header file for config.c.
Header for confline.c.
int connection_fetch_from_buf_http(connection_t *conn, char **headers_out, size_t max_headerlen, char **body_out, size_t *body_used, size_t max_bodylen, int force_complete)
Definition: connection.c:4340
void connection_buf_add_buf(connection_t *conn, buf_t *buf)
Definition: connection.c:4833
Header file for connection.c.
#define CONN_TYPE_METRICS
Definition: connection.h:79
#define CONN_TYPE_METRICS_LISTENER
Definition: connection.h:77
Header file for connection_or.c.
Base connection structure.
int parse_http_command(const char *headers, char **command_out, char **url_out)
Definition: directory.c:271
Header file for directory.c.
const char * escaped(const char *s)
Definition: escape.c:126
#define LD_EDGE
Definition: log.h:94
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:56
int metrics_connection_process_inbuf(connection_t *conn)
Definition: metrics.c:100
static void write_metrics_http_response(const size_t data_len, connection_t *conn)
Definition: metrics.c:51
int metrics_connection_reached_eof(connection_t *conn)
Definition: metrics.c:252
void metrics_init(void)
Definition: metrics.c:272
int metrics_connection_finished_flushing(connection_t *conn)
Definition: metrics.c:264
static bool metrics_request_allowed(const tor_addr_t *peer_addr)
Definition: metrics.c:41
buf_t * metrics_get_output(const metrics_format_t fmt)
Definition: metrics.c:71
static metrics_format_t the_format
Definition: metrics.c:36
void metrics_cleanup(void)
Definition: metrics.c:278
int metrics_parse_ports(or_options_t *options, smartlist_t *ports, char **err_msg_out)
Definition: metrics.c:175
Header for feature/metrics/metrics.c.
metrics_format_t
@ METRICS_FORMAT_PROMETHEUS
void metrics_store_get_output(const metrics_format_t fmt, const metrics_store_t *store, buf_t *data)
Header for lib/metrics/metrics_store.c.
Declarations for types used throughout the Tor networking system.
Master header file for Tor-specific functionality.
long tor_parse_long(const char *s, int base, long min, long max, int *ok, char **next)
Definition: parse_int.c:59
int metrics_policy_permits_address(const tor_addr_t *addr)
Definition: policies.c:1072
Header file for policies.c.
Listener port configuration structure.
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
Header for printf.c.
Header for proto_http.c.
int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
Definition: resolve.c:252
Header for resolve.c.
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, int flags, int max)
unsigned int type
Definition: connection_st.h:50
tor_addr_t addr
struct config_line_t * MetricsPort_lines
uint8_t type
Definition: port_cfg_st.h:23
tor_addr_t addr
Definition: port_cfg_st.h:20
bool supported
Definition: subsys.h:54
const struct smartlist_t *(* get_metrics)(void)
Definition: subsys.h:204
Header for subsysmgr.c.
const struct subsys_fns_t * tor_subsystems[]
void format_rfc1123_time(char *buf, time_t t)
Definition: time_fmt.c:213
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:103
int strcmpstart(const char *s1, const char *s2)
Definition: util_string.c:217