Line data Source code
1 : /* Copyright (c) 2001 Matej Pfajfar.
2 : * Copyright (c) 2001-2004, Roger Dingledine.
3 : * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 : * Copyright (c) 2007-2021, The Tor Project, Inc. */
5 : /* See LICENSE for licensing information */
6 :
7 : /**
8 : * @file transport_config.c
9 : * @brief Code to interpret the user's configuration of Tor's server
10 : * pluggable transports.
11 : **/
12 :
13 : #include "orconfig.h"
14 : #define RELAY_TRANSPORT_CONFIG_PRIVATE
15 : #include "feature/relay/transport_config.h"
16 :
17 : #include "lib/encoding/confline.h"
18 : #include "lib/encoding/keyval.h"
19 :
20 : #include "lib/container/smartlist.h"
21 :
22 : /* Required for dirinfo_type_t in or_options_t */
23 : #include "core/or/or.h"
24 : #include "app/config/config.h"
25 :
26 : #include "feature/relay/ext_orport.h"
27 : #include "feature/relay/routermode.h"
28 :
29 : /* Copied from config.c, we will refactor later in 29211. */
30 : #define REJECT(arg) \
31 : STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
32 :
33 : /** Given a ServerTransportListenAddr <b>line</b>, return its
34 : * <address:port> string. Return NULL if the line was not
35 : * well-formed.
36 : *
37 : * If <b>transport</b> is set, return NULL if the line is not
38 : * referring to <b>transport</b>.
39 : *
40 : * The returned string is allocated on the heap and it's the
41 : * responsibility of the caller to free it. */
42 : static char *
43 8 : get_bindaddr_from_transport_listen_line(const char *line,
44 : const char *transport)
45 : {
46 8 : smartlist_t *items = NULL;
47 8 : const char *parsed_transport = NULL;
48 8 : char *addrport = NULL;
49 8 : tor_addr_t addr;
50 8 : uint16_t port = 0;
51 :
52 8 : items = smartlist_new();
53 8 : smartlist_split_string(items, line, NULL,
54 : SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
55 :
56 8 : if (smartlist_len(items) < 2) {
57 1 : log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line.");
58 1 : goto err;
59 : }
60 :
61 7 : parsed_transport = smartlist_get(items, 0);
62 7 : addrport = tor_strdup(smartlist_get(items, 1));
63 :
64 : /* If 'transport' is given, check if it matches the one on the line */
65 7 : if (transport && strcmp(transport, parsed_transport))
66 0 : goto err;
67 :
68 : /* Validate addrport */
69 7 : if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) {
70 1 : log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr "
71 : "address '%s'", addrport);
72 1 : goto err;
73 : }
74 :
75 6 : goto done;
76 :
77 2 : err:
78 2 : tor_free(addrport);
79 2 : addrport = NULL;
80 :
81 8 : done:
82 23 : SMARTLIST_FOREACH(items, char*, s, tor_free(s));
83 8 : smartlist_free(items);
84 :
85 8 : return addrport;
86 : }
87 :
88 : /** Given the name of a pluggable transport in <b>transport</b>, check
89 : * the configuration file to see if the user has explicitly asked for
90 : * it to listen on a specific port. Return a <address:port> string if
91 : * so, otherwise NULL. */
92 : char *
93 0 : pt_get_bindaddr_from_config(const char *transport)
94 : {
95 0 : config_line_t *cl;
96 0 : const or_options_t *options = get_options();
97 :
98 0 : for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
99 0 : char *bindaddr =
100 0 : get_bindaddr_from_transport_listen_line(cl->value, transport);
101 0 : if (bindaddr)
102 0 : return bindaddr;
103 : }
104 :
105 : return NULL;
106 : }
107 :
108 : /** Given a ServerTransportOptions <b>line</b>, return a smartlist
109 : * with the options. Return NULL if the line was not well-formed.
110 : *
111 : * If <b>transport</b> is set, return NULL if the line is not
112 : * referring to <b>transport</b>.
113 : *
114 : * The returned smartlist and its strings are allocated on the heap
115 : * and it's the responsibility of the caller to free it. */
116 : STATIC smartlist_t *
117 20 : get_options_from_transport_options_line(const char *line,
118 : const char *transport)
119 : {
120 20 : smartlist_t *items = smartlist_new();
121 20 : smartlist_t *pt_options = smartlist_new();
122 20 : const char *parsed_transport = NULL;
123 :
124 20 : smartlist_split_string(items, line, NULL,
125 : SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
126 :
127 20 : if (smartlist_len(items) < 2) {
128 2 : log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line.");
129 2 : goto err;
130 : }
131 :
132 18 : parsed_transport = smartlist_get(items, 0);
133 : /* If 'transport' is given, check if it matches the one on the line */
134 18 : if (transport && strcmp(transport, parsed_transport))
135 7 : goto err;
136 :
137 35 : SMARTLIST_FOREACH_BEGIN(items, const char *, option) {
138 26 : if (option_sl_idx == 0) /* skip the transport field (first field)*/
139 11 : continue;
140 :
141 : /* validate that it's a k=v value */
142 15 : if (!string_is_key_value(LOG_WARN, option)) {
143 2 : log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option));
144 2 : goto err;
145 : }
146 :
147 : /* add it to the options smartlist */
148 13 : smartlist_add_strdup(pt_options, option);
149 13 : log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option));
150 24 : } SMARTLIST_FOREACH_END(option);
151 :
152 9 : goto done;
153 :
154 11 : err:
155 11 : SMARTLIST_FOREACH(pt_options, char*, s, tor_free(s));
156 11 : smartlist_free(pt_options);
157 11 : pt_options = NULL;
158 :
159 20 : done:
160 68 : SMARTLIST_FOREACH(items, char*, s, tor_free(s));
161 20 : smartlist_free(items);
162 :
163 20 : return pt_options;
164 : }
165 :
166 : /** Given the name of a pluggable transport in <b>transport</b>, check
167 : * the configuration file to see if the user has asked us to pass any
168 : * parameters to the pluggable transport. Return a smartlist
169 : * containing the parameters, otherwise NULL. */
170 : smartlist_t *
171 3 : pt_get_options_for_server_transport(const char *transport)
172 : {
173 3 : config_line_t *cl;
174 3 : const or_options_t *options = get_options();
175 :
176 9 : for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
177 8 : smartlist_t *options_sl =
178 8 : get_options_from_transport_options_line(cl->value, transport);
179 8 : if (options_sl)
180 2 : return options_sl;
181 : }
182 :
183 : return NULL;
184 : }
185 :
186 : /**
187 : * Legacy validation/normalization function for the server transport options.
188 : * Uses old_options as the previous options.
189 : *
190 : * Returns 0 on success, returns -1 and sets *msg to a newly allocated string
191 : * on error.
192 : */
193 : int
194 447 : options_validate_server_transport(const or_options_t *old_options,
195 : or_options_t *options,
196 : char **msg)
197 : {
198 447 : (void)old_options;
199 :
200 447 : if (BUG(!options))
201 0 : return -1;
202 :
203 447 : if (BUG(!msg))
204 0 : return -1;
205 :
206 447 : config_line_t *cl;
207 :
208 447 : if (options->ServerTransportPlugin && !server_mode(options)) {
209 11 : log_notice(LD_GENERAL, "Tor is not configured as a relay but you specified"
210 : " a ServerTransportPlugin line (%s). The ServerTransportPlugin "
211 : "line will be ignored.",
212 : escaped(options->ServerTransportPlugin->value));
213 : }
214 :
215 447 : if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) {
216 2 : log_notice(LD_GENERAL, "You need at least a single managed-proxy to "
217 : "specify a transport listen address. The "
218 : "ServerTransportListenAddr line will be ignored.");
219 : }
220 :
221 466 : for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
222 20 : if (pt_parse_transport_line(options, cl->value, 1, 1) < 0)
223 1 : REJECT("Invalid server transport line. See logs for details.");
224 : }
225 :
226 452 : for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
227 : /** If get_bindaddr_from_transport_listen_line() fails with
228 : 'transport' being NULL, it means that something went wrong
229 : while parsing the ServerTransportListenAddr line. */
230 8 : char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL);
231 8 : if (!bindaddr)
232 2 : REJECT("ServerTransportListenAddr did not parse. See logs for details.");
233 6 : tor_free(bindaddr);
234 : }
235 :
236 449 : for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
237 : /** If get_options_from_transport_options_line() fails with
238 : 'transport' being NULL, it means that something went wrong
239 : while parsing the ServerTransportOptions line. */
240 14 : smartlist_t *options_sl =
241 7 : get_options_from_transport_options_line(cl->value, NULL);
242 7 : if (!options_sl)
243 2 : REJECT("ServerTransportOptions did not parse. See logs for details.");
244 :
245 10 : SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp));
246 5 : smartlist_free(options_sl);
247 : }
248 :
249 : return 0;
250 : }
251 :
252 : /** Fetch the active option list, and take server pluggable transport actions
253 : * based on it. All of the things we do should survive being done repeatedly.
254 : * If present, <b>old_options</b> contains the previous value of the options.
255 : *
256 : * Return 0 if all goes well, return -1 if it's time to die.
257 : *
258 : * Note: We haven't moved all the "act on new configuration" logic
259 : * into the options_act* functions yet. Some is still in do_hup() and other
260 : * places.
261 : */
262 : int
263 213 : options_act_server_transport(const or_options_t *old_options)
264 : {
265 213 : (void)old_options;
266 :
267 213 : config_line_t *cl;
268 213 : const or_options_t *options = get_options();
269 213 : int running_tor = options->command == CMD_RUN_TOR;
270 :
271 : /* If we are a bridge with a pluggable transport proxy but no
272 : Extended ORPort, inform the user that they are missing out. */
273 213 : if (options->ServerTransportPlugin &&
274 15 : !options->ExtORPort_lines) {
275 3 : log_notice(LD_CONFIG, "We use pluggable transports but the Extended "
276 : "ORPort is disabled. Tor and your pluggable transports proxy "
277 : "communicate with each other via the Extended ORPort so it "
278 : "is suggested you enable it: it will also allow your Bridge "
279 : "to collect statistics about its clients that use pluggable "
280 : "transports. Please enable it using the ExtORPort torrc option "
281 : "(e.g. set 'ExtORPort auto').");
282 : }
283 :
284 : /* If we have an ExtORPort, initialize its auth cookie. */
285 217 : if (running_tor &&
286 4 : init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) {
287 0 : log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file.");
288 0 : return -1;
289 : }
290 :
291 213 : if (!options->DisableNetwork) {
292 175 : if (options->ServerTransportPlugin) {
293 30 : for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
294 15 : if (pt_parse_transport_line(options, cl->value, 0, 1) < 0) {
295 : // LCOV_EXCL_START
296 : log_warn(LD_BUG,
297 : "Previously validated ServerTransportPlugin line "
298 : "could not be added!");
299 : return -1;
300 : // LCOV_EXCL_STOP
301 : }
302 : }
303 : }
304 : }
305 :
306 : return 0;
307 : }
|