transport_config.c (9985B)
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 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 * 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 * 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 * 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 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 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 }