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