Get all default flags from port_cfg_new()

Now port_cfg_new() returns all default flags and
port_parse_config() acts on defaults returned by port_cfg_new()
that is uses the default port_cfg_t object returned by port_cfg_new()
and modifies them later according to the port specifications in
configuration files
Might close tor#32994.
This commit is contained in:
MrSquanchee 2020-03-12 12:56:49 +05:30 committed by teor
parent 3b4303e7f6
commit 1a9cbc5bb4
No known key found for this signature in database
GPG Key ID: 10FEAA0E7075672A
2 changed files with 94 additions and 95 deletions

8
changes/ticket32994 Normal file
View File

@ -0,0 +1,8 @@
o Code simplification and refactoring:
- port_new_cfg() returns default object with reasonable values.
- port_parse_config() uses this default object instead of
temporary variables.
- Files changed -> src/app/config/config.c
- Functions changed -> port_new_cfg() and port_parse_config()
- Closes ticket 32994.
- Patch by MrSquanchee

View File

@ -5886,12 +5886,18 @@ port_cfg_new(size_t namelen)
{ {
tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1); tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1);
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t) + namelen + 1); port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t) + namelen + 1);
/* entry_cfg flags */
cfg->entry_cfg.ipv4_traffic = 1; cfg->entry_cfg.ipv4_traffic = 1;
cfg->entry_cfg.ipv6_traffic = 1; cfg->entry_cfg.ipv6_traffic = 1;
cfg->entry_cfg.prefer_ipv6 = 1; cfg->entry_cfg.prefer_ipv6 = 1;
cfg->entry_cfg.dns_request = 1; cfg->entry_cfg.dns_request = 1;
cfg->entry_cfg.onion_traffic = 1; cfg->entry_cfg.onion_traffic = 1;
cfg->entry_cfg.prefer_ipv6_virtaddr = 1; cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
/* Other flags default to 0 due to tor_malloc_zero */
return cfg; return cfg;
} }
@ -6095,11 +6101,12 @@ port_parse_config(smartlist_t *out,
const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET; const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET;
int got_zero_port=0, got_nonzero_port=0; int got_zero_port=0, got_nonzero_port=0;
char *unix_socket_path = NULL; char *unix_socket_path = NULL;
port_cfg_t *cfg = NULL;
/* If there's no FooPort, then maybe make a default one. */ /* If there's no FooPort, then maybe make a default one. */
if (! ports) { if (! ports) {
if (defaultport && defaultaddr && out) { if (defaultport && defaultaddr && out) {
port_cfg_t *cfg = port_cfg_new(is_unix_socket ? strlen(defaultaddr) : 0); cfg = port_cfg_new(is_unix_socket ? strlen(defaultaddr) : 0);
cfg->type = listener_type; cfg->type = listener_type;
if (is_unix_socket) { if (is_unix_socket) {
tor_addr_make_unspec(&cfg->addr); tor_addr_make_unspec(&cfg->addr);
@ -6109,8 +6116,6 @@ port_parse_config(smartlist_t *out,
cfg->port = defaultport; cfg->port = defaultport;
tor_addr_parse(&cfg->addr, defaultaddr); tor_addr_parse(&cfg->addr, defaultaddr);
} }
cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
smartlist_add(out, cfg); smartlist_add(out, cfg);
} }
return 0; return 0;
@ -6124,28 +6129,12 @@ port_parse_config(smartlist_t *out,
for (; ports; ports = ports->next) { for (; ports; ports = ports->next) {
tor_addr_t addr; tor_addr_t addr;
tor_addr_make_unspec(&addr); tor_addr_make_unspec(&addr);
int port, ok,
int port; has_used_unix_socket_only_option = 0,
int sessiongroup = SESSION_GROUP_UNSET; is_unix_tagged_addr = 0;
unsigned isolation = ISO_DEFAULT;
int prefer_no_auth = 0;
int socks_iso_keep_alive = 0;
uint16_t ptmp=0; uint16_t ptmp=0;
int ok;
/* This must be kept in sync with port_cfg_new's defaults */
int no_listen = 0, no_advertise = 0, all_addrs = 0,
bind_ipv4_only = 0, bind_ipv6_only = 0,
ipv4_traffic = 1, ipv6_traffic = 1, prefer_ipv6 = 1, dns_request = 1,
onion_traffic = 1,
cache_ipv4 = 0, use_cached_ipv4 = 0,
cache_ipv6 = 0, use_cached_ipv6 = 0,
prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0,
relax_dirmode_check = 0,
has_used_unix_socket_only_option = 0, extended_errors = 0;
int is_unix_tagged_addr = 0;
const char *rest_of_line = NULL; const char *rest_of_line = NULL;
if (port_cfg_line_extract_addrport(ports->value, if (port_cfg_line_extract_addrport(ports->value,
&addrport, &is_unix_tagged_addr, &rest_of_line)<0) { &addrport, &is_unix_tagged_addr, &rest_of_line)<0) {
log_warn(LD_CONFIG, "Invalid %sPort line with unparsable address", log_warn(LD_CONFIG, "Invalid %sPort line with unparsable address",
@ -6221,17 +6210,20 @@ port_parse_config(smartlist_t *out,
} }
} }
/* Default port_cfg_t object initialization */
cfg = port_cfg_new(unix_socket_path ? strlen(unix_socket_path) : 0);
if (unix_socket_path && default_to_group_writable) if (unix_socket_path && default_to_group_writable)
group_writable = 1; cfg->is_group_writable = 1;
/* Now parse the rest of the options, if any. */ /* Now parse the rest of the options, if any. */
if (use_server_options) { if (use_server_options) {
/* This is a server port; parse advertising options */ /* This is a server port; parse advertising options */
SMARTLIST_FOREACH_BEGIN(elts, char *, elt) { SMARTLIST_FOREACH_BEGIN(elts, char *, elt) {
if (!strcasecmp(elt, "NoAdvertise")) { if (!strcasecmp(elt, "NoAdvertise")) {
no_advertise = 1; cfg->server_cfg.no_advertise = 1;
} else if (!strcasecmp(elt, "NoListen")) { } else if (!strcasecmp(elt, "NoListen")) {
no_listen = 1; cfg->server_cfg.no_listen = 1;
#if 0 #if 0
/* not implemented yet. */ /* not implemented yet. */
} else if (!strcasecmp(elt, "AllAddrs")) { } else if (!strcasecmp(elt, "AllAddrs")) {
@ -6239,33 +6231,36 @@ port_parse_config(smartlist_t *out,
all_addrs = 1; all_addrs = 1;
#endif /* 0 */ #endif /* 0 */
} else if (!strcasecmp(elt, "IPv4Only")) { } else if (!strcasecmp(elt, "IPv4Only")) {
bind_ipv4_only = 1; cfg->server_cfg.bind_ipv4_only = 1;
} else if (!strcasecmp(elt, "IPv6Only")) { } else if (!strcasecmp(elt, "IPv6Only")) {
bind_ipv6_only = 1; cfg->server_cfg.bind_ipv6_only = 1;
} else { } else {
log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'", log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'",
portname, escaped(elt)); portname, escaped(elt));
} }
} SMARTLIST_FOREACH_END(elt); } SMARTLIST_FOREACH_END(elt);
if (no_advertise && no_listen) { if (cfg->server_cfg.no_advertise && cfg->server_cfg.no_listen) {
log_warn(LD_CONFIG, "Tried to set both NoListen and NoAdvertise " log_warn(LD_CONFIG, "Tried to set both NoListen and NoAdvertise "
"on %sPort line '%s'", "on %sPort line '%s'",
portname, escaped(ports->value)); portname, escaped(ports->value));
goto err; goto err;
} }
if (bind_ipv4_only && bind_ipv6_only) { if (cfg->server_cfg.bind_ipv4_only &&
cfg->server_cfg.bind_ipv6_only) {
log_warn(LD_CONFIG, "Tried to set both IPv4Only and IPv6Only " log_warn(LD_CONFIG, "Tried to set both IPv4Only and IPv6Only "
"on %sPort line '%s'", "on %sPort line '%s'",
portname, escaped(ports->value)); portname, escaped(ports->value));
goto err; goto err;
} }
if (bind_ipv4_only && tor_addr_family(&addr) != AF_INET) { if (cfg->server_cfg.bind_ipv4_only &&
tor_addr_family(&addr) != AF_INET) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4", log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
portname); portname);
goto err; goto err;
} }
if (bind_ipv6_only && tor_addr_family(&addr) != AF_INET6) { if (cfg->server_cfg.bind_ipv6_only &&
tor_addr_family(&addr) != AF_INET6) {
log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6", log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
portname); portname);
goto err; goto err;
@ -6284,12 +6279,12 @@ port_parse_config(smartlist_t *out,
portname, escaped(elt)); portname, escaped(elt));
goto err; goto err;
} }
if (sessiongroup >= 0) { if (cfg->entry_cfg.session_group >= 0) {
log_warn(LD_CONFIG, "Multiple SessionGroup options on %sPort", log_warn(LD_CONFIG, "Multiple SessionGroup options on %sPort",
portname); portname);
goto err; goto err;
} }
sessiongroup = group; cfg->entry_cfg.session_group = group;
continue; continue;
} }
@ -6299,15 +6294,15 @@ port_parse_config(smartlist_t *out,
} }
if (!strcasecmp(elt, "GroupWritable")) { if (!strcasecmp(elt, "GroupWritable")) {
group_writable = !no; cfg->is_group_writable = !no;
has_used_unix_socket_only_option = 1; has_used_unix_socket_only_option = 1;
continue; continue;
} else if (!strcasecmp(elt, "WorldWritable")) { } else if (!strcasecmp(elt, "WorldWritable")) {
world_writable = !no; cfg->is_world_writable = !no;
has_used_unix_socket_only_option = 1; has_used_unix_socket_only_option = 1;
continue; continue;
} else if (!strcasecmp(elt, "RelaxDirModeCheck")) { } else if (!strcasecmp(elt, "RelaxDirModeCheck")) {
relax_dirmode_check = !no; cfg->relax_dirmode_check = !no;
has_used_unix_socket_only_option = 1; has_used_unix_socket_only_option = 1;
continue; continue;
} }
@ -6320,19 +6315,19 @@ port_parse_config(smartlist_t *out,
if (takes_hostnames) { if (takes_hostnames) {
if (!strcasecmp(elt, "IPv4Traffic")) { if (!strcasecmp(elt, "IPv4Traffic")) {
ipv4_traffic = ! no; cfg->entry_cfg.ipv4_traffic = ! no;
continue; continue;
} else if (!strcasecmp(elt, "IPv6Traffic")) { } else if (!strcasecmp(elt, "IPv6Traffic")) {
ipv6_traffic = ! no; cfg->entry_cfg.ipv6_traffic = ! no;
continue; continue;
} else if (!strcasecmp(elt, "PreferIPv6")) { } else if (!strcasecmp(elt, "PreferIPv6")) {
prefer_ipv6 = ! no; cfg->entry_cfg.prefer_ipv6 = ! no;
continue; continue;
} else if (!strcasecmp(elt, "DNSRequest")) { } else if (!strcasecmp(elt, "DNSRequest")) {
dns_request = ! no; cfg->entry_cfg.dns_request = ! no;
continue; continue;
} else if (!strcasecmp(elt, "OnionTraffic")) { } else if (!strcasecmp(elt, "OnionTraffic")) {
onion_traffic = ! no; cfg->entry_cfg.onion_traffic = ! no;
continue; continue;
} else if (!strcasecmp(elt, "OnionTrafficOnly")) { } else if (!strcasecmp(elt, "OnionTrafficOnly")) {
/* Only connect to .onion addresses. Equivalent to /* Only connect to .onion addresses. Equivalent to
@ -6343,46 +6338,50 @@ port_parse_config(smartlist_t *out,
"DNSRequest, IPv4Traffic, and/or IPv6Traffic instead.", "DNSRequest, IPv4Traffic, and/or IPv6Traffic instead.",
portname, escaped(elt)); portname, escaped(elt));
} else { } else {
ipv4_traffic = ipv6_traffic = dns_request = 0; cfg->entry_cfg.ipv4_traffic = 0;
cfg->entry_cfg.ipv6_traffic = 0;
cfg->entry_cfg.dns_request = 0;
} }
continue; continue;
} }
} }
if (!strcasecmp(elt, "CacheIPv4DNS")) { if (!strcasecmp(elt, "CacheIPv4DNS")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
cache_ipv4 = ! no; cfg->entry_cfg.cache_ipv4_answers = ! no;
continue; continue;
} else if (!strcasecmp(elt, "CacheIPv6DNS")) { } else if (!strcasecmp(elt, "CacheIPv6DNS")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
cache_ipv6 = ! no; cfg->entry_cfg.cache_ipv6_answers = ! no;
continue; continue;
} else if (!strcasecmp(elt, "CacheDNS")) { } else if (!strcasecmp(elt, "CacheDNS")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
cache_ipv4 = cache_ipv6 = ! no; cfg->entry_cfg.cache_ipv4_answers = ! no;
cfg->entry_cfg.cache_ipv6_answers = ! no;
continue; continue;
} else if (!strcasecmp(elt, "UseIPv4Cache")) { } else if (!strcasecmp(elt, "UseIPv4Cache")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
use_cached_ipv4 = ! no; cfg->entry_cfg.use_cached_ipv4_answers = ! no;
continue; continue;
} else if (!strcasecmp(elt, "UseIPv6Cache")) { } else if (!strcasecmp(elt, "UseIPv6Cache")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
use_cached_ipv6 = ! no; cfg->entry_cfg.use_cached_ipv6_answers = ! no;
continue; continue;
} else if (!strcasecmp(elt, "UseDNSCache")) { } else if (!strcasecmp(elt, "UseDNSCache")) {
warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
use_cached_ipv4 = use_cached_ipv6 = ! no; cfg->entry_cfg.use_cached_ipv4_answers = ! no;
cfg->entry_cfg.use_cached_ipv6_answers = ! no;
continue; continue;
} else if (!strcasecmp(elt, "PreferIPv6Automap")) { } else if (!strcasecmp(elt, "PreferIPv6Automap")) {
prefer_ipv6_automap = ! no; cfg->entry_cfg.prefer_ipv6_virtaddr = ! no;
continue; continue;
} else if (!strcasecmp(elt, "PreferSOCKSNoAuth")) { } else if (!strcasecmp(elt, "PreferSOCKSNoAuth")) {
prefer_no_auth = ! no; cfg->entry_cfg.socks_prefer_no_auth = ! no;
continue; continue;
} else if (!strcasecmp(elt, "KeepAliveIsolateSOCKSAuth")) { } else if (!strcasecmp(elt, "KeepAliveIsolateSOCKSAuth")) {
socks_iso_keep_alive = ! no; cfg->entry_cfg.socks_iso_keep_alive = ! no;
continue; continue;
} else if (!strcasecmp(elt, "ExtendedErrors")) { } else if (!strcasecmp(elt, "ExtendedErrors")) {
extended_errors = ! no; cfg->entry_cfg.extended_socks5_codes = ! no;
continue; continue;
} }
@ -6405,9 +6404,9 @@ port_parse_config(smartlist_t *out,
} }
if (no) { if (no) {
isolation &= ~isoflag; cfg->entry_cfg.isolation_flags &= ~isoflag;
} else { } else {
isolation |= isoflag; cfg->entry_cfg.isolation_flags |= isoflag;
} }
} SMARTLIST_FOREACH_END(elt); } SMARTLIST_FOREACH_END(elt);
} }
@ -6417,51 +6416,51 @@ port_parse_config(smartlist_t *out,
else else
got_zero_port = 1; got_zero_port = 1;
if (dns_request == 0 && listener_type == CONN_TYPE_AP_DNS_LISTENER) { if (cfg->entry_cfg.dns_request == 0 &&
listener_type == CONN_TYPE_AP_DNS_LISTENER) {
log_warn(LD_CONFIG, "You have a %sPort entry with DNS disabled; that " log_warn(LD_CONFIG, "You have a %sPort entry with DNS disabled; that "
"won't work.", portname); "won't work.", portname);
goto err; goto err;
} }
if (cfg->entry_cfg.ipv4_traffic == 0 &&
if (ipv4_traffic == 0 && ipv6_traffic == 0 && onion_traffic == 0 cfg->entry_cfg.ipv6_traffic == 0 &&
&& listener_type != CONN_TYPE_AP_DNS_LISTENER) { cfg->entry_cfg.onion_traffic == 0 &&
listener_type != CONN_TYPE_AP_DNS_LISTENER) {
log_warn(LD_CONFIG, "You have a %sPort entry with all of IPv4 and " log_warn(LD_CONFIG, "You have a %sPort entry with all of IPv4 and "
"IPv6 and .onion disabled; that won't work.", portname); "IPv6 and .onion disabled; that won't work.", portname);
goto err; goto err;
} }
if (cfg->entry_cfg.dns_request == 1 &&
if (dns_request == 1 && ipv4_traffic == 0 && ipv6_traffic == 0 cfg->entry_cfg.ipv4_traffic == 0 &&
&& listener_type != CONN_TYPE_AP_DNS_LISTENER) { cfg->entry_cfg.ipv6_traffic == 0 &&
listener_type != CONN_TYPE_AP_DNS_LISTENER) {
log_warn(LD_CONFIG, "You have a %sPort entry with DNSRequest enabled, " log_warn(LD_CONFIG, "You have a %sPort entry with DNSRequest enabled, "
"but IPv4 and IPv6 disabled; DNS-based sites won't work.", "but IPv4 and IPv6 disabled; DNS-based sites won't work.",
portname); portname);
goto err; goto err;
} }
if ( has_used_unix_socket_only_option && ! unix_socket_path) { if ( has_used_unix_socket_only_option && ! unix_socket_path) {
log_warn(LD_CONFIG, "You have a %sPort entry with GroupWritable, " log_warn(LD_CONFIG, "You have a %sPort entry with GroupWritable, "
"WorldWritable, or RelaxDirModeCheck, but it is not a " "WorldWritable, or RelaxDirModeCheck, but it is not a "
"unix socket.", portname); "unix socket.", portname);
goto err; goto err;
} }
if (!(cfg->entry_cfg.isolation_flags & ISO_SOCKSAUTH) &&
if (!(isolation & ISO_SOCKSAUTH) && socks_iso_keep_alive) { cfg->entry_cfg.socks_iso_keep_alive) {
log_warn(LD_CONFIG, "You have a %sPort entry with both " log_warn(LD_CONFIG, "You have a %sPort entry with both "
"NoIsolateSOCKSAuth and KeepAliveIsolateSOCKSAuth set.", "NoIsolateSOCKSAuth and KeepAliveIsolateSOCKSAuth set.",
portname); portname);
goto err; goto err;
} }
if (unix_socket_path &&
if (unix_socket_path && (isolation & ISO_CLIENTADDR)) { (cfg->entry_cfg.isolation_flags & ISO_CLIENTADDR)) {
/* `IsolateClientAddr` is nonsensical in the context of AF_LOCAL. /* `IsolateClientAddr` is nonsensical in the context of AF_LOCAL.
* just silently remove the isolation flag. * just silently remove the isolation flag.
*/ */
isolation &= ~ISO_CLIENTADDR; cfg->entry_cfg.isolation_flags &= ~ISO_CLIENTADDR;
} }
if (out && port) { if (out && port) {
size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0; size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0;
port_cfg_t *cfg = port_cfg_new(namelen);
if (unix_socket_path) { if (unix_socket_path) {
tor_addr_make_unspec(&cfg->addr); tor_addr_make_unspec(&cfg->addr);
memcpy(cfg->unix_addr, unix_socket_path, namelen + 1); memcpy(cfg->unix_addr, unix_socket_path, namelen + 1);
@ -6472,33 +6471,13 @@ port_parse_config(smartlist_t *out,
cfg->port = port; cfg->port = port;
} }
cfg->type = listener_type; cfg->type = listener_type;
cfg->is_world_writable = world_writable; if (! (cfg->entry_cfg.isolation_flags & ISO_SOCKSAUTH))
cfg->is_group_writable = group_writable;
cfg->relax_dirmode_check = relax_dirmode_check;
cfg->entry_cfg.isolation_flags = isolation;
cfg->entry_cfg.session_group = sessiongroup;
cfg->server_cfg.no_advertise = no_advertise;
cfg->server_cfg.no_listen = no_listen;
cfg->server_cfg.all_addrs = all_addrs;
cfg->server_cfg.bind_ipv4_only = bind_ipv4_only;
cfg->server_cfg.bind_ipv6_only = bind_ipv6_only;
cfg->entry_cfg.ipv4_traffic = ipv4_traffic;
cfg->entry_cfg.ipv6_traffic = ipv6_traffic;
cfg->entry_cfg.prefer_ipv6 = prefer_ipv6;
cfg->entry_cfg.dns_request = dns_request;
cfg->entry_cfg.onion_traffic = onion_traffic;
cfg->entry_cfg.cache_ipv4_answers = cache_ipv4;
cfg->entry_cfg.cache_ipv6_answers = cache_ipv6;
cfg->entry_cfg.use_cached_ipv4_answers = use_cached_ipv4;
cfg->entry_cfg.use_cached_ipv6_answers = use_cached_ipv6;
cfg->entry_cfg.prefer_ipv6_virtaddr = prefer_ipv6_automap;
cfg->entry_cfg.socks_prefer_no_auth = prefer_no_auth;
if (! (isolation & ISO_SOCKSAUTH))
cfg->entry_cfg.socks_prefer_no_auth = 1; cfg->entry_cfg.socks_prefer_no_auth = 1;
cfg->entry_cfg.socks_iso_keep_alive = socks_iso_keep_alive;
cfg->entry_cfg.extended_socks5_codes = extended_errors;
smartlist_add(out, cfg); smartlist_add(out, cfg);
/* out owns cfg now, don't re-use or free it */
cfg = NULL;
} else {
tor_free(cfg);
} }
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_clear(elts); smartlist_clear(elts);
@ -6524,10 +6503,22 @@ port_parse_config(smartlist_t *out,
retval = 0; retval = 0;
err: err:
/* There are two ways we can error out:
* 1. part way through the loop: cfg needs to be freed;
* 2. ending the loop normally: cfg is always NULL.
* In this case, cfg has either been:
* - added to out, then set to NULL, or
* - freed and set to NULL (because out is NULL, or port is 0).
*/
tor_free(cfg);
/* Free the other variables from the loop.
* elts is always non-NULL here, but it may or may not be empty. */
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts); smartlist_free(elts);
tor_free(unix_socket_path); tor_free(unix_socket_path);
tor_free(addrport); tor_free(addrport);
return retval; return retval;
} }