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 *
get_bindaddr_from_transport_listen_line(const char * line,const char * transport)43 get_bindaddr_from_transport_listen_line(const char *line,
44                                         const char *transport)
45 {
46   smartlist_t *items = NULL;
47   const char *parsed_transport = NULL;
48   char *addrport = NULL;
49   tor_addr_t addr;
50   uint16_t port = 0;
51 
52   items = smartlist_new();
53   smartlist_split_string(items, line, NULL,
54                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
55 
56   if (smartlist_len(items) < 2) {
57     log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line.");
58     goto err;
59   }
60 
61   parsed_transport = smartlist_get(items, 0);
62   addrport = tor_strdup(smartlist_get(items, 1));
63 
64   /* If 'transport' is given, check if it matches the one on the line */
65   if (transport && strcmp(transport, parsed_transport))
66     goto err;
67 
68   /* Validate addrport */
69   if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) {
70     log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr "
71              "address '%s'", addrport);
72     goto err;
73   }
74 
75   goto done;
76 
77  err:
78   tor_free(addrport);
79   addrport = NULL;
80 
81  done:
82   SMARTLIST_FOREACH(items, char*, s, tor_free(s));
83   smartlist_free(items);
84 
85   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 *
pt_get_bindaddr_from_config(const char * transport)93 pt_get_bindaddr_from_config(const char *transport)
94 {
95   config_line_t *cl;
96   const or_options_t *options = get_options();
97 
98   for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
99     char *bindaddr =
100       get_bindaddr_from_transport_listen_line(cl->value, transport);
101     if (bindaddr)
102       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 *
get_options_from_transport_options_line(const char * line,const char * transport)117 get_options_from_transport_options_line(const char *line,
118                                         const char *transport)
119 {
120   smartlist_t *items = smartlist_new();
121   smartlist_t *pt_options = smartlist_new();
122   const char *parsed_transport = NULL;
123 
124   smartlist_split_string(items, line, NULL,
125                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
126 
127   if (smartlist_len(items) < 2) {
128     log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line.");
129     goto err;
130   }
131 
132   parsed_transport = smartlist_get(items, 0);
133   /* If 'transport' is given, check if it matches the one on the line */
134   if (transport && strcmp(transport, parsed_transport))
135     goto err;
136 
137   SMARTLIST_FOREACH_BEGIN(items, const char *, option) {
138     if (option_sl_idx == 0) /* skip the transport field (first field)*/
139       continue;
140 
141     /* validate that it's a k=v value */
142     if (!string_is_key_value(LOG_WARN, option)) {
143       log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option));
144       goto err;
145     }
146 
147     /* add it to the options smartlist */
148     smartlist_add_strdup(pt_options, option);
149     log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option));
150   } SMARTLIST_FOREACH_END(option);
151 
152   goto done;
153 
154  err:
155   SMARTLIST_FOREACH(pt_options, char*, s, tor_free(s));
156   smartlist_free(pt_options);
157   pt_options = NULL;
158 
159  done:
160   SMARTLIST_FOREACH(items, char*, s, tor_free(s));
161   smartlist_free(items);
162 
163   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 *
pt_get_options_for_server_transport(const char * transport)171 pt_get_options_for_server_transport(const char *transport)
172 {
173   config_line_t *cl;
174   const or_options_t *options = get_options();
175 
176   for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
177     smartlist_t *options_sl =
178       get_options_from_transport_options_line(cl->value, transport);
179     if (options_sl)
180       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
options_validate_server_transport(const or_options_t * old_options,or_options_t * options,char ** msg)194 options_validate_server_transport(const or_options_t *old_options,
195                                   or_options_t *options,
196                                   char **msg)
197 {
198   (void)old_options;
199 
200   if (BUG(!options))
201     return -1;
202 
203   if (BUG(!msg))
204     return -1;
205 
206   config_line_t *cl;
207 
208   if (options->ServerTransportPlugin && !server_mode(options)) {
209     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   if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) {
216     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   for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
222     if (pt_parse_transport_line(options, cl->value, 1, 1) < 0)
223       REJECT("Invalid server transport line. See logs for details.");
224   }
225 
226   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     char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL);
231     if (!bindaddr)
232       REJECT("ServerTransportListenAddr did not parse. See logs for details.");
233     tor_free(bindaddr);
234   }
235 
236   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     smartlist_t *options_sl =
241       get_options_from_transport_options_line(cl->value, NULL);
242     if (!options_sl)
243       REJECT("ServerTransportOptions did not parse. See logs for details.");
244 
245     SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp));
246     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
options_act_server_transport(const or_options_t * old_options)263 options_act_server_transport(const or_options_t *old_options)
264 {
265   (void)old_options;
266 
267   config_line_t *cl;
268   const or_options_t *options = get_options();
269   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   if (options->ServerTransportPlugin &&
274       !options->ExtORPort_lines) {
275     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   if (running_tor &&
286       init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) {
287     log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file.");
288     return -1;
289   }
290 
291   if (!options->DisableNetwork) {
292     if (options->ServerTransportPlugin) {
293       for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
294         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 }
308